diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e83778dac3..3d66321d71 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,7 @@ name: CI on: + workflow_dispatch: push: pull_request: paths-ignore: @@ -10,23 +11,131 @@ jobs: build: strategy: matrix: - os: [ubuntu-latest, macos-latest, windows-latest] + os: [ubuntu-22.04, macos-13, windows-latest] fail-fast: false runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: lfs: true - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - name: Set up JDK 21 + uses: actions/setup-java@v4 with: - java-version: '11' + java-version: '21' distribution: 'adopt' cache: gradle - name: Build with Gradle run: ./gradlew build --stacktrace --scan + - uses: actions/upload-artifact@v3 + if: failure() + with: + name: error-reports-${{ matrix.os }} + path: ${{ github.workspace }}/desktop/build/reports - name: cache nodes dependencies uses: actions/upload-artifact@v3 with: + include-hidden-files: true name: cached-localnet path: .localnet + - name: Install dependencies + if: ${{ matrix.os == 'ubuntu-22.04' }} + run: | + sudo apt update + sudo apt install -y rpm libfuse2 flatpak flatpak-builder appstream + flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo + - name: Install WiX Toolset + if: ${{ matrix.os == 'windows-latest' }} + run: | + Invoke-WebRequest -Uri 'https://github.com/wixtoolset/wix3/releases/download/wix314rtm/wix314.exe' -OutFile wix314.exe + .\wix314.exe /quiet /norestart + shell: powershell + - name: Build Haveno Installer + run: | + ./gradlew clean build --refresh-keys --refresh-dependencies + ./gradlew packageInstallers + working-directory: . + + # get version from jar + - name: Set Version Unix + if: ${{ matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-13' }} + run: | + export VERSION=$(ls desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 | grep -Eo 'desktop-[0-9]+\.[0-9]+\.[0-9]+' | sed 's/desktop-//') + echo "VERSION=$VERSION" >> $GITHUB_ENV + - name: Set Version Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + $VERSION = (Get-ChildItem -Path desktop\build\temp-*/binaries\desktop-*.jar.SHA-256).Name -replace 'desktop-', '' -replace '-.*', '' + "VERSION=$VERSION" | Out-File -FilePath $env:GITHUB_ENV -Append + shell: powershell + + - name: Move Release Files on Unix + if: ${{ matrix.os == 'ubuntu-22.04' || matrix.os == 'macos-13' }} + run: | + if [ "${{ matrix.os }}" == "ubuntu-22.04" ]; then + mkdir ${{ github.workspace }}/release-linux-rpm + mkdir ${{ github.workspace }}/release-linux-deb + mkdir ${{ github.workspace }}/release-linux-flatpak + mkdir ${{ github.workspace }}/release-linux-appimage + mv desktop/build/temp-*/binaries/haveno-*.rpm ${{ github.workspace }}/release-linux-rpm/haveno-v${{ env.VERSION }}-linux-x86_64-installer.rpm + mv desktop/build/temp-*/binaries/haveno_*.deb ${{ github.workspace }}/release-linux-deb/haveno-v${{ env.VERSION }}-linux-x86_64-installer.deb + mv desktop/build/temp-*/binaries/*.flatpak ${{ github.workspace }}/release-linux-flatpak/haveno-v${{ env.VERSION }}-linux-x86_64.flatpak + mv desktop/build/temp-*/binaries/haveno_*.AppImage ${{ github.workspace }}/release-linux-appimage/haveno-v${{ env.VERSION }}-linux-x86_64.AppImage + cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-linux-deb + cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-linux-rpm + cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-linux-appimage + cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-linux-flatpak + else + mkdir ${{ github.workspace }}/release-macos + mv desktop/build/temp-*/binaries/Haveno-*.dmg ${{ github.workspace }}/release-macos/haveno-v${{ env.VERSION }}-macos-installer.dmg + cp desktop/build/temp-*/binaries/desktop-*.jar.SHA-256 ${{ github.workspace }}/release-macos + fi + shell: bash + - name: Move Release Files on Windows + if: ${{ matrix.os == 'windows-latest' }} + run: | + mkdir ${{ github.workspace }}/release-windows + Move-Item -Path desktop\build\temp-*/binaries\Haveno-*.exe -Destination ${{ github.workspace }}/release-windows/haveno-v${{ env.VERSION }}-windows-installer.exe + Move-Item -Path desktop\build\temp-*/binaries\desktop-*.jar.SHA-256 -Destination ${{ github.workspace }}/release-windows + shell: powershell + + # win + - uses: actions/upload-artifact@v3 + name: "Windows artifacts" + if: ${{ matrix.os == 'windows-latest'}} + with: + name: haveno-windows + path: ${{ github.workspace }}/release-windows + # macos + - uses: actions/upload-artifact@v3 + name: "macOS artifacts" + if: ${{ matrix.os == 'macos-13' }} + with: + name: haveno-macos + path: ${{ github.workspace }}/release-macos + # linux + - uses: actions/upload-artifact@v3 + name: "Linux - deb artifact" + if: ${{ matrix.os == 'ubuntu-22.04' }} + with: + name: haveno-linux-deb + path: ${{ github.workspace }}/release-linux-deb + - uses: actions/upload-artifact@v3 + name: "Linux - rpm artifact" + if: ${{ matrix.os == 'ubuntu-22.04' }} + with: + name: haveno-linux-rpm + path: ${{ github.workspace }}/release-linux-rpm + + - uses: actions/upload-artifact@v3 + name: "Linux - AppImage artifact" + if: ${{ matrix.os == 'ubuntu-22.04' }} + with: + name: haveno-linux-appimage + path: ${{ github.workspace }}/release-linux-appimage + + - uses: actions/upload-artifact@v3 + name: "Linux - flatpak artifact" + if: ${{ matrix.os == 'ubuntu-22.04' }} + with: + name: haveno-linux-flatpak + path: ${{ github.workspace }}/release-linux-flatpak diff --git a/.github/workflows/codacy-code-reporter.yml b/.github/workflows/codacy-code-reporter.yml index 152d2f9b5e..1bf5b3cec5 100644 --- a/.github/workflows/codacy-code-reporter.yml +++ b/.github/workflows/codacy-code-reporter.yml @@ -7,15 +7,16 @@ permissions: jobs: build: + if: github.repository == 'haveno-dex/haveno' name: Publish coverage runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - - name: Set up JDK 11 - uses: actions/setup-java@v3 + - name: Set up JDK 21 + uses: actions/setup-java@v4 with: - java-version: '11' + java-version: '21' distribution: 'adopt' - name: Build with Gradle diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2cebc57e9e..8b8699ad69 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -33,7 +33,14 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'adopt' + cache: gradle # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL @@ -47,8 +54,8 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below). - - name: Autobuild - uses: github/codeql-action/autobuild@v2 +# - name: Autobuild +# uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -57,8 +64,8 @@ jobs: # and modify them (or add more) to build your code if your project # uses a compiled language - #- run: | - # ./gradlew build + - name: Build + run: ./gradlew build --stacktrace -x test -x checkstyleMain -x checkstyleTest - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 66f702c248..d29b0e28eb 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -10,16 +10,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Bounty explanation - uses: peter-evans/create-or-update-comment@v2 + uses: peter-evans/create-or-update-comment@v3 if: github.event.label.name == '💰bounty' with: token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} body: > - There is a bounty on this issue, the amount is in the title. The reward will be awarded to the first person or group of people who resolves this issue. + There is a bounty on this issue. The amount is in the title. The reward will be awarded to the first person or group of people whose solution is accepted and merged. - If you are starting to work on this bounty, please write a comment, so that we can assign the issue to you. We expect contributors to provide a PR in a reasonable time frame or, in case of an extensive work, updates on their progresses. We will unassign the issue if we feel the assignee is not responsive or has abandoned the task. + In some cases, we may assign the issue to specific contributors. We expect contributors to provide a PR in a reasonable time frame or, in case of an extensive work, updates on their progress. We will unassign the issue if we feel the assignee is not responsive or has abandoned the task. Read the [full conditions and details](https://github.com/haveno-dex/haveno/blob/master/docs/bounties.md) of our bounty system. diff --git a/.gitignore b/.gitignore index a8e80e085f..28973e8838 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,8 @@ deploy /monitor/monitor-tor/* .java-version .localnet -.vscode \ No newline at end of file +.vscode +.vim/* +*/.factorypath +.flatpak-builder +exchange.haveno.Haveno.yaml diff --git a/Makefile b/Makefile index ee212d569d..51d55af341 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ haveno-apps: refresh-deps: ./gradlew --write-verification-metadata sha256 && ./gradlew build --refresh-keys --refresh-dependencies -x test -x checkstyleMain -x checkstyleTest -deploy: +deploy-screen: # create a new screen session named 'localnet' screen -dmS localnet # deploy each node in its own named screen window @@ -40,23 +40,21 @@ deploy: screen -S localnet -X screen -t $$target; \ screen -S localnet -p $$target -X stuff "make $$target\n"; \ done; - # give bitcoind rpc server time to start + # give time to start sleep 5 -bitcoind: - ./.localnet/bitcoind \ - -regtest \ - -peerbloomfilters=1 \ - -datadir=.localnet/ \ - -rpcuser=haveno \ - -rpcpassword=1234 - -btc-blocks: - ./.localnet/bitcoin-cli \ - -regtest \ - -rpcuser=haveno \ - -rpcpassword=1234 \ - generatetoaddress 101 bcrt1q6j90vywv8x7eyevcnn2tn2wrlg3vsjlsvt46qz +deploy-tmux: + # Start a new tmux session named 'localnet' (detached) + tmux new-session -d -s localnet -n main "make seednode-local" + # Split the window into panes and run each node in its own pane + tmux split-window -h -t localnet "make user1-desktop-local" # Split horizontally for user1 + tmux split-window -v -t localnet:0.0 "make user2-desktop-local" # Split vertically on the left for user2 + tmux split-window -v -t localnet:0.1 "make arbitrator-desktop-local" # Split vertically on the right for arbitrator + tmux select-layout -t localnet tiled + # give time to start + sleep 5 + # Attach to the tmux session + tmux attach-session -t localnet .PHONY: build seednode localnet @@ -69,12 +67,12 @@ monerod1-local: --hide-my-port \ --data-dir .localnet/xmr_local/node1 \ --p2p-bind-ip 127.0.0.1 \ - --p2p-bind-port 48080 \ - --rpc-bind-port 48081 \ - --no-zmq \ - --add-exclusive-node 127.0.0.1:28080 \ + --log-level 0 \ + --add-exclusive-node 127.0.0.1:48080 \ + --add-exclusive-node 127.0.0.1:58080 \ --rpc-access-control-origins http://localhost:8080 \ - --fixed-difficulty 400 + --fixed-difficulty 500 \ + --disable-rpc-ban \ monerod2-local: ./.localnet/monerod \ @@ -83,21 +81,34 @@ monerod2-local: --hide-my-port \ --data-dir .localnet/xmr_local/node2 \ --p2p-bind-ip 127.0.0.1 \ - --rpc-bind-ip 0.0.0.0 \ - --no-zmq \ + --p2p-bind-port 48080 \ + --rpc-bind-port 48081 \ + --zmq-rpc-bind-port 48082 \ + --log-level 0 \ --confirm-external-bind \ + --add-exclusive-node 127.0.0.1:28080 \ + --add-exclusive-node 127.0.0.1:58080 \ + --rpc-access-control-origins http://localhost:8080 \ + --fixed-difficulty 500 \ + --disable-rpc-ban \ + +monerod3-local: + ./.localnet/monerod \ + --testnet \ + --no-igd \ + --hide-my-port \ + --data-dir .localnet/xmr_local/node3 \ + --p2p-bind-ip 127.0.0.1 \ + --p2p-bind-port 58080 \ + --rpc-bind-port 58081 \ + --zmq-rpc-bind-port 58082 \ + --log-level 0 \ + --confirm-external-bind \ + --add-exclusive-node 127.0.0.1:28080 \ --add-exclusive-node 127.0.0.1:48080 \ --rpc-access-control-origins http://localhost:8080 \ - --fixed-difficulty 400 - -funding-wallet-stagenet: - ./.localnet/monero-wallet-rpc \ - --rpc-bind-port 18084 \ - --rpc-login rpc_user:abc123 \ - --rpc-access-control-origins http://localhost:8080 \ - --wallet-dir ./.localnet \ - --daemon-ssl-allow-any-cert \ - --daemon-address http://127.0.0.1:38081 + --fixed-difficulty 500 \ + --disable-rpc-ban \ #--proxy 127.0.0.1:49775 \ @@ -108,7 +119,24 @@ funding-wallet-local: --rpc-bind-port 28084 \ --rpc-login rpc_user:abc123 \ --rpc-access-control-origins http://localhost:8080 \ - --wallet-dir ./.localnet + --wallet-dir ./.localnet \ + +funding-wallet-stagenet: + ./.localnet/monero-wallet-rpc \ + --stagenet \ + --rpc-bind-port 38084 \ + --rpc-login rpc_user:abc123 \ + --rpc-access-control-origins http://localhost:8080 \ + --wallet-dir ./.localnet \ + --daemon-ssl-allow-any-cert \ + --daemon-address http://127.0.0.1:38081 \ + +funding-wallet-mainnet: + ./.localnet/monero-wallet-rpc \ + --rpc-bind-port 18084 \ + --rpc-login rpc_user:abc123 \ + --rpc-access-control-origins http://localhost:8080 \ + --wallet-dir ./.localnet \ # use .bat extension for windows binaries APP_EXT := @@ -144,7 +172,8 @@ arbitrator-daemon-local: --appName=haveno-XMR_LOCAL_arbitrator \ --apiPassword=apitest \ --apiPort=9998 \ - --passwordRequired=false + --passwordRequired=false \ + --useNativeXmrWallet=false \ arbitrator-desktop-local: # Arbitrator needs to be registered before making trades @@ -155,7 +184,8 @@ arbitrator-desktop-local: --nodePort=4444 \ --appName=haveno-XMR_LOCAL_arbitrator \ --apiPassword=apitest \ - --apiPort=9998 + --apiPort=9998 \ + --useNativeXmrWallet=false \ arbitrator2-daemon-local: # Arbitrator needs to be registered before making trades @@ -166,7 +196,8 @@ arbitrator2-daemon-local: --nodePort=7777 \ --appName=haveno-XMR_LOCAL_arbitrator2 \ --apiPassword=apitest \ - --apiPort=10001 + --apiPort=10001 \ + --useNativeXmrWallet=false \ arbitrator2-desktop-local: # Arbitrator needs to be registered before making trades @@ -177,7 +208,8 @@ arbitrator2-desktop-local: --nodePort=7777 \ --appName=haveno-XMR_LOCAL_arbitrator2 \ --apiPassword=apitest \ - --apiPort=10001 + --apiPort=10001 \ + --useNativeXmrWallet=false \ user1-daemon-local: ./haveno-daemon$(APP_EXT) \ @@ -189,7 +221,8 @@ user1-daemon-local: --apiPassword=apitest \ --apiPort=9999 \ --walletRpcBindPort=38091 \ - --passwordRequired=false + --passwordRequired=false \ + --useNativeXmrWallet=false \ user1-desktop-local: ./haveno-desktop$(APP_EXT) \ @@ -201,7 +234,8 @@ user1-desktop-local: --apiPassword=apitest \ --apiPort=9999 \ --walletRpcBindPort=38091 \ - --logLevel=info + --logLevel=info \ + --useNativeXmrWallet=false \ user2-desktop-local: ./haveno-desktop$(APP_EXT) \ @@ -212,7 +246,8 @@ user2-desktop-local: --appName=haveno-XMR_LOCAL_user2 \ --apiPassword=apitest \ --apiPort=10000 \ - --walletRpcBindPort=38092 + --walletRpcBindPort=38092 \ + --useNativeXmrWallet=false \ user2-daemon-local: ./haveno-daemon$(APP_EXT) \ @@ -224,7 +259,33 @@ user2-daemon-local: --apiPassword=apitest \ --apiPort=10000 \ --walletRpcBindPort=38092 \ - --passwordRequired=false + --passwordRequired=false \ + --useNativeXmrWallet=false \ + +user3-desktop-local: + ./haveno-desktop$(APP_EXT) \ + --baseCurrencyNetwork=XMR_LOCAL \ + --useLocalhostForP2P=true \ + --useDevPrivilegeKeys=true \ + --nodePort=7778 \ + --appName=haveno-XMR_LOCAL_user3 \ + --apiPassword=apitest \ + --apiPort=10002 \ + --walletRpcBindPort=38093 \ + --useNativeXmrWallet=false \ + +user3-daemon-local: + ./haveno-daemon$(APP_EXT) \ + --baseCurrencyNetwork=XMR_LOCAL \ + --useLocalhostForP2P=true \ + --useDevPrivilegeKeys=true \ + --nodePort=7778 \ + --appName=haveno-XMR_LOCAL_user3 \ + --apiPassword=apitest \ + --apiPort=10002 \ + --walletRpcBindPort=38093 \ + --passwordRequired=false \ + --useNativeXmrWallet=false \ # Stagenet network @@ -241,7 +302,7 @@ monerod-stagenet-custom: --p2p-bind-port 39080 \ --rpc-bind-port 39081 \ --bootstrap-daemon-address auto \ - --rpc-access-control-origins http://localhost:8080 + --rpc-access-control-origins http://localhost:8080 \ seednode-stagenet: ./haveno-seednode$(APP_EXT) \ @@ -250,7 +311,7 @@ seednode-stagenet: --useDevPrivilegeKeys=false \ --nodePort=3002 \ --appName=haveno-XMR_STAGENET_Seed_3002 \ - --xmrNode=http://127.0.0.1:38081 + --xmrNode=http://127.0.0.1:38081 \ seednode2-stagenet: ./haveno-seednode$(APP_EXT) \ @@ -259,7 +320,7 @@ seednode2-stagenet: --useDevPrivilegeKeys=false \ --nodePort=3003 \ --appName=haveno-XMR_STAGENET_Seed_3003 \ - --xmrNode=http://127.0.0.1:38081 + --xmrNode=http://127.0.0.1:38081 \ arbitrator-daemon-stagenet: # Arbitrator needs to be registered before making trades @@ -267,12 +328,13 @@ arbitrator-daemon-stagenet: --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3100 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_arbitrator \ --apiPassword=apitest \ --apiPort=3200 \ --passwordRequired=false \ - --xmrNode=http://127.0.0.1:38081 + --xmrNode=http://127.0.0.1:38081 \ + --useNativeXmrWallet=false \ # Arbitrator needs to be registered before making trades arbitrator-desktop-stagenet: @@ -280,63 +342,80 @@ arbitrator-desktop-stagenet: --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3100 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_arbitrator \ --apiPassword=apitest \ --apiPort=3200 \ - --xmrNode=http://127.0.0.1:38081 + --xmrNode=http://127.0.0.1:38081 \ + --useNativeXmrWallet=false \ user1-daemon-stagenet: ./haveno-daemon$(APP_EXT) \ --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3101 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_user1 \ --apiPassword=apitest \ --apiPort=3201 \ - --passwordRequired=false + --passwordRequired=false \ + --useNativeXmrWallet=false \ user1-desktop-stagenet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3101 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_user1 \ --apiPassword=apitest \ - --apiPort=3201 + --apiPort=3201 \ + --useNativeXmrWallet=false \ user2-daemon-stagenet: ./haveno-daemon$(APP_EXT) \ --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3102 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_user2 \ --apiPassword=apitest \ --apiPort=3202 \ - --passwordRequired=false + --passwordRequired=false \ + --useNativeXmrWallet=false \ user2-desktop-stagenet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3102 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_user2 \ --apiPassword=apitest \ - --apiPort=3202 + --apiPort=3202 \ + --useNativeXmrWallet=false \ user3-desktop-stagenet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_STAGENET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=3103 \ + --nodePort=9999 \ --appName=haveno-XMR_STAGENET_user3 \ --apiPassword=apitest \ - --apiPort=3203 + --apiPort=3203 \ + --useNativeXmrWallet=false \ + +haveno-desktop-stagenet: + ./haveno-desktop$(APP_EXT) \ + --baseCurrencyNetwork=XMR_STAGENET \ + --useLocalhostForP2P=false \ + --useDevPrivilegeKeys=false \ + --nodePort=9999 \ + --appName=Haveno \ + --apiPassword=apitest \ + --apiPort=3204 \ + --useNativeXmrWallet=false \ # Mainnet network @@ -352,7 +431,7 @@ seednode: --useDevPrivilegeKeys=false \ --nodePort=1002 \ --appName=haveno-XMR_MAINNET_Seed_1002 \ - --xmrNode=http://127.0.0.1:18081 + --xmrNode=http://127.0.0.1:18081 \ seednode2: ./haveno-seednode$(APP_EXT) \ @@ -361,81 +440,116 @@ seednode2: --useDevPrivilegeKeys=false \ --nodePort=1003 \ --appName=haveno-XMR_MAINNET_Seed_1003 \ - --xmrNode=http://127.0.0.1:18081 + --xmrNode=http://127.0.0.1:18081 \ -arbitrator-daemon: +arbitrator-daemon-mainnet: # Arbitrator needs to be registered before making trades ./haveno-daemon$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1100 \ + --nodePort=9999 \ --appName=haveno-XMR_MAINNET_arbitrator \ --apiPassword=apitest \ --apiPort=1200 \ --passwordRequired=false \ - --xmrNode=http://127.0.0.1:18081 + --xmrNode=http://127.0.0.1:18081 \ + --useNativeXmrWallet=false \ -# Arbitrator needs to be registered before making trades -arbitrator-desktop: +arbitrator-desktop-mainnet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1100 \ + --nodePort=9999 \ --appName=haveno-XMR_MAINNET_arbitrator \ --apiPassword=apitest \ --apiPort=1200 \ - --xmrNode=http://127.0.0.1:18081 + --xmrNode=http://127.0.0.1:18081 \ + --useNativeXmrWallet=false \ -user1-daemon: +haveno-daemon-mainnet: ./haveno-daemon$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1101 \ - --appName=haveno-XMR_MAINNET_user1 \ + --nodePort=9999 \ + --appName=Haveno \ --apiPassword=apitest \ --apiPort=1201 \ - --passwordRequired=false + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ -user1-desktop: +haveno-desktop-mainnet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1101 \ - --appName=haveno-XMR_MAINNET_user1 \ + --nodePort=9999 \ + --appName=Haveno \ --apiPassword=apitest \ - --apiPort=1201 + --apiPort=1201 \ + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ -user2-daemon: +user1-daemon-mainnet: ./haveno-daemon$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1102 \ - --appName=haveno-XMR_MAINNET_user2 \ + --nodePort=9999 \ + --appName=haveno-XMR_MAINNET_user1 \ --apiPassword=apitest \ --apiPort=1202 \ - --passwordRequired=false + --passwordRequired=false \ + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ -user2-desktop: +user1-desktop-mainnet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1102 \ + --nodePort=9999 \ + --appName=haveno-XMR_MAINNET_user1 \ + --apiPassword=apitest \ + --apiPort=1202 \ + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ + +user2-daemon-mainnet: + ./haveno-daemon$(APP_EXT) \ + --baseCurrencyNetwork=XMR_MAINNET \ + --useLocalhostForP2P=false \ + --useDevPrivilegeKeys=false \ + --nodePort=9999 \ --appName=haveno-XMR_MAINNET_user2 \ --apiPassword=apitest \ - --apiPort=1202 + --apiPort=1203 \ + --passwordRequired=false \ + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ -user3-desktop: +user2-desktop-mainnet: ./haveno-desktop$(APP_EXT) \ --baseCurrencyNetwork=XMR_MAINNET \ --useLocalhostForP2P=false \ --useDevPrivilegeKeys=false \ - --nodePort=1103 \ + --nodePort=9999 \ + --appName=haveno-XMR_MAINNET_user2 \ + --apiPassword=apitest \ + --apiPort=1203 \ + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ + +user3-desktop-mainnet: + ./haveno-desktop$(APP_EXT) \ + --baseCurrencyNetwork=XMR_MAINNET \ + --useLocalhostForP2P=false \ + --useDevPrivilegeKeys=false \ + --nodePort=9999 \ --appName=haveno-XMR_MAINNET_user3 \ --apiPassword=apitest \ - --apiPort=1203 \ No newline at end of file + --apiPort=1204 \ + --useNativeXmrWallet=false \ + --ignoreLocalXmrNode=false \ diff --git a/README.md b/README.md index 551dcb0843..6f3f24a596 100644 --- a/README.md +++ b/README.md @@ -1,60 +1,62 @@ <div align="center"> <img src="https://raw.githubusercontent.com/haveno-dex/haveno-meta/721e52919b28b44d12b6e1e5dac57265f1c05cda/logo/haveno_logo_landscape.svg" alt="Haveno logo"> - [](https://app.codacy.com/gh/haveno-dex/haveno/dashboard)  - [](https://github.com/orgs/haveno-dex/projects/2) | + [](https://github.com/haveno-dex/haveno/issues?q=is%3Aopen+is%3Aissue+label%3A%F0%9F%92%B0bounty) [](https://twitter.com/havenodex) [](https://matrix.to/#/#haveno:monero.social) [](https://github.com/haveno-dex/.github/blob/master/CODE_OF_CONDUCT.md) </div> ## What is Haveno? -Haveno (pronounced ha‧ve‧no) is a platform for people who want to exchange [Monero](https://getmonero.org) for fiat currencies like EUR, GBP, and USD or other cryptocurrencies like BTC, ETH, BCH, and WOW. +Haveno (pronounced ha‧ve‧no) is an open source platform to exchange [Monero](https://getmonero.org) for fiat currencies like USD, EUR, and GBP or other cryptocurrencies like BTC, ETH, BCH, and WOW. Main features: -- All communications are routed through **Tor**, to preserve your privacy +- Communications are routed through **Tor**, to preserve your privacy. -- Trades are **peer-to-peer**: trades on Haveno will happen between people only, there is no central authority. +- Trades are **peer-to-peer**: trades on Haveno happen between people only, there is no central authority. -- Trades are **non-custodial**: Haveno provides arbitration in case something goes wrong during the trade, but we will never have access to your funds. +- Trades are **non-custodial**: Haveno supports arbitration in case something goes wrong during the trade, but arbitrators never have access to your funds. -- There is **No token**, because we don't need it. Transactions between traders are secured by non-custodial multisignature transactions on the Monero network. - -- The revenue generated by Haveno will be managed by an entity called Council (more info soon), composed by members of the Monero/Haveno community, not the Haveno Core Team and will be used to **fund Haveno and Monero** development. +- There is **No token**, because it's not needed. Transactions between traders are secured by non-custodial multisignature transactions on the Monero network. See the [FAQ on our website](https://haveno.exchange/faq/) for more information. -## Status of the project +## Installing Haveno -A live test network is online and users can already run Haveno and make test trades between each others using Monero's stagenet. See the [instructions to build Haveno and connect to the network](https://github.com/haveno-dex/haveno/blob/master/docs/installing.md). Note that Haveno is still very much in development. If you find issues or bugs, please let us know. +Haveno can be installed on Linux, macOS, and Windows by using a third party installer and network. -Main repositories: +> [!note] +> The official Haveno repository does not support making real trades directly. +> +> To make real trades with Haveno, first find a third party network, and then use their installer or build their repository. We do not endorse any networks at this time. + +A test network is also available for users to make test trades using Monero's stagenet. See the [instructions](https://github.com/haveno-dex/haveno/blob/master/docs/installing.md) to build Haveno and connect to the test network. + +Alternatively, you can [create your own mainnet network](create-mainnet.md). + +Note that Haveno is being actively developed. If you find issues or bugs, please let us know. + +## Main repositories - **[haveno](https://github.com/haveno-dex/haveno)** - This repository. The core of Haveno. -- **[haveno-ui](https://github.com/haveno-dex/haveno-ui)** - The user interface. - **[haveno-ts](https://github.com/haveno-dex/haveno-ts)** - TypeScript library for using Haveno. +- **[haveno-ui](https://github.com/haveno-dex/haveno-ui)** - A new user interface (WIP). - **[haveno-meta](https://github.com/haveno-dex/haveno-meta)** - For project-wide discussions and proposals. -If you wish to help, take a look at the repositories above and look for open issues. We run a bounty program to incentivize development. See [Bounties](#bounties) - -The PGP keys of the core team members are in `gpg_keys/`. +If you wish to help, take a look at the repositories above and look for open issues. We run a bounty program to incentivize development. See [Bounties](#bounties). ## Keep in touch and help out! Haveno is a community-driven project. For it to be successful it's fundamental to have the support and help of the community. Join the community rooms on our Matrix server: - General discussions: **Haveno** ([#haveno:monero.social](https://matrix.to/#/#haveno:monero.social)) relayed on IRC/Libera (`#haveno`) -- Development discussions: **Haveno Development** ([#haveno-dev:monero.social](https://matrix.to/#/#haveno-dev:monero.social)) relayed on IRC/Libera (`#haveno-dev`) +- Development discussions: **Haveno Development** ([#haveno-development:monero.social](https://matrix.to/#/#haveno-development:monero.social)) relayed on IRC/Libera (`#haveno-development`) Email: contact@haveno.exchange Website: [haveno.exchange](https://haveno.exchange) -## Running a local Haveno test network - -See [docs/installing.md](docs/installing.md) - ## Contributing to Haveno See the [developer guide](docs/developer-guide.md) to get started developing for Haveno. @@ -65,7 +67,7 @@ If you are not able to contribute code and want to contribute development resour ## Bounties -To incentivize development and reward contributors we adopt a simple bounty system. Contributors may be awarded bounties after completing a task (resolving an issue). Take a look at the issues eligible for a bounty on the [dedicated Kanban board](https://github.com/orgs/haveno-dex/projects/2) or look for [issues labelled '💰bounty'](https://github.com/haveno-dex/haveno/issues?q=is%3Aissue+is%3Aopen+label%3A%F0%9F%92%B0bounty) in the main `haveno` repository. [Details and conditions for receiving a bounty](docs/bounties.md). +To incentivize development and reward contributors, we adopt a simple bounty system. Contributors may be awarded bounties after completing a task (resolving an issue). Take a look at the [issues labeled '💰bounty'](https://github.com/haveno-dex/haveno/issues?q=is%3Aopen+is%3Aissue+label%3A%F0%9F%92%B0bounty) in the main `haveno` repository. [Details and conditions for receiving a bounty](docs/bounties.md). ## Support and sponsorships @@ -73,14 +75,16 @@ To bring Haveno to life, we need resources. If you have the possibility, please ### Monero -`42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F` - -<!--  --> +<p> + <img src="https://raw.githubusercontent.com/haveno-dex/haveno/master/media/donate_monero.png" alt="Donate Monero" width="115" height="115"><br> + <code>42sjokkT9FmiWPqVzrWPFE5NCJXwt96bkBozHf4vgLR9hXyJDqKHEHKVscAARuD7in5wV1meEcSTJTanCTDzidTe2cFXS1F</code> +</p> If you are using a wallet that supports OpenAlias (like the 'official' CLI and GUI wallets), you can simply put `fund@haveno.exchange` as the "receiver" address. ### Bitcoin -`1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ` - -<!--  --> +<p> + <img src="https://raw.githubusercontent.com/haveno-dex/haveno/master/media/donate_bitcoin.png" alt="Donate Bitcoin" width="115" height="115"><br> + <code>1AKq3CE1yBAnxGmHXbNFfNYStcByNDc5gQ</code> +</p> diff --git a/apitest/src/main/java/haveno/apitest/ApiTestMain.java b/apitest/src/main/java/haveno/apitest/ApiTestMain.java index d18775581c..ad383ff1ef 100644 --- a/apitest/src/main/java/haveno/apitest/ApiTestMain.java +++ b/apitest/src/main/java/haveno/apitest/ApiTestMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest; @@ -78,7 +78,7 @@ public class ApiTestMain { } catch (Throwable ex) { err.println("Fault: An unexpected error occurred. " + - "Please file a report at https://haveno.exchange/issues"); + "Please file a report at https://github.com/haveno-dex/haveno/issues"); ex.printStackTrace(err); exit(EXIT_FAILURE); } diff --git a/apitest/src/main/java/haveno/apitest/Scaffold.java b/apitest/src/main/java/haveno/apitest/Scaffold.java index 7f7bdea715..0384872dd5 100644 --- a/apitest/src/main/java/haveno/apitest/Scaffold.java +++ b/apitest/src/main/java/haveno/apitest/Scaffold.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest; diff --git a/apitest/src/main/java/haveno/apitest/SetupTask.java b/apitest/src/main/java/haveno/apitest/SetupTask.java index ae8464596a..542359c709 100644 --- a/apitest/src/main/java/haveno/apitest/SetupTask.java +++ b/apitest/src/main/java/haveno/apitest/SetupTask.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest; diff --git a/apitest/src/main/java/haveno/apitest/SmokeTestBashCommand.java b/apitest/src/main/java/haveno/apitest/SmokeTestBashCommand.java index cadb8b2c6b..f0b2195ca5 100644 --- a/apitest/src/main/java/haveno/apitest/SmokeTestBashCommand.java +++ b/apitest/src/main/java/haveno/apitest/SmokeTestBashCommand.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest; diff --git a/apitest/src/main/java/haveno/apitest/SmokeTestBitcoind.java b/apitest/src/main/java/haveno/apitest/SmokeTestBitcoind.java index 8cf029ffcf..61e8669b9f 100644 --- a/apitest/src/main/java/haveno/apitest/SmokeTestBitcoind.java +++ b/apitest/src/main/java/haveno/apitest/SmokeTestBitcoind.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest; diff --git a/apitest/src/main/java/haveno/apitest/config/ApiTestConfig.java b/apitest/src/main/java/haveno/apitest/config/ApiTestConfig.java index 998d3353a1..9a1242776c 100644 --- a/apitest/src/main/java/haveno/apitest/config/ApiTestConfig.java +++ b/apitest/src/main/java/haveno/apitest/config/ApiTestConfig.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.config; diff --git a/apitest/src/main/java/haveno/apitest/config/HavenoAppConfig.java b/apitest/src/main/java/haveno/apitest/config/HavenoAppConfig.java index 40565a0df9..6e8a1f10dc 100644 --- a/apitest/src/main/java/haveno/apitest/config/HavenoAppConfig.java +++ b/apitest/src/main/java/haveno/apitest/config/HavenoAppConfig.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.config; diff --git a/apitest/src/main/java/haveno/apitest/linux/AbstractLinuxProcess.java b/apitest/src/main/java/haveno/apitest/linux/AbstractLinuxProcess.java index 6d839edfeb..86de555a8a 100644 --- a/apitest/src/main/java/haveno/apitest/linux/AbstractLinuxProcess.java +++ b/apitest/src/main/java/haveno/apitest/linux/AbstractLinuxProcess.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/BashCommand.java b/apitest/src/main/java/haveno/apitest/linux/BashCommand.java index b42a864835..350384fc37 100644 --- a/apitest/src/main/java/haveno/apitest/linux/BashCommand.java +++ b/apitest/src/main/java/haveno/apitest/linux/BashCommand.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/BitcoinCli.java b/apitest/src/main/java/haveno/apitest/linux/BitcoinCli.java index 7a7074e1e8..25661eda0e 100644 --- a/apitest/src/main/java/haveno/apitest/linux/BitcoinCli.java +++ b/apitest/src/main/java/haveno/apitest/linux/BitcoinCli.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/BitcoinDaemon.java b/apitest/src/main/java/haveno/apitest/linux/BitcoinDaemon.java index 1038233af4..01c7e216f4 100644 --- a/apitest/src/main/java/haveno/apitest/linux/BitcoinDaemon.java +++ b/apitest/src/main/java/haveno/apitest/linux/BitcoinDaemon.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/HavenoProcess.java b/apitest/src/main/java/haveno/apitest/linux/HavenoProcess.java index 35b03a72b1..13f54c479e 100644 --- a/apitest/src/main/java/haveno/apitest/linux/HavenoProcess.java +++ b/apitest/src/main/java/haveno/apitest/linux/HavenoProcess.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/LinuxProcess.java b/apitest/src/main/java/haveno/apitest/linux/LinuxProcess.java index b9603433ef..37b722cecc 100644 --- a/apitest/src/main/java/haveno/apitest/linux/LinuxProcess.java +++ b/apitest/src/main/java/haveno/apitest/linux/LinuxProcess.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/SystemCommandExecutor.java b/apitest/src/main/java/haveno/apitest/linux/SystemCommandExecutor.java index f9ce4711e2..13a744393d 100644 --- a/apitest/src/main/java/haveno/apitest/linux/SystemCommandExecutor.java +++ b/apitest/src/main/java/haveno/apitest/linux/SystemCommandExecutor.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/main/java/haveno/apitest/linux/ThreadedStreamHandler.java b/apitest/src/main/java/haveno/apitest/linux/ThreadedStreamHandler.java index 611ddd6aa0..a103eb8a51 100644 --- a/apitest/src/main/java/haveno/apitest/linux/ThreadedStreamHandler.java +++ b/apitest/src/main/java/haveno/apitest/linux/ThreadedStreamHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.linux; diff --git a/apitest/src/test/java/haveno/apitest/ApiTestCase.java b/apitest/src/test/java/haveno/apitest/ApiTestCase.java index 7e0db28868..4bd495d91d 100644 --- a/apitest/src/test/java/haveno/apitest/ApiTestCase.java +++ b/apitest/src/test/java/haveno/apitest/ApiTestCase.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest; diff --git a/apitest/src/test/java/haveno/apitest/method/BitcoinCliHelper.java b/apitest/src/test/java/haveno/apitest/method/BitcoinCliHelper.java index cebaec9893..aace7c5a08 100644 --- a/apitest/src/test/java/haveno/apitest/method/BitcoinCliHelper.java +++ b/apitest/src/test/java/haveno/apitest/method/BitcoinCliHelper.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method; diff --git a/apitest/src/test/java/haveno/apitest/method/CallRateMeteringInterceptorTest.java b/apitest/src/test/java/haveno/apitest/method/CallRateMeteringInterceptorTest.java index 2613212fb5..816a2a38e4 100644 --- a/apitest/src/test/java/haveno/apitest/method/CallRateMeteringInterceptorTest.java +++ b/apitest/src/test/java/haveno/apitest/method/CallRateMeteringInterceptorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method; diff --git a/apitest/src/test/java/haveno/apitest/method/GetMethodHelpTest.java b/apitest/src/test/java/haveno/apitest/method/GetMethodHelpTest.java index d40466f1ca..92e82c03f0 100644 --- a/apitest/src/test/java/haveno/apitest/method/GetMethodHelpTest.java +++ b/apitest/src/test/java/haveno/apitest/method/GetMethodHelpTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method; diff --git a/apitest/src/test/java/haveno/apitest/method/GetVersionTest.java b/apitest/src/test/java/haveno/apitest/method/GetVersionTest.java index 7431c8183f..774c1cb464 100644 --- a/apitest/src/test/java/haveno/apitest/method/GetVersionTest.java +++ b/apitest/src/test/java/haveno/apitest/method/GetVersionTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method; diff --git a/apitest/src/test/java/haveno/apitest/method/MethodTest.java b/apitest/src/test/java/haveno/apitest/method/MethodTest.java index 2dbd89863f..01c7a3bfd3 100644 --- a/apitest/src/test/java/haveno/apitest/method/MethodTest.java +++ b/apitest/src/test/java/haveno/apitest/method/MethodTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method; @@ -43,7 +43,7 @@ import java.util.stream.Collectors; import static haveno.apitest.config.ApiTestConfig.BTC; import static haveno.apitest.config.ApiTestRateMeterInterceptorConfig.getTestRateMeterInterceptorConfig; import static haveno.cli.table.builder.TableType.BTC_BALANCE_TBL; -import static haveno.core.xmr.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent; +import static haveno.core.xmr.wallet.Restrictions.getDefaultSecurityDepositAsPercent; import static java.lang.String.format; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.stream; @@ -157,8 +157,8 @@ public class MethodTest extends ApiTestCase { return haveno.core.payment.PaymentAccount.fromProto(paymentAccount, CORE_PROTO_RESOLVER); } - public static final Supplier<Double> defaultBuyerSecurityDepositPct = () -> { - var defaultPct = BigDecimal.valueOf(getDefaultBuyerSecurityDepositAsPercent()); + public static final Supplier<Double> defaultSecurityDepositPct = () -> { + var defaultPct = BigDecimal.valueOf(getDefaultSecurityDepositAsPercent()); if (defaultPct.precision() != 2) throw new IllegalStateException(format( "Unexpected decimal precision, expected 2 but actual is %d%n." diff --git a/apitest/src/test/java/haveno/apitest/method/RegisterDisputeAgentsTest.java b/apitest/src/test/java/haveno/apitest/method/RegisterDisputeAgentsTest.java index 5717830d1a..4a333a834f 100644 --- a/apitest/src/test/java/haveno/apitest/method/RegisterDisputeAgentsTest.java +++ b/apitest/src/test/java/haveno/apitest/method/RegisterDisputeAgentsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method; diff --git a/apitest/src/test/java/haveno/apitest/method/offer/AbstractOfferTest.java b/apitest/src/test/java/haveno/apitest/method/offer/AbstractOfferTest.java index 438a41876b..446d070f89 100644 --- a/apitest/src/test/java/haveno/apitest/method/offer/AbstractOfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/offer/AbstractOfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.offer; diff --git a/apitest/src/test/java/haveno/apitest/method/offer/CancelOfferTest.java b/apitest/src/test/java/haveno/apitest/method/offer/CancelOfferTest.java index 3e9bcdff38..1867605507 100644 --- a/apitest/src/test/java/haveno/apitest/method/offer/CancelOfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/offer/CancelOfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.offer; @@ -47,7 +47,7 @@ public class CancelOfferTest extends AbstractOfferTest { 10000000L, 10000000L, 0.00, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), paymentAccountId, NO_TRIGGER_PRICE); }; diff --git a/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingFixedPriceTest.java b/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingFixedPriceTest.java index 2f066acf4c..49c01d5ae4 100644 --- a/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingFixedPriceTest.java +++ b/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingFixedPriceTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.offer; @@ -49,7 +49,7 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { 10_000_000L, 10_000_000L, "36000", - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), audAccount.getId()); log.debug("Offer #1:\n{}", toOfferTable.apply(newOffer)); assertTrue(newOffer.getIsMyOffer()); @@ -64,7 +64,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertEquals(10_000_000, newOffer.getMinAmount()); assertEquals("3600", newOffer.getVolume()); assertEquals("3600", newOffer.getMinVolume()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(audAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals("AUD", newOffer.getCounterCurrencyCode()); @@ -80,7 +81,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertEquals(10_000_000, newOffer.getMinAmount()); assertEquals("3600", newOffer.getVolume()); assertEquals("3600", newOffer.getMinVolume()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(audAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals("AUD", newOffer.getCounterCurrencyCode()); @@ -95,7 +97,7 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { 10_000_000L, 10_000_000L, "30000.1234", - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), usdAccount.getId()); log.debug("Offer #2:\n{}", toOfferTable.apply(newOffer)); assertTrue(newOffer.getIsMyOffer()); @@ -110,7 +112,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertEquals(10_000_000, newOffer.getMinAmount()); assertEquals("3000", newOffer.getVolume()); assertEquals("3000", newOffer.getMinVolume()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(USD, newOffer.getCounterCurrencyCode()); @@ -126,7 +129,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertEquals(10_000_000, newOffer.getMinAmount()); assertEquals("3000", newOffer.getVolume()); assertEquals("3000", newOffer.getMinVolume()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(USD, newOffer.getCounterCurrencyCode()); @@ -141,7 +145,7 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { 10_000_000L, 5_000_000L, "29500.1234", - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), eurAccount.getId()); log.debug("Offer #3:\n{}", toOfferTable.apply(newOffer)); assertTrue(newOffer.getIsMyOffer()); @@ -156,7 +160,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertEquals(5_000_000, newOffer.getMinAmount()); assertEquals("2950", newOffer.getVolume()); assertEquals("1475", newOffer.getMinVolume()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(eurAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(EUR, newOffer.getCounterCurrencyCode()); @@ -172,7 +177,8 @@ public class CreateOfferUsingFixedPriceTest extends AbstractOfferTest { assertEquals(5_000_000, newOffer.getMinAmount()); assertEquals("2950", newOffer.getVolume()); assertEquals("1475", newOffer.getMinVolume()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(eurAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(EUR, newOffer.getCounterCurrencyCode()); diff --git a/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java b/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java index 84068bca21..f4dff640c1 100644 --- a/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java +++ b/apitest/src/test/java/haveno/apitest/method/offer/CreateOfferUsingMarketPriceMarginTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.offer; @@ -66,7 +66,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { 10_000_000L, 10_000_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), usdAccount.getId(), NO_TRIGGER_PRICE); log.debug("Offer #1:\n{}", toOfferTable.apply(newOffer)); @@ -80,7 +80,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(10_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals(USD, newOffer.getCounterCurrencyCode()); @@ -94,7 +95,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(10_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(usdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals(USD, newOffer.getCounterCurrencyCode()); @@ -112,7 +114,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { 10_000_000L, 10_000_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), nzdAccount.getId(), NO_TRIGGER_PRICE); log.debug("Offer #2:\n{}", toOfferTable.apply(newOffer)); @@ -126,7 +128,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(10_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(nzdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals("NZD", newOffer.getCounterCurrencyCode()); @@ -140,7 +143,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(10_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(nzdAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals("NZD", newOffer.getCounterCurrencyCode()); @@ -158,7 +162,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { 10_000_000L, 5_000_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), gbpAccount.getId(), NO_TRIGGER_PRICE); log.debug("Offer #3:\n{}", toOfferTable.apply(newOffer)); @@ -172,7 +176,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(5_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(gbpAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals("GBP", newOffer.getCounterCurrencyCode()); @@ -186,7 +191,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(5_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(gbpAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals("GBP", newOffer.getCounterCurrencyCode()); @@ -204,7 +210,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { 10_000_000L, 5_000_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), brlAccount.getId(), NO_TRIGGER_PRICE); log.debug("Offer #4:\n{}", toOfferTable.apply(newOffer)); @@ -218,7 +224,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(5_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(brlAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals("BRL", newOffer.getCounterCurrencyCode()); @@ -232,7 +239,8 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { assertEquals(priceMarginPctInput, newOffer.getMarketPriceMarginPct()); assertEquals(10_000_000, newOffer.getAmount()); assertEquals(5_000_000, newOffer.getMinAmount()); - assertEquals(1_500_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(brlAccount.getId(), newOffer.getPaymentAccountId()); assertEquals(BTC, newOffer.getBaseCurrencyCode()); assertEquals("BRL", newOffer.getCounterCurrencyCode()); @@ -251,7 +259,7 @@ public class CreateOfferUsingMarketPriceMarginTest extends AbstractOfferTest { 10_000_000L, 5_000_000L, 0.0, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), usdAccount.getId(), triggerPrice); assertTrue(newOffer.getIsMyOffer()); diff --git a/apitest/src/test/java/haveno/apitest/method/offer/CreateXMROffersTest.java b/apitest/src/test/java/haveno/apitest/method/offer/CreateXMROffersTest.java index 4226f8c9cf..8571c0c59d 100644 --- a/apitest/src/test/java/haveno/apitest/method/offer/CreateXMROffersTest.java +++ b/apitest/src/test/java/haveno/apitest/method/offer/CreateXMROffersTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.offer; @@ -62,7 +62,7 @@ public class CreateXMROffersTest extends AbstractOfferTest { 100_000_000L, 75_000_000L, "0.005", // FIXED PRICE IN BTC FOR 1 XMR - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesXmrAcct.getId()); log.debug("Sell XMR (Buy BTC) offer:\n{}", toOfferTable.apply(newOffer)); assertTrue(newOffer.getIsMyOffer()); @@ -75,7 +75,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertEquals("0.00500000", newOffer.getPrice()); assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(75_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -91,7 +92,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertEquals("0.00500000", newOffer.getPrice()); assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(75_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -106,7 +108,7 @@ public class CreateXMROffersTest extends AbstractOfferTest { 100_000_000L, 50_000_000L, "0.005", // FIXED PRICE IN BTC (satoshis) FOR 1 XMR - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesXmrAcct.getId()); log.debug("Buy XMR (Sell BTC) offer:\n{}", toOfferTable.apply(newOffer)); assertTrue(newOffer.getIsMyOffer()); @@ -119,7 +121,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertEquals("0.00500000", newOffer.getPrice()); assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(50_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -135,7 +138,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertEquals("0.00500000", newOffer.getPrice()); assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(50_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -152,7 +156,7 @@ public class CreateXMROffersTest extends AbstractOfferTest { 100_000_000L, 75_000_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesXmrAcct.getId(), triggerPrice); log.debug("Pending Sell XMR (Buy BTC) offer:\n{}", toOfferTable.apply(newOffer)); @@ -169,7 +173,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(75_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -189,7 +194,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(75_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -205,7 +211,7 @@ public class CreateXMROffersTest extends AbstractOfferTest { 100_000_000L, 50_000_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesXmrAcct.getId(), NO_TRIGGER_PRICE); log.debug("Buy XMR (Sell BTC) offer:\n{}", toOfferTable.apply(newOffer)); @@ -218,7 +224,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertTrue(newOffer.getUseMarketBasedPrice()); assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(50_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); @@ -233,7 +240,8 @@ public class CreateXMROffersTest extends AbstractOfferTest { assertTrue(newOffer.getUseMarketBasedPrice()); assertEquals(100_000_000L, newOffer.getAmount()); assertEquals(50_000_000L, newOffer.getMinAmount()); - assertEquals(15_000_000, newOffer.getBuyerSecurityDeposit()); + assertEquals(.15, newOffer.getBuyerSecurityDepositPct()); + assertEquals(.15, newOffer.getSellerSecurityDepositPct()); assertEquals(alicesXmrAcct.getId(), newOffer.getPaymentAccountId()); assertEquals(XMR, newOffer.getBaseCurrencyCode()); assertEquals(BTC, newOffer.getCounterCurrencyCode()); diff --git a/apitest/src/test/java/haveno/apitest/method/offer/ValidateCreateOfferTest.java b/apitest/src/test/java/haveno/apitest/method/offer/ValidateCreateOfferTest.java index 3fcf703877..e8745c1b2c 100644 --- a/apitest/src/test/java/haveno/apitest/method/offer/ValidateCreateOfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/offer/ValidateCreateOfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.offer; @@ -47,7 +47,7 @@ public class ValidateCreateOfferTest extends AbstractOfferTest { 100000000000L, // exceeds amount limit 100000000000L, "10000.0000", - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), usdAccount.getId())); assertEquals("UNKNOWN: An error occurred at task: ValidateOffer", exception.getMessage()); } @@ -63,7 +63,7 @@ public class ValidateCreateOfferTest extends AbstractOfferTest { 10000000L, 10000000L, "40000.0000", - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), chfAccount.getId())); String expectedError = format("UNKNOWN: cannot create EUR offer with payment account %s", chfAccount.getId()); assertEquals(expectedError, exception.getMessage()); @@ -80,7 +80,7 @@ public class ValidateCreateOfferTest extends AbstractOfferTest { 10000000L, 10000000L, "63000.0000", - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), audAccount.getId())); String expectedError = format("UNKNOWN: cannot create CAD offer with payment account %s", audAccount.getId()); assertEquals(expectedError, exception.getMessage()); diff --git a/apitest/src/test/java/haveno/apitest/method/payment/CreatePaymentAccountTest.java b/apitest/src/test/java/haveno/apitest/method/payment/CreatePaymentAccountTest.java index ca16cfbf09..e1ee0113b0 100644 --- a/apitest/src/test/java/haveno/apitest/method/payment/CreatePaymentAccountTest.java +++ b/apitest/src/test/java/haveno/apitest/method/payment/CreatePaymentAccountTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.payment; @@ -676,7 +676,7 @@ public class CreatePaymentAccountTest extends AbstractPaymentAccountTest { assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_SELECTED_TRADE_CURRENCY), paymentAccount.getSelectedTradeCurrency().getCode()); verifyCommonFormEntries(paymentAccount); - assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_USERNAME), paymentAccount.getUserName()); + assertEquals(COMPLETED_FORM_MAP.get(PROPERTY_NAME_USERNAME), paymentAccount.getUsername()); print(paymentAccount); } diff --git a/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferTest.java b/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferTest.java index c7519a399a..abbec38ff6 100644 --- a/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.trade; @@ -52,7 +52,7 @@ public class TakeBuyBTCOfferTest extends AbstractTradeTest { 12_500_000L, 12_500_000L, // min-amount = amount 0.00, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesUsdAccount.getId(), NO_TRIGGER_PRICE); var offerId = alicesOffer.getId(); diff --git a/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferWithNationalBankAcctTest.java b/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferWithNationalBankAcctTest.java index 930ba348d8..3199a6b053 100644 --- a/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferWithNationalBankAcctTest.java +++ b/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyBTCOfferWithNationalBankAcctTest.java @@ -1,35 +1,35 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.trade; @@ -96,7 +96,7 @@ public class TakeBuyBTCOfferWithNationalBankAcctTest extends AbstractTradeTest { 1_000_000L, 1_000_000L, // min-amount = amount 0.00, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesPaymentAccount.getId(), NO_TRIGGER_PRICE); var offerId = alicesOffer.getId(); diff --git a/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyXMROfferTest.java b/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyXMROfferTest.java index 68c3f40cce..f61203400b 100644 --- a/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyXMROfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/trade/TakeBuyXMROfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.trade; @@ -65,7 +65,7 @@ public class TakeBuyXMROfferTest extends AbstractTradeTest { 15_000_000L, 7_500_000L, "0.00455500", // FIXED PRICE IN BTC (satoshis) FOR 1 XMR - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesXmrAcct.getId()); log.debug("Alice's BUY XMR (SELL BTC) Offer:\n{}", new TableBuilder(OFFER_TBL, alicesOffer).build()); genBtcBlocksThenWait(1, 5000); diff --git a/apitest/src/test/java/haveno/apitest/method/trade/TakeSellBTCOfferTest.java b/apitest/src/test/java/haveno/apitest/method/trade/TakeSellBTCOfferTest.java index 95ef134bdb..4f43c21cd7 100644 --- a/apitest/src/test/java/haveno/apitest/method/trade/TakeSellBTCOfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/trade/TakeSellBTCOfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.trade; @@ -58,7 +58,7 @@ public class TakeSellBTCOfferTest extends AbstractTradeTest { 12_500_000L, 12_500_000L, // min-amount = amount 0.00, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesUsdAccount.getId(), NO_TRIGGER_PRICE); var offerId = alicesOffer.getId(); diff --git a/apitest/src/test/java/haveno/apitest/method/trade/TakeSellXMROfferTest.java b/apitest/src/test/java/haveno/apitest/method/trade/TakeSellXMROfferTest.java index f1e98959f7..9a769b5f04 100644 --- a/apitest/src/test/java/haveno/apitest/method/trade/TakeSellXMROfferTest.java +++ b/apitest/src/test/java/haveno/apitest/method/trade/TakeSellXMROfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.method.trade; @@ -71,7 +71,7 @@ public class TakeSellXMROfferTest extends AbstractTradeTest { 20_000_000L, 10_500_000L, priceMarginPctInput, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), alicesXmrAcct.getId(), NO_TRIGGER_PRICE); log.debug("Alice's SELL XMR (BUY BTC) Offer:\n{}", new TableBuilder(OFFER_TBL, alicesOffer).build()); diff --git a/apitest/src/test/java/haveno/apitest/scenario/LongRunningOfferDeactivationTest.java b/apitest/src/test/java/haveno/apitest/scenario/LongRunningOfferDeactivationTest.java index c2d7b55060..356b77ef8a 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/LongRunningOfferDeactivationTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/LongRunningOfferDeactivationTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; @@ -57,7 +57,7 @@ public class LongRunningOfferDeactivationTest extends AbstractOfferTest { 1_000_000, 1_000_000, 0.00, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), paymentAcct.getId(), triggerPrice); log.info("SELL offer {} created with margin based price {}.", @@ -103,7 +103,7 @@ public class LongRunningOfferDeactivationTest extends AbstractOfferTest { 1_000_000, 1_000_000, 0.00, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), paymentAcct.getId(), triggerPrice); log.info("BUY offer {} created with margin based price {}.", diff --git a/apitest/src/test/java/haveno/apitest/scenario/LongRunningTradesTest.java b/apitest/src/test/java/haveno/apitest/scenario/LongRunningTradesTest.java index 6f4c299675..aa45775b4e 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/LongRunningTradesTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/LongRunningTradesTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; diff --git a/apitest/src/test/java/haveno/apitest/scenario/OfferTest.java b/apitest/src/test/java/haveno/apitest/scenario/OfferTest.java index 067679ef92..85146d95de 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/OfferTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/OfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; diff --git a/apitest/src/test/java/haveno/apitest/scenario/ScriptedBotTest.java b/apitest/src/test/java/haveno/apitest/scenario/ScriptedBotTest.java index 630d6b78eb..cb1072724e 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/ScriptedBotTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/ScriptedBotTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; diff --git a/apitest/src/test/java/haveno/apitest/scenario/StartupTest.java b/apitest/src/test/java/haveno/apitest/scenario/StartupTest.java index 05e6e13137..d1fa3f7562 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/StartupTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/StartupTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; diff --git a/apitest/src/test/java/haveno/apitest/scenario/TradeTest.java b/apitest/src/test/java/haveno/apitest/scenario/TradeTest.java index b1c97cce02..7fdd337b61 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/TradeTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/TradeTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; diff --git a/apitest/src/test/java/haveno/apitest/scenario/WalletTest.java b/apitest/src/test/java/haveno/apitest/scenario/WalletTest.java index 17e065b211..4e14de68cb 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/WalletTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/WalletTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/AbstractBotTest.java b/apitest/src/test/java/haveno/apitest/scenario/bot/AbstractBotTest.java index 827fbd7fa1..9ea30e676b 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/AbstractBotTest.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/AbstractBotTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/BotClient.java b/apitest/src/test/java/haveno/apitest/scenario/bot/BotClient.java index e6b1b6d01a..31df689434 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/BotClient.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/BotClient.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/InvalidRandomOfferException.java b/apitest/src/test/java/haveno/apitest/scenario/bot/InvalidRandomOfferException.java index 10d42dc254..9cb5bfe32d 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/InvalidRandomOfferException.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/InvalidRandomOfferException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/PaymentAccountNotFoundException.java b/apitest/src/test/java/haveno/apitest/scenario/bot/PaymentAccountNotFoundException.java index a090c14960..731deda250 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/PaymentAccountNotFoundException.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/PaymentAccountNotFoundException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/RandomOffer.java b/apitest/src/test/java/haveno/apitest/scenario/bot/RandomOffer.java index e295cd03e0..4e8b86afac 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/RandomOffer.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/RandomOffer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot; @@ -28,7 +28,7 @@ import java.text.DecimalFormat; import java.util.Objects; import java.util.function.Supplier; -import static haveno.apitest.method.offer.AbstractOfferTest.defaultBuyerSecurityDepositPct; +import static haveno.apitest.method.offer.AbstractOfferTest.defaultSecurityDepositPct; import static haveno.cli.CurrencyFormat.formatInternalFiatPrice; import static haveno.cli.CurrencyFormat.formatSatoshis; import static haveno.common.util.MathUtils.scaleDownByPowerOf10; @@ -119,7 +119,7 @@ public class RandomOffer { amount, minAmount, priceMargin, - defaultBuyerSecurityDepositPct.get(), + defaultSecurityDepositPct.get(), "0" /*no trigger price*/); } else { this.offer = botClient.createOfferAtFixedPrice(paymentAccount, @@ -128,7 +128,7 @@ public class RandomOffer { amount, minAmount, fixedOfferPrice, - defaultBuyerSecurityDepositPct.get()); + defaultSecurityDepositPct.get()); } this.id = offer.getId(); return this; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/RobotBob.java b/apitest/src/test/java/haveno/apitest/scenario/bot/RobotBob.java index 7787419c84..89b87e4ca7 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/RobotBob.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/RobotBob.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/protocol/BotProtocol.java b/apitest/src/test/java/haveno/apitest/scenario/bot/protocol/BotProtocol.java index 6c831d41e9..d7be0256d3 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/protocol/BotProtocol.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/protocol/BotProtocol.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot.protocol; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/script/BashScriptGenerator.java b/apitest/src/test/java/haveno/apitest/scenario/bot/script/BashScriptGenerator.java index 52af873516..87fbbf3c79 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/script/BashScriptGenerator.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/script/BashScriptGenerator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot.script; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScript.java b/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScript.java index 642154d10b..d231b56dcc 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScript.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScript.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot.script; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScriptGenerator.java b/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScriptGenerator.java index fbda837b98..02d1822c50 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScriptGenerator.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/script/BotScriptGenerator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot.script; diff --git a/apitest/src/test/java/haveno/apitest/scenario/bot/shutdown/ManualBotShutdownException.java b/apitest/src/test/java/haveno/apitest/scenario/bot/shutdown/ManualBotShutdownException.java index 9c51b83ab9..68b893930b 100644 --- a/apitest/src/test/java/haveno/apitest/scenario/bot/shutdown/ManualBotShutdownException.java +++ b/apitest/src/test/java/haveno/apitest/scenario/bot/shutdown/ManualBotShutdownException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.apitest.scenario.bot.shutdown; diff --git a/assets/src/main/java/haveno/asset/AbstractAsset.java b/assets/src/main/java/haveno/asset/AbstractAsset.java index 781038e3a3..08ea558b31 100644 --- a/assets/src/main/java/haveno/asset/AbstractAsset.java +++ b/assets/src/main/java/haveno/asset/AbstractAsset.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/AddressValidationResult.java b/assets/src/main/java/haveno/asset/AddressValidationResult.java index a5d0153b44..ccdc49288c 100644 --- a/assets/src/main/java/haveno/asset/AddressValidationResult.java +++ b/assets/src/main/java/haveno/asset/AddressValidationResult.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/AddressValidator.java b/assets/src/main/java/haveno/asset/AddressValidator.java index be5d623539..192c8583b6 100644 --- a/assets/src/main/java/haveno/asset/AddressValidator.java +++ b/assets/src/main/java/haveno/asset/AddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/Asset.java b/assets/src/main/java/haveno/asset/Asset.java index eeed4885ef..2d5bb99a17 100644 --- a/assets/src/main/java/haveno/asset/Asset.java +++ b/assets/src/main/java/haveno/asset/Asset.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/AssetRegistry.java b/assets/src/main/java/haveno/asset/AssetRegistry.java index c0079804d3..519032feee 100644 --- a/assets/src/main/java/haveno/asset/AssetRegistry.java +++ b/assets/src/main/java/haveno/asset/AssetRegistry.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/Base58AddressValidator.java b/assets/src/main/java/haveno/asset/Base58AddressValidator.java index 3942e5b78f..82d34921ef 100644 --- a/assets/src/main/java/haveno/asset/Base58AddressValidator.java +++ b/assets/src/main/java/haveno/asset/Base58AddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/BitcoinAddressValidator.java b/assets/src/main/java/haveno/asset/BitcoinAddressValidator.java index 7bcbbcbbd4..3a8e7101cb 100644 --- a/assets/src/main/java/haveno/asset/BitcoinAddressValidator.java +++ b/assets/src/main/java/haveno/asset/BitcoinAddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/Coin.java b/assets/src/main/java/haveno/asset/Coin.java index 5d6e48aeee..e7c81ec4a7 100644 --- a/assets/src/main/java/haveno/asset/Coin.java +++ b/assets/src/main/java/haveno/asset/Coin.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/CryptoNoteAddressValidator.java b/assets/src/main/java/haveno/asset/CryptoNoteAddressValidator.java index 861b0ecbc5..b7a7193842 100644 --- a/assets/src/main/java/haveno/asset/CryptoNoteAddressValidator.java +++ b/assets/src/main/java/haveno/asset/CryptoNoteAddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/CryptoNoteUtils.java b/assets/src/main/java/haveno/asset/CryptoNoteUtils.java index 5169f04cf5..4939e9ebd6 100644 --- a/assets/src/main/java/haveno/asset/CryptoNoteUtils.java +++ b/assets/src/main/java/haveno/asset/CryptoNoteUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/Erc20Token.java b/assets/src/main/java/haveno/asset/Erc20Token.java index 89364927e4..621f5acae4 100644 --- a/assets/src/main/java/haveno/asset/Erc20Token.java +++ b/assets/src/main/java/haveno/asset/Erc20Token.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/EtherAddressValidator.java b/assets/src/main/java/haveno/asset/EtherAddressValidator.java index a427dbfce4..5c7a0b18f8 100644 --- a/assets/src/main/java/haveno/asset/EtherAddressValidator.java +++ b/assets/src/main/java/haveno/asset/EtherAddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/GrinAddressValidator.java b/assets/src/main/java/haveno/asset/GrinAddressValidator.java index a4ff40bfa7..20da23f8f7 100644 --- a/assets/src/main/java/haveno/asset/GrinAddressValidator.java +++ b/assets/src/main/java/haveno/asset/GrinAddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/NetworkParametersAdapter.java b/assets/src/main/java/haveno/asset/NetworkParametersAdapter.java index 9e23a12321..e6c6e74489 100644 --- a/assets/src/main/java/haveno/asset/NetworkParametersAdapter.java +++ b/assets/src/main/java/haveno/asset/NetworkParametersAdapter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/PrintTool.java b/assets/src/main/java/haveno/asset/PrintTool.java index 1272bf6544..02eae3c7e1 100644 --- a/assets/src/main/java/haveno/asset/PrintTool.java +++ b/assets/src/main/java/haveno/asset/PrintTool.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/RegexAddressValidator.java b/assets/src/main/java/haveno/asset/RegexAddressValidator.java index ed75c76947..3f9ae4d0ce 100644 --- a/assets/src/main/java/haveno/asset/RegexAddressValidator.java +++ b/assets/src/main/java/haveno/asset/RegexAddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/Token.java b/assets/src/main/java/haveno/asset/Token.java index 4d45cde91b..8215b31ce3 100644 --- a/assets/src/main/java/haveno/asset/Token.java +++ b/assets/src/main/java/haveno/asset/Token.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/main/java/haveno/asset/tokens/USDCoin.java b/assets/src/main/java/haveno/asset/Trc20Token.java similarity index 68% rename from assets/src/main/java/haveno/asset/tokens/USDCoin.java rename to assets/src/main/java/haveno/asset/Trc20Token.java index 158899b3c7..3cffa34455 100644 --- a/assets/src/main/java/haveno/asset/tokens/USDCoin.java +++ b/assets/src/main/java/haveno/asset/Trc20Token.java @@ -15,13 +15,15 @@ * along with Haveno. If not, see <http://www.gnu.org/licenses/>. */ -package haveno.asset.tokens; +package haveno.asset; -import haveno.asset.Erc20Token; +/** + * Abstract base class for Tron-based {@link Token}s that implement the + * TRC-20 Token Standard. + */ +public abstract class Trc20Token extends Token { -public class USDCoin extends Erc20Token { - - public USDCoin() { - super("USD Coin", "USDC"); + public Trc20Token(String name, String tickerSymbol) { + super(name, tickerSymbol, new RegexAddressValidator("T[A-Za-z1-9]{33}")); } } diff --git a/assets/src/main/java/haveno/asset/coins/Bitcoin.java b/assets/src/main/java/haveno/asset/coins/Bitcoin.java index a5e03eb882..e7b8540e29 100644 --- a/assets/src/main/java/haveno/asset/coins/Bitcoin.java +++ b/assets/src/main/java/haveno/asset/coins/Bitcoin.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; diff --git a/assets/src/main/java/haveno/asset/coins/Ether.java b/assets/src/main/java/haveno/asset/coins/Ether.java index 865935f269..35d5b1986c 100644 --- a/assets/src/main/java/haveno/asset/coins/Ether.java +++ b/assets/src/main/java/haveno/asset/coins/Ether.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; diff --git a/assets/src/main/java/haveno/asset/coins/Litecoin.java b/assets/src/main/java/haveno/asset/coins/Litecoin.java index 96f273c887..56ffe0be78 100644 --- a/assets/src/main/java/haveno/asset/coins/Litecoin.java +++ b/assets/src/main/java/haveno/asset/coins/Litecoin.java @@ -1,35 +1,36 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; -import haveno.asset.Base58AddressValidator; +import haveno.asset.BitcoinAddressValidator; import haveno.asset.Coin; import haveno.asset.NetworkParametersAdapter; public class Litecoin extends Coin { public Litecoin() { - super("Litecoin", "LTC", new Base58AddressValidator(new LitecoinMainNetParams()), Network.MAINNET); + super("Litecoin", "LTC", new BitcoinAddressValidator(new LitecoinMainNetParams()), Network.MAINNET); } public static class LitecoinMainNetParams extends NetworkParametersAdapter { public LitecoinMainNetParams() { this.addressHeader = 48; - this.p2shHeader = 5; + this.p2shHeader = 50; + this.segwitAddressHrp = "ltc"; } } -} +} \ No newline at end of file diff --git a/assets/src/main/java/haveno/asset/coins/Monero.java b/assets/src/main/java/haveno/asset/coins/Monero.java index 4fa408f189..02ec60d3fb 100644 --- a/assets/src/main/java/haveno/asset/coins/Monero.java +++ b/assets/src/main/java/haveno/asset/coins/Monero.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; diff --git a/assets/src/main/java/haveno/asset/package-info.java b/assets/src/main/java/haveno/asset/package-info.java index 6f5b53773a..a50b986115 100644 --- a/assets/src/main/java/haveno/asset/package-info.java +++ b/assets/src/main/java/haveno/asset/package-info.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /** diff --git a/assets/src/main/java/haveno/asset/tokens/AugmintEuro.java b/assets/src/main/java/haveno/asset/tokens/AugmintEuro.java index 4699c8559d..56ca5cecdf 100644 --- a/assets/src/main/java/haveno/asset/tokens/AugmintEuro.java +++ b/assets/src/main/java/haveno/asset/tokens/AugmintEuro.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.tokens; diff --git a/assets/src/main/java/haveno/asset/tokens/DaiStablecoin.java b/assets/src/main/java/haveno/asset/tokens/DaiStablecoin.java index 760bd15aeb..e9cc01f74f 100644 --- a/assets/src/main/java/haveno/asset/tokens/DaiStablecoin.java +++ b/assets/src/main/java/haveno/asset/tokens/DaiStablecoin.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.tokens; diff --git a/assets/src/main/java/haveno/asset/tokens/EtherStone.java b/assets/src/main/java/haveno/asset/tokens/EtherStone.java index f9d001cb6b..524c4fe397 100644 --- a/assets/src/main/java/haveno/asset/tokens/EtherStone.java +++ b/assets/src/main/java/haveno/asset/tokens/EtherStone.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.tokens; diff --git a/assets/src/main/java/haveno/asset/tokens/TetherUSDERC20.java b/assets/src/main/java/haveno/asset/tokens/TetherUSDERC20.java new file mode 100644 index 0000000000..1afb7ff1f2 --- /dev/null +++ b/assets/src/main/java/haveno/asset/tokens/TetherUSDERC20.java @@ -0,0 +1,11 @@ +package haveno.asset.tokens; + +import haveno.asset.Erc20Token; + +public class TetherUSDERC20 extends Erc20Token { + public TetherUSDERC20() { + // If you add a new USDT variant or want to change this ticker symbol you should also look here: + // core/src/main/java/haveno/core/provider/price/PriceProvider.java:getAll() + super("Tether USD (ERC20)", "USDT-ERC20"); + } +} diff --git a/assets/src/main/java/haveno/asset/tokens/TetherUSDTRC20.java b/assets/src/main/java/haveno/asset/tokens/TetherUSDTRC20.java new file mode 100644 index 0000000000..c5669d126a --- /dev/null +++ b/assets/src/main/java/haveno/asset/tokens/TetherUSDTRC20.java @@ -0,0 +1,11 @@ +package haveno.asset.tokens; + +import haveno.asset.Trc20Token; + +public class TetherUSDTRC20 extends Trc20Token { + public TetherUSDTRC20() { + // If you add a new USDT variant or want to change this ticker symbol you should also look here: + // core/src/main/java/haveno/core/provider/price/PriceProvider.java:getAll() + super("Tether USD (TRC20)", "USDT-TRC20"); + } +} diff --git a/assets/src/main/java/haveno/asset/tokens/TrueUSD.java b/assets/src/main/java/haveno/asset/tokens/TrueUSD.java index adb80ce778..3178825ad0 100644 --- a/assets/src/main/java/haveno/asset/tokens/TrueUSD.java +++ b/assets/src/main/java/haveno/asset/tokens/TrueUSD.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.tokens; diff --git a/assets/src/main/java/haveno/asset/tokens/USDCoinERC20.java b/assets/src/main/java/haveno/asset/tokens/USDCoinERC20.java new file mode 100644 index 0000000000..a65c021df9 --- /dev/null +++ b/assets/src/main/java/haveno/asset/tokens/USDCoinERC20.java @@ -0,0 +1,27 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.asset.tokens; + +import haveno.asset.Erc20Token; + +public class USDCoinERC20 extends Erc20Token { + + public USDCoinERC20() { + super("USD Coin (ERC20)", "USDC-ERC20"); + } +} diff --git a/assets/src/main/java/haveno/asset/tokens/VectorspaceAI.java b/assets/src/main/java/haveno/asset/tokens/VectorspaceAI.java index 2f659aac52..24c44be962 100644 --- a/assets/src/main/java/haveno/asset/tokens/VectorspaceAI.java +++ b/assets/src/main/java/haveno/asset/tokens/VectorspaceAI.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.tokens; diff --git a/assets/src/main/resources/META-INF/services/haveno.asset.Asset b/assets/src/main/resources/META-INF/services/haveno.asset.Asset index ad71f5a711..734fc92be5 100644 --- a/assets/src/main/resources/META-INF/services/haveno.asset.Asset +++ b/assets/src/main/resources/META-INF/services/haveno.asset.Asset @@ -7,4 +7,7 @@ haveno.asset.coins.BitcoinCash haveno.asset.coins.Ether haveno.asset.coins.Litecoin haveno.asset.coins.Monero +haveno.asset.tokens.TetherUSDERC20 +haveno.asset.tokens.TetherUSDTRC20 +haveno.asset.tokens.USDCoinERC20 haveno.asset.coins.Wownero diff --git a/assets/src/test/java/haveno/asset/AbstractAssetTest.java b/assets/src/test/java/haveno/asset/AbstractAssetTest.java index e6da4c7f4f..ab7731d013 100644 --- a/assets/src/test/java/haveno/asset/AbstractAssetTest.java +++ b/assets/src/test/java/haveno/asset/AbstractAssetTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset; diff --git a/assets/src/test/java/haveno/asset/coins/BitcoinTest.java b/assets/src/test/java/haveno/asset/coins/BitcoinTest.java index 319559f148..e90c25b6f7 100644 --- a/assets/src/test/java/haveno/asset/coins/BitcoinTest.java +++ b/assets/src/test/java/haveno/asset/coins/BitcoinTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; @@ -32,6 +32,7 @@ public class BitcoinTest extends AbstractAssetTest { assertValidAddress("3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX"); assertValidAddress("1111111111111111111114oLvT2"); assertValidAddress("1BitcoinEaterAddressDontSendf59kuE"); + assertValidAddress("bc1qj89046x7zv6pm4n00qgqp505nvljnfp6xfznyw"); } @Test diff --git a/assets/src/test/java/haveno/asset/coins/LitecoinTest.java b/assets/src/test/java/haveno/asset/coins/LitecoinTest.java index 1f014429f3..ddc7656643 100644 --- a/assets/src/test/java/haveno/asset/coins/LitecoinTest.java +++ b/assets/src/test/java/haveno/asset/coins/LitecoinTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; @@ -31,6 +31,17 @@ public class LitecoinTest extends AbstractAssetTest { assertValidAddress("Lg3PX8wRWmApFCoCMAsPF5P9dPHYQHEWKW"); assertValidAddress("LTuoeY6RBHV3n3cfhXVVTbJbxzxnXs9ofm"); assertValidAddress("LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW"); + assertValidAddress("M8T1B2Z97gVdvmfkQcAtYbEepune1tzGua"); + assertValidAddress("ltc1qr07zu594qf63xm7l7x6pu3a2v39m2z6hh5pp4t"); + assertValidAddress("ltc1qzvcgmntglcuv4smv3lzj6k8szcvsrmvk0phrr9wfq8w493r096ssm2fgsw"); + assertValidAddress("MESruSiB2uC9i7tMU6VMUVom91ohM7Rnbd"); + assertValidAddress("ltc1q2a0laq2jg2gntzhfs43qptajd325kkx7hrq9cs"); + assertValidAddress("ltc1qd6d54mt8xxcg0xg3l0vh6fymdfvd2tv0vnwyrv"); + assertValidAddress("ltc1gmay6ht028aurcm680f8e8wxdup07y2tq46f6z2d4v8rutewqmmcqk29jtm"); + assertValidAddress("MTf4tP1TCNBn8dNkyxeBVoPrFCcVzxJvvh"); + assertValidAddress("LaRoRBC6utQtY3U2FbHwhmhhDPyxodDeKA"); + assertValidAddress("MDMFP9Dx84tyaxiYksjvkG1jymBdqCuHGA"); + //assertValidAddress("3MSvaVbVFFLML86rt5eqgA9SvW23upaXdY"); // deprecated } @Test @@ -38,5 +49,14 @@ public class LitecoinTest extends AbstractAssetTest { assertInvalidAddress("1LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW"); assertInvalidAddress("LgfapHEPhZbdRF9pMd5WPT35hFXcZS1USrW"); assertInvalidAddress("LgfapHEPhZbRF9pMd5WPT35hFXcZS1USrW#"); + assertInvalidAddress("3MSvaVbVFFLML86rt5eqgl9SvW23upaXdY"); // contains lowercase l + assertInvalidAddress("LURw7hYhREXjWHyiXhQNsKInWtPezwNe98"); // contains uppercase I + assertInvalidAddress("LM4ch8ZtAowdiGLSnf92MrMOC9dVmve2hr"); // contains uppercase O + assertInvalidAddress("MArsfeyS7P0HzsqLpAFGC9pFdhuqHgdL2R"); // contains number 0 + assertInvalidAddress("ltc1qr6quwn3v2gxpadd0cu040r9385gayk5vdcyl5"); // too short + assertInvalidAddress("ltc1q5det08ke2gpet06wczcdfs2v3hgfqllxw28uln8vxxx82qlue6uswceljma"); // too long + assertInvalidAddress("MADpfTtabZ6pDjms4pMd3ZmnrgyhTCo4N8?time=1708476729&exp=86400"); // additional information + assertInvalidAddress("ltc1q8tk47lvgqu55h4pfast39r3t9360gmll5z9m6z?time=1708476604&exp=600"); // additional information + assertInvalidAddress("ltc1q026xyextkwhmveh7rpf6v6mp5p88vwc25aynxr?time=1708476626"); // additional information } } diff --git a/assets/src/test/java/haveno/asset/coins/MoneroTest.java b/assets/src/test/java/haveno/asset/coins/MoneroTest.java index 4171534dc2..c05d0e502b 100644 --- a/assets/src/test/java/haveno/asset/coins/MoneroTest.java +++ b/assets/src/test/java/haveno/asset/coins/MoneroTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.asset.coins; diff --git a/assets/src/test/java/haveno/asset/coins/TetherUSDERC20Test.java b/assets/src/test/java/haveno/asset/coins/TetherUSDERC20Test.java new file mode 100644 index 0000000000..fd7d97ce7d --- /dev/null +++ b/assets/src/test/java/haveno/asset/coins/TetherUSDERC20Test.java @@ -0,0 +1,43 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.asset.coins; + +import haveno.asset.AbstractAssetTest; +import haveno.asset.tokens.TetherUSDERC20; + +import org.junit.jupiter.api.Test; + + public class TetherUSDERC20Test extends AbstractAssetTest { + + public TetherUSDERC20Test() { + super(new TetherUSDERC20()); + } + + @Test + public void testValidAddresses() { + assertValidAddress("0x2a65Aca4D5fC5B5C859090a6c34d164135398226"); + assertValidAddress("2a65Aca4D5fC5B5C859090a6c34d164135398226"); + } + + @Test + public void testInvalidAddresses() { + assertInvalidAddress("0x2a65Aca4D5fC5B5C859090a6c34d1641353982266"); + assertInvalidAddress("0x2a65Aca4D5fC5B5C859090a6c34d16413539822g"); + assertInvalidAddress("2a65Aca4D5fC5B5C859090a6c34d16413539822g"); + } + } \ No newline at end of file diff --git a/assets/src/test/java/haveno/asset/coins/TetherUSDTRC20Test.java b/assets/src/test/java/haveno/asset/coins/TetherUSDTRC20Test.java new file mode 100644 index 0000000000..7fef554c75 --- /dev/null +++ b/assets/src/test/java/haveno/asset/coins/TetherUSDTRC20Test.java @@ -0,0 +1,42 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.asset.coins; + +import haveno.asset.AbstractAssetTest; +import haveno.asset.tokens.TetherUSDTRC20; + +import org.junit.jupiter.api.Test; + + public class TetherUSDTRC20Test extends AbstractAssetTest { + + public TetherUSDTRC20Test() { + super(new TetherUSDTRC20()); + } + + @Test + public void testValidAddresses() { + assertValidAddress("TVnmu3E6DYVL4bpAoZnPNEPVUrgC7eSWaX"); + } + + @Test + public void testInvalidAddresses() { + assertInvalidAddress("0x2a65Aca4D5fC5B5C859090a6c34d1641353982266"); + assertInvalidAddress("0x2a65Aca4D5fC5B5C859090a6c34d16413539822g"); + assertInvalidAddress("2a65Aca4D5fC5B5C859090a6c34d16413539822g"); + } + } \ No newline at end of file diff --git a/build.gradle b/build.gradle index e3845410ba..d35c6bd05c 100644 --- a/build.gradle +++ b/build.gradle @@ -9,8 +9,8 @@ buildscript { classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.17' classpath 'com.google.gradle:osdetector-gradle-plugin:1.7.3' classpath 'com.github.johnrengelman:shadow:8.1.1' - classpath 'org.springframework.boot:spring-boot-gradle-plugin:2.6.3' - classpath 'com.gradle:gradle-enterprise-gradle-plugin:3.12.4' // added for windows build verification-metadata.xml error + classpath 'org.springframework.boot:spring-boot-gradle-plugin:3.2.3' + classpath 'com.gradle:gradle-enterprise-gradle-plugin:3.16.1' // added for windows build verification-metadata.xml error } } @@ -31,7 +31,7 @@ configure(subprojects) { apply plugin: 'jacoco-report-aggregation' apply plugin: 'checkstyle' - sourceCompatibility = JavaVersion.VERSION_11 + sourceCompatibility = JavaVersion.VERSION_21 ext { // in alphabetical order bcVersion = '1.63' @@ -47,16 +47,16 @@ configure(subprojects) { fontawesomefxMaterialdesignfontVersion = '2.0.26-9.1.2' grpcVersion = '1.42.1' gsonVersion = '2.8.5' - guavaVersion = '30.1.1-jre' - guiceVersion = '5.1.0' - moneroJavaVersion = '0.8.6' + guavaVersion = '32.1.1-jre' + guiceVersion = '7.0.0' + moneroJavaVersion = '0.8.33' httpclient5Version = '5.0' hamcrestVersion = '2.2' httpclientVersion = '4.5.12' httpcoreVersion = '4.4.13' ioVersion = '2.6' jacksonVersion = '2.12.1' - javafxVersion = '16' + javafxVersion = '21.0.2' javaxAnnotationVersion = '1.2' jcsvVersion = '1.4.0' jetbrainsAnnotationsVersion = '13.0' @@ -69,9 +69,9 @@ configure(subprojects) { langVersion = '3.11' logbackVersion = '1.1.11' loggingVersion = '1.2' - lombokVersion = '1.18.24' - mockitoVersion = '5.2.0' - netlayerVersion = '6797461310f077bbea4f43a3a509c077b0ed8c34' // Netlayer version 0.7.3 with Tor browser version 11.0.14 and tor binary version: 0.4.7.7 + lombokVersion = '1.18.30' + mockitoVersion = '5.10.0' + netlayerVersion = 'e2ce2a142c' // Tor browser version 13.0.15 and tor binary version: 0.4.8.11 protobufVersion = '3.19.1' protocVersion = protobufVersion pushyVersion = '0.13.2' @@ -163,18 +163,33 @@ configure([project(':cli'), // edit generated shell scripts such that they expect to be executed in the // project root dir as opposed to a 'bin' subdirectory - def windowsScriptFile = file("${rootProject.projectDir}/haveno-${applicationName}.bat") - windowsScriptFile.text = windowsScriptFile.text.replace( - 'set APP_HOME=%DIRNAME%..', 'set APP_HOME=%DIRNAME%') + if (osdetector.os == 'windows') { + def windowsScriptFile = file("${rootProject.projectDir}/haveno-${applicationName}.bat") + windowsScriptFile.text = windowsScriptFile.text.replace( + 'set APP_HOME=%DIRNAME%..', 'set APP_HOME=%DIRNAME%') - def unixScriptFile = file("${rootProject.projectDir}/haveno-$applicationName") - unixScriptFile.text = unixScriptFile.text.replace( - 'APP_HOME=$( cd "${APP_HOME:-./}.." && pwd -P ) || exit', 'APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit') + if (applicationName == 'desktop') { + windowsScriptFile.text = windowsScriptFile.text.replace( + 'DEFAULT_JVM_OPTS=', 'DEFAULT_JVM_OPTS=-XX:MaxRAM=4g ' + + '--add-opens=javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED ' + + '--add-opens=javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED ' + + '--add-opens=java.base/java.lang.reflect=ALL-UNNAMED ' + + '--add-opens=javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED') + } + } + else { + def unixScriptFile = file("${rootProject.projectDir}/haveno-$applicationName") + unixScriptFile.text = unixScriptFile.text.replace( + 'APP_HOME=$( cd "${APP_HOME:-./}.." > /dev/null && pwd -P ) || exit', 'APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit') - if (applicationName == 'desktop') { - def script = file("${rootProject.projectDir}/haveno-$applicationName") - script.text = script.text.replace( - 'DEFAULT_JVM_OPTS=""', 'DEFAULT_JVM_OPTS="-XX:MaxRAM=4g"') + if (applicationName == 'desktop') { + unixScriptFile.text = unixScriptFile.text.replace( + 'DEFAULT_JVM_OPTS=""', 'DEFAULT_JVM_OPTS="-XX:MaxRAM=4g ' + + '--add-opens=javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED ' + + '--add-opens=javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED ' + + '--add-opens=java.base/java.lang.reflect=ALL-UNNAMED ' + + '--add-opens=javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED"') + } } if (applicationName == 'apitest') { @@ -302,9 +317,8 @@ configure(project(':common')) { exclude(module: 'animal-sniffer-annotations') } - // override transitive dependency version from 1.5 to the same version just identified by commit number. - // Remove this if transitive dependency is changed to something else than 1.5 - implementation(group: 'com.github.JesusMcCloud', name: 'jtorctl') { version { strictly "[9b5ba2036b]" } } + // override transitive dependency and use latest version from bisq + implementation(group: 'com.github.bisq-network', name: 'jtorctl') { version { strictly "[b2a172f44edcd8deaa5ed75d936dcbb007f0d774]" } } implementation "org.openjfx:javafx-base:$javafxVersion:$os" implementation "org.openjfx:javafx-graphics:$javafxVersion:$os" } @@ -320,10 +334,11 @@ configure(project(':p2p')) { implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation "org.fxmisc.easybind:easybind:$easybindVersion" implementation "org.slf4j:slf4j-api:$slf4jVersion" - implementation("com.github.bisq-network.netlayer:tor.external:$netlayerVersion") { + implementation "org.apache.commons:commons-lang3:$langVersion" + implementation("com.github.haveno-dex.netlayer:tor.external:$netlayerVersion") { exclude(module: 'slf4j-api') } - implementation("com.github.bisq-network.netlayer:tor.native:$netlayerVersion") { + implementation("com.github.haveno-dex.netlayer:tor.native:$netlayerVersion") { exclude(module: 'slf4j-api') } implementation("com.github.bisq-network:bitcoinj:$bitcoinjVersion") { @@ -350,6 +365,7 @@ configure(project(':p2p')) { testImplementation "ch.qos.logback:logback-core:$logbackVersion" testImplementation "org.apache.commons:commons-lang3:$langVersion" testImplementation("org.mockito:mockito-core:$mockitoVersion") + testImplementation("org.mockito:mockito-junit-jupiter:$mockitoVersion") implementation "org.openjfx:javafx-base:$javafxVersion:$os" implementation "org.openjfx:javafx-graphics:$javafxVersion:$os" @@ -384,10 +400,10 @@ configure(project(':core')) { implementation("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") { exclude(module: 'jackson-annotations') } - implementation("com.github.bisq-network.netlayer:tor.native:$netlayerVersion") { + implementation("com.github.haveno-dex.netlayer:tor.native:$netlayerVersion") { exclude(module: 'slf4j-api') } - implementation("com.github.bisq-network.netlayer:tor.external:$netlayerVersion") { + implementation("com.github.haveno-dex.netlayer:tor.external:$netlayerVersion") { exclude(module: 'slf4j-api') } implementation("com.github.bisq-network:bitcoinj:$bitcoinjVersion") { @@ -419,7 +435,7 @@ configure(project(':core')) { implementation "org.openjfx:javafx-base:$javafxVersion:$os" implementation "org.openjfx:javafx-graphics:$javafxVersion:$os" - implementation("io.github.monero-ecosystem:monero-java:$moneroJavaVersion") { + implementation("io.github.woodser:monero-java:$moneroJavaVersion") { exclude(module: 'jackson-core') exclude(module: 'jackson-annotations') exclude(module: 'jackson-databind') @@ -432,16 +448,23 @@ configure(project(':core')) { systemProperty 'jdk.attach.allowAttachSelf', true } + task generateKeypairs(type: JavaExec) { + mainClass = 'haveno.core.util.GenerateKeyPairs' + classpath = sourceSets.main.runtimeClasspath + } + task havenoDeps { doLast { // get monero binaries download url Map moneroBinaries = [ - 'linux' : 'https://github.com/haveno-dex/monero/releases/download/testing13/monero-bins-haveno-linux.tar.gz', - 'linux-sha256' : 'eac55092b97162854f2a94f7895d52cf4a20eba0a55a1769ce053060d6be6195', - 'mac' : 'https://github.com/haveno-dex/monero/releases/download/testing13/monero-bins-haveno-mac.tar.gz', - 'mac-sha256' : 'e7bf40ef35cb278649c63f8651cee6124d4a5e97448dfa407b193572ebd85fb6', - 'windows' : 'https://github.com/haveno-dex/monero/releases/download/testing13/monero-bins-haveno-windows.zip', - 'windows-sha256': 'f7da08d793041103c069b23229040fc4f9632009317b84d201f63f477d3ca3dd' + 'linux-x86_64' : 'https://github.com/haveno-dex/monero/releases/download/release4/monero-bins-haveno-linux-x86_64.tar.gz', + 'linux-x86_64-sha256' : '0810808292fd5ad595a46a7fcc8ecb28d251d80f8d75c0e7a7d51afbeb413b68', + 'linux-aarch64' : 'https://github.com/haveno-dex/monero/releases/download/release4/monero-bins-haveno-linux-aarch64.tar.gz', + 'linux-aarch64-sha256' : '61222ee8e2021aaf59ab8813543afc5548f484190ee9360bc9cfa8fdf21cc1de', + 'mac' : 'https://github.com/haveno-dex/monero/releases/download/release4/monero-bins-haveno-mac.tar.gz', + 'mac-sha256' : '5debb8d8d8dd63809e8351368a11aa85c47987f1a8a8f2dcca343e60bcff3287', + 'windows' : 'https://github.com/haveno-dex/monero/releases/download/release4/monero-bins-haveno-windows.zip', + 'windows-sha256' : 'd7c14f029db37ae2a8bc6b74c35f572283257df5fbcc8cc97b704d1a97be9888' ] String osKey @@ -450,7 +473,12 @@ configure(project(':core')) { } else if (Os.isFamily(Os.FAMILY_MAC)) { osKey = 'mac' } else { - osKey = 'linux' + String architecture = System.getProperty("os.arch").toLowerCase() + if (architecture.contains('aarch64') || architecture.contains('arm')) { + osKey = 'linux-aarch64' + } else { + osKey = 'linux-x86_64' + } } String moneroDownloadUrl = moneroBinaries[osKey] @@ -509,6 +537,7 @@ configure(project(':core')) { ext.downloadAndVerifyDependencies = { String archiveURL, String archiveSHA256, File destinationArchiveFile -> ext.dependencyDownloadedAndVerified = false + // if archive exists, check to see if its already up to date if (destinationArchiveFile.exists()) { println "Verifying existing archive ${destinationArchiveFile}" @@ -522,14 +551,15 @@ configure(project(':core')) { } } + // download archives println "Downloading ${archiveURL}" ant.get(src: archiveURL, dest: destinationArchiveFile) println 'Download saved to ' + destinationArchiveFile + // verify checksum println 'Verifying checksum for downloaded binary ...' ant.archiveHash = archiveSHA256 - // use a different verifyProperty name from existing verification or it will always fail - ant.checksum(file: destinationArchiveFile, algorithm: 'SHA-256', property: '${archiveHash}', verifyProperty: 'downloadedHashMatches') + ant.checksum(file: destinationArchiveFile, algorithm: 'SHA-256', property: '${archiveHash}', verifyProperty: 'downloadedHashMatches') // use a different verifyProperty name from existing verification or it will always fail if (ant.properties['downloadedHashMatches'] != 'true') { ant.fail('Checksum mismatch: Downloaded archive has a different checksum than expected') } @@ -580,7 +610,7 @@ configure(project(':desktop')) { apply plugin: 'com.github.johnrengelman.shadow' apply from: 'package/package.gradle' - version = '1.0.11-SNAPSHOT' + version = '1.0.14-SNAPSHOT' jar.manifest.attributes( "Implementation-Title": project.name, @@ -641,7 +671,7 @@ configure(project(':desktop')) { testImplementation "org.junit.jupiter:junit-jupiter-api:$jupiterVersion" testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$jupiterVersion" - implementation("io.github.monero-ecosystem:monero-java:$moneroJavaVersion") { + implementation("io.github.woodser:monero-java:$moneroJavaVersion") { exclude(module: 'jackson-core') exclude(module: 'jackson-annotations') exclude(module: 'jackson-databind') @@ -675,10 +705,10 @@ configure(project(':monitor')) { implementation "ch.qos.logback:logback-core:$logbackVersion" implementation "com.google.guava:guava:$guavaVersion" implementation "org.slf4j:slf4j-api:$slf4jVersion" - implementation("com.github.bisq-network.netlayer:tor.external:$netlayerVersion") { + implementation("com.github.haveno-dex.netlayer:tor.external:$netlayerVersion") { exclude(module: 'slf4j-api') } - implementation("com.github.bisq-network.netlayer:tor.native:$netlayerVersion") { + implementation("com.github.haveno-dex.netlayer:tor.native:$netlayerVersion") { exclude(module: 'slf4j-api') } implementation("com.google.inject:guice:$guiceVersion") { @@ -805,7 +835,7 @@ configure(project(':daemon')) { testImplementation "org.junit.jupiter:junit-jupiter-params:$jupiterVersion" testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$jupiterVersion") - implementation("io.github.monero-ecosystem:monero-java:$moneroJavaVersion") { + implementation("io.github.woodser:monero-java:$moneroJavaVersion") { exclude(module: 'jackson-core') exclude(module: 'jackson-annotations') exclude(module: 'jackson-databind') diff --git a/cli/src/main/java/haveno/cli/CliMain.java b/cli/src/main/java/haveno/cli/CliMain.java index 6063227be8..58dcce4631 100644 --- a/cli/src/main/java/haveno/cli/CliMain.java +++ b/cli/src/main/java/haveno/cli/CliMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/ColumnHeaderConstants.java b/cli/src/main/java/haveno/cli/ColumnHeaderConstants.java index 19e7ccfd98..5f1ef39e69 100644 --- a/cli/src/main/java/haveno/cli/ColumnHeaderConstants.java +++ b/cli/src/main/java/haveno/cli/ColumnHeaderConstants.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/CryptoCurrencyUtil.java b/cli/src/main/java/haveno/cli/CryptoCurrencyUtil.java index cd9b5ef8d0..572130db86 100644 --- a/cli/src/main/java/haveno/cli/CryptoCurrencyUtil.java +++ b/cli/src/main/java/haveno/cli/CryptoCurrencyUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/CurrencyFormat.java b/cli/src/main/java/haveno/cli/CurrencyFormat.java index 4686dee1a5..c88b8c62e7 100644 --- a/cli/src/main/java/haveno/cli/CurrencyFormat.java +++ b/cli/src/main/java/haveno/cli/CurrencyFormat.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/DirectionFormat.java b/cli/src/main/java/haveno/cli/DirectionFormat.java index f0d99a67c5..28a30f170e 100644 --- a/cli/src/main/java/haveno/cli/DirectionFormat.java +++ b/cli/src/main/java/haveno/cli/DirectionFormat.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/GrpcClient.java b/cli/src/main/java/haveno/cli/GrpcClient.java index f08a16df93..229104ccde 100644 --- a/cli/src/main/java/haveno/cli/GrpcClient.java +++ b/cli/src/main/java/haveno/cli/GrpcClient.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/GrpcStubs.java b/cli/src/main/java/haveno/cli/GrpcStubs.java index 677372d8fc..417496178d 100644 --- a/cli/src/main/java/haveno/cli/GrpcStubs.java +++ b/cli/src/main/java/haveno/cli/GrpcStubs.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/Method.java b/cli/src/main/java/haveno/cli/Method.java index 395da4b289..f83416c3b1 100644 --- a/cli/src/main/java/haveno/cli/Method.java +++ b/cli/src/main/java/haveno/cli/Method.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/PasswordCallCredentials.java b/cli/src/main/java/haveno/cli/PasswordCallCredentials.java index fd7289ce6d..f7809d1a88 100644 --- a/cli/src/main/java/haveno/cli/PasswordCallCredentials.java +++ b/cli/src/main/java/haveno/cli/PasswordCallCredentials.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/TransactionFormat.java b/cli/src/main/java/haveno/cli/TransactionFormat.java index e8a2cdcaea..fc0b5ab93a 100644 --- a/cli/src/main/java/haveno/cli/TransactionFormat.java +++ b/cli/src/main/java/haveno/cli/TransactionFormat.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli; diff --git a/cli/src/main/java/haveno/cli/opts/AbstractMethodOptionParser.java b/cli/src/main/java/haveno/cli/opts/AbstractMethodOptionParser.java index d9c372975e..9ad9a374d2 100644 --- a/cli/src/main/java/haveno/cli/opts/AbstractMethodOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/AbstractMethodOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/ArgumentList.java b/cli/src/main/java/haveno/cli/opts/ArgumentList.java index 0ef04d2ca9..cf8ff977bd 100644 --- a/cli/src/main/java/haveno/cli/opts/ArgumentList.java +++ b/cli/src/main/java/haveno/cli/opts/ArgumentList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/CancelOfferOptionParser.java b/cli/src/main/java/haveno/cli/opts/CancelOfferOptionParser.java index 1588aa83e9..b0439b5f4d 100644 --- a/cli/src/main/java/haveno/cli/opts/CancelOfferOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/CancelOfferOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java b/cli/src/main/java/haveno/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java index d11383e06c..9a65e7ca4b 100644 --- a/cli/src/main/java/haveno/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/CreateCryptoCurrencyPaymentAcctOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/CreateOfferOptionParser.java b/cli/src/main/java/haveno/cli/opts/CreateOfferOptionParser.java index 204e04c3ae..610667cd0b 100644 --- a/cli/src/main/java/haveno/cli/opts/CreateOfferOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/CreateOfferOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/CreatePaymentAcctOptionParser.java b/cli/src/main/java/haveno/cli/opts/CreatePaymentAcctOptionParser.java index 3b5cddd7c5..8070a83446 100644 --- a/cli/src/main/java/haveno/cli/opts/CreatePaymentAcctOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/CreatePaymentAcctOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetAddressBalanceOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetAddressBalanceOptionParser.java index c316b9a1eb..f0f9ff1c63 100644 --- a/cli/src/main/java/haveno/cli/opts/GetAddressBalanceOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetAddressBalanceOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetBTCMarketPriceOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetBTCMarketPriceOptionParser.java index 9b2d1d592f..8efc94be80 100644 --- a/cli/src/main/java/haveno/cli/opts/GetBTCMarketPriceOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetBTCMarketPriceOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetBalanceOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetBalanceOptionParser.java index 671741b395..9fa008c3f5 100644 --- a/cli/src/main/java/haveno/cli/opts/GetBalanceOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetBalanceOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetOfferOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetOfferOptionParser.java index 4ad5e89e63..961674de27 100644 --- a/cli/src/main/java/haveno/cli/opts/GetOfferOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetOfferOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetOffersOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetOffersOptionParser.java index 74064d877e..a06652554b 100644 --- a/cli/src/main/java/haveno/cli/opts/GetOffersOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetOffersOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetPaymentAcctFormOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetPaymentAcctFormOptionParser.java index fab6283419..101bca8e14 100644 --- a/cli/src/main/java/haveno/cli/opts/GetPaymentAcctFormOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetPaymentAcctFormOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetTradeOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetTradeOptionParser.java index 60bfd0df2e..372bf3fb14 100644 --- a/cli/src/main/java/haveno/cli/opts/GetTradeOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetTradeOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetTradesOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetTradesOptionParser.java index 484fd094b8..9d7ca04bb0 100644 --- a/cli/src/main/java/haveno/cli/opts/GetTradesOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetTradesOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/GetTransactionOptionParser.java b/cli/src/main/java/haveno/cli/opts/GetTransactionOptionParser.java index 722427e4e4..32bbf0f862 100644 --- a/cli/src/main/java/haveno/cli/opts/GetTransactionOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/GetTransactionOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/MethodOpts.java b/cli/src/main/java/haveno/cli/opts/MethodOpts.java index 55053a8483..167cec87e6 100644 --- a/cli/src/main/java/haveno/cli/opts/MethodOpts.java +++ b/cli/src/main/java/haveno/cli/opts/MethodOpts.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/OfferIdOptionParser.java b/cli/src/main/java/haveno/cli/opts/OfferIdOptionParser.java index 7c8d316f3f..4161e5e039 100644 --- a/cli/src/main/java/haveno/cli/opts/OfferIdOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/OfferIdOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/OptLabel.java b/cli/src/main/java/haveno/cli/opts/OptLabel.java index 1ec5ad62a2..79ad2ae1f6 100644 --- a/cli/src/main/java/haveno/cli/opts/OptLabel.java +++ b/cli/src/main/java/haveno/cli/opts/OptLabel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/RegisterDisputeAgentOptionParser.java b/cli/src/main/java/haveno/cli/opts/RegisterDisputeAgentOptionParser.java index 29f78c4c5d..c9c2292682 100644 --- a/cli/src/main/java/haveno/cli/opts/RegisterDisputeAgentOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/RegisterDisputeAgentOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/RemoveWalletPasswordOptionParser.java b/cli/src/main/java/haveno/cli/opts/RemoveWalletPasswordOptionParser.java index 66d77a475f..4483af9457 100644 --- a/cli/src/main/java/haveno/cli/opts/RemoveWalletPasswordOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/RemoveWalletPasswordOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/SendBtcOptionParser.java b/cli/src/main/java/haveno/cli/opts/SendBtcOptionParser.java index 6f13d55a04..12eec3bc5a 100644 --- a/cli/src/main/java/haveno/cli/opts/SendBtcOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/SendBtcOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/SetTxFeeRateOptionParser.java b/cli/src/main/java/haveno/cli/opts/SetTxFeeRateOptionParser.java index 5a15a668f5..3fbd9ab3ea 100644 --- a/cli/src/main/java/haveno/cli/opts/SetTxFeeRateOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/SetTxFeeRateOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/SetWalletPasswordOptionParser.java b/cli/src/main/java/haveno/cli/opts/SetWalletPasswordOptionParser.java index 9e2b0dc584..4b180fe328 100644 --- a/cli/src/main/java/haveno/cli/opts/SetWalletPasswordOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/SetWalletPasswordOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/SimpleMethodOptionParser.java b/cli/src/main/java/haveno/cli/opts/SimpleMethodOptionParser.java index 1390a76c26..93ee2ce715 100644 --- a/cli/src/main/java/haveno/cli/opts/SimpleMethodOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/SimpleMethodOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/TakeOfferOptionParser.java b/cli/src/main/java/haveno/cli/opts/TakeOfferOptionParser.java index f63ce86fee..e45ea776c1 100644 --- a/cli/src/main/java/haveno/cli/opts/TakeOfferOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/TakeOfferOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/UnlockWalletOptionParser.java b/cli/src/main/java/haveno/cli/opts/UnlockWalletOptionParser.java index 1079dce163..dad3f8269f 100644 --- a/cli/src/main/java/haveno/cli/opts/UnlockWalletOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/UnlockWalletOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/opts/WithdrawFundsOptionParser.java b/cli/src/main/java/haveno/cli/opts/WithdrawFundsOptionParser.java index afe28c8b68..9670299470 100644 --- a/cli/src/main/java/haveno/cli/opts/WithdrawFundsOptionParser.java +++ b/cli/src/main/java/haveno/cli/opts/WithdrawFundsOptionParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.opts; diff --git a/cli/src/main/java/haveno/cli/request/OffersServiceRequest.java b/cli/src/main/java/haveno/cli/request/OffersServiceRequest.java index c9b441d9fb..2fcb3426d1 100644 --- a/cli/src/main/java/haveno/cli/request/OffersServiceRequest.java +++ b/cli/src/main/java/haveno/cli/request/OffersServiceRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.request; @@ -81,7 +81,7 @@ public class OffersServiceRequest { .setUseMarketBasedPrice(useMarketBasedPrice) .setPrice(fixedPrice) .setMarketPriceMarginPct(marketPriceMarginPct) - .setBuyerSecurityDepositPct(securityDepositPct) + .setSecurityDepositPct(securityDepositPct) .setPaymentAccountId(paymentAcctId) .setTriggerPrice(triggerPrice) .build(); diff --git a/cli/src/main/java/haveno/cli/request/PaymentAccountsServiceRequest.java b/cli/src/main/java/haveno/cli/request/PaymentAccountsServiceRequest.java index dc2e059d6c..4aaa53ebb3 100644 --- a/cli/src/main/java/haveno/cli/request/PaymentAccountsServiceRequest.java +++ b/cli/src/main/java/haveno/cli/request/PaymentAccountsServiceRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.request; diff --git a/cli/src/main/java/haveno/cli/request/TradesServiceRequest.java b/cli/src/main/java/haveno/cli/request/TradesServiceRequest.java index 513dbf8522..e4826771c0 100644 --- a/cli/src/main/java/haveno/cli/request/TradesServiceRequest.java +++ b/cli/src/main/java/haveno/cli/request/TradesServiceRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.request; diff --git a/cli/src/main/java/haveno/cli/request/WalletsServiceRequest.java b/cli/src/main/java/haveno/cli/request/WalletsServiceRequest.java index 7ff6eebb0b..dde9ce2529 100644 --- a/cli/src/main/java/haveno/cli/request/WalletsServiceRequest.java +++ b/cli/src/main/java/haveno/cli/request/WalletsServiceRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.request; diff --git a/cli/src/main/java/haveno/cli/table/Table.java b/cli/src/main/java/haveno/cli/table/Table.java index 3f0c45f5bc..66a14c4093 100644 --- a/cli/src/main/java/haveno/cli/table/Table.java +++ b/cli/src/main/java/haveno/cli/table/Table.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table; diff --git a/cli/src/main/java/haveno/cli/table/builder/AbstractTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/AbstractTableBuilder.java index c97333e313..17cf2f71f4 100644 --- a/cli/src/main/java/haveno/cli/table/builder/AbstractTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/AbstractTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java b/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java index 848dfd742f..b279f68b8e 100644 --- a/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/AbstractTradeListBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; @@ -60,9 +60,9 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { @Nullable protected final MixedTradeFeeColumn colMixedTradeFee; @Nullable - protected final Column<Long> colBuyerDeposit; + protected final Column<Double> colBuyerDeposit; @Nullable - protected final Column<Long> colSellerDeposit; + protected final Column<Double> colSellerDeposit; @Nullable protected final Column<String> colPaymentMethod; @Nullable @@ -189,7 +189,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { protected final Function<TradeInfo, Long> toTradeFeeBtc = (t) -> { var isMyOffer = t.getOffer().getIsMyOffer(); if (isMyOffer) { - return t.getOffer().getMakerFee(); + return t.getMakerFee(); } else { return t.getTakerFee(); } @@ -198,7 +198,7 @@ abstract class AbstractTradeListBuilder extends AbstractTableBuilder { protected final Function<TradeInfo, Long> toMyMakerOrTakerFee = (t) -> { return isTaker.test(t) ? t.getTakerFee() - : t.getOffer().getMakerFee(); + : t.getMakerFee(); }; protected final Function<TradeInfo, String> toOfferType = (t) -> { diff --git a/cli/src/main/java/haveno/cli/table/builder/AddressBalanceTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/AddressBalanceTableBuilder.java index b2c1376a08..4c26d30c05 100644 --- a/cli/src/main/java/haveno/cli/table/builder/AddressBalanceTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/AddressBalanceTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/BtcBalanceTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/BtcBalanceTableBuilder.java index 40180f6040..41f3a18f38 100644 --- a/cli/src/main/java/haveno/cli/table/builder/BtcBalanceTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/BtcBalanceTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/ClosedTradeTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/ClosedTradeTableBuilder.java index 251eeb4211..c57baf63d8 100644 --- a/cli/src/main/java/haveno/cli/table/builder/ClosedTradeTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/ClosedTradeTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; @@ -61,8 +61,8 @@ class ClosedTradeTableBuilder extends AbstractTradeListBuilder { colMixedTradeFee.addRow(toTradeFeeBtc.apply(t), false); - colBuyerDeposit.addRow(t.getOffer().getBuyerSecurityDeposit()); - colSellerDeposit.addRow(t.getOffer().getSellerSecurityDeposit()); + colBuyerDeposit.addRow(t.getOffer().getBuyerSecurityDepositPct()); + colSellerDeposit.addRow(t.getOffer().getSellerSecurityDepositPct()); colOfferType.addRow(toOfferType.apply(t)); }); } diff --git a/cli/src/main/java/haveno/cli/table/builder/FailedTradeTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/FailedTradeTableBuilder.java index 3cecb2cb7e..9f30cfe81f 100644 --- a/cli/src/main/java/haveno/cli/table/builder/FailedTradeTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/FailedTradeTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/OfferTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/OfferTableBuilder.java index 4a2d1d71fa..23b93ca6ae 100644 --- a/cli/src/main/java/haveno/cli/table/builder/OfferTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/OfferTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/OpenTradeTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/OpenTradeTableBuilder.java index e6ce9b0dfd..dab9e09a8c 100644 --- a/cli/src/main/java/haveno/cli/table/builder/OpenTradeTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/OpenTradeTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/PaymentAccountTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/PaymentAccountTableBuilder.java index 3f211020a1..3cfbfcaa31 100644 --- a/cli/src/main/java/haveno/cli/table/builder/PaymentAccountTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/PaymentAccountTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/TableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/TableBuilder.java index 235b2cb9db..cff4dde629 100644 --- a/cli/src/main/java/haveno/cli/table/builder/TableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/TableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/TableBuilderConstants.java b/cli/src/main/java/haveno/cli/table/builder/TableBuilderConstants.java index d9e0f793c0..893f9f8bf2 100644 --- a/cli/src/main/java/haveno/cli/table/builder/TableBuilderConstants.java +++ b/cli/src/main/java/haveno/cli/table/builder/TableBuilderConstants.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/TableType.java b/cli/src/main/java/haveno/cli/table/builder/TableType.java index a009ca60b1..871240abb3 100644 --- a/cli/src/main/java/haveno/cli/table/builder/TableType.java +++ b/cli/src/main/java/haveno/cli/table/builder/TableType.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/TradeDetailTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/TradeDetailTableBuilder.java index 4e12998d79..bf8a0c2bce 100644 --- a/cli/src/main/java/haveno/cli/table/builder/TradeDetailTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/TradeDetailTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/builder/TradeTableColumnSupplier.java b/cli/src/main/java/haveno/cli/table/builder/TradeTableColumnSupplier.java index c0972f28bd..d1974344df 100644 --- a/cli/src/main/java/haveno/cli/table/builder/TradeTableColumnSupplier.java +++ b/cli/src/main/java/haveno/cli/table/builder/TradeTableColumnSupplier.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; import haveno.cli.table.column.CryptoVolumeColumn; +import haveno.cli.table.column.DoubleColumn; import haveno.cli.table.column.BooleanColumn; import haveno.cli.table.column.BtcColumn; import haveno.cli.table.column.Column; @@ -169,8 +170,8 @@ class TradeTableColumnSupplier { : null; }; - final Function<String, Column<Long>> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get() - ? new SatoshiColumn(name) + final Function<String, Column<Double>> toSecurityDepositColumn = (name) -> isClosedTradeTblBuilder.get() + ? new DoubleColumn(name) : null; final Supplier<StringColumn> offerTypeColumn = () -> isTradeDetailTblBuilder.get() diff --git a/cli/src/main/java/haveno/cli/table/builder/TransactionTableBuilder.java b/cli/src/main/java/haveno/cli/table/builder/TransactionTableBuilder.java index 91692c982d..a07b135ccd 100644 --- a/cli/src/main/java/haveno/cli/table/builder/TransactionTableBuilder.java +++ b/cli/src/main/java/haveno/cli/table/builder/TransactionTableBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.builder; diff --git a/cli/src/main/java/haveno/cli/table/column/AbstractColumn.java b/cli/src/main/java/haveno/cli/table/column/AbstractColumn.java index 6a28f251b2..b9f3b074e0 100644 --- a/cli/src/main/java/haveno/cli/table/column/AbstractColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/AbstractColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/BooleanColumn.java b/cli/src/main/java/haveno/cli/table/column/BooleanColumn.java index 4b95f29d6f..4a34e098d4 100644 --- a/cli/src/main/java/haveno/cli/table/column/BooleanColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/BooleanColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/Column.java b/cli/src/main/java/haveno/cli/table/column/Column.java index a9a059f469..7078730658 100644 --- a/cli/src/main/java/haveno/cli/table/column/Column.java +++ b/cli/src/main/java/haveno/cli/table/column/Column.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/CryptoVolumeColumn.java b/cli/src/main/java/haveno/cli/table/column/CryptoVolumeColumn.java index 8eb9b574a5..153e2735d5 100644 --- a/cli/src/main/java/haveno/cli/table/column/CryptoVolumeColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/CryptoVolumeColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/DoubleColumn.java b/cli/src/main/java/haveno/cli/table/column/DoubleColumn.java index ce4039aaf1..812f421c14 100644 --- a/cli/src/main/java/haveno/cli/table/column/DoubleColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/DoubleColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/IntegerColumn.java b/cli/src/main/java/haveno/cli/table/column/IntegerColumn.java index 1b769ba820..5d9538e581 100644 --- a/cli/src/main/java/haveno/cli/table/column/IntegerColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/IntegerColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/Iso8601DateTimeColumn.java b/cli/src/main/java/haveno/cli/table/column/Iso8601DateTimeColumn.java index 46c71cf20b..df87a50044 100644 --- a/cli/src/main/java/haveno/cli/table/column/Iso8601DateTimeColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/Iso8601DateTimeColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/LongColumn.java b/cli/src/main/java/haveno/cli/table/column/LongColumn.java index 812dae0cab..1499b0cba2 100644 --- a/cli/src/main/java/haveno/cli/table/column/LongColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/LongColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/MixedTradeFeeColumn.java b/cli/src/main/java/haveno/cli/table/column/MixedTradeFeeColumn.java index e6bee9b43e..4e54759eca 100644 --- a/cli/src/main/java/haveno/cli/table/column/MixedTradeFeeColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/MixedTradeFeeColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/NumberColumn.java b/cli/src/main/java/haveno/cli/table/column/NumberColumn.java index 6a2d0dd4fd..69c6784409 100644 --- a/cli/src/main/java/haveno/cli/table/column/NumberColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/NumberColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/SatoshiColumn.java b/cli/src/main/java/haveno/cli/table/column/SatoshiColumn.java index d6ee310f03..767e878d57 100644 --- a/cli/src/main/java/haveno/cli/table/column/SatoshiColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/SatoshiColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/StringColumn.java b/cli/src/main/java/haveno/cli/table/column/StringColumn.java index 91de7af364..6762228728 100644 --- a/cli/src/main/java/haveno/cli/table/column/StringColumn.java +++ b/cli/src/main/java/haveno/cli/table/column/StringColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/cli/src/main/java/haveno/cli/table/column/ZippedStringColumns.java b/cli/src/main/java/haveno/cli/table/column/ZippedStringColumns.java index 2b1d736ffa..d55468d8fa 100644 --- a/cli/src/main/java/haveno/cli/table/column/ZippedStringColumns.java +++ b/cli/src/main/java/haveno/cli/table/column/ZippedStringColumns.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.cli.table.column; diff --git a/common/src/main/java/haveno/common/ClockWatcher.java b/common/src/main/java/haveno/common/ClockWatcher.java index b810b367a5..7bd8454c78 100644 --- a/common/src/main/java/haveno/common/ClockWatcher.java +++ b/common/src/main/java/haveno/common/ClockWatcher.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Singleton; +import com.google.inject.Singleton; import java.util.LinkedList; import java.util.List; import java.util.concurrent.TimeUnit; +import lombok.extern.slf4j.Slf4j; // Helps configure listener objects that are run by the `UserThread` each second // and can do per second, per minute and delayed second actions. Also detects when we were in standby, and logs it. @@ -55,25 +54,27 @@ public class ClockWatcher { if (timer == null) { lastSecondTick = System.currentTimeMillis(); timer = UserThread.runPeriodically(() -> { - listeners.forEach(Listener::onSecondTick); - counter++; - if (counter >= 60) { - counter = 0; - listeners.forEach(Listener::onMinuteTick); - } - - long currentTimeMillis = System.currentTimeMillis(); - long diff = currentTimeMillis - lastSecondTick; - if (diff > 1000) { - long missedMs = diff - 1000; - listeners.forEach(listener -> listener.onMissedSecondTick(missedMs)); - - if (missedMs > ClockWatcher.IDLE_TOLERANCE_MS) { - log.info("We have been in standby mode for {} sec", missedMs / 1000); - listeners.forEach(listener -> listener.onAwakeFromStandby(missedMs)); + synchronized (listeners) { + listeners.forEach(Listener::onSecondTick); + counter++; + if (counter >= 60) { + counter = 0; + listeners.forEach(Listener::onMinuteTick); } + + long currentTimeMillis = System.currentTimeMillis(); + long diff = currentTimeMillis - lastSecondTick; + if (diff > 1000) { + long missedMs = diff - 1000; + listeners.forEach(listener -> listener.onMissedSecondTick(missedMs)); + + if (missedMs > ClockWatcher.IDLE_TOLERANCE_MS) { + log.info("We have been in standby mode for {} sec", missedMs / 1000); + listeners.forEach(listener -> listener.onAwakeFromStandby(missedMs)); + } + } + lastSecondTick = currentTimeMillis; } - lastSecondTick = currentTimeMillis; }, 1, TimeUnit.SECONDS); } } @@ -85,10 +86,14 @@ public class ClockWatcher { } public void addListener(Listener listener) { - listeners.add(listener); + synchronized (listeners) { + listeners.add(listener); + } } public void removeListener(Listener listener) { - listeners.remove(listener); + synchronized (listeners) { + listeners.remove(listener); + } } } diff --git a/common/src/main/java/haveno/common/Envelope.java b/common/src/main/java/haveno/common/Envelope.java index 457c896f59..783e5b05a8 100644 --- a/common/src/main/java/haveno/common/Envelope.java +++ b/common/src/main/java/haveno/common/Envelope.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/FrameRateTimer.java b/common/src/main/java/haveno/common/FrameRateTimer.java index aca251daf2..32a1513369 100644 --- a/common/src/main/java/haveno/common/FrameRateTimer.java +++ b/common/src/main/java/haveno/common/FrameRateTimer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/HavenoException.java b/common/src/main/java/haveno/common/HavenoException.java index f34ca8544f..3ff8ef22c4 100644 --- a/common/src/main/java/haveno/common/HavenoException.java +++ b/common/src/main/java/haveno/common/HavenoException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/MasterTimer.java b/common/src/main/java/haveno/common/MasterTimer.java index bbdfe731b2..dde6ea146d 100644 --- a/common/src/main/java/haveno/common/MasterTimer.java +++ b/common/src/main/java/haveno/common/MasterTimer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/Payload.java b/common/src/main/java/haveno/common/Payload.java index ca9328fdf1..281be043e3 100644 --- a/common/src/main/java/haveno/common/Payload.java +++ b/common/src/main/java/haveno/common/Payload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/Proto.java b/common/src/main/java/haveno/common/Proto.java index a6d0e14d70..afac700bc6 100644 --- a/common/src/main/java/haveno/common/Proto.java +++ b/common/src/main/java/haveno/common/Proto.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/ThreadUtils.java b/common/src/main/java/haveno/common/ThreadUtils.java new file mode 100644 index 0000000000..e463e83154 --- /dev/null +++ b/common/src/main/java/haveno/common/ThreadUtils.java @@ -0,0 +1,151 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.common; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public class ThreadUtils { + + private static final Map<String, ExecutorService> EXECUTORS = new HashMap<>(); + private static final Map<String, Thread> THREADS = new HashMap<>(); + private static final int POOL_SIZE = 10; + private static final ExecutorService POOL = Executors.newFixedThreadPool(POOL_SIZE); + + /** + * Execute the given command in a thread with the given id. + * + * @param command the command to execute + * @param threadId the thread id + */ + public static Future<?> execute(Runnable command, String threadId) { + synchronized (EXECUTORS) { + if (!EXECUTORS.containsKey(threadId)) EXECUTORS.put(threadId, Executors.newFixedThreadPool(1)); + return EXECUTORS.get(threadId).submit(() -> { + synchronized (THREADS) { + THREADS.put(threadId, Thread.currentThread()); + } + Thread.currentThread().setName(threadId); + command.run(); + }); + } + } + + /** + * Awaits execution of the given command, but does not throw its exception. + * + * @param command the command to execute + * @param threadId the thread id + */ + public static void await(Runnable command, String threadId) { + try { + execute(command, threadId).get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void shutDown(String threadId) { + shutDown(threadId, null); + } + + public static void shutDown(String threadId, Long timeoutMs) { + if (timeoutMs == null) timeoutMs = Long.MAX_VALUE; + ExecutorService pool = null; + synchronized (EXECUTORS) { + pool = EXECUTORS.get(threadId); + } + if (pool == null) return; // thread not found + pool.shutdown(); + try { + if (!pool.awaitTermination(timeoutMs, TimeUnit.MILLISECONDS)) pool.shutdownNow(); + } catch (InterruptedException e) { + pool.shutdownNow(); + throw new RuntimeException(e); + } finally { + remove(threadId); + } + } + + public static void remove(String threadId) { + synchronized (EXECUTORS) { + EXECUTORS.remove(threadId); + } + synchronized (THREADS) { + THREADS.remove(threadId); + } + } + + // TODO: consolidate and cleanup apis + + public static Future<?> submitToPool(Runnable task) { + return submitToPool(Arrays.asList(task)).get(0); + } + + public static List<Future<?>> submitToPool(List<Runnable> tasks) { + List<Future<?>> futures = new ArrayList<>(); + for (Runnable task : tasks) futures.add(POOL.submit(task)); + return futures; + } + + public static Future<?> awaitTask(Runnable task) { + return awaitTask(task, null); + } + + public static Future<?> awaitTask(Runnable task, Long timeoutMs) { + return awaitTasks(Arrays.asList(task), 1, timeoutMs).get(0); + } + + public static List<Future<?>> awaitTasks(Collection<Runnable> tasks) { + return awaitTasks(tasks, tasks.size()); + } + + public static List<Future<?>> awaitTasks(Collection<Runnable> tasks, int maxConcurrency) { + return awaitTasks(tasks, maxConcurrency, null); + } + + public static List<Future<?>> awaitTasks(Collection<Runnable> tasks, int maxConcurrency, Long timeoutMs) { + if (timeoutMs == null) timeoutMs = Long.MAX_VALUE; + if (tasks.isEmpty()) return new ArrayList<>(); + ExecutorService executorService = Executors.newFixedThreadPool(tasks.size()); + try { + List<Future<?>> futures = new ArrayList<>(); + for (Runnable task : tasks) futures.add(executorService.submit(task, null)); + for (Future<?> future : futures) future.get(timeoutMs, TimeUnit.MILLISECONDS); + return futures; + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + executorService.shutdownNow(); + } + } + + private static boolean isCurrentThread(Thread thread, String threadId) { + synchronized (THREADS) { + if (!THREADS.containsKey(threadId)) return false; + return thread == THREADS.get(threadId); + } + } +} diff --git a/common/src/main/java/haveno/common/Timer.java b/common/src/main/java/haveno/common/Timer.java index 38d159fb41..e5e11c5844 100644 --- a/common/src/main/java/haveno/common/Timer.java +++ b/common/src/main/java/haveno/common/Timer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; diff --git a/common/src/main/java/haveno/common/UserThread.java b/common/src/main/java/haveno/common/UserThread.java index 51019ee1c2..dde27098b4 100644 --- a/common/src/main/java/haveno/common/UserThread.java +++ b/common/src/main/java/haveno/common/UserThread.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common; @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; import java.lang.reflect.InvocationTargetException; import java.time.Duration; import java.util.Random; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; @@ -44,6 +45,7 @@ public class UserThread { @Getter @Setter private static Executor executor; + private static Thread USER_THREAD; public static void setTimerClass(Class<? extends Timer> timerClass) { UserThread.timerClass = timerClass; @@ -56,7 +58,39 @@ public class UserThread { } public static void execute(Runnable command) { - UserThread.executor.execute(command); + executor.execute(() -> { + synchronized (executor) { + USER_THREAD = Thread.currentThread(); + command.run(); + } + }); + } + + public static void await(Runnable command) { + if (isUserThread(Thread.currentThread())) { + command.run(); + } else { + CountDownLatch latch = new CountDownLatch(1); + execute(() -> { + try { + command.run(); + } catch (Exception e) { + throw e; + } finally { + latch.countDown(); + } + }); + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + public static boolean isUserThread(Thread thread) { + return thread == USER_THREAD; + } // Prefer FxTimer if a delay is needed in a JavaFx class (gui module) @@ -74,7 +108,7 @@ public class UserThread { } public static Timer runAfter(Runnable runnable, long delay, TimeUnit timeUnit) { - return getTimer().runLater(Duration.ofMillis(timeUnit.toMillis(delay)), runnable); + return getTimer().runLater(Duration.ofMillis(timeUnit.toMillis(delay)), () -> execute(runnable)); } public static Timer runPeriodically(Runnable runnable, long intervalInSec) { @@ -82,7 +116,7 @@ public class UserThread { } public static Timer runPeriodically(Runnable runnable, long interval, TimeUnit timeUnit) { - return getTimer().runPeriodically(Duration.ofMillis(timeUnit.toMillis(interval)), runnable); + return getTimer().runPeriodically(Duration.ofMillis(timeUnit.toMillis(interval)), () -> execute(runnable)); } private static Timer getTimer() { diff --git a/common/src/main/java/haveno/common/app/AppModule.java b/common/src/main/java/haveno/common/app/AppModule.java index 258175b3eb..84f0cd139f 100644 --- a/common/src/main/java/haveno/common/app/AppModule.java +++ b/common/src/main/java/haveno/common/app/AppModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/main/java/haveno/common/app/AsciiLogo.java b/common/src/main/java/haveno/common/app/AsciiLogo.java index b89ca083f1..a5f1b5cfa7 100644 --- a/common/src/main/java/haveno/common/app/AsciiLogo.java +++ b/common/src/main/java/haveno/common/app/AsciiLogo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/main/java/haveno/common/app/Capabilities.java b/common/src/main/java/haveno/common/app/Capabilities.java index 48238cebe6..5bb3bd0bc4 100644 --- a/common/src/main/java/haveno/common/app/Capabilities.java +++ b/common/src/main/java/haveno/common/app/Capabilities.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; @@ -59,7 +59,11 @@ public class Capabilities { } public Capabilities(Collection<Capability> capabilities) { - this.capabilities.addAll(capabilities); + synchronized (capabilities) { + synchronized (this.capabilities) { + this.capabilities.addAll(capabilities); + } + } } public void set(Capability... capabilities) { @@ -71,21 +75,36 @@ public class Capabilities { } public void set(Collection<Capability> capabilities) { - this.capabilities.clear(); - this.capabilities.addAll(capabilities); + synchronized (capabilities) { + synchronized (this.capabilities) { + this.capabilities.clear(); + this.capabilities.addAll(capabilities); + } + } } public void addAll(Capability... capabilities) { - this.capabilities.addAll(Arrays.asList(capabilities)); + synchronized (this.capabilities) { + this.capabilities.addAll(Arrays.asList(capabilities)); + } } public void addAll(Capabilities capabilities) { - if (capabilities != null) - this.capabilities.addAll(capabilities.capabilities); + if (capabilities != null) { + synchronized (capabilities.capabilities) { + synchronized (this.capabilities) { + this.capabilities.addAll(capabilities.capabilities); + } + } + } } public boolean containsAll(final Set<Capability> requiredItems) { - return capabilities.containsAll(requiredItems); + synchronized(requiredItems) { + synchronized (this.capabilities) { + return capabilities.containsAll(requiredItems); + } + } } public boolean containsAll(final Capabilities capabilities) { @@ -93,15 +112,21 @@ public class Capabilities { } public boolean containsAll(Capability... capabilities) { - return this.capabilities.containsAll(Arrays.asList(capabilities)); + synchronized (this.capabilities) { + return this.capabilities.containsAll(Arrays.asList(capabilities)); + } } public boolean contains(Capability capability) { - return this.capabilities.contains(capability); + synchronized (this.capabilities) { + return this.capabilities.contains(capability); + } } public boolean isEmpty() { - return capabilities.isEmpty(); + synchronized (this.capabilities) { + return capabilities.isEmpty(); + } } @@ -112,7 +137,9 @@ public class Capabilities { * @return int list of Capability ordinals */ public static List<Integer> toIntList(Capabilities capabilities) { - return capabilities.capabilities.stream().map(Enum::ordinal).sorted().collect(Collectors.toList()); + synchronized (capabilities.capabilities) { + return capabilities.capabilities.stream().map(Enum::ordinal).sorted().collect(Collectors.toList()); + } } /** @@ -122,11 +149,13 @@ public class Capabilities { * @return a {@link Capabilities} object */ public static Capabilities fromIntList(List<Integer> capabilities) { - return new Capabilities(capabilities.stream() - .filter(integer -> integer < Capability.values().length) - .filter(integer -> integer >= 0) - .map(integer -> Capability.values()[integer]) - .collect(Collectors.toSet())); + synchronized (capabilities) { + return new Capabilities(capabilities.stream() + .filter(integer -> integer < Capability.values().length) + .filter(integer -> integer >= 0) + .map(integer -> Capability.values()[integer]) + .collect(Collectors.toSet())); + } } /** @@ -164,7 +193,9 @@ public class Capabilities { } public static boolean hasMandatoryCapability(Capabilities capabilities, Capability mandatoryCapability) { - return capabilities.capabilities.stream().anyMatch(c -> c == mandatoryCapability); + synchronized (capabilities.capabilities) { + return capabilities.capabilities.stream().anyMatch(c -> c == mandatoryCapability); + } } @Override @@ -173,10 +204,12 @@ public class Capabilities { } public String prettyPrint() { - return capabilities.stream() - .sorted(Comparator.comparingInt(Enum::ordinal)) - .map(e -> e.name() + " [" + e.ordinal() + "]") - .collect(Collectors.joining(", ")); + synchronized (capabilities) { + return capabilities.stream() + .sorted(Comparator.comparingInt(Enum::ordinal)) + .map(e -> e.name() + " [" + e.ordinal() + "]") + .collect(Collectors.joining(", ")); + } } public int size() { @@ -192,8 +225,10 @@ public class Capabilities { // Neither would support removal of past capabilities, a use case we never had so far and which might have // backward compatibility issues, so we should treat capabilities as an append-only data structure. public int findHighestCapability(Capabilities capabilities) { - return (int) capabilities.capabilities.stream() - .mapToLong(e -> (long) e.ordinal()) - .sum(); + synchronized (capabilities.capabilities) { + return (int) capabilities.capabilities.stream() + .mapToLong(e -> (long) e.ordinal()) + .sum(); + } } } diff --git a/common/src/main/java/haveno/common/app/Capability.java b/common/src/main/java/haveno/common/app/Capability.java index 801651337d..6219df343c 100644 --- a/common/src/main/java/haveno/common/app/Capability.java +++ b/common/src/main/java/haveno/common/app/Capability.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/main/java/haveno/common/app/DevEnv.java b/common/src/main/java/haveno/common/app/DevEnv.java index 63ceea150b..2fd0441020 100644 --- a/common/src/main/java/haveno/common/app/DevEnv.java +++ b/common/src/main/java/haveno/common/app/DevEnv.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/main/java/haveno/common/app/HasCapabilities.java b/common/src/main/java/haveno/common/app/HasCapabilities.java index be3d5baa12..55cff0d713 100644 --- a/common/src/main/java/haveno/common/app/HasCapabilities.java +++ b/common/src/main/java/haveno/common/app/HasCapabilities.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/main/java/haveno/common/app/Log.java b/common/src/main/java/haveno/common/app/Log.java index 45ddc45dc2..67ca2ab9ed 100644 --- a/common/src/main/java/haveno/common/app/Log.java +++ b/common/src/main/java/haveno/common/app/Log.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; @@ -21,6 +21,7 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import ch.qos.logback.classic.LoggerContext; import ch.qos.logback.classic.encoder.PatternLayoutEncoder; +import ch.qos.logback.classic.filter.ThresholdFilter; import ch.qos.logback.classic.spi.ILoggingEvent; import ch.qos.logback.core.rolling.FixedWindowRollingPolicy; import ch.qos.logback.core.rolling.RollingFileAppender; @@ -52,11 +53,12 @@ public class Log { SizeBasedTriggeringPolicy<ILoggingEvent> triggeringPolicy = new SizeBasedTriggeringPolicy<>(); triggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB")); + triggeringPolicy.setContext(loggerContext); triggeringPolicy.start(); PatternLayoutEncoder encoder = new PatternLayoutEncoder(); encoder.setContext(loggerContext); - encoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n"); + encoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg%n"); encoder.start(); appender.setEncoder(encoder); @@ -64,25 +66,43 @@ public class Log { appender.setTriggeringPolicy(triggeringPolicy); appender.start(); - logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); - logbackLogger.addAppender(appender); - logbackLogger.setLevel(Level.INFO); - // log errors in separate file - // not working as expected still.... damn logback... - /* FileAppender errorAppender = new FileAppender(); - errorAppender.setEncoder(encoder); + PatternLayoutEncoder errorEncoder = new PatternLayoutEncoder(); + errorEncoder.setContext(loggerContext); + errorEncoder.setPattern("%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger: %msg%n%ex"); + errorEncoder.start(); + + RollingFileAppender<ILoggingEvent> errorAppender = new RollingFileAppender<>(); + errorAppender.setEncoder(errorEncoder); errorAppender.setName("Error"); errorAppender.setContext(loggerContext); errorAppender.setFile(fileName + "_error.log"); - LevelFilter levelFilter = new LevelFilter(); - levelFilter.setLevel(Level.ERROR); - levelFilter.setOnMatch(FilterReply.ACCEPT); - levelFilter.setOnMismatch(FilterReply.DENY); - levelFilter.start(); - errorAppender.addFilter(levelFilter); + + FixedWindowRollingPolicy errorRollingPolicy = new FixedWindowRollingPolicy(); + errorRollingPolicy.setContext(loggerContext); + errorRollingPolicy.setParent(errorAppender); + errorRollingPolicy.setFileNamePattern(fileName + "_error_%i.log"); + errorRollingPolicy.setMinIndex(1); + errorRollingPolicy.setMaxIndex(20); + errorRollingPolicy.start(); + + SizeBasedTriggeringPolicy<ILoggingEvent> errorTriggeringPolicy = new SizeBasedTriggeringPolicy<>(); + errorTriggeringPolicy.setMaxFileSize(FileSize.valueOf("10MB")); + errorTriggeringPolicy.start(); + + ThresholdFilter thresholdFilter = new ThresholdFilter(); + thresholdFilter.setLevel("WARN"); + thresholdFilter.start(); + + errorAppender.setRollingPolicy(errorRollingPolicy); + errorAppender.setTriggeringPolicy(errorTriggeringPolicy); + errorAppender.addFilter(thresholdFilter); errorAppender.start(); - logbackLogger.addAppender(errorAppender);*/ + + logbackLogger = loggerContext.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); + logbackLogger.addAppender(errorAppender); + logbackLogger.addAppender(appender); + logbackLogger.setLevel(Level.INFO); } public static void setCustomLogLevel(String pattern, Level logLevel) { diff --git a/common/src/main/java/haveno/common/app/LogHighlighter.java b/common/src/main/java/haveno/common/app/LogHighlighter.java new file mode 100644 index 0000000000..0caa0fe363 --- /dev/null +++ b/common/src/main/java/haveno/common/app/LogHighlighter.java @@ -0,0 +1,50 @@ +/** + * Logback: the reliable, generic, fast and flexible logging framework. + * Copyright (C) 1999-2015, QOS.ch. All rights reserved. + * + * This program and the accompanying materials are dual-licensed under + * either the terms of the Eclipse Public License v1.0 as published by + * the Eclipse Foundation + * + * or (per the licensee's choosing) + * + * under the terms of the GNU Lesser General Public License version 2.1 + * as published by the Free Software Foundation. + */ + +/* Derived from https://logback.qos.ch/xref/ch/qos/logback/classic/pattern/color/HighlightingCompositeConverter.html */ + +package haveno.common.app; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import static ch.qos.logback.core.pattern.color.ANSIConstants.BOLD; +import static ch.qos.logback.core.pattern.color.ANSIConstants.DEFAULT_FG; +import static ch.qos.logback.core.pattern.color.ANSIConstants.RED_FG; +import ch.qos.logback.core.pattern.color.ForegroundCompositeConverterBase; + +/** + * Highlights inner-text depending on the level, in bold red for events of level + * ERROR, in red for WARN, in the default color for INFO, and in the default color for other + * levels. + */ + +public class LogHighlighter extends ForegroundCompositeConverterBase<ILoggingEvent> { + + @Override + protected String getForegroundColorCode(ILoggingEvent event) { + Level level = event.getLevel(); + switch (level.toInt()) { + case Level.ERROR_INT: + return BOLD + RED_FG; + case Level.WARN_INT: + return RED_FG; + case Level.INFO_INT: + return DEFAULT_FG; + default: + return DEFAULT_FG; + } + + } +} + diff --git a/common/src/main/java/haveno/common/app/Version.java b/common/src/main/java/haveno/common/app/Version.java index 65d3bff216..2b4b01b036 100644 --- a/common/src/main/java/haveno/common/app/Version.java +++ b/common/src/main/java/haveno/common/app/Version.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; @@ -28,7 +28,7 @@ import static com.google.common.base.Preconditions.checkArgument; public class Version { // The application versions // We use semantic versioning with major, minor and patch - public static final String VERSION = "1.0.11"; + public static final String VERSION = "1.0.14"; /** * Holds a list of the tagged resource files for optimizing the getData requests. diff --git a/common/src/main/java/haveno/common/config/BaseCurrencyNetwork.java b/common/src/main/java/haveno/common/config/BaseCurrencyNetwork.java index 891570f702..684eb2bcd4 100644 --- a/common/src/main/java/haveno/common/config/BaseCurrencyNetwork.java +++ b/common/src/main/java/haveno/common/config/BaseCurrencyNetwork.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.config; @@ -76,7 +76,7 @@ public enum BaseCurrencyNetwork { } } - private static class XmrStageNetParams extends RegTestParams { + private static class XmrStageNetParams extends MainNetParams { @Override public MonetaryFormat getMonetaryFormat() { return XMR_MONETARY_FORMAT; diff --git a/common/src/main/java/haveno/common/config/Config.java b/common/src/main/java/haveno/common/config/Config.java index a1d702b3d8..92359c76f9 100644 --- a/common/src/main/java/haveno/common/config/Config.java +++ b/common/src/main/java/haveno/common/config/Config.java @@ -77,13 +77,15 @@ public class Config { public static final String SEED_NODES = "seedNodes"; public static final String BAN_LIST = "banList"; public static final String NODE_PORT = "nodePort"; + public static final String HIDDEN_SERVICE_ADDRESS = "hiddenServiceAddress"; public static final String USE_LOCALHOST_FOR_P2P = "useLocalhostForP2P"; public static final String MAX_CONNECTIONS = "maxConnections"; - public static final String SOCKS_5_PROXY_BTC_ADDRESS = "socks5ProxyBtcAddress"; + public static final String SOCKS_5_PROXY_XMR_ADDRESS = "socks5ProxyXmrAddress"; public static final String SOCKS_5_PROXY_HTTP_ADDRESS = "socks5ProxyHttpAddress"; public static final String USE_TOR_FOR_XMR = "useTorForXmr"; public static final String TORRC_FILE = "torrcFile"; public static final String TORRC_OPTIONS = "torrcOptions"; + public static final String TOR_CONTROL_HOST = "torControlHost"; public static final String TOR_CONTROL_PORT = "torControlPort"; public static final String TOR_CONTROL_PASSWORD = "torControlPassword"; public static final String TOR_CONTROL_COOKIE_FILE = "torControlCookieFile"; @@ -99,6 +101,7 @@ public class Config { public static final String XMR_NODE_USERNAME = "xmrNodeUsername"; public static final String XMR_NODE_PASSWORD = "xmrNodePassword"; public static final String XMR_NODES = "xmrNodes"; + public static final String USE_NATIVE_XMR_WALLET = "useNativeXmrWallet"; public static final String SOCKS5_DISCOVER_MODE = "socks5DiscoverMode"; public static final String USE_ALL_PROVIDED_NODES = "useAllProvidedNodes"; public static final String USER_AGENT = "userAgent"; @@ -149,6 +152,7 @@ public class Config { public final File appDataDir; public final int walletRpcBindPort; public final int nodePort; + public final String hiddenServiceAddress; public final int maxMemory; public final String logLevel; public final List<String> bannedXmrNodes; @@ -169,10 +173,11 @@ public class Config { public final List<String> banList; public final boolean useLocalhostForP2P; public final int maxConnections; - public final String socks5ProxyBtcAddress; + public final String socks5ProxyXmrAddress; public final String socks5ProxyHttpAddress; public final File torrcFile; public final String torrcOptions; + public final String torControlHost; public final int torControlPort; public final String torControlPassword; public final File torControlCookieFile; @@ -186,6 +191,7 @@ public class Config { public final String xmrNodeUsername; public final String xmrNodePassword; public final String xmrNodes; + public final boolean useNativeXmrWallet; public final UseTorForXmr useTorForXmr; public final boolean useTorForXmrOptionSetExplicitly; public final String socks5DiscoverMode; @@ -282,6 +288,12 @@ public class Config { .ofType(Integer.class) .defaultsTo(9999); + ArgumentAcceptingOptionSpec<String> hiddenServiceAddressOpt = + parser.accepts(HIDDEN_SERVICE_ADDRESS, "Hidden Service Address to listen on") + .withRequiredArg() + .ofType(String.class) + .defaultsTo(""); + ArgumentAcceptingOptionSpec<Integer> walletRpcBindPortOpt = parser.accepts(WALLET_RPC_BIND_PORT, "Port to bind the wallet RPC on") .withRequiredArg() @@ -418,8 +430,8 @@ public class Config { .ofType(int.class) .defaultsTo(12); - ArgumentAcceptingOptionSpec<String> socks5ProxyBtcAddressOpt = - parser.accepts(SOCKS_5_PROXY_BTC_ADDRESS, "A proxy address to be used for Bitcoin network.") + ArgumentAcceptingOptionSpec<String> socks5ProxyXmrAddressOpt = + parser.accepts(SOCKS_5_PROXY_XMR_ADDRESS, "A proxy address to be used for Bitcoin network.") .withRequiredArg() .describedAs("host:port") .defaultsTo(""); @@ -446,6 +458,11 @@ public class Config { .withValuesConvertedBy(RegexMatcher.regex("^([^\\s,]+\\s[^,]+,?\\s*)+$")) .defaultsTo(""); + ArgumentAcceptingOptionSpec<String> torControlHostOpt = + parser.accepts(TOR_CONTROL_HOST, "The control hostname of an already running Tor service to be used by Haveno.") + .withRequiredArg() + .defaultsTo("127.0.0.1"); + ArgumentAcceptingOptionSpec<Integer> torControlPortOpt = parser.accepts(TOR_CONTROL_PORT, "The control port of an already running Tor service to be used by Haveno.") @@ -525,6 +542,12 @@ public class Config { .describedAs("ip[,...]") .defaultsTo(""); + ArgumentAcceptingOptionSpec<Boolean> useNativeXmrWalletOpt = + parser.accepts(USE_NATIVE_XMR_WALLET, "Use native wallet libraries instead of monero-wallet-rpc server") + .withRequiredArg() + .ofType(boolean.class) + .defaultsTo(false); + //noinspection rawtypes ArgumentAcceptingOptionSpec<Enum> useTorForXmrOpt = parser.accepts(USE_TOR_FOR_XMR, "Configure TOR for Monero connections, one of: after_sync, off, or on.") @@ -655,6 +678,7 @@ public class Config { this.helpRequested = options.has(helpOpt); this.configFile = configFile; this.nodePort = options.valueOf(nodePortOpt); + this.hiddenServiceAddress = options.valueOf(hiddenServiceAddressOpt); this.walletRpcBindPort = options.valueOf(walletRpcBindPortOpt); this.maxMemory = options.valueOf(maxMemoryOpt); this.logLevel = options.valueOf(logLevelOpt); @@ -667,6 +691,7 @@ public class Config { this.bitcoinRegtestHost = options.valueOf(bitcoinRegtestHostOpt); this.torrcFile = options.has(torrcFileOpt) ? options.valueOf(torrcFileOpt).toFile() : null; this.torrcOptions = options.valueOf(torrcOptionsOpt); + this.torControlHost = options.valueOf(torControlHostOpt); this.torControlPort = options.valueOf(torControlPortOpt); this.torControlPassword = options.valueOf(torControlPasswordOpt); this.torControlCookieFile = options.has(torControlCookieFileOpt) ? @@ -684,7 +709,7 @@ public class Config { this.banList = options.valuesOf(banListOpt); this.useLocalhostForP2P = !this.baseCurrencyNetwork.isMainnet() && options.valueOf(useLocalhostForP2POpt); this.maxConnections = options.valueOf(maxConnectionsOpt); - this.socks5ProxyBtcAddress = options.valueOf(socks5ProxyBtcAddressOpt); + this.socks5ProxyXmrAddress = options.valueOf(socks5ProxyXmrAddressOpt); this.socks5ProxyHttpAddress = options.valueOf(socks5ProxyHttpAddressOpt); this.msgThrottlePerSec = options.valueOf(msgThrottlePerSecOpt); this.msgThrottlePer10Sec = options.valueOf(msgThrottlePer10SecOpt); @@ -694,6 +719,7 @@ public class Config { this.xmrNodeUsername = options.valueOf(xmrNodeUsernameOpt); this.xmrNodePassword = options.valueOf(xmrNodePasswordOpt); this.xmrNodes = options.valueOf(xmrNodesOpt); + this.useNativeXmrWallet = options.valueOf(useNativeXmrWalletOpt); this.useTorForXmr = (UseTorForXmr) options.valueOf(useTorForXmrOpt); this.useTorForXmrOptionSetExplicitly = options.has(useTorForXmrOpt); this.socks5DiscoverMode = options.valueOf(socks5DiscoverModeOpt); diff --git a/common/src/main/java/haveno/common/config/EnumValueConverter.java b/common/src/main/java/haveno/common/config/EnumValueConverter.java index bd46a3c0f6..80b00f2150 100644 --- a/common/src/main/java/haveno/common/config/EnumValueConverter.java +++ b/common/src/main/java/haveno/common/config/EnumValueConverter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.config; diff --git a/common/src/main/java/haveno/common/config/HavenoHelpFormatter.java b/common/src/main/java/haveno/common/config/HavenoHelpFormatter.java index b86e755d73..5d594549c9 100644 --- a/common/src/main/java/haveno/common/config/HavenoHelpFormatter.java +++ b/common/src/main/java/haveno/common/config/HavenoHelpFormatter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.config; diff --git a/common/src/main/java/haveno/common/consensus/UsedForTradeContractJson.java b/common/src/main/java/haveno/common/consensus/UsedForTradeContractJson.java index cf00fc8407..35d2311730 100644 --- a/common/src/main/java/haveno/common/consensus/UsedForTradeContractJson.java +++ b/common/src/main/java/haveno/common/consensus/UsedForTradeContractJson.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.consensus; diff --git a/common/src/main/java/haveno/common/crypto/CryptoException.java b/common/src/main/java/haveno/common/crypto/CryptoException.java index 3cef78aedd..5f3a2f936d 100644 --- a/common/src/main/java/haveno/common/crypto/CryptoException.java +++ b/common/src/main/java/haveno/common/crypto/CryptoException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/CryptoUtils.java b/common/src/main/java/haveno/common/crypto/CryptoUtils.java index 2406319689..4e57292249 100644 --- a/common/src/main/java/haveno/common/crypto/CryptoUtils.java +++ b/common/src/main/java/haveno/common/crypto/CryptoUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/Encryption.java b/common/src/main/java/haveno/common/crypto/Encryption.java index efa852b475..93d5a527fb 100644 --- a/common/src/main/java/haveno/common/crypto/Encryption.java +++ b/common/src/main/java/haveno/common/crypto/Encryption.java @@ -1,34 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; import haveno.common.util.Hex; import haveno.common.util.Utilities; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.crypto.Cipher; -import javax.crypto.KeyGenerator; -import javax.crypto.Mac; -import javax.crypto.SecretKey; -import javax.crypto.spec.OAEPParameterSpec; -import javax.crypto.spec.PSource; -import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.InvalidKeyException; @@ -43,10 +33,17 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.MGF1ParameterSpec; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; +import javax.crypto.spec.SecretKeySpec; +import lombok.extern.slf4j.Slf4j; +@Slf4j public class Encryption { - private static final Logger log = LoggerFactory.getLogger(Encryption.class); - public static final String ASYM_KEY_ALGO = "RSA"; private static final String ASYM_CIPHER = "RSA/ECB/OAEPWithSHA-256AndMGF1PADDING"; diff --git a/common/src/main/java/haveno/common/crypto/Hash.java b/common/src/main/java/haveno/common/crypto/Hash.java index 34787134d5..7a3b3418c6 100644 --- a/common/src/main/java/haveno/common/crypto/Hash.java +++ b/common/src/main/java/haveno/common/crypto/Hash.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/IncorrectPasswordException.java b/common/src/main/java/haveno/common/crypto/IncorrectPasswordException.java index 0a05ed0faf..f771770ada 100644 --- a/common/src/main/java/haveno/common/crypto/IncorrectPasswordException.java +++ b/common/src/main/java/haveno/common/crypto/IncorrectPasswordException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/KeyConversionException.java b/common/src/main/java/haveno/common/crypto/KeyConversionException.java index 382be057c7..7969133932 100644 --- a/common/src/main/java/haveno/common/crypto/KeyConversionException.java +++ b/common/src/main/java/haveno/common/crypto/KeyConversionException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/KeyRing.java b/common/src/main/java/haveno/common/crypto/KeyRing.java index e03fc1969a..89552c7c74 100644 --- a/common/src/main/java/haveno/common/crypto/KeyRing.java +++ b/common/src/main/java/haveno/common/crypto/KeyRing.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.security.KeyPair; +import javax.annotation.Nullable; +import javax.crypto.SecretKey; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; -import javax.crypto.SecretKey; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.security.KeyPair; - @Getter @EqualsAndHashCode @Slf4j diff --git a/common/src/main/java/haveno/common/crypto/KeyStorage.java b/common/src/main/java/haveno/common/crypto/KeyStorage.java index 4acc01662a..05280b8d4a 100644 --- a/common/src/main/java/haveno/common/crypto/KeyStorage.java +++ b/common/src/main/java/haveno/common/crypto/KeyStorage.java @@ -1,32 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.file.FileUtil; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.crypto.SecretKey; -import javax.inject.Named; -import javax.inject.Singleton; +import static haveno.common.util.Preconditions.checkDir; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -48,8 +44,10 @@ import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.RSAPublicKeySpec; - -import static haveno.common.util.Preconditions.checkDir; +import javax.crypto.SecretKey; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * KeyStorage uses password protection to save a symmetric key in PKCS#12 format. diff --git a/common/src/main/java/haveno/common/crypto/PubKeyRing.java b/common/src/main/java/haveno/common/crypto/PubKeyRing.java index 5233c119ad..a881d4cb5c 100644 --- a/common/src/main/java/haveno/common/crypto/PubKeyRing.java +++ b/common/src/main/java/haveno/common/crypto/PubKeyRing.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/ScryptUtil.java b/common/src/main/java/haveno/common/crypto/ScryptUtil.java index 9dbe35b171..54687ecf04 100644 --- a/common/src/main/java/haveno/common/crypto/ScryptUtil.java +++ b/common/src/main/java/haveno/common/crypto/ScryptUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/SealedAndSigned.java b/common/src/main/java/haveno/common/crypto/SealedAndSigned.java index e0ecf5681e..5b55dbed89 100644 --- a/common/src/main/java/haveno/common/crypto/SealedAndSigned.java +++ b/common/src/main/java/haveno/common/crypto/SealedAndSigned.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/crypto/Sig.java b/common/src/main/java/haveno/common/crypto/Sig.java index ff1b92ed14..6cb662bda3 100644 --- a/common/src/main/java/haveno/common/crypto/Sig.java +++ b/common/src/main/java/haveno/common/crypto/Sig.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.crypto; diff --git a/common/src/main/java/haveno/common/file/CorruptedStorageFileHandler.java b/common/src/main/java/haveno/common/file/CorruptedStorageFileHandler.java index 76cce42779..65d7a07c50 100644 --- a/common/src/main/java/haveno/common/file/CorruptedStorageFileHandler.java +++ b/common/src/main/java/haveno/common/file/CorruptedStorageFileHandler.java @@ -1,29 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.file; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; +import com.google.inject.Inject; +import com.google.inject.Singleton; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton diff --git a/common/src/main/java/haveno/common/file/FileUtil.java b/common/src/main/java/haveno/common/file/FileUtil.java index d0a4d6147b..ca533cc0d2 100644 --- a/common/src/main/java/haveno/common/file/FileUtil.java +++ b/common/src/main/java/haveno/common/file/FileUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.file; @@ -26,21 +26,28 @@ import org.apache.commons.io.IOUtils; import javax.annotation.Nullable; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.List; +import java.util.Scanner; @Slf4j public class FileUtil { + + private static final String BACKUP_DIR = "backup"; + public static void rollingBackup(File dir, String fileName, int numMaxBackupFiles) { + if (numMaxBackupFiles <= 0) return; if (dir.exists()) { - File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString()); + File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); if (!backupDir.exists()) if (!backupDir.mkdir()) log.warn("make dir failed.\nBackupDir=" + backupDir.getAbsolutePath()); @@ -62,15 +69,32 @@ public class FileUtil { pruneBackup(backupFileDir, numMaxBackupFiles); } catch (IOException e) { - log.error("Backup key failed: " + e.getMessage()); - e.printStackTrace(); + log.error("Backup key failed: {}\n", e.getMessage(), e); } } } } + public static List<File> getBackupFiles(File dir, String fileName) { + File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); + if (!backupDir.exists()) return new ArrayList<File>(); + String dirName = "backups_" + fileName; + if (dirName.contains(".")) dirName = dirName.replace(".", "_"); + File backupFileDir = new File(Paths.get(backupDir.getAbsolutePath(), dirName).toString()); + if (!backupFileDir.exists()) return new ArrayList<File>(); + File[] files = backupFileDir.listFiles(); + return Arrays.asList(files); + } + + public static File getLatestBackupFile(File dir, String fileName) { + List<File> files = getBackupFiles(dir, fileName); + if (files.isEmpty()) return null; + files.sort(Comparator.comparing(File::getName)); + return files.get(files.size() - 1); + } + public static void deleteRollingBackup(File dir, String fileName) { - File backupDir = new File(Paths.get(dir.getAbsolutePath(), "backup").toString()); + File backupDir = new File(Paths.get(dir.getAbsolutePath(), BACKUP_DIR).toString()); if (!backupDir.exists()) return; String dirName = "backups_" + fileName; if (dirName.contains(".")) dirName = dirName.replace(".", "_"); @@ -78,7 +102,7 @@ public class FileUtil { try { FileUtils.deleteDirectory(backupFileDir); } catch (IOException e) { - e.printStackTrace(); + log.error("Delete backup key failed: {}\n", e.getMessage(), e); } } @@ -154,8 +178,7 @@ public class FileUtil { } } } catch (Throwable t) { - log.error(t.toString()); - t.printStackTrace(); + log.error("Could not delete file, error={}\n", t.getMessage(), t); throw new IOException(t); } } @@ -239,4 +262,14 @@ public class FileUtil { renameFile(storageFile, corruptedFile); } } + + public static boolean doesFileContainKeyword(File file, String keyword) throws FileNotFoundException { + Scanner s = new Scanner(file); + while (s.hasNextLine()) { + if (s.nextLine().contains(keyword)) { + return true; + } + } + return false; + } } diff --git a/common/src/main/java/haveno/common/file/JsonFileManager.java b/common/src/main/java/haveno/common/file/JsonFileManager.java index 3fbc8c36cc..99d3022274 100644 --- a/common/src/main/java/haveno/common/file/JsonFileManager.java +++ b/common/src/main/java/haveno/common/file/JsonFileManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.file; diff --git a/common/src/main/java/haveno/common/file/ResourceNotFoundException.java b/common/src/main/java/haveno/common/file/ResourceNotFoundException.java index ab59bae85b..1c8ce2e078 100644 --- a/common/src/main/java/haveno/common/file/ResourceNotFoundException.java +++ b/common/src/main/java/haveno/common/file/ResourceNotFoundException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.file; diff --git a/common/src/main/java/haveno/common/handlers/ErrorMessageHandler.java b/common/src/main/java/haveno/common/handlers/ErrorMessageHandler.java index 19555c2d29..69464fb40a 100644 --- a/common/src/main/java/haveno/common/handlers/ErrorMessageHandler.java +++ b/common/src/main/java/haveno/common/handlers/ErrorMessageHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.handlers; diff --git a/common/src/main/java/haveno/common/handlers/ExceptionHandler.java b/common/src/main/java/haveno/common/handlers/ExceptionHandler.java index bb08cf8e25..c829f105e0 100644 --- a/common/src/main/java/haveno/common/handlers/ExceptionHandler.java +++ b/common/src/main/java/haveno/common/handlers/ExceptionHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.handlers; diff --git a/common/src/main/java/haveno/common/handlers/FaultHandler.java b/common/src/main/java/haveno/common/handlers/FaultHandler.java index 7d29af6528..6ce2f00d71 100644 --- a/common/src/main/java/haveno/common/handlers/FaultHandler.java +++ b/common/src/main/java/haveno/common/handlers/FaultHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.handlers; diff --git a/common/src/main/java/haveno/common/handlers/ResultHandler.java b/common/src/main/java/haveno/common/handlers/ResultHandler.java index 3b389f96b6..64be2e5e94 100644 --- a/common/src/main/java/haveno/common/handlers/ResultHandler.java +++ b/common/src/main/java/haveno/common/handlers/ResultHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.handlers; diff --git a/common/src/main/java/haveno/common/persistence/PersistenceManager.java b/common/src/main/java/haveno/common/persistence/PersistenceManager.java index 7bdb4cb1e7..b9d38bd82f 100644 --- a/common/src/main/java/haveno/common/persistence/PersistenceManager.java +++ b/common/src/main/java/haveno/common/persistence/PersistenceManager.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.persistence; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.app.DevEnv; @@ -30,13 +32,9 @@ import haveno.common.file.FileUtil; import haveno.common.handlers.ResultHandler; import haveno.common.proto.persistable.PersistableEnvelope; import haveno.common.proto.persistable.PersistenceProtoResolver; -import haveno.common.util.SingleThreadExecutorUtils; import haveno.common.util.GcUtil; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Named; +import static haveno.common.util.Preconditions.checkDir; +import haveno.common.util.SingleThreadExecutorUtils; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -51,9 +49,9 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; - -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.common.util.Preconditions.checkDir; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; /** * Responsible for reading persisted data and writing it on disk. We read usually only at start-up and keep data in RAM. diff --git a/common/src/main/java/haveno/common/proto/ProtoResolver.java b/common/src/main/java/haveno/common/proto/ProtoResolver.java index 336fc0d980..6e0436c518 100644 --- a/common/src/main/java/haveno/common/proto/ProtoResolver.java +++ b/common/src/main/java/haveno/common/proto/ProtoResolver.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto; diff --git a/common/src/main/java/haveno/common/proto/ProtoUtil.java b/common/src/main/java/haveno/common/proto/ProtoUtil.java index 9cb2a53465..d5469b38fd 100644 --- a/common/src/main/java/haveno/common/proto/ProtoUtil.java +++ b/common/src/main/java/haveno/common/proto/ProtoUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto; diff --git a/common/src/main/java/haveno/common/proto/ProtobufferException.java b/common/src/main/java/haveno/common/proto/ProtobufferException.java index 345e27e066..46d3f6e772 100644 --- a/common/src/main/java/haveno/common/proto/ProtobufferException.java +++ b/common/src/main/java/haveno/common/proto/ProtobufferException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto; diff --git a/common/src/main/java/haveno/common/proto/ProtobufferRuntimeException.java b/common/src/main/java/haveno/common/proto/ProtobufferRuntimeException.java index e7f0e5d777..1e1b2c00a6 100644 --- a/common/src/main/java/haveno/common/proto/ProtobufferRuntimeException.java +++ b/common/src/main/java/haveno/common/proto/ProtobufferRuntimeException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto; diff --git a/common/src/main/java/haveno/common/proto/network/GetDataResponsePriority.java b/common/src/main/java/haveno/common/proto/network/GetDataResponsePriority.java index 924358cc7e..fc286879c5 100644 --- a/common/src/main/java/haveno/common/proto/network/GetDataResponsePriority.java +++ b/common/src/main/java/haveno/common/proto/network/GetDataResponsePriority.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.network; diff --git a/common/src/main/java/haveno/common/proto/network/NetworkEnvelope.java b/common/src/main/java/haveno/common/proto/network/NetworkEnvelope.java index bac84f53e9..ef7038af97 100644 --- a/common/src/main/java/haveno/common/proto/network/NetworkEnvelope.java +++ b/common/src/main/java/haveno/common/proto/network/NetworkEnvelope.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.network; diff --git a/common/src/main/java/haveno/common/proto/network/NetworkPayload.java b/common/src/main/java/haveno/common/proto/network/NetworkPayload.java index 030247d684..b0357663dd 100644 --- a/common/src/main/java/haveno/common/proto/network/NetworkPayload.java +++ b/common/src/main/java/haveno/common/proto/network/NetworkPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.network; diff --git a/common/src/main/java/haveno/common/proto/network/NetworkProtoResolver.java b/common/src/main/java/haveno/common/proto/network/NetworkProtoResolver.java index f6aa188c59..5860186cc5 100644 --- a/common/src/main/java/haveno/common/proto/network/NetworkProtoResolver.java +++ b/common/src/main/java/haveno/common/proto/network/NetworkProtoResolver.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.network; diff --git a/common/src/main/java/haveno/common/proto/persistable/NavigationPath.java b/common/src/main/java/haveno/common/proto/persistable/NavigationPath.java index ba2a48d573..23704e5e10 100644 --- a/common/src/main/java/haveno/common/proto/persistable/NavigationPath.java +++ b/common/src/main/java/haveno/common/proto/persistable/NavigationPath.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/proto/persistable/PersistableEnvelope.java b/common/src/main/java/haveno/common/proto/persistable/PersistableEnvelope.java index e4b3cde021..26de1dc0f0 100644 --- a/common/src/main/java/haveno/common/proto/persistable/PersistableEnvelope.java +++ b/common/src/main/java/haveno/common/proto/persistable/PersistableEnvelope.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/proto/persistable/PersistableList.java b/common/src/main/java/haveno/common/proto/persistable/PersistableList.java index 0b6326dfd7..6c9a6dc416 100644 --- a/common/src/main/java/haveno/common/proto/persistable/PersistableList.java +++ b/common/src/main/java/haveno/common/proto/persistable/PersistableList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/proto/persistable/PersistableListAsObservable.java b/common/src/main/java/haveno/common/proto/persistable/PersistableListAsObservable.java index 09926bf257..ba1c6b6119 100644 --- a/common/src/main/java/haveno/common/proto/persistable/PersistableListAsObservable.java +++ b/common/src/main/java/haveno/common/proto/persistable/PersistableListAsObservable.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/proto/persistable/PersistablePayload.java b/common/src/main/java/haveno/common/proto/persistable/PersistablePayload.java index 1b78a697e8..af40ec5252 100644 --- a/common/src/main/java/haveno/common/proto/persistable/PersistablePayload.java +++ b/common/src/main/java/haveno/common/proto/persistable/PersistablePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/proto/persistable/PersistedDataHost.java b/common/src/main/java/haveno/common/proto/persistable/PersistedDataHost.java index 30ad8d2798..c0452ba5db 100644 --- a/common/src/main/java/haveno/common/proto/persistable/PersistedDataHost.java +++ b/common/src/main/java/haveno/common/proto/persistable/PersistedDataHost.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/proto/persistable/PersistenceProtoResolver.java b/common/src/main/java/haveno/common/proto/persistable/PersistenceProtoResolver.java index a24c98d22c..d165e7afb2 100644 --- a/common/src/main/java/haveno/common/proto/persistable/PersistenceProtoResolver.java +++ b/common/src/main/java/haveno/common/proto/persistable/PersistenceProtoResolver.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.proto.persistable; diff --git a/common/src/main/java/haveno/common/setup/CommonSetup.java b/common/src/main/java/haveno/common/setup/CommonSetup.java index 64190d2ed8..0c929b3ae4 100644 --- a/common/src/main/java/haveno/common/setup/CommonSetup.java +++ b/common/src/main/java/haveno/common/setup/CommonSetup.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.setup; @@ -69,11 +69,7 @@ public class CommonSetup { "The system tray is not supported on the current platform.".equals(throwable.getMessage())) { log.warn(throwable.getMessage()); } else { - log.error("Uncaught Exception from thread " + Thread.currentThread().getName()); - log.error("throwableMessage= " + throwable.getMessage()); - log.error("throwableClass= " + throwable.getClass()); - log.error("Stack trace:\n" + ExceptionUtils.getStackTrace(throwable)); - throwable.printStackTrace(); + log.error("Uncaught Exception from thread {}, error={}\n", Thread.currentThread().getName(), throwable.getMessage(), throwable); UserThread.execute(() -> uncaughtExceptionHandler.handleUncaughtException(throwable, false)); } }; @@ -113,8 +109,7 @@ public class CommonSetup { if (!pathOfCodeSource.endsWith("classes")) log.info("Path to Haveno jar file: " + pathOfCodeSource); } catch (URISyntaxException e) { - log.error(e.toString()); - e.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(e)); } } } diff --git a/common/src/main/java/haveno/common/setup/GracefulShutDownHandler.java b/common/src/main/java/haveno/common/setup/GracefulShutDownHandler.java index b852b4e418..222df95517 100644 --- a/common/src/main/java/haveno/common/setup/GracefulShutDownHandler.java +++ b/common/src/main/java/haveno/common/setup/GracefulShutDownHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.setup; diff --git a/common/src/main/java/haveno/common/setup/UncaughtExceptionHandler.java b/common/src/main/java/haveno/common/setup/UncaughtExceptionHandler.java index f3deabdfa1..7379a9a385 100644 --- a/common/src/main/java/haveno/common/setup/UncaughtExceptionHandler.java +++ b/common/src/main/java/haveno/common/setup/UncaughtExceptionHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.setup; diff --git a/common/src/main/java/haveno/common/taskrunner/InterceptTaskException.java b/common/src/main/java/haveno/common/taskrunner/InterceptTaskException.java index 5f61351208..ecbc07597a 100644 --- a/common/src/main/java/haveno/common/taskrunner/InterceptTaskException.java +++ b/common/src/main/java/haveno/common/taskrunner/InterceptTaskException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.taskrunner; diff --git a/common/src/main/java/haveno/common/taskrunner/Model.java b/common/src/main/java/haveno/common/taskrunner/Model.java index 15c6e72eca..0f2dee9791 100644 --- a/common/src/main/java/haveno/common/taskrunner/Model.java +++ b/common/src/main/java/haveno/common/taskrunner/Model.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.taskrunner; diff --git a/common/src/main/java/haveno/common/taskrunner/Task.java b/common/src/main/java/haveno/common/taskrunner/Task.java index a12a7c3c96..f990f511d8 100644 --- a/common/src/main/java/haveno/common/taskrunner/Task.java +++ b/common/src/main/java/haveno/common/taskrunner/Task.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.taskrunner; @@ -74,6 +74,7 @@ public abstract class Task<T extends Model> { // t.printStackTrace(pw); // errorMessage = sw.toString(); + if (taskHandler.isCanceled()) return; errorMessage = t.getMessage() + " (task " + getClass().getSimpleName() + ")"; log.error(errorMessage, t); taskHandler.handleErrorMessage(errorMessage); diff --git a/common/src/main/java/haveno/common/taskrunner/TaskRunner.java b/common/src/main/java/haveno/common/taskrunner/TaskRunner.java index c9be26a7f5..087ffce702 100644 --- a/common/src/main/java/haveno/common/taskrunner/TaskRunner.java +++ b/common/src/main/java/haveno/common/taskrunner/TaskRunner.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.taskrunner; @@ -25,6 +25,8 @@ import java.util.Arrays; import java.util.Queue; import java.util.concurrent.LinkedBlockingQueue; +import org.apache.commons.lang3.exception.ExceptionUtils; + @Slf4j public class TaskRunner<T extends Model> { private final Queue<Class<? extends Task<T>>> tasks = new LinkedBlockingQueue<>(); @@ -67,8 +69,8 @@ public class TaskRunner<T extends Model> { log.info("Run task: " + currentTask.getSimpleName()); currentTask.getDeclaredConstructor(TaskRunner.class, sharedModelClass).newInstance(this, sharedModel).run(); } catch (Throwable throwable) { - throwable.printStackTrace(); - handleErrorMessage("Error at taskRunner: " + throwable.getMessage()); + log.error(ExceptionUtils.getStackTrace(throwable)); + handleErrorMessage("Error at taskRunner, error=" + throwable.getMessage()); } } else { resultHandler.handleResult(); @@ -80,11 +82,16 @@ public class TaskRunner<T extends Model> { isCanceled = true; } + public boolean isCanceled() { + return isCanceled; + } + void handleComplete() { next(); } void handleErrorMessage(String errorMessage) { + if (isCanceled) return; log.error("Task failed: " + currentTask.getSimpleName() + " / errorMessage: " + errorMessage); failed = true; errorMessageHandler.handleErrorMessage(errorMessage); diff --git a/common/src/main/java/haveno/common/util/Base64.java b/common/src/main/java/haveno/common/util/Base64.java index 5c0ce6cfd2..0da8bbaeec 100644 --- a/common/src/main/java/haveno/common/util/Base64.java +++ b/common/src/main/java/haveno/common/util/Base64.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/CompletableFutureUtils.java b/common/src/main/java/haveno/common/util/CompletableFutureUtils.java index b59596c6af..b119eff806 100644 --- a/common/src/main/java/haveno/common/util/CompletableFutureUtils.java +++ b/common/src/main/java/haveno/common/util/CompletableFutureUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/DesktopUtil.java b/common/src/main/java/haveno/common/util/DesktopUtil.java index c50bbc8f82..f9d5892d8c 100644 --- a/common/src/main/java/haveno/common/util/DesktopUtil.java +++ b/common/src/main/java/haveno/common/util/DesktopUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/DoubleSummaryStatisticsWithStdDev.java b/common/src/main/java/haveno/common/util/DoubleSummaryStatisticsWithStdDev.java index 9222ca0c18..af3d4961c9 100644 --- a/common/src/main/java/haveno/common/util/DoubleSummaryStatisticsWithStdDev.java +++ b/common/src/main/java/haveno/common/util/DoubleSummaryStatisticsWithStdDev.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/ExtraDataMapValidator.java b/common/src/main/java/haveno/common/util/ExtraDataMapValidator.java index 558cd27e5c..d1fdd4ddc8 100644 --- a/common/src/main/java/haveno/common/util/ExtraDataMapValidator.java +++ b/common/src/main/java/haveno/common/util/ExtraDataMapValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/GcUtil.java b/common/src/main/java/haveno/common/util/GcUtil.java index 4989e88b71..e4faa007da 100644 --- a/common/src/main/java/haveno/common/util/GcUtil.java +++ b/common/src/main/java/haveno/common/util/GcUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/Hex.java b/common/src/main/java/haveno/common/util/Hex.java index 30ad8debcd..11e5f04b3c 100644 --- a/common/src/main/java/haveno/common/util/Hex.java +++ b/common/src/main/java/haveno/common/util/Hex.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/InvalidVersionException.java b/common/src/main/java/haveno/common/util/InvalidVersionException.java index 02a03e834f..9ae5b84b54 100644 --- a/common/src/main/java/haveno/common/util/InvalidVersionException.java +++ b/common/src/main/java/haveno/common/util/InvalidVersionException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/JsonExclude.java b/common/src/main/java/haveno/common/util/JsonExclude.java index 98d6d9cf2f..13f042611b 100644 --- a/common/src/main/java/haveno/common/util/JsonExclude.java +++ b/common/src/main/java/haveno/common/util/JsonExclude.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/MathUtils.java b/common/src/main/java/haveno/common/util/MathUtils.java index 71816bbfac..25c91ed254 100644 --- a/common/src/main/java/haveno/common/util/MathUtils.java +++ b/common/src/main/java/haveno/common/util/MathUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/PermutationUtil.java b/common/src/main/java/haveno/common/util/PermutationUtil.java index ce2942dcff..97ef0c3b3f 100644 --- a/common/src/main/java/haveno/common/util/PermutationUtil.java +++ b/common/src/main/java/haveno/common/util/PermutationUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/Profiler.java b/common/src/main/java/haveno/common/util/Profiler.java index d849607347..826a8ff11e 100644 --- a/common/src/main/java/haveno/common/util/Profiler.java +++ b/common/src/main/java/haveno/common/util/Profiler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/ReflectionUtils.java b/common/src/main/java/haveno/common/util/ReflectionUtils.java index d676f0dfc8..20a91854b0 100644 --- a/common/src/main/java/haveno/common/util/ReflectionUtils.java +++ b/common/src/main/java/haveno/common/util/ReflectionUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/RestartUtil.java b/common/src/main/java/haveno/common/util/RestartUtil.java index 8daeb1c2d2..6bba00c5b2 100644 --- a/common/src/main/java/haveno/common/util/RestartUtil.java +++ b/common/src/main/java/haveno/common/util/RestartUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/SingleThreadExecutorUtils.java b/common/src/main/java/haveno/common/util/SingleThreadExecutorUtils.java index 101e417f53..d9af624c67 100644 --- a/common/src/main/java/haveno/common/util/SingleThreadExecutorUtils.java +++ b/common/src/main/java/haveno/common/util/SingleThreadExecutorUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public + * License along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; @@ -25,38 +25,67 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +/** + * Utility class for creating single-threaded executors. + */ public class SingleThreadExecutorUtils { + + private SingleThreadExecutorUtils() { + // Prevent instantiation + } + public static ExecutorService getSingleThreadExecutor(Class<?> aClass) { - String name = aClass.getSimpleName(); - return getSingleThreadExecutor(name); + validateClass(aClass); + return getSingleThreadExecutor(aClass.getSimpleName()); } public static ExecutorService getNonDaemonSingleThreadExecutor(Class<?> aClass) { - String name = aClass.getSimpleName(); - return getSingleThreadExecutor(name, false); + validateClass(aClass); + return getSingleThreadExecutor(aClass.getSimpleName(), false); } public static ExecutorService getSingleThreadExecutor(String name) { + validateName(name); return getSingleThreadExecutor(name, true); } public static ListeningExecutorService getSingleThreadListeningExecutor(String name) { + validateName(name); return MoreExecutors.listeningDecorator(getSingleThreadExecutor(name)); } public static ExecutorService getSingleThreadExecutor(ThreadFactory threadFactory) { + validateThreadFactory(threadFactory); return Executors.newSingleThreadExecutor(threadFactory); } private static ExecutorService getSingleThreadExecutor(String name, boolean isDaemonThread) { - final ThreadFactory threadFactory = getThreadFactory(name, isDaemonThread); + ThreadFactory threadFactory = getThreadFactory(name, isDaemonThread); return Executors.newSingleThreadExecutor(threadFactory); } private static ThreadFactory getThreadFactory(String name, boolean isDaemonThread) { return new ThreadFactoryBuilder() - .setNameFormat(name) + .setNameFormat(name + "-%d") .setDaemon(isDaemonThread) .build(); } + + private static void validateClass(Class<?> aClass) { + if (aClass == null) { + throw new IllegalArgumentException("Class must not be null."); + } + } + + private static void validateName(String name) { + if (name == null || name.isEmpty()) { + throw new IllegalArgumentException("Name must not be null or empty."); + } + } + + private static void validateThreadFactory(ThreadFactory threadFactory) { + if (threadFactory == null) { + throw new IllegalArgumentException("ThreadFactory must not be null."); + } + } } diff --git a/common/src/main/java/haveno/common/util/Tuple2.java b/common/src/main/java/haveno/common/util/Tuple2.java index b84e6332cc..0838101441 100644 --- a/common/src/main/java/haveno/common/util/Tuple2.java +++ b/common/src/main/java/haveno/common/util/Tuple2.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/Tuple3.java b/common/src/main/java/haveno/common/util/Tuple3.java index 8688573d55..a8938dc9ca 100644 --- a/common/src/main/java/haveno/common/util/Tuple3.java +++ b/common/src/main/java/haveno/common/util/Tuple3.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/Tuple4.java b/common/src/main/java/haveno/common/util/Tuple4.java index f2648466c7..45d08169f9 100644 --- a/common/src/main/java/haveno/common/util/Tuple4.java +++ b/common/src/main/java/haveno/common/util/Tuple4.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/Tuple5.java b/common/src/main/java/haveno/common/util/Tuple5.java index 24d71b98ea..5af8601225 100644 --- a/common/src/main/java/haveno/common/util/Tuple5.java +++ b/common/src/main/java/haveno/common/util/Tuple5.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/main/java/haveno/common/util/Utilities.java b/common/src/main/java/haveno/common/util/Utilities.java index 963dd800f3..240ea49ee9 100644 --- a/common/src/main/java/haveno/common/util/Utilities.java +++ b/common/src/main/java/haveno/common/util/Utilities.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; @@ -331,8 +331,7 @@ public class Utilities { clipboard.setContent(clipboardContent); } } catch (Throwable e) { - log.error("copyToClipboard failed " + e.getMessage()); - e.printStackTrace(); + log.error("copyToClipboard failed: {}\n", e.getMessage(), e); } } diff --git a/common/src/main/java/haveno/common/util/ZipUtils.java b/common/src/main/java/haveno/common/util/ZipUtils.java index 0558867c5c..f5a32b69d9 100644 --- a/common/src/main/java/haveno/common/util/ZipUtils.java +++ b/common/src/main/java/haveno/common/util/ZipUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; @@ -24,6 +24,7 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -38,13 +39,14 @@ public class ZipUtils { * @param dir The directory to create the zip from. * @param out The stream to write to. */ - public static void zipDirToStream(File dir, OutputStream out, int bufferSize) throws Exception { + public static void zipDirToStream(File dir, OutputStream out, int bufferSize, Collection<File> excludedFiles) throws Exception { // Get all files in directory and subdirectories. - ArrayList<String> fileList = new ArrayList<>(); - getFilesRecursive(dir, fileList); + List<File> fileList = new ArrayList<>(); + getFilesRecursive(dir, fileList, excludedFiles); try (ZipOutputStream zos = new ZipOutputStream(out)) { - for (String filePath : fileList) { + for (File file : fileList) { + String filePath = file.getAbsolutePath(); log.info("Compressing: " + filePath); // Creates a zip entry. @@ -73,14 +75,15 @@ public class ZipUtils { /** * Get files list from the directory recursive to the subdirectory. */ - public static void getFilesRecursive(File directory, List<String> fileList) { + public static void getFilesRecursive(File directory, List<File> fileList, Collection<File> excludedFiles) { File[] files = directory.listFiles(); if (files != null && files.length > 0) { for (File file : files) { + if (excludedFiles != null && excludedFiles.contains(file)) continue; if (file.isFile()) { - fileList.add(file.getAbsolutePath()); + fileList.add(file); } else { - getFilesRecursive(file, fileList); + getFilesRecursive(file, fileList, excludedFiles); } } } diff --git a/common/src/test/java/haveno/common/app/CapabilitiesTest.java b/common/src/test/java/haveno/common/app/CapabilitiesTest.java index 08a629f535..5e9a8dbb0e 100644 --- a/common/src/test/java/haveno/common/app/CapabilitiesTest.java +++ b/common/src/test/java/haveno/common/app/CapabilitiesTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/test/java/haveno/common/app/VersionTest.java b/common/src/test/java/haveno/common/app/VersionTest.java index b82d7b2adb..0c76980635 100644 --- a/common/src/test/java/haveno/common/app/VersionTest.java +++ b/common/src/test/java/haveno/common/app/VersionTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.app; diff --git a/common/src/test/java/haveno/common/util/MathUtilsTest.java b/common/src/test/java/haveno/common/util/MathUtilsTest.java index 82195b1286..29e990702d 100644 --- a/common/src/test/java/haveno/common/util/MathUtilsTest.java +++ b/common/src/test/java/haveno/common/util/MathUtilsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/test/java/haveno/common/util/PermutationTest.java b/common/src/test/java/haveno/common/util/PermutationTest.java index cab0e4b0a7..051d98b8ea 100644 --- a/common/src/test/java/haveno/common/util/PermutationTest.java +++ b/common/src/test/java/haveno/common/util/PermutationTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/common/src/test/java/haveno/common/util/UtilitiesTest.java b/common/src/test/java/haveno/common/util/UtilitiesTest.java index 085d0a3465..b8bf47615c 100644 --- a/common/src/test/java/haveno/common/util/UtilitiesTest.java +++ b/common/src/test/java/haveno/common/util/UtilitiesTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.common.util; diff --git a/core/src/main/java/haveno/core/account/sign/SignedWitness.java b/core/src/main/java/haveno/core/account/sign/SignedWitness.java index 65aebe7216..37d892cd5d 100644 --- a/core/src/main/java/haveno/core/account/sign/SignedWitness.java +++ b/core/src/main/java/haveno/core/account/sign/SignedWitness.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.sign; @@ -23,6 +23,7 @@ import haveno.common.app.Capability; import haveno.common.crypto.Hash; import haveno.common.proto.ProtoUtil; import haveno.common.util.Utilities; +import haveno.core.trade.HavenoUtils; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.payload.CapabilityRequiringPayload; import haveno.network.p2p.storage.payload.DateTolerantPayload; @@ -30,7 +31,6 @@ import haveno.network.p2p.storage.payload.PersistableNetworkPayload; import haveno.network.p2p.storage.payload.ProcessOncePersistableNetworkPayload; import lombok.Value; import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Coin; import java.time.Clock; import java.time.Instant; @@ -176,7 +176,7 @@ public class SignedWitness implements ProcessOncePersistableNetworkPayload, Pers ",\n signerPubKey=" + Utilities.bytesAsHexString(signerPubKey) + ",\n witnessOwnerPubKey=" + Utilities.bytesAsHexString(witnessOwnerPubKey) + ",\n date=" + Instant.ofEpochMilli(date) + - ",\n tradeAmount=" + Coin.valueOf(tradeAmount).toFriendlyString() + + ",\n tradeAmount=" + HavenoUtils.formatXmr(tradeAmount, true) + ",\n hash=" + Utilities.bytesAsHexString(hash) + "\n}"; } diff --git a/core/src/main/java/haveno/core/account/sign/SignedWitnessService.java b/core/src/main/java/haveno/core/account/sign/SignedWitnessService.java index b40a7fb0e8..b4ba7b58a8 100644 --- a/core/src/main/java/haveno/core/account/sign/SignedWitnessService.java +++ b/core/src/main/java/haveno/core/account/sign/SignedWitnessService.java @@ -1,24 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.sign; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.common.crypto.CryptoException; import haveno.common.crypto.Hash; @@ -34,12 +35,6 @@ import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.P2PService; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.persistence.AppendOnlyDataStoreService; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Coin; -import org.bitcoinj.core.ECKey; -import org.bitcoinj.core.Utils; - -import javax.inject.Inject; import java.math.BigInteger; import java.security.PublicKey; import java.security.SignatureException; @@ -57,12 +52,15 @@ import java.util.Optional; import java.util.Set; import java.util.Stack; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.ECKey; +import org.bitcoinj.core.Utils; @Slf4j public class SignedWitnessService { public static final long SIGNER_AGE_DAYS = 30; private static final long SIGNER_AGE = SIGNER_AGE_DAYS * ChronoUnit.DAYS.getDuration().toMillis(); - public static final BigInteger MINIMUM_TRADE_AMOUNT_FOR_SIGNING = HavenoUtils.coinToAtomicUnits(Coin.parseCoin("0.0025")); + public static final BigInteger MINIMUM_TRADE_AMOUNT_FOR_SIGNING = HavenoUtils.xmrToAtomicUnits(.1); private final KeyRing keyRing; private final P2PService p2PService; @@ -134,7 +132,7 @@ public class SignedWitnessService { } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { onBootstrapComplete(); } }); diff --git a/core/src/main/java/haveno/core/account/sign/SignedWitnessStorageService.java b/core/src/main/java/haveno/core/account/sign/SignedWitnessStorageService.java index 304ff09759..a27c55a47a 100644 --- a/core/src/main/java/haveno/core/account/sign/SignedWitnessStorageService.java +++ b/core/src/main/java/haveno/core/account/sign/SignedWitnessStorageService.java @@ -1,33 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.sign; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; import haveno.network.p2p.storage.persistence.MapStoreService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Named; import java.io.File; import java.util.Map; +import lombok.extern.slf4j.Slf4j; @Slf4j public class SignedWitnessStorageService extends MapStoreService<SignedWitnessStore, PersistableNetworkPayload> { diff --git a/core/src/main/java/haveno/core/account/sign/SignedWitnessStore.java b/core/src/main/java/haveno/core/account/sign/SignedWitnessStore.java index e79ce17152..480e1b428c 100644 --- a/core/src/main/java/haveno/core/account/sign/SignedWitnessStore.java +++ b/core/src/main/java/haveno/core/account/sign/SignedWitnessStore.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.sign; diff --git a/core/src/main/java/haveno/core/account/witness/AccountAgeWitness.java b/core/src/main/java/haveno/core/account/witness/AccountAgeWitness.java index d4bdd47e8b..dfacc07b94 100644 --- a/core/src/main/java/haveno/core/account/witness/AccountAgeWitness.java +++ b/core/src/main/java/haveno/core/account/witness/AccountAgeWitness.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.witness; diff --git a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java index a97a2b1b41..978b6dd715 100644 --- a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java +++ b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessService.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.witness; import com.google.common.annotations.VisibleForTesting; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.common.crypto.CryptoException; import haveno.common.crypto.Hash; @@ -38,6 +40,7 @@ import haveno.core.offer.OfferDirection; import haveno.core.offer.OfferRestrictions; import haveno.core.payment.ChargeBackRisk; import haveno.core.payment.PaymentAccount; +import haveno.core.payment.TradeLimits; import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.payment.payload.PaymentMethod; import haveno.core.support.dispute.Dispute; @@ -51,12 +54,6 @@ import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.P2PService; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.persistence.AppendOnlyDataStoreService; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.ECKey; -import org.bitcoinj.core.Utils; - -import javax.inject.Inject; import java.math.BigInteger; import java.security.PublicKey; import java.time.Clock; @@ -74,8 +71,10 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.google.common.base.Preconditions.checkNotNull; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.ECKey; +import org.bitcoinj.core.Utils; @Slf4j public class AccountAgeWitnessService { @@ -202,7 +201,7 @@ public class AccountAgeWitnessService { } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { onBootStrapped(); } }); @@ -433,10 +432,12 @@ public class AccountAgeWitnessService { limit = BigInteger.valueOf(MathUtils.roundDoubleToLong(maxTradeLimit.longValueExact() * factor)); } - log.debug("limit={}, factor={}, accountAgeWitnessHash={}", - limit, - factor, - Utilities.bytesAsHexString(accountAgeWitness.getHash())); + if (accountAgeWitness != null) { + log.debug("limit={}, factor={}, accountAgeWitnessHash={}", + limit, + factor, + Utilities.bytesAsHexString(accountAgeWitness.getHash())); + } return limit; } @@ -498,10 +499,15 @@ public class AccountAgeWitnessService { return getAccountAge(getMyWitness(paymentAccountPayload), new Date()); } - public long getMyTradeLimit(PaymentAccount paymentAccount, String currencyCode, OfferDirection direction) { + public long getMyTradeLimit(PaymentAccount paymentAccount, String currencyCode, OfferDirection direction, boolean buyerAsTakerWithoutDeposit) { if (paymentAccount == null) return 0; + if (buyerAsTakerWithoutDeposit) { + TradeLimits tradeLimits = new TradeLimits(); + return tradeLimits.getMaxTradeLimitBuyerAsTakerWithoutDeposit().longValueExact(); + } + AccountAgeWitness accountAgeWitness = getMyWitness(paymentAccount.getPaymentAccountPayload()); BigInteger maxTradeLimit = paymentAccount.getPaymentMethod().getMaxTradeLimit(currencyCode); if (hasTradeLimitException(accountAgeWitness)) { @@ -518,6 +524,15 @@ public class AccountAgeWitnessService { paymentAccount.getPaymentMethod()).longValueExact(); } + public long getUnsignedTradeLimit(PaymentMethod paymentMethod, String currencyCode, OfferDirection direction) { + return getTradeLimit(paymentMethod.getMaxTradeLimit(currencyCode), + currencyCode, + null, + AccountAge.UNVERIFIED, + direction, + paymentMethod).longValueExact(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Verification /////////////////////////////////////////////////////////////////////////////////////////// @@ -728,14 +743,13 @@ public class AccountAgeWitnessService { } public Optional<SignedWitness> traderSignAndPublishPeersAccountAgeWitness(Trade trade) { - AccountAgeWitness peersWitness = findTradePeerWitness(trade).orElse(null); - BigInteger tradeAmount = trade.getAmount(); checkNotNull(trade.getTradePeer().getPubKeyRing(), "Peer must have a keyring"); PublicKey peersPubKey = trade.getTradePeer().getPubKeyRing().getSignaturePubKey(); - checkNotNull(peersWitness, "Not able to find peers witness, unable to sign for trade {}", - trade.toString()); - checkNotNull(tradeAmount, "Trade amount must not be null"); checkNotNull(peersPubKey, "Peers pub key must not be null"); + AccountAgeWitness peersWitness = findTradePeerWitness(trade).orElse(null); + checkNotNull(peersWitness, "Not able to find peers witness, unable to sign for trade " + trade.toString()); + BigInteger tradeAmount = trade.getAmount(); + checkNotNull(tradeAmount, "Trade amount must not be null"); try { return signedWitnessService.signAndPublishAccountAgeWitness(tradeAmount, peersWitness, peersPubKey); @@ -844,7 +858,7 @@ public class AccountAgeWitnessService { } public SignState getSignState(Trade trade) { - if (trade instanceof ArbitratorTrade) return SignState.UNSIGNED; // TODO (woodser): arbitrator has two peers + if (trade instanceof ArbitratorTrade) return SignState.UNSIGNED; return findTradePeerWitness(trade) .map(this::getSignState) .orElse(SignState.UNSIGNED); diff --git a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStorageService.java b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStorageService.java index 2c4c95287c..3a635c0129 100644 --- a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStorageService.java +++ b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStorageService.java @@ -1,31 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.witness; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; import haveno.network.p2p.storage.persistence.HistoricalDataStoreService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Named; import java.io.File; +import lombok.extern.slf4j.Slf4j; @Slf4j public class AccountAgeWitnessStorageService extends HistoricalDataStoreService<AccountAgeWitnessStore> { diff --git a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStore.java b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStore.java index 32b0cbe96b..ed103b71ff 100644 --- a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStore.java +++ b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessStore.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.witness; diff --git a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessUtils.java b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessUtils.java index 433e2414dd..ed5645b910 100644 --- a/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessUtils.java +++ b/core/src/main/java/haveno/core/account/witness/AccountAgeWitnessUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.witness; diff --git a/core/src/main/java/haveno/core/alert/Alert.java b/core/src/main/java/haveno/core/alert/Alert.java index c06c8f7328..8731a906a7 100644 --- a/core/src/main/java/haveno/core/alert/Alert.java +++ b/core/src/main/java/haveno/core/alert/Alert.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.alert; diff --git a/core/src/main/java/haveno/core/alert/AlertManager.java b/core/src/main/java/haveno/core/alert/AlertManager.java index 7aab57301c..a54f45c489 100644 --- a/core/src/main/java/haveno/core/alert/AlertManager.java +++ b/core/src/main/java/haveno/core/alert/AlertManager.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.alert; import com.google.common.base.Charsets; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.app.DevEnv; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; @@ -26,22 +28,19 @@ import haveno.network.p2p.P2PService; import haveno.network.p2p.storage.HashMapChangedListener; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; import haveno.network.p2p.storage.payload.ProtectedStoragePayload; +import java.math.BigInteger; +import java.security.SignatureException; +import java.util.Collection; +import java.util.List; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.Utils; +import static org.bitcoinj.core.Utils.HEX; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.inject.Inject; -import javax.inject.Named; -import java.math.BigInteger; -import java.security.SignatureException; -import java.util.Collection; - -import static org.bitcoinj.core.Utils.HEX; - public class AlertManager { private static final Logger log = LoggerFactory.getLogger(AlertManager.class); @@ -49,9 +48,8 @@ public class AlertManager { private final KeyRing keyRing; private final User user; private final ObjectProperty<Alert> alertMessageProperty = new SimpleObjectProperty<>(); + private final boolean useDevPrivilegeKeys; - // Pub key for developer global alert message - private final String pubKeyAsHex; private ECKey alertSigningKey; @@ -68,6 +66,7 @@ public class AlertManager { this.p2PService = p2PService; this.keyRing = keyRing; this.user = user; + this.useDevPrivilegeKeys = useDevPrivilegeKeys; if (!ignoreDevMsg) { p2PService.addHashSetChangedListener(new HashMapChangedListener() { @@ -95,9 +94,25 @@ public class AlertManager { } }); } - pubKeyAsHex = useDevPrivilegeKeys ? - DevEnv.DEV_PRIVILEGE_PUB_KEY : - "036d8a1dfcb406886037d2381da006358722823e1940acc2598c844bbc0fd1026f"; + } + + protected List<String> getPubKeyList() { + if (useDevPrivilegeKeys) return List.of(DevEnv.DEV_PRIVILEGE_PUB_KEY); + switch (Config.baseCurrencyNetwork()) { + case XMR_LOCAL: + return List.of( + "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee", + "024baabdba90e7cc0dc4626ef73ea9d722ea7085d1104491da8c76f28187513492"); + case XMR_STAGENET: + return List.of( + "036d8a1dfcb406886037d2381da006358722823e1940acc2598c844bbc0fd1026f", + "026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854", + "025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36"); + case XMR_MAINNET: + return List.of(); + default: + throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork()); + } } @@ -143,7 +158,7 @@ public class AlertManager { private boolean isKeyValid(String privKeyString) { try { alertSigningKey = ECKey.fromPrivate(new BigInteger(1, HEX.decode(privKeyString))); - return pubKeyAsHex.equals(Utils.HEX.encode(alertSigningKey.getPubKey())); + return getPubKeyList().contains(Utils.HEX.encode(alertSigningKey.getPubKey())); } catch (Throwable t) { return false; } @@ -157,12 +172,15 @@ public class AlertManager { private boolean verifySignature(Alert alert) { String alertMessageAsHex = Utils.HEX.encode(alert.getMessage().getBytes(Charsets.UTF_8)); - try { - ECKey.fromPublicOnly(HEX.decode(pubKeyAsHex)).verifyMessage(alertMessageAsHex, alert.getSignatureAsBase64()); - return true; - } catch (SignatureException e) { - log.warn("verifySignature failed"); - return false; + for (String pubKeyAsHex : getPubKeyList()) { + try { + ECKey.fromPublicOnly(HEX.decode(pubKeyAsHex)).verifyMessage(alertMessageAsHex, alert.getSignatureAsBase64()); + return true; + } catch (SignatureException e) { + // ignore + } } + log.warn("verifySignature failed"); + return false; } } diff --git a/core/src/main/java/haveno/core/alert/AlertModule.java b/core/src/main/java/haveno/core/alert/AlertModule.java index 95cdec5d50..52eb7970d6 100644 --- a/core/src/main/java/haveno/core/alert/AlertModule.java +++ b/core/src/main/java/haveno/core/alert/AlertModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.alert; diff --git a/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java b/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java index ef0d885b0e..fd6abac552 100644 --- a/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java +++ b/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.alert; @@ -22,6 +22,8 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.app.DevEnv; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; @@ -37,25 +39,22 @@ import haveno.network.p2p.network.MessageListener; import haveno.network.p2p.network.NetworkNode; import haveno.network.p2p.peers.keepalive.messages.Ping; import haveno.network.p2p.peers.keepalive.messages.Pong; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import org.bitcoinj.core.ECKey; -import org.bitcoinj.core.Utils; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; import java.math.BigInteger; import java.security.SignatureException; +import java.util.List; import java.util.Random; import java.util.UUID; import java.util.function.Consumer; - +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javax.annotation.Nullable; +import org.bitcoinj.core.ECKey; +import org.bitcoinj.core.Utils; import static org.bitcoinj.core.Utils.HEX; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PrivateNotificationManager implements MessageListener { private static final Logger log = LoggerFactory.getLogger(PrivateNotificationManager.class); @@ -64,9 +63,7 @@ public class PrivateNotificationManager implements MessageListener { private final MailboxMessageService mailboxMessageService; private final KeyRing keyRing; private final ObjectProperty<PrivateNotificationPayload> privateNotificationMessageProperty = new SimpleObjectProperty<>(); - - // Pub key for developer global privateNotification message - private final String pubKeyAsHex; + private final boolean useDevPrivilegeKeys; private ECKey privateNotificationSigningKey; @Nullable @@ -90,14 +87,31 @@ public class PrivateNotificationManager implements MessageListener { this.networkNode = networkNode; this.mailboxMessageService = mailboxMessageService; this.keyRing = keyRing; + this.useDevPrivilegeKeys = useDevPrivilegeKeys; if (!ignoreDevMsg) { this.p2PService.addDecryptedDirectMessageListener(this::handleMessage); this.mailboxMessageService.addDecryptedMailboxListener(this::handleMessage); } - pubKeyAsHex = useDevPrivilegeKeys ? - DevEnv.DEV_PRIVILEGE_PUB_KEY : - "02ba7c5de295adfe57b60029f3637a2c6b1d0e969a8aaefb9e0ddc3a7963f26925"; + } + + protected List<String> getPubKeyList() { + if (useDevPrivilegeKeys) return List.of(DevEnv.DEV_PRIVILEGE_PUB_KEY); + switch (Config.baseCurrencyNetwork()) { + case XMR_LOCAL: + return List.of( + "027a381b5333a56e1cc3d90d3a7d07f26509adf7029ed06fc997c656621f8da1ee", + "024baabdba90e7cc0dc4626ef73ea9d722ea7085d1104491da8c76f28187513492"); + case XMR_STAGENET: + return List.of( + "02ba7c5de295adfe57b60029f3637a2c6b1d0e969a8aaefb9e0ddc3a7963f26925", + "026c581ad773d987e6bd10785ac7f7e0e64864aedeb8bce5af37046de812a37854", + "025b058c9f2c60d839669dbfa5578cf5a8117d60e6b70e2f0946f8a691273c6a36"); + case XMR_MAINNET: + return List.of(); + default: + throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork()); + } } private void handleMessage(DecryptedMessageWithPubKey decryptedMessageWithPubKey, NodeAddress senderNodeAddress) { @@ -157,7 +171,7 @@ public class PrivateNotificationManager implements MessageListener { private boolean isKeyValid(String privKeyString) { try { privateNotificationSigningKey = ECKey.fromPrivate(new BigInteger(1, HEX.decode(privKeyString))); - return pubKeyAsHex.equals(Utils.HEX.encode(privateNotificationSigningKey.getPubKey())); + return getPubKeyList().contains(Utils.HEX.encode(privateNotificationSigningKey.getPubKey())); } catch (Throwable t) { return false; } @@ -171,13 +185,16 @@ public class PrivateNotificationManager implements MessageListener { private boolean verifySignature(PrivateNotificationPayload privateNotification) { String privateNotificationMessageAsHex = Utils.HEX.encode(privateNotification.getMessage().getBytes(Charsets.UTF_8)); - try { - ECKey.fromPublicOnly(HEX.decode(pubKeyAsHex)).verifyMessage(privateNotificationMessageAsHex, privateNotification.getSignatureAsBase64()); - return true; - } catch (SignatureException e) { - log.warn("verifySignature failed"); - return false; + for (String pubKeyAsHex : getPubKeyList()) { + try { + ECKey.fromPublicOnly(HEX.decode(pubKeyAsHex)).verifyMessage(privateNotificationMessageAsHex, privateNotification.getSignatureAsBase64()); + return true; + } catch (SignatureException e) { + // ignore + } } + log.warn("verifySignature failed"); + return false; } public void sendPing(NodeAddress peersNodeAddress, Consumer<String> resultHandler) { @@ -193,7 +210,7 @@ public class PrivateNotificationManager implements MessageListener { @Override public void onFailure(@NotNull Throwable throwable) { - String errorMessage = "Sending ping to " + peersNodeAddress.getHostNameForDisplay() + + String errorMessage = "Sending ping to " + peersNodeAddress.getAddressForDisplay() + " failed. That is expected if the peer is offline.\n\tping=" + ping + ".\n\tException=" + throwable.getMessage(); log.info(errorMessage); diff --git a/core/src/main/java/haveno/core/alert/PrivateNotificationMessage.java b/core/src/main/java/haveno/core/alert/PrivateNotificationMessage.java index bed397361f..fba2376948 100644 --- a/core/src/main/java/haveno/core/alert/PrivateNotificationMessage.java +++ b/core/src/main/java/haveno/core/alert/PrivateNotificationMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.alert; diff --git a/core/src/main/java/haveno/core/alert/PrivateNotificationPayload.java b/core/src/main/java/haveno/core/alert/PrivateNotificationPayload.java index 93d8ed98f2..96ee72e049 100644 --- a/core/src/main/java/haveno/core/alert/PrivateNotificationPayload.java +++ b/core/src/main/java/haveno/core/alert/PrivateNotificationPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.alert; diff --git a/core/src/main/java/haveno/core/api/CoreAccountService.java b/core/src/main/java/haveno/core/api/CoreAccountService.java index 7f24c06c38..2190e0c4f1 100644 --- a/core/src/main/java/haveno/core/api/CoreAccountService.java +++ b/core/src/main/java/haveno/core/api/CoreAccountService.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api; +import static com.google.common.base.Preconditions.checkState; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.Config; import haveno.common.crypto.IncorrectPasswordException; import haveno.common.crypto.KeyRing; @@ -24,21 +27,18 @@ import haveno.common.crypto.KeyStorage; import haveno.common.file.FileUtil; import haveno.common.persistence.PersistenceManager; import haveno.common.util.ZipUtils; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; - -import javax.inject.Inject; -import javax.inject.Singleton; +import haveno.core.xmr.wallet.XmrWalletService; import java.io.File; import java.io.InputStream; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.Consumer; - -import static com.google.common.base.Preconditions.checkState; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; /** * Manages the account state. A created account must have a password which encrypts @@ -141,6 +141,7 @@ public class CoreAccountService { } } + // TODO: share common code with BackupView to backup public void backupAccount(int bufferSize, Consumer<InputStream> consume, Consumer<Exception> error) { if (!accountExists()) throw new IllegalStateException("Cannot backup non existing account"); @@ -151,9 +152,16 @@ public class CoreAccountService { PipedInputStream in = new PipedInputStream(bufferSize); // pipe the serialized account object to stream which will be read by the consumer PipedOutputStream out = new PipedOutputStream(in); log.info("Zipping directory " + dataDir); + + // exclude monero binaries from backup so they're reinstalled with permissions + List<File> excludedFiles = Arrays.asList( + new File(XmrWalletService.MONERO_WALLET_RPC_PATH), + new File(XmrLocalNode.MONEROD_PATH) + ); + new Thread(() -> { try { - ZipUtils.zipDirToStream(dataDir, out, bufferSize); + ZipUtils.zipDirToStream(dataDir, out, bufferSize, excludedFiles); } catch (Exception ex) { error.accept(ex); } diff --git a/core/src/main/java/haveno/core/api/CoreApi.java b/core/src/main/java/haveno/core/api/CoreApi.java index ab0479b261..c91d4a405b 100644 --- a/core/src/main/java/haveno/core/api/CoreApi.java +++ b/core/src/main/java/haveno/core/api/CoreApi.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,8 @@ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.app.Version; import haveno.common.config.Config; import haveno.common.crypto.IncorrectPasswordException; @@ -43,17 +62,8 @@ import haveno.core.support.messages.ChatMessage; import haveno.core.trade.Trade; import haveno.core.trade.statistics.TradeStatistics3; import haveno.core.trade.statistics.TradeStatisticsManager; -import haveno.core.xmr.MoneroNodeSettings; +import haveno.core.xmr.XmrNodeSettings; import haveno.proto.grpc.NotificationMessage; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import monero.common.MoneroRpcConnection; -import monero.wallet.model.MoneroDestination; -import monero.wallet.model.MoneroTxWallet; -import org.bitcoinj.core.Transaction; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; @@ -63,6 +73,12 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroRpcConnection; +import monero.wallet.model.MoneroDestination; +import monero.wallet.model.MoneroTxWallet; +import org.bitcoinj.core.Transaction; /** * Provides high level interface to functionality of core Haveno features. @@ -86,8 +102,8 @@ public class CoreApi { private final CoreWalletsService walletsService; private final TradeStatisticsManager tradeStatisticsManager; private final CoreNotificationService notificationService; - private final CoreMoneroConnectionsService coreMoneroConnectionsService; - private final LocalMoneroNode coreMoneroNodeService; + private final XmrConnectionService xmrConnectionService; + private final XmrLocalNode xmrLocalNode; @Inject public CoreApi(Config config, @@ -103,8 +119,8 @@ public class CoreApi { CoreWalletsService walletsService, TradeStatisticsManager tradeStatisticsManager, CoreNotificationService notificationService, - CoreMoneroConnectionsService coreMoneroConnectionsService, - LocalMoneroNode coreMoneroNodeService) { + XmrConnectionService xmrConnectionService, + XmrLocalNode xmrLocalNode) { this.config = config; this.appStartupState = appStartupState; this.coreAccountService = coreAccountService; @@ -118,8 +134,8 @@ public class CoreApi { this.walletsService = walletsService; this.tradeStatisticsManager = tradeStatisticsManager; this.notificationService = notificationService; - this.coreMoneroConnectionsService = coreMoneroConnectionsService; - this.coreMoneroNodeService = coreMoneroNodeService; + this.xmrConnectionService = xmrConnectionService; + this.xmrLocalNode = xmrLocalNode; } @SuppressWarnings("SameReturnValue") @@ -183,72 +199,76 @@ public class CoreApi { // Monero Connections /////////////////////////////////////////////////////////////////////////////////////////// - public void addMoneroConnection(MoneroRpcConnection connection) { - coreMoneroConnectionsService.addConnection(connection); + public void addXmrConnection(MoneroRpcConnection connection) { + xmrConnectionService.addConnection(connection); } - public void removeMoneroConnection(String connectionUri) { - coreMoneroConnectionsService.removeConnection(connectionUri); + public void removeXmrConnection(String connectionUri) { + xmrConnectionService.removeConnection(connectionUri); } - public MoneroRpcConnection getMoneroConnection() { - return coreMoneroConnectionsService.getConnection(); + public MoneroRpcConnection getXmrConnection() { + return xmrConnectionService.getConnection(); } - public List<MoneroRpcConnection> getMoneroConnections() { - return coreMoneroConnectionsService.getConnections(); + public List<MoneroRpcConnection> getXmrConnections() { + return xmrConnectionService.getConnections(); } - public void setMoneroConnection(String connectionUri) { - coreMoneroConnectionsService.setConnection(connectionUri); + public void setXmrConnection(String connectionUri) { + xmrConnectionService.setConnection(connectionUri); } - public void setMoneroConnection(MoneroRpcConnection connection) { - coreMoneroConnectionsService.setConnection(connection); + public void setXmrConnection(MoneroRpcConnection connection) { + xmrConnectionService.setConnection(connection); } - public MoneroRpcConnection checkMoneroConnection() { - return coreMoneroConnectionsService.checkConnection(); + public MoneroRpcConnection checkXmrConnection() { + return xmrConnectionService.checkConnection(); } - public List<MoneroRpcConnection> checkMoneroConnections() { - return coreMoneroConnectionsService.checkConnections(); + public List<MoneroRpcConnection> checkXmrConnections() { + return xmrConnectionService.checkConnections(); } - public void startCheckingMoneroConnection(Long refreshPeriod) { - coreMoneroConnectionsService.startCheckingConnection(refreshPeriod); + public void startCheckingXmrConnection(Long refreshPeriod) { + xmrConnectionService.startCheckingConnection(refreshPeriod); } - public void stopCheckingMoneroConnection() { - coreMoneroConnectionsService.stopCheckingConnection(); + public void stopCheckingXmrConnection() { + xmrConnectionService.stopCheckingConnection(); } - public MoneroRpcConnection getBestAvailableMoneroConnection() { - return coreMoneroConnectionsService.getBestAvailableConnection(); + public MoneroRpcConnection getBestAvailableXmrConnection() { + return xmrConnectionService.getBestAvailableConnection(); } - public void setMoneroConnectionAutoSwitch(boolean autoSwitch) { - coreMoneroConnectionsService.setAutoSwitch(autoSwitch); + public void setXmrConnectionAutoSwitch(boolean autoSwitch) { + xmrConnectionService.setAutoSwitch(autoSwitch); + } + + public boolean getXmrConnectionAutoSwitch() { + return xmrConnectionService.getAutoSwitch(); } /////////////////////////////////////////////////////////////////////////////////////////// // Monero node /////////////////////////////////////////////////////////////////////////////////////////// - public boolean isMoneroNodeOnline() { - return coreMoneroNodeService.isDetected(); + public boolean isXmrNodeOnline() { + return xmrLocalNode.isDetected(); } - public MoneroNodeSettings getMoneroNodeSettings() { - return coreMoneroNodeService.getMoneroNodeSettings(); + public XmrNodeSettings getXmrNodeSettings() { + return xmrLocalNode.getNodeSettings(); } - public void startMoneroNode(MoneroNodeSettings settings) throws IOException { - coreMoneroNodeService.startMoneroNode(settings); + public void startXmrNode(XmrNodeSettings settings) throws IOException { + xmrLocalNode.start(settings); } - public void stopMoneroNode() { - coreMoneroNodeService.stopMoneroNode(); + public void stopXmrNode() { + xmrLocalNode.stop(); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -399,10 +419,12 @@ public class CoreApi { double marketPriceMargin, long amountAsLong, long minAmountAsLong, - double buyerSecurityDeposit, + double securityDepositPct, String triggerPriceAsString, boolean reserveExactAmount, String paymentAccountId, + boolean isPrivateOffer, + boolean buyerAsTakerWithoutDeposit, Consumer<Offer> resultHandler, ErrorMessageHandler errorMessageHandler) { coreOffersService.postOffer(currencyCode, @@ -412,10 +434,12 @@ public class CoreApi { marketPriceMargin, amountAsLong, minAmountAsLong, - buyerSecurityDeposit, + securityDepositPct, triggerPriceAsString, reserveExactAmount, paymentAccountId, + isPrivateOffer, + buyerAsTakerWithoutDeposit, resultHandler, errorMessageHandler); } @@ -428,8 +452,10 @@ public class CoreApi { double marketPriceMargin, BigInteger amount, BigInteger minAmount, - double buyerSecurityDeposit, - PaymentAccount paymentAccount) { + double securityDepositPct, + PaymentAccount paymentAccount, + boolean isPrivateOffer, + boolean buyerAsTakerWithoutDeposit) { return coreOffersService.editOffer(offerId, currencyCode, direction, @@ -438,12 +464,14 @@ public class CoreApi { marketPriceMargin, amount, minAmount, - buyerSecurityDeposit, - paymentAccount); + securityDepositPct, + paymentAccount, + isPrivateOffer, + buyerAsTakerWithoutDeposit); } - public void cancelOffer(String id) { - coreOffersService.cancelOffer(id); + public void cancelOffer(String id, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + coreOffersService.cancelOffer(id, resultHandler, errorMessageHandler); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -480,6 +508,10 @@ public class CoreApi { tradeInstant); } + public void deletePaymentAccount(String paymentAccountId) { + paymentAccountsService.deletePaymentAccount(paymentAccountId); + } + public List<PaymentMethod> getCryptoCurrencyPaymentMethods() { return paymentAccountsService.getCryptoCurrencyPaymentMethods(); } @@ -511,9 +543,11 @@ public class CoreApi { public void takeOffer(String offerId, String paymentAccountId, long amountAsLong, + String challenge, Consumer<Trade> resultHandler, ErrorMessageHandler errorMessageHandler) { Offer offer = coreOffersService.getOffer(offerId); + offer.setChallenge(challenge); coreTradesService.takeOffer(offer, paymentAccountId, amountAsLong, resultHandler, errorMessageHandler); } @@ -541,10 +575,6 @@ public class CoreApi { return coreTradesService.getTrades(); } - public String getTradeRole(String tradeId) { - return coreTradesService.getTradeRole(tradeId); - } - public List<ChatMessage> getChatMessages(String tradeId) { return coreTradesService.getChatMessages(tradeId); } diff --git a/core/src/main/java/haveno/core/api/CoreContext.java b/core/src/main/java/haveno/core/api/CoreContext.java index c22a10705c..4ff01edf22 100644 --- a/core/src/main/java/haveno/core/api/CoreContext.java +++ b/core/src/main/java/haveno/core/api/CoreContext.java @@ -1,29 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton @Slf4j public class CoreContext { diff --git a/core/src/main/java/haveno/core/api/CoreDisputeAgentsService.java b/core/src/main/java/haveno/core/api/CoreDisputeAgentsService.java index c069268583..529a2a8ac1 100644 --- a/core/src/main/java/haveno/core/api/CoreDisputeAgentsService.java +++ b/core/src/main/java/haveno/core/api/CoreDisputeAgentsService.java @@ -1,27 +1,33 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.support.SupportType; +import static haveno.core.support.SupportType.ARBITRATION; +import static haveno.core.support.SupportType.MEDIATION; +import static haveno.core.support.SupportType.REFUND; +import static haveno.core.support.SupportType.TRADE; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import haveno.core.support.dispute.mediation.mediator.Mediator; @@ -32,24 +38,16 @@ import haveno.core.user.User; import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.ECKey; - -import javax.inject.Inject; -import javax.inject.Singleton; +import static java.lang.String.format; +import static java.net.InetAddress.getLoopbackAddress; import java.util.ArrayList; +import static java.util.Arrays.asList; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.Optional; - -import static haveno.core.support.SupportType.ARBITRATION; -import static haveno.core.support.SupportType.MEDIATION; -import static haveno.core.support.SupportType.REFUND; -import static haveno.core.support.SupportType.TRADE; -import static java.lang.String.format; -import static java.net.InetAddress.getLoopbackAddress; -import static java.util.Arrays.asList; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.ECKey; @Singleton @Slf4j diff --git a/core/src/main/java/haveno/core/api/CoreDisputesService.java b/core/src/main/java/haveno/core/api/CoreDisputesService.java index 64755d5469..f4bb4c803d 100644 --- a/core/src/main/java/haveno/core/api/CoreDisputesService.java +++ b/core/src/main/java/haveno/core/api/CoreDisputesService.java @@ -1,6 +1,28 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.api; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; import com.google.inject.name.Named; + +import haveno.common.ThreadUtils; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; import haveno.common.handlers.FaultHandler; @@ -14,6 +36,7 @@ import haveno.core.support.dispute.Dispute; import haveno.core.support.dispute.DisputeManager; import haveno.core.support.dispute.DisputeResult; import haveno.core.support.dispute.DisputeSummaryVerification; +import haveno.core.support.dispute.DisputeResult.SubtractFeeFrom; import haveno.core.support.dispute.arbitration.ArbitrationManager; import haveno.core.support.messages.ChatMessage; import haveno.core.trade.Contract; @@ -23,29 +46,28 @@ import haveno.core.trade.TradeManager; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; import haveno.core.xmr.wallet.XmrWalletService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; +import static java.lang.String.format; import java.math.BigInteger; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Optional; -import static com.google.common.base.Preconditions.checkNotNull; -import static java.lang.String.format; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j public class CoreDisputesService { - public enum DisputePayout { + // TODO: persist in DisputeResult? + public enum PayoutSuggestion { BUYER_GETS_TRADE_AMOUNT, - BUYER_GETS_ALL, // used in desktop + BUYER_GETS_ALL, SELLER_GETS_TRADE_AMOUNT, - SELLER_GETS_ALL, // used in desktop + SELLER_GETS_ALL, CUSTOM } @@ -80,7 +102,8 @@ public class CoreDisputesService { Trade trade = tradeManager.getOpenTrade(tradeId).orElseThrow(() -> new IllegalArgumentException(format("trade with id '%s' not found", tradeId))); - synchronized (trade) { + // open dispute on trade thread + ThreadUtils.execute(() -> { Offer offer = trade.getOffer(); if (offer == null) throw new IllegalStateException(format("offer with tradeId '%s' is null", tradeId)); @@ -93,13 +116,13 @@ public class CoreDisputesService { // Sends the openNewDisputeMessage to arbitrator, who will then create 2 disputes // one for the opener, the other for the peer, see sendPeerOpenedDisputeMessage. - disputeManager.sendDisputeOpenedMessage(dispute, false, trade.getSelf().getUpdatedMultisigHex(), resultHandler, faultHandler); + disputeManager.sendDisputeOpenedMessage(dispute, resultHandler, faultHandler); tradeManager.requestPersistence(); - } + }, trade.getId()); } public Dispute createDisputeForTrade(Trade trade, Offer offer, PubKeyRing pubKey, boolean isMaker, boolean isSupportTicket) { - synchronized (trade) { + synchronized (trade.getLock()) { byte[] payoutTxSerialized = null; String payoutTxHashAsString = null; @@ -144,28 +167,26 @@ public class CoreDisputesService { if (winningDisputeOptional.isPresent()) winningDispute = winningDisputeOptional.get(); else throw new IllegalStateException(format("dispute for tradeId '%s' not found", tradeId)); - synchronized (trade) { + synchronized (trade.getLock()) { try { - var closeDate = new Date(); - var disputeResult = createDisputeResult(winningDispute, winner, reason, summaryNotes, closeDate); - DisputePayout payout; + // create dispute result + var closeDate = new Date(); + var winnerDisputeResult = createDisputeResult(winningDispute, winner, reason, summaryNotes, closeDate); + PayoutSuggestion payoutSuggestion; if (customWinnerAmount > 0) { - payout = DisputePayout.CUSTOM; + payoutSuggestion = PayoutSuggestion.CUSTOM; } else if (winner == DisputeResult.Winner.BUYER) { - payout = DisputePayout.BUYER_GETS_TRADE_AMOUNT; + payoutSuggestion = PayoutSuggestion.BUYER_GETS_TRADE_AMOUNT; } else if (winner == DisputeResult.Winner.SELLER) { - payout = DisputePayout.SELLER_GETS_TRADE_AMOUNT; + payoutSuggestion = PayoutSuggestion.SELLER_GETS_TRADE_AMOUNT; } else { throw new IllegalStateException("Unexpected DisputeResult.Winner: " + winner); } - applyPayoutAmountsToDisputeResult(payout, winningDispute, disputeResult, customWinnerAmount); - - // create dispute payout tx - trade.getProcessModel().setUnsignedPayoutTx(arbitrationManager.createDisputePayoutTx(trade, winningDispute.getContract(), disputeResult, false)); + applyPayoutAmountsToDisputeResult(payoutSuggestion, winningDispute, winnerDisputeResult, customWinnerAmount); // close winning dispute ticket - closeDisputeTicket(arbitrationManager, winningDispute, disputeResult, () -> { + closeDisputeTicket(arbitrationManager, winningDispute, winnerDisputeResult, () -> { arbitrationManager.requestPersistence(); }, (errMessage, err) -> { throw new IllegalStateException(errMessage, err); @@ -178,15 +199,16 @@ public class CoreDisputesService { if (!loserDisputeOptional.isPresent()) throw new IllegalStateException("could not find peer dispute"); var loserDispute = loserDisputeOptional.get(); var loserDisputeResult = createDisputeResult(loserDispute, winner, reason, summaryNotes, closeDate); - loserDisputeResult.setBuyerPayoutAmount(disputeResult.getBuyerPayoutAmount()); - loserDisputeResult.setSellerPayoutAmount(disputeResult.getSellerPayoutAmount()); + loserDisputeResult.setBuyerPayoutAmountBeforeCost(winnerDisputeResult.getBuyerPayoutAmountBeforeCost()); + loserDisputeResult.setSellerPayoutAmountBeforeCost(winnerDisputeResult.getSellerPayoutAmountBeforeCost()); + loserDisputeResult.setSubtractFeeFrom(winnerDisputeResult.getSubtractFeeFrom()); closeDisputeTicket(arbitrationManager, loserDispute, loserDisputeResult, () -> { arbitrationManager.requestPersistence(); }, (errMessage, err) -> { throw new IllegalStateException(errMessage, err); }); } catch (Exception e) { - e.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(e)); throw new IllegalStateException(e.getMessage() == null ? ("Error resolving dispute for trade " + trade.getId()) : e.getMessage()); } } @@ -206,38 +228,32 @@ public class CoreDisputesService { * Sets payout amounts given a payout type. If custom is selected, the winner gets a custom amount, and the peer * receives the remaining amount minus the mining fee. */ - public void applyPayoutAmountsToDisputeResult(DisputePayout payout, Dispute dispute, DisputeResult disputeResult, long customWinnerAmount) { + public void applyPayoutAmountsToDisputeResult(PayoutSuggestion payoutSuggestion, Dispute dispute, DisputeResult disputeResult, long customWinnerAmount) { Contract contract = dispute.getContract(); Trade trade = tradeManager.getTrade(dispute.getTradeId()); - BigInteger buyerSecurityDeposit = trade.getBuyerSecurityDeposit(); - BigInteger sellerSecurityDeposit = trade.getSellerSecurityDeposit(); + BigInteger buyerSecurityDeposit = trade.getBuyer().getSecurityDeposit(); + BigInteger sellerSecurityDeposit = trade.getSeller().getSecurityDeposit(); BigInteger tradeAmount = contract.getTradeAmount(); - if (payout == DisputePayout.BUYER_GETS_TRADE_AMOUNT) { - disputeResult.setBuyerPayoutAmount(tradeAmount.add(buyerSecurityDeposit)); - disputeResult.setSellerPayoutAmount(sellerSecurityDeposit); - } else if (payout == DisputePayout.BUYER_GETS_ALL) { - disputeResult.setBuyerPayoutAmount(tradeAmount - .add(buyerSecurityDeposit) - .add(sellerSecurityDeposit)); // TODO (woodser): apply min payout to incentivize loser? (see post v1.1.7) - disputeResult.setSellerPayoutAmount(BigInteger.valueOf(0)); - } else if (payout == DisputePayout.SELLER_GETS_TRADE_AMOUNT) { - disputeResult.setBuyerPayoutAmount(buyerSecurityDeposit); - disputeResult.setSellerPayoutAmount(tradeAmount.add(sellerSecurityDeposit)); - } else if (payout == DisputePayout.SELLER_GETS_ALL) { - disputeResult.setBuyerPayoutAmount(BigInteger.valueOf(0)); - disputeResult.setSellerPayoutAmount(tradeAmount - .add(sellerSecurityDeposit) - .add(buyerSecurityDeposit)); - } else if (payout == DisputePayout.CUSTOM) { - if (customWinnerAmount > trade.getWallet().getBalance().longValueExact()) { - throw new RuntimeException("Winner payout is more than the trade wallet's balance"); - } + disputeResult.setSubtractFeeFrom(DisputeResult.SubtractFeeFrom.BUYER_AND_SELLER); + if (payoutSuggestion == PayoutSuggestion.BUYER_GETS_TRADE_AMOUNT) { + disputeResult.setBuyerPayoutAmountBeforeCost(tradeAmount.add(buyerSecurityDeposit)); + disputeResult.setSellerPayoutAmountBeforeCost(sellerSecurityDeposit); + } else if (payoutSuggestion == PayoutSuggestion.BUYER_GETS_ALL) { + disputeResult.setBuyerPayoutAmountBeforeCost(tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit)); // TODO (woodser): apply min payout to incentivize loser? (see post v1.1.7) + disputeResult.setSellerPayoutAmountBeforeCost(BigInteger.ZERO); + } else if (payoutSuggestion == PayoutSuggestion.SELLER_GETS_TRADE_AMOUNT) { + disputeResult.setBuyerPayoutAmountBeforeCost(buyerSecurityDeposit); + disputeResult.setSellerPayoutAmountBeforeCost(tradeAmount.add(sellerSecurityDeposit)); + } else if (payoutSuggestion == PayoutSuggestion.SELLER_GETS_ALL) { + disputeResult.setBuyerPayoutAmountBeforeCost(BigInteger.ZERO); + disputeResult.setSellerPayoutAmountBeforeCost(tradeAmount.add(sellerSecurityDeposit).add(buyerSecurityDeposit)); + } else if (payoutSuggestion == PayoutSuggestion.CUSTOM) { + if (customWinnerAmount > trade.getWallet().getBalance().longValueExact()) throw new RuntimeException("Winner payout is more than the trade wallet's balance"); long loserAmount = tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit).subtract(BigInteger.valueOf(customWinnerAmount)).longValueExact(); - if (loserAmount < 0) { - throw new RuntimeException("Loser payout cannot be negative"); - } - disputeResult.setBuyerPayoutAmount(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? customWinnerAmount : loserAmount)); - disputeResult.setSellerPayoutAmount(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? loserAmount : customWinnerAmount)); + if (loserAmount < 0) throw new RuntimeException("Loser payout cannot be negative"); + disputeResult.setBuyerPayoutAmountBeforeCost(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? customWinnerAmount : loserAmount)); + disputeResult.setSellerPayoutAmountBeforeCost(BigInteger.valueOf(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? loserAmount : customWinnerAmount)); + disputeResult.setSubtractFeeFrom(disputeResult.getWinner() == DisputeResult.Winner.BUYER ? SubtractFeeFrom.SELLER_ONLY : SubtractFeeFrom.BUYER_ONLY); // winner gets exact amount, loser pays mining fee } } @@ -258,15 +274,17 @@ public class CoreDisputesService { currencyCode, Res.get("disputeSummaryWindow.reason." + reason.name()), amount, - HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmount(), true), - HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmount(), true), + HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmountBeforeCost(), true), + HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmountBeforeCost(), true), disputeResult.summaryNotesProperty().get() ); - if (reason == DisputeResult.Reason.OPTION_TRADE && + synchronized (dispute.getChatMessages()) { + if (reason == DisputeResult.Reason.OPTION_TRADE && dispute.getChatMessages().size() > 1 && dispute.getChatMessages().get(1).isSystemMessage()) { - textToSign += "\n" + dispute.getChatMessages().get(1).getMessage() + "\n"; + textToSign += "\n" + dispute.getChatMessages().get(1).getMessage() + "\n"; + } } String summaryText = DisputeSummaryVerification.signAndApply(disputeManager, disputeResult, textToSign); diff --git a/core/src/main/java/haveno/core/api/CoreHelpService.java b/core/src/main/java/haveno/core/api/CoreHelpService.java index e56ccd48d6..cc216b9014 100644 --- a/core/src/main/java/haveno/core/api/CoreHelpService.java +++ b/core/src/main/java/haveno/core/api/CoreHelpService.java @@ -1,34 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; +import com.google.inject.Inject; +import com.google.inject.Singleton; import java.io.BufferedReader; +import static java.io.File.separator; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; - -import static java.io.File.separator; import static java.lang.String.format; import static java.lang.System.out; +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j diff --git a/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java b/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java deleted file mode 100644 index e316901ea7..0000000000 --- a/core/src/main/java/haveno/core/api/CoreMoneroConnectionsService.java +++ /dev/null @@ -1,601 +0,0 @@ -package haveno.core.api; - -import haveno.common.UserThread; -import haveno.common.app.DevEnv; -import haveno.common.config.Config; -import haveno.core.trade.HavenoUtils; -import haveno.core.user.Preferences; -import haveno.core.xmr.model.EncryptedConnectionList; -import haveno.core.xmr.nodes.XmrNodes; -import haveno.core.xmr.nodes.XmrNodesSetupPreferences; -import haveno.core.xmr.nodes.XmrNodes.XmrNode; -import haveno.core.xmr.setup.DownloadListener; -import haveno.core.xmr.setup.WalletsSetup; -import haveno.network.Socks5ProxyProvider; -import haveno.network.p2p.P2PService; -import haveno.network.p2p.P2PServiceListener; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.LongProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.property.ReadOnlyIntegerProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleLongProperty; -import javafx.beans.property.SimpleObjectProperty; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import monero.common.MoneroConnectionManager; -import monero.common.MoneroConnectionManagerListener; -import monero.common.MoneroRpcConnection; -import monero.common.TaskLooper; -import monero.daemon.MoneroDaemonRpc; -import monero.daemon.model.MoneroDaemonInfo; -import monero.daemon.model.MoneroPeer; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -@Slf4j -@Singleton -public final class CoreMoneroConnectionsService { - - private static final int MIN_BROADCAST_CONNECTIONS = 0; // TODO: 0 for stagenet, 5+ for mainnet - private static final long REFRESH_PERIOD_LOCAL_MS = 5000; // refresh period when connected to local node - private static final long REFRESH_PERIOD_HTTP_MS = 20000; // refresh period when connected to remote node over http - private static final long REFRESH_PERIOD_ONION_MS = 30000; // refresh period when connected to remote node over tor - private static final long MIN_ERROR_LOG_PERIOD_MS = 300000; // minimum period between logging errors fetching daemon info - private static Long lastErrorTimestamp; - - - - private final Object lock = new Object(); - private final Config config; - private final CoreContext coreContext; - private final Preferences preferences; - private final CoreAccountService accountService; - private final XmrNodes xmrNodes; - private final LocalMoneroNode nodeService; - private final MoneroConnectionManager connectionManager; - private final EncryptedConnectionList connectionList; - private final ObjectProperty<List<MoneroPeer>> peers = new SimpleObjectProperty<>(); - private final IntegerProperty numPeers = new SimpleIntegerProperty(0); - private final LongProperty chainHeight = new SimpleLongProperty(0); - private final DownloadListener downloadListener = new DownloadListener(); - private Socks5ProxyProvider socks5ProxyProvider; - - private boolean isInitialized; - private MoneroDaemonRpc daemon; - @Getter - private MoneroDaemonInfo lastInfo; - private TaskLooper daemonPollLooper; - private boolean isShutDownStarted; - private List<MoneroConnectionManagerListener> listeners = new ArrayList<>(); - - @Inject - public CoreMoneroConnectionsService(P2PService p2PService, - Config config, - CoreContext coreContext, - Preferences preferences, - WalletsSetup walletsSetup, - CoreAccountService accountService, - XmrNodes xmrNodes, - LocalMoneroNode nodeService, - MoneroConnectionManager connectionManager, - EncryptedConnectionList connectionList, - Socks5ProxyProvider socks5ProxyProvider) { - this.config = config; - this.coreContext = coreContext; - this.preferences = preferences; - this.accountService = accountService; - this.xmrNodes = xmrNodes; - this.nodeService = nodeService; - this.connectionManager = connectionManager; - this.connectionList = connectionList; - this.socks5ProxyProvider = socks5ProxyProvider; - - // initialize when connected to p2p network - p2PService.addP2PServiceListener(new P2PServiceListener() { - @Override - public void onTorNodeReady() { - initialize(); - } - @Override - public void onHiddenServicePublished() {} - @Override - public void onDataReceived() {} - @Override - public void onNoSeedNodeAvailable() {} - @Override - public void onNoPeersAvailable() {} - @Override - public void onUpdatedDataReceived() {} - }); - } - - public void onShutDownStarted() { - log.info("{}.onShutDownStarted()", getClass().getSimpleName()); - isShutDownStarted = true; - synchronized (this) { - // ensures request not in progress - } - } - - public void shutDown() { - log.info("Shutting down started for {}", getClass().getSimpleName()); - synchronized (lock) { - isInitialized = false; - if (daemonPollLooper != null) daemonPollLooper.stop(); - connectionManager.stopPolling(); - daemon = null; - } - } - - // ------------------------ CONNECTION MANAGEMENT ------------------------- - - public MoneroDaemonRpc getDaemon() { - accountService.checkAccountOpen(); - return this.daemon; - } - - public String getProxyUri() { - return socks5ProxyProvider.getSocks5Proxy() == null ? null : socks5ProxyProvider.getSocks5Proxy().getInetAddress().getHostAddress() + ":" + socks5ProxyProvider.getSocks5Proxy().getPort(); - } - - public void addConnectionListener(MoneroConnectionManagerListener listener) { - synchronized (lock) { - listeners.add(listener); - } - } - - public Boolean isConnected() { - return connectionManager.isConnected(); - } - - public void addConnection(MoneroRpcConnection connection) { - synchronized (lock) { - accountService.checkAccountOpen(); - if (coreContext.isApiUser()) connectionList.addConnection(connection); - connectionManager.addConnection(connection); - } - } - - public void removeConnection(String uri) { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionList.removeConnection(uri); - connectionManager.removeConnection(uri); - } - } - - public MoneroRpcConnection getConnection() { - synchronized (lock) { - accountService.checkAccountOpen(); - return connectionManager.getConnection(); - } - } - - public List<MoneroRpcConnection> getConnections() { - synchronized (lock) { - accountService.checkAccountOpen(); - return connectionManager.getConnections(); - } - } - - public void setConnection(String connectionUri) { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionManager.setConnection(connectionUri); // listener will update connection list - } - } - - public void setConnection(MoneroRpcConnection connection) { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionManager.setConnection(connection); // listener will update connection list - } - } - - public MoneroRpcConnection checkConnection() { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionManager.checkConnection(); - return getConnection(); - } - } - - public List<MoneroRpcConnection> checkConnections() { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionManager.checkConnections(); - return getConnections(); - } - } - - public void startCheckingConnection(Long refreshPeriod) { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionList.setRefreshPeriod(refreshPeriod); - updatePolling(); - } - } - - public void stopCheckingConnection() { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionManager.stopPolling(); - connectionList.setRefreshPeriod(-1L); - } - } - - public MoneroRpcConnection getBestAvailableConnection() { - synchronized (lock) { - accountService.checkAccountOpen(); - return connectionManager.getBestAvailableConnection(); - } - } - - public void setAutoSwitch(boolean autoSwitch) { - synchronized (lock) { - accountService.checkAccountOpen(); - connectionManager.setAutoSwitch(autoSwitch); - connectionList.setAutoSwitch(autoSwitch); - } - } - - public boolean isConnectionLocal() { - return isConnectionLocal(getConnection()); - } - - public long getRefreshPeriodMs() { - return connectionList.getRefreshPeriod() > 0 ? connectionList.getRefreshPeriod() : getDefaultRefreshPeriodMs(); - } - - public void verifyConnection() { - if (daemon == null) throw new RuntimeException("No connection to Monero node"); - if (!isSyncedWithinTolerance()) throw new RuntimeException("Monero node is not synced"); - } - - public boolean isSyncedWithinTolerance() { - if (daemon == null) return false; - Long targetHeight = lastInfo.getTargetHeight(); // the last time the node thought it was behind the network and was in active sync mode to catch up - if (targetHeight == 0) return true; // monero-daemon-rpc sync_info's target_height returns 0 when node is fully synced - long currentHeight = chainHeight.get(); - if (targetHeight - currentHeight <= 3) { // synced if not more than 3 blocks behind target height - return true; - } - log.warn("Our chain height: {} is out of sync with peer nodes chain height: {}", chainHeight.get(), targetHeight); - return false; - } - - // ----------------------------- APP METHODS ------------------------------ - - public ReadOnlyIntegerProperty numPeersProperty() { - return numPeers; - } - - public ReadOnlyObjectProperty<List<MoneroPeer>> peerConnectionsProperty() { - return peers; - } - - public boolean hasSufficientPeersForBroadcast() { - return numPeers.get() >= getMinBroadcastConnections(); - } - - public LongProperty chainHeightProperty() { - return chainHeight; - } - - public ReadOnlyDoubleProperty downloadPercentageProperty() { - return downloadListener.percentageProperty(); - } - - public int getMinBroadcastConnections() { - return MIN_BROADCAST_CONNECTIONS; - } - - public boolean isDownloadComplete() { - return downloadPercentageProperty().get() == 1d; - } - - /** - * Signals that both the daemon and wallet have synced. - * - * TODO: separate daemon and wallet download/done listeners - */ - public void doneDownload() { - downloadListener.doneDownload(); - } - - // ------------------------------- HELPERS -------------------------------- - - private boolean isConnectionLocal(MoneroRpcConnection connection) { - return connection != null && HavenoUtils.isLocalHost(connection.getUri()); - } - - private long getDefaultRefreshPeriodMs() { - MoneroRpcConnection connection = getConnection(); - if (connection == null) return REFRESH_PERIOD_LOCAL_MS; - if (isConnectionLocal(connection)) { - if (lastInfo != null && (lastInfo.isBusySyncing() || (lastInfo.getHeightWithoutBootstrap() != null && lastInfo.getHeightWithoutBootstrap() > 0 && lastInfo.getHeightWithoutBootstrap() < lastInfo.getHeight()))) return REFRESH_PERIOD_HTTP_MS; // refresh slower if syncing or bootstrapped - else return REFRESH_PERIOD_LOCAL_MS; // TODO: announce faster refresh after done syncing - } else if (useProxy(connection)) { - return REFRESH_PERIOD_ONION_MS; - } else { - return REFRESH_PERIOD_HTTP_MS; - } - } - - private boolean useProxy(MoneroRpcConnection connection) { - return connection.isOnion() || (preferences.getUseTorForXmr().isUseTorForXmr() && !HavenoUtils.isLocalHost(connection.getUri())); - } - - private void initialize() { - - // initialize connections - initializeConnections(); - - // listen for account to be opened or password changed - accountService.addListener(new AccountServiceListener() { - - @Override - public void onAccountOpened() { - try { - log.info(getClass() + ".onAccountOpened() called"); - initialize(); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - @Override - public void onPasswordChanged(String oldPassword, String newPassword) { - log.info(getClass() + ".onPasswordChanged({}, {}) called", oldPassword == null ? null : "***", newPassword == null ? null : "***"); - connectionList.changePassword(oldPassword, newPassword); - } - }); - } - - private void initializeConnections() { - synchronized (lock) { - - // reset connection manager - connectionManager.reset(); - connectionManager.setTimeout(REFRESH_PERIOD_HTTP_MS); - - // run once - if (!isInitialized) { - - // register local node listener - nodeService.addListener(new LocalMoneroNodeListener() { - @Override - public void onNodeStarted(MoneroDaemonRpc daemon) { - log.info(getClass() + ".onNodeStarted() called"); - daemon.getRpcConnection().checkConnection(connectionManager.getTimeout()); - setConnection(daemon.getRpcConnection()); - checkConnection(); - } - - @Override - public void onNodeStopped() { - log.info(getClass() + ".onNodeStopped() called"); - checkConnection(); - } - }); - } - - // restore connections - if ("".equals(config.xmrNode)) { - - // load previous or default connections - if (coreContext.isApiUser()) { - - // load previous connections - for (MoneroRpcConnection connection : connectionList.getConnections()) connectionManager.addConnection(connection); - log.info("Read " + connectionList.getConnections().size() + " previous connections from disk"); - - // add default connections - for (XmrNode node : xmrNodes.getAllXmrNodes()) { - if (node.hasClearNetAddress()) { - MoneroRpcConnection connection = new MoneroRpcConnection(node.getAddress() + ":" + node.getPort()).setPriority(node.getPriority()); - if (!connectionList.hasConnection(connection.getUri())) addConnection(connection); - } - if (node.hasOnionAddress()) { - MoneroRpcConnection connection = new MoneroRpcConnection(node.getOnionAddress() + ":" + node.getPort()).setPriority(node.getPriority()); - if (!connectionList.hasConnection(connection.getUri())) addConnection(connection); - } - } - } else { - - // add default connections - for (XmrNode node : xmrNodes.selectPreferredNodes(new XmrNodesSetupPreferences(preferences))) { - if (node.hasClearNetAddress()) { - MoneroRpcConnection connection = new MoneroRpcConnection(node.getAddress() + ":" + node.getPort()).setPriority(node.getPriority()); - addConnection(connection); - } - if (node.hasOnionAddress()) { - MoneroRpcConnection connection = new MoneroRpcConnection(node.getOnionAddress() + ":" + node.getPort()).setPriority(node.getPriority()); - addConnection(connection); - } - } - } - - // restore last connection - if (connectionList.getCurrentConnectionUri().isPresent()) { - connectionManager.setConnection(connectionList.getCurrentConnectionUri().get()); - } - - // set connection proxies - log.info("TOR proxy URI: " + getProxyUri()); - for (MoneroRpcConnection connection : connectionManager.getConnections()) { - if (useProxy(connection)) connection.setProxyUri(getProxyUri()); - } - - // restore auto switch - if (coreContext.isApiUser()) connectionManager.setAutoSwitch(connectionList.getAutoSwitch()); - else connectionManager.setAutoSwitch(true); - - // start local node if used last and offline - maybeStartLocalNode(); - - // update connection - if (connectionManager.getConnection() == null || connectionManager.getAutoSwitch()) { - setConnection(getBestAvailableConnection()); - } else { - checkConnection(); - } - } else if (!isInitialized) { - - // set connection from startup argument if given - connectionManager.setAutoSwitch(false); - MoneroRpcConnection connection = new MoneroRpcConnection(config.xmrNode, config.xmrNodeUsername, config.xmrNodePassword).setPriority(1); - if (useProxy(connection)) connection.setProxyUri(getProxyUri()); - connectionManager.setConnection(connection); - - // start local node if used last and offline - maybeStartLocalNode(); - - // update connection - checkConnection(); - } - - // register connection listener - connectionManager.addListener(this::onConnectionChanged); - - // start polling for best connection after delay - if ("".equals(config.xmrNode)) { - UserThread.runAfter(() -> { - if (!isShutDownStarted) connectionManager.startPolling(getRefreshPeriodMs() * 2); - }, getDefaultRefreshPeriodMs() * 2 / 1000); - } - - // notify final connection - isInitialized = true; - onConnectionChanged(connectionManager.getConnection()); - } - } - - private void maybeStartLocalNode() { - - // skip if seed node - if (HavenoUtils.havenoSetup == null) return; - - // start local node if offline and used as last connection - if (connectionManager.getConnection() != null && nodeService.equalsUri(connectionManager.getConnection().getUri()) && !nodeService.isDetected()) { - try { - log.info("Starting local node"); - nodeService.startMoneroNode(); - } catch (Exception e) { - log.warn("Unable to start local monero node: " + e.getMessage()); - e.printStackTrace(); - } - } - } - - private void onConnectionChanged(MoneroRpcConnection currentConnection) { - log.info("CoreMoneroConnectionsService.onConnectionChanged() uri={}, connected={}", currentConnection == null ? null : currentConnection.getUri(), currentConnection == null ? "false" : currentConnection.isConnected()); - if (isShutDownStarted) return; - synchronized (lock) { - if (currentConnection == null) { - daemon = null; - connectionList.setCurrentConnectionUri(null); - } else { - daemon = new MoneroDaemonRpc(currentConnection); - connectionList.removeConnection(currentConnection.getUri()); - connectionList.addConnection(currentConnection); - connectionList.setCurrentConnectionUri(currentConnection.getUri()); - } - } - updatePolling(); - - // notify listeners - synchronized (lock) { - for (MoneroConnectionManagerListener listener : listeners) listener.onConnectionChanged(currentConnection); - } - } - - private void updatePolling() { - new Thread(() -> { - synchronized (lock) { - stopPolling(); - if (connectionList.getRefreshPeriod() >= 0) startPolling(); // 0 means default refresh poll - } - }).start(); - } - - private void startPolling() { - synchronized (lock) { - if (daemonPollLooper != null) daemonPollLooper.stop(); - daemonPollLooper = new TaskLooper(() -> pollDaemonInfo()); - daemonPollLooper.start(getRefreshPeriodMs()); - } - } - - private void stopPolling() { - synchronized (lock) { - if (daemonPollLooper != null) daemonPollLooper.stop(); - } - } - - private void pollDaemonInfo() { - if (isShutDownStarted) return; - try { - log.debug("Polling daemon info"); - if (daemon == null) throw new RuntimeException("No daemon connection"); - synchronized (this) { - lastInfo = daemon.getInfo(); - } - chainHeight.set(lastInfo.getTargetHeight() == 0 ? lastInfo.getHeight() : lastInfo.getTargetHeight()); - - // set peer connections - // TODO: peers often uknown due to restricted RPC call, skipping call to get peer connections - // try { - // peers.set(getOnlinePeers()); - // } catch (Exception err) { - // // TODO: peers unknown due to restricted RPC call - // } - // numPeers.set(peers.get().size()); - numPeers.set(lastInfo.getNumOutgoingConnections() + lastInfo.getNumIncomingConnections()); - peers.set(new ArrayList<MoneroPeer>()); - - // handle error recovery - if (lastErrorTimestamp != null) { - log.info("Successfully fetched daemon info after previous error"); - lastErrorTimestamp = null; - if (HavenoUtils.havenoSetup != null) HavenoUtils.havenoSetup.getWalletServiceErrorMsg().set(null); - } - - // update and notify connected state - if (!Boolean.TRUE.equals(connectionManager.isConnected())) { - connectionManager.checkConnection(); - } - } catch (Exception e) { - - // log error message periodically - if ((lastErrorTimestamp == null || System.currentTimeMillis() - lastErrorTimestamp > MIN_ERROR_LOG_PERIOD_MS)) { - lastErrorTimestamp = System.currentTimeMillis(); - log.warn("Could not update daemon info: " + e.getMessage()); - if (DevEnv.isDevMode()) e.printStackTrace(); - } - - // notify error message - if (HavenoUtils.havenoSetup != null) HavenoUtils.havenoSetup.getWalletServiceErrorMsg().set(e.getMessage()); - - // check connection which notifies of changes - synchronized (this) { - if (connectionManager.getAutoSwitch()) connectionManager.setConnection(connectionManager.getBestAvailableConnection()); - else connectionManager.checkConnection(); - } - } - } - - private List<MoneroPeer> getOnlinePeers() { - return daemon.getPeers().stream() - .filter(peer -> peer.isOnline()) - .collect(Collectors.toList()); - } -} diff --git a/core/src/main/java/haveno/core/api/CoreNotificationService.java b/core/src/main/java/haveno/core/api/CoreNotificationService.java index f7646a5758..edd3651539 100644 --- a/core/src/main/java/haveno/core/api/CoreNotificationService.java +++ b/core/src/main/java/haveno/core/api/CoreNotificationService.java @@ -1,17 +1,21 @@ package haveno.core.api; +import com.google.inject.Singleton; import haveno.core.api.model.TradeInfo; import haveno.core.support.messages.ChatMessage; +import haveno.core.trade.BuyerTrade; +import haveno.core.trade.HavenoUtils; +import haveno.core.trade.MakerTrade; +import haveno.core.trade.SellerTrade; import haveno.core.trade.Trade; +import haveno.core.trade.Trade.Phase; import haveno.proto.grpc.NotificationMessage; import haveno.proto.grpc.NotificationMessage.NotificationType; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Singleton; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j @@ -47,7 +51,18 @@ public class CoreNotificationService { .build()); } - public void sendTradeNotification(Trade trade, String title, String message) { + public void sendTradeNotification(Trade trade, Phase phase, String title, String message) { + + // play chime when maker's trade is taken + if (trade instanceof MakerTrade && phase == Trade.Phase.DEPOSITS_PUBLISHED) HavenoUtils.playChimeSound(); + + // play chime when buyer can confirm payment sent + if (trade instanceof BuyerTrade && phase == Trade.Phase.DEPOSITS_UNLOCKED) HavenoUtils.playChimeSound(); + + // play chime when seller sees buyer confirm payment sent + if (trade instanceof SellerTrade && phase == Trade.Phase.PAYMENT_SENT) HavenoUtils.playChimeSound(); + + // send notification sendNotification(NotificationMessage.newBuilder() .setType(NotificationType.TRADE_UPDATE) .setTrade(TradeInfo.toTradeInfo(trade).toProtoMessage()) @@ -58,10 +73,11 @@ public class CoreNotificationService { } public void sendChatNotification(ChatMessage chatMessage) { + HavenoUtils.playChimeSound(); sendNotification(NotificationMessage.newBuilder() .setType(NotificationType.CHAT_MESSAGE) .setTimestamp(System.currentTimeMillis()) - .setChatMessage(chatMessage.toProtoChatMessageBuilder()) + .setChatMessage(chatMessage.toProtoNetworkEnvelope().getChatMessage()) .build()); } diff --git a/core/src/main/java/haveno/core/api/CoreOffersService.java b/core/src/main/java/haveno/core/api/CoreOffersService.java index 65e9e9f083..8232827887 100644 --- a/core/src/main/java/haveno/core/api/CoreOffersService.java +++ b/core/src/main/java/haveno/core/api/CoreOffersService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,8 +34,14 @@ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.common.handlers.ErrorMessageHandler; +import haveno.common.handlers.ResultHandler; +import static haveno.common.util.MathUtils.exactMultiply; +import static haveno.common.util.MathUtils.roundDoubleToLong; +import static haveno.common.util.MathUtils.scaleUpByPowerOf10; import haveno.core.locale.CurrencyUtil; import haveno.core.monetary.CryptoMoney; import haveno.core.monetary.Price; @@ -27,37 +50,30 @@ import haveno.core.offer.CreateOfferService; import haveno.core.offer.Offer; import haveno.core.offer.OfferBookService; import haveno.core.offer.OfferDirection; +import static haveno.core.offer.OfferDirection.BUY; import haveno.core.offer.OfferFilterService; import haveno.core.offer.OfferFilterService.Result; import haveno.core.offer.OfferUtil; import haveno.core.offer.OpenOffer; import haveno.core.offer.OpenOfferManager; import haveno.core.payment.PaymentAccount; +import static haveno.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer; import haveno.core.user.User; import haveno.core.util.PriceUtil; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Transaction; - -import javax.inject.Inject; -import javax.inject.Singleton; +import static java.lang.String.format; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Comparator; +import static java.util.Comparator.comparing; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; - -import static haveno.common.util.MathUtils.exactMultiply; -import static haveno.common.util.MathUtils.roundDoubleToLong; -import static haveno.common.util.MathUtils.scaleUpByPowerOf10; -import static haveno.core.offer.OfferDirection.BUY; -import static haveno.core.payment.PaymentAccountUtil.isPaymentAccountValidForOffer; -import static java.lang.String.format; -import static java.util.Comparator.comparing; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.Transaction; @Singleton @Slf4j @@ -156,10 +172,12 @@ public class CoreOffersService { double marketPriceMargin, long amountAsLong, long minAmountAsLong, - double buyerSecurityDeposit, + double securityDepositPct, String triggerPriceAsString, boolean reserveExactAmount, String paymentAccountId, + boolean isPrivateOffer, + boolean buyerAsTakerWithoutDeposit, Consumer<Offer> resultHandler, ErrorMessageHandler errorMessageHandler) { coreWalletsService.verifyWalletsAreAvailable(); @@ -183,8 +201,10 @@ public class CoreOffersService { price, useMarketBasedPrice, exactMultiply(marketPriceMargin, 0.01), - buyerSecurityDeposit, - paymentAccount); + securityDepositPct, + paymentAccount, + isPrivateOffer, + buyerAsTakerWithoutDeposit); verifyPaymentAccountIsValidForNewOffer(offer, paymentAccount); @@ -207,8 +227,10 @@ public class CoreOffersService { double marketPriceMargin, BigInteger amount, BigInteger minAmount, - double buyerSecurityDeposit, - PaymentAccount paymentAccount) { + double securityDepositPct, + PaymentAccount paymentAccount, + boolean isPrivateOffer, + boolean buyerAsTakerWithoutDeposit) { return createOfferService.createAndGetOffer(offerId, direction, currencyCode.toUpperCase(), @@ -217,18 +239,15 @@ public class CoreOffersService { price, useMarketBasedPrice, exactMultiply(marketPriceMargin, 0.01), - buyerSecurityDeposit, - paymentAccount); + securityDepositPct, + paymentAccount, + isPrivateOffer, + buyerAsTakerWithoutDeposit); } - void cancelOffer(String id) { + void cancelOffer(String id, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { Offer offer = getMyOffer(id).getOffer(); - openOfferManager.removeOffer(offer, - () -> { - }, - errorMessage -> { - throw new IllegalStateException(errorMessage); - }); + openOfferManager.removeOffer(offer, resultHandler, errorMessageHandler); } // -------------------------- PRIVATE HELPERS ----------------------------- @@ -243,7 +262,7 @@ public class CoreOffersService { for (Offer offer2 : offers) { if (offer == offer2) continue; if (offer2.getOfferPayload().getReserveTxKeyImages().contains(keyImage)) { - log.warn("Key image {} belongs to multiple offers, seen in offer {}", keyImage, offer2.getId()); + log.warn("Key image {} belongs to multiple offers, seen in offer {} and {}", keyImage, offer.getId(), offer2.getId()); duplicateFundedOffers.add(offer2); } } @@ -273,6 +292,7 @@ public class CoreOffersService { useSavingsWallet, triggerPriceAsLong, reserveExactAmount, + true, resultHandler::accept, errorMessageHandler); } diff --git a/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java b/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java index 0339929013..b506a00ac1 100644 --- a/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java +++ b/core/src/main/java/haveno/core/api/CorePaymentAccountsService.java @@ -1,29 +1,34 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.asset.Asset; import haveno.asset.AssetRegistry; +import static haveno.common.config.Config.baseCurrencyNetwork; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.api.model.PaymentAccountForm; import haveno.core.api.model.PaymentAccountFormField; import haveno.core.locale.CryptoCurrency; import haveno.core.locale.CurrencyUtil; +import static haveno.core.locale.CurrencyUtil.findAsset; +import static haveno.core.locale.CurrencyUtil.getCryptoCurrency; import haveno.core.locale.TradeCurrency; import haveno.core.payment.AssetAccount; import haveno.core.payment.CryptoCurrencyAccount; @@ -32,21 +37,14 @@ import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccountFactory; import haveno.core.payment.payload.PaymentMethod; import haveno.core.user.User; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.io.File; +import static java.lang.String.format; import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - -import static haveno.common.config.Config.baseCurrencyNetwork; -import static haveno.core.locale.CurrencyUtil.findAsset; -import static haveno.core.locale.CurrencyUtil.getCryptoCurrency; -import static java.lang.String.format; +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j @@ -66,9 +64,14 @@ class CorePaymentAccountsService { } PaymentAccount createPaymentAccount(PaymentAccountForm form) { + validateFormFields(form); PaymentAccount paymentAccount = form.toPaymentAccount(); setSelectedTradeCurrency(paymentAccount); // TODO: selected trade currency is function of offer, not payment account payload verifyPaymentAccountHasRequiredFields(paymentAccount); + if (paymentAccount instanceof CryptoCurrencyAccount) { + CryptoCurrencyAccount cryptoAccount = (CryptoCurrencyAccount) paymentAccount; + verifyCryptoCurrencyAddress(cryptoAccount.getSingleTradeCurrency().getCode(), cryptoAccount.getAddress()); + } user.addPaymentAccountIfNotExists(paymentAccount); accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); log.info("Saved payment account with id {} and payment method {}.", @@ -147,6 +150,16 @@ class CorePaymentAccountsService { return cryptoCurrencyAccount; } + synchronized void deletePaymentAccount(String paymentAccountId) { + accountService.checkAccountOpen(); + PaymentAccount paymentAccount = getPaymentAccount(paymentAccountId); + if (paymentAccount == null) throw new IllegalArgumentException(format("Payment account with id %s not found", paymentAccountId)); + user.removePaymentAccount(paymentAccount); + log.info("Deleted payment account with id {} and payment method {}.", + paymentAccount.getId(), + paymentAccount.getPaymentAccountPayload().getPaymentMethodId()); + } + // TODO Support all alt coin payment methods supported by UI. // The getCryptoCurrencyPaymentMethods method below will be // callable from the CLI when more are supported. @@ -158,6 +171,12 @@ class CorePaymentAccountsService { .collect(Collectors.toList()); } + private void validateFormFields(PaymentAccountForm form) { + for (PaymentAccountFormField field : form.getFields()) { + validateFormField(form, field.getId(), field.getValue()); + } + } + void validateFormField(PaymentAccountForm form, PaymentAccountFormField.FieldId fieldId, String value) { // get payment method id diff --git a/core/src/main/java/haveno/core/api/CorePriceService.java b/core/src/main/java/haveno/core/api/CorePriceService.java index 27cf3b46aa..ddd194ebab 100644 --- a/core/src/main/java/haveno/core/api/CorePriceService.java +++ b/core/src/main/java/haveno/core/api/CorePriceService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,6 +35,8 @@ package haveno.core.api; import com.google.common.math.LongMath; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.api.model.MarketDepthInfo; import haveno.core.api.model.MarketPriceInfo; import haveno.core.locale.CurrencyUtil; @@ -27,16 +46,13 @@ import haveno.core.offer.OfferBookService; import haveno.core.offer.OfferDirection; import haveno.core.provider.price.PriceFeedService; import haveno.core.trade.HavenoUtils; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.Comparator; import java.util.LinkedHashMap; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Singleton @@ -56,7 +72,7 @@ class CorePriceService { * @return Price per 1 XMR in the given currency (traditional or crypto) */ public double getMarketPrice(String currencyCode) throws ExecutionException, InterruptedException, TimeoutException, IllegalArgumentException { - var marketPrice = priceFeedService.requestAllPrices().get(currencyCode); + var marketPrice = priceFeedService.requestAllPrices().get(CurrencyUtil.getCurrencyCodeBase(currencyCode)); if (marketPrice == null) { throw new IllegalArgumentException("Currency not found: " + currencyCode); // message sent to client } diff --git a/core/src/main/java/haveno/core/api/CoreTradesService.java b/core/src/main/java/haveno/core/api/CoreTradesService.java index 25a97420fc..14f10b4f00 100644 --- a/core/src/main/java/haveno/core/api/CoreTradesService.java +++ b/core/src/main/java/haveno/core/api/CoreTradesService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,8 @@ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.offer.Offer; @@ -38,20 +57,18 @@ import haveno.core.user.User; import haveno.core.util.coin.CoinUtil; import haveno.core.util.validation.BtcAddressValidator; import haveno.core.xmr.model.AddressEntry; +import static haveno.core.xmr.model.AddressEntry.Context.TRADE_PAYOUT; import haveno.core.xmr.wallet.BtcWalletService; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Coin; - -import javax.inject.Inject; -import javax.inject.Singleton; +import static java.lang.String.format; import java.math.BigInteger; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; +import lombok.extern.slf4j.Slf4j; -import static haveno.core.xmr.model.AddressEntry.Context.TRADE_PAYOUT; -import static java.lang.String.format; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.bitcoinj.core.Coin; @Singleton @Slf4j @@ -115,7 +132,7 @@ class CoreTradesService { // adjust amount for fixed-price offer (based on TakeOfferViewModel) String currencyCode = offer.getCurrencyCode(); OfferDirection direction = offer.getOfferPayload().getDirection(); - long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction); + long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, offer.hasBuyerAsTakerWithoutDeposit()); if (offer.getPrice() != null) { if (PaymentMethod.isRoundedForAtmCash(paymentAccount.getPaymentMethod().getId())) { amount = CoinUtil.getRoundedAtmCashAmount(amount, offer.getPrice(), maxTradeLimit); @@ -128,18 +145,15 @@ class CoreTradesService { } // synchronize access to take offer model // TODO (woodser): to avoid synchronizing, don't use stateful model - BigInteger takerFee; BigInteger fundsNeededForTrade; synchronized (takeOfferModel) { takeOfferModel.initModel(offer, paymentAccount, amount, useSavingsWallet); - takerFee = takeOfferModel.getTakerFee(); fundsNeededForTrade = takeOfferModel.getFundsNeededForTrade(); - log.info("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel); + log.debug("Initiating take {} offer, {}", offer.isBuyOffer() ? "buy" : "sell", takeOfferModel); } // take offer tradeManager.onTakeOffer(amount, - takerFee, fundsNeededForTrade, offer, paymentAccountId, @@ -149,7 +163,7 @@ class CoreTradesService { errorMessageHandler ); } catch (Exception e) { - e.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(e)); errorMessageHandler.handleErrorMessage(e.getMessage()); } } diff --git a/core/src/main/java/haveno/core/api/CoreWalletsService.java b/core/src/main/java/haveno/core/api/CoreWalletsService.java index dfdb79d390..68ec8c13ea 100644 --- a/core/src/main/java/haveno/core/api/CoreWalletsService.java +++ b/core/src/main/java/haveno/core/api/CoreWalletsService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -20,6 +37,9 @@ package haveno.core.api; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.Timer; import haveno.common.UserThread; import haveno.core.api.model.AddressBalanceInfo; @@ -29,13 +49,22 @@ import haveno.core.api.model.XmrBalanceInfo; import haveno.core.app.AppStartupState; import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; +import static haveno.core.util.ParsingUtils.parseToCoin; import haveno.core.util.coin.CoinFormatter; import haveno.core.xmr.Balances; import haveno.core.xmr.model.AddressEntry; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.BtcWalletService; +import static haveno.core.xmr.wallet.Restrictions.getMinNonDustOutput; import haveno.core.xmr.wallet.WalletsManager; import haveno.core.xmr.wallet.XmrWalletService; +import static java.lang.String.format; +import java.util.List; +import java.util.Optional; +import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.annotation.Nullable; import lombok.extern.slf4j.Slf4j; import monero.wallet.model.MoneroDestination; import monero.wallet.model.MoneroTxWallet; @@ -47,20 +76,6 @@ import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.crypto.KeyCrypterScrypt; import org.bouncycastle.crypto.params.KeyParameter; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import java.util.List; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static haveno.core.util.ParsingUtils.parseToCoin; -import static haveno.core.xmr.wallet.Restrictions.getMinNonDustOutput; -import static java.lang.String.format; -import static java.util.concurrent.TimeUnit.SECONDS; - @Singleton @Slf4j class CoreWalletsService { @@ -118,7 +133,6 @@ class CoreWalletsService { verifyWalletCurrencyCodeIsValid(currencyCode); verifyWalletsAreAvailable(); verifyEncryptedWalletIsUnlocked(); - if (balances.getAvailableBalance().get() == null) throw new IllegalStateException("balance is not yet available"); switch (currencyCode.trim().toUpperCase()) { case "": @@ -144,7 +158,7 @@ class CoreWalletsService { List<MoneroTxWallet> getXmrTxs() { accountService.checkAccountOpen(); - return xmrWalletService.getWallet().getTxs(); + return xmrWalletService.getTxs(); } MoneroTxWallet createXmrTx(List<MoneroDestination> destinations) { @@ -164,7 +178,7 @@ class CoreWalletsService { verifyWalletsAreAvailable(); verifyEncryptedWalletIsUnlocked(); try { - return xmrWalletService.getWallet().relayTx(metadata); + return xmrWalletService.relayTx(metadata); } catch (Exception ex) { log.error("", ex); throw new IllegalStateException(ex); @@ -403,28 +417,8 @@ class CoreWalletsService { private XmrBalanceInfo getXmrBalances() { verifyWalletsAreAvailable(); verifyEncryptedWalletIsUnlocked(); - - var availableBalance = balances.getAvailableBalance().get(); - if (availableBalance == null) - throw new IllegalStateException("available balance is not yet available"); - - var pendingBalance = balances.getPendingBalance().get(); - if (pendingBalance == null) - throw new IllegalStateException("locked balance is not yet available"); - - var reservedOfferBalance = balances.getReservedOfferBalance().get(); - if (reservedOfferBalance == null) - throw new IllegalStateException("reserved offer balance is not yet available"); - - var reservedTradeBalance = balances.getReservedTradeBalance().get(); - if (reservedTradeBalance == null) - throw new IllegalStateException("reserved trade balance is not yet available"); - - return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(), - availableBalance.longValue(), - pendingBalance.longValue(), - reservedOfferBalance.longValue(), - reservedTradeBalance.longValue()); + if (balances.getAvailableBalance() == null) throw new IllegalStateException("Balances are not yet available"); + return balances.getBalances(); } // Returns a Coin for the transfer amount string, or a RuntimeException if invalid. diff --git a/core/src/main/java/haveno/core/api/NotificationListener.java b/core/src/main/java/haveno/core/api/NotificationListener.java index 28cce350ac..3cef2a9cc2 100644 --- a/core/src/main/java/haveno/core/api/NotificationListener.java +++ b/core/src/main/java/haveno/core/api/NotificationListener.java @@ -4,20 +4,20 @@ import haveno.proto.grpc.NotificationMessage; import lombok.NonNull; /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ public interface NotificationListener { diff --git a/core/src/main/java/haveno/core/api/XmrConnectionService.java b/core/src/main/java/haveno/core/api/XmrConnectionService.java new file mode 100644 index 0000000000..664daaca8a --- /dev/null +++ b/core/src/main/java/haveno/core/api/XmrConnectionService.java @@ -0,0 +1,844 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.api; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import haveno.common.ThreadUtils; +import haveno.common.UserThread; +import haveno.common.app.DevEnv; +import haveno.common.config.BaseCurrencyNetwork; +import haveno.common.config.Config; +import haveno.core.trade.HavenoUtils; +import haveno.core.user.Preferences; +import haveno.core.xmr.model.EncryptedConnectionList; +import haveno.core.xmr.nodes.XmrNodes; +import haveno.core.xmr.nodes.XmrNodes.XmrNode; +import haveno.core.xmr.nodes.XmrNodesSetupPreferences; +import haveno.core.xmr.setup.DownloadListener; +import haveno.core.xmr.setup.WalletsSetup; +import haveno.network.Socks5ProxyProvider; +import haveno.network.p2p.P2PService; +import haveno.network.p2p.P2PServiceListener; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.LongProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.property.ReadOnlyIntegerProperty; +import javafx.beans.property.ReadOnlyLongProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleLongProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroConnectionManager; +import monero.common.MoneroConnectionManagerListener; +import monero.common.MoneroRpcConnection; +import monero.common.TaskLooper; +import monero.daemon.MoneroDaemonRpc; +import monero.daemon.model.MoneroDaemonInfo; + +@Slf4j +@Singleton +public final class XmrConnectionService { + + private static final int MIN_BROADCAST_CONNECTIONS = 0; // TODO: 0 for stagenet, 5+ for mainnet + private static final long REFRESH_PERIOD_HTTP_MS = 20000; // refresh period when connected to remote node over http + private static final long REFRESH_PERIOD_ONION_MS = 30000; // refresh period when connected to remote node over tor + + private final Object lock = new Object(); + private final Object pollLock = new Object(); + private final Object listenerLock = new Object(); + private final Config config; + private final CoreContext coreContext; + private final Preferences preferences; + private final CoreAccountService accountService; + private final XmrNodes xmrNodes; + private final XmrLocalNode xmrLocalNode; + private final MoneroConnectionManager connectionManager; + private final EncryptedConnectionList connectionList; + private final ObjectProperty<List<MoneroRpcConnection>> connections = new SimpleObjectProperty<>(); + private final IntegerProperty numConnections = new SimpleIntegerProperty(0); + private final ObjectProperty<MoneroRpcConnection> connectionProperty = new SimpleObjectProperty<>(); + private final LongProperty chainHeight = new SimpleLongProperty(0); + private final DownloadListener downloadListener = new DownloadListener(); + @Getter + private final BooleanProperty connectionServiceFallbackHandlerActive = new SimpleBooleanProperty(); + @Getter + private final StringProperty connectionServiceErrorMsg = new SimpleStringProperty(); + private final LongProperty numUpdates = new SimpleLongProperty(0); + private Socks5ProxyProvider socks5ProxyProvider; + + private boolean isInitialized; + private boolean pollInProgress; + private MoneroDaemonRpc daemon; + private Boolean isConnected = false; + @Getter + private MoneroDaemonInfo lastInfo; + private Long lastFallbackInvocation; + private Long lastLogPollErrorTimestamp; + private long lastLogDaemonNotSyncedTimestamp; + private Long syncStartHeight; + private TaskLooper daemonPollLooper; + private long lastRefreshPeriodMs; + @Getter + private boolean isShutDownStarted; + private List<MoneroConnectionManagerListener> listeners = new ArrayList<>(); + + // connection switching + private static final int EXCLUDE_CONNECTION_SECONDS = 180; + private static final int MAX_SWITCH_REQUESTS_PER_MINUTE = 2; + private static final int SKIP_SWITCH_WITHIN_MS = 10000; + private int numRequestsLastMinute; + private long lastSwitchTimestamp; + private Set<MoneroRpcConnection> excludedConnections = new HashSet<>(); + private static final long FALLBACK_INVOCATION_PERIOD_MS = 1000 * 60 * 1; // offer to fallback up to once every minute + private boolean fallbackApplied; + + @Inject + public XmrConnectionService(P2PService p2PService, + Config config, + CoreContext coreContext, + Preferences preferences, + WalletsSetup walletsSetup, + CoreAccountService accountService, + XmrNodes xmrNodes, + XmrLocalNode xmrLocalNode, + MoneroConnectionManager connectionManager, + EncryptedConnectionList connectionList, + Socks5ProxyProvider socks5ProxyProvider) { + this.config = config; + this.coreContext = coreContext; + this.preferences = preferences; + this.accountService = accountService; + this.xmrNodes = xmrNodes; + this.xmrLocalNode = xmrLocalNode; + this.connectionManager = connectionManager; + this.connectionList = connectionList; + this.socks5ProxyProvider = socks5ProxyProvider; + + // initialize when connected to p2p network + p2PService.addP2PServiceListener(new P2PServiceListener() { + @Override + public void onTorNodeReady() { + ThreadUtils.submitToPool(() -> initialize()); + } + @Override + public void onHiddenServicePublished() {} + @Override + public void onDataReceived() {} + @Override + public void onNoSeedNodeAvailable() {} + @Override + public void onNoPeersAvailable() {} + @Override + public void onUpdatedDataReceived() {} + }); + } + + public void onShutDownStarted() { + log.info("{}.onShutDownStarted()", getClass().getSimpleName()); + isShutDownStarted = true; + } + + public void shutDown() { + log.info("Shutting down {}", getClass().getSimpleName()); + isInitialized = false; + synchronized (lock) { + if (daemonPollLooper != null) daemonPollLooper.stop(); + daemon = null; + } + } + + // ------------------------ CONNECTION MANAGEMENT ------------------------- + + public MoneroDaemonRpc getDaemon() { + accountService.checkAccountOpen(); + return this.daemon; + } + + public String getProxyUri() { + return socks5ProxyProvider.getSocks5Proxy() == null ? null : socks5ProxyProvider.getSocks5Proxy().getInetAddress().getHostAddress() + ":" + socks5ProxyProvider.getSocks5Proxy().getPort(); + } + + public void addConnectionListener(MoneroConnectionManagerListener listener) { + synchronized (listenerLock) { + listeners.add(listener); + } + } + + public Boolean isConnected() { + return isConnected; + } + + public void addConnection(MoneroRpcConnection connection) { + accountService.checkAccountOpen(); + if (coreContext.isApiUser()) connectionList.addConnection(connection); + connectionManager.addConnection(connection); + } + + public void removeConnection(String uri) { + accountService.checkAccountOpen(); + connectionList.removeConnection(uri); + connectionManager.removeConnection(uri); + } + + public MoneroRpcConnection getConnection() { + accountService.checkAccountOpen(); + return connectionManager.getConnection(); + } + + public List<MoneroRpcConnection> getConnections() { + accountService.checkAccountOpen(); + return connectionManager.getConnections(); + } + + public void setConnection(String connectionUri) { + accountService.checkAccountOpen(); + connectionManager.setConnection(connectionUri); // listener will update connection list + } + + public void setConnection(MoneroRpcConnection connection) { + accountService.checkAccountOpen(); + connectionManager.setConnection(connection); // listener will update connection list + } + + public MoneroRpcConnection checkConnection() { + accountService.checkAccountOpen(); + connectionManager.checkConnection(); + return getConnection(); + } + + public List<MoneroRpcConnection> checkConnections() { + accountService.checkAccountOpen(); + connectionManager.checkConnections(); + return getConnections(); + } + + public void startCheckingConnection(Long refreshPeriod) { + accountService.checkAccountOpen(); + connectionList.setRefreshPeriod(refreshPeriod); + updatePolling(); + } + + public void stopCheckingConnection() { + accountService.checkAccountOpen(); + connectionList.setRefreshPeriod(-1L); + updatePolling(); + } + + public MoneroRpcConnection getBestAvailableConnection() { + accountService.checkAccountOpen(); + List<MoneroRpcConnection> ignoredConnections = new ArrayList<MoneroRpcConnection>(); + addLocalNodeIfIgnored(ignoredConnections); + return connectionManager.getBestAvailableConnection(ignoredConnections.toArray(new MoneroRpcConnection[0])); + } + + private MoneroRpcConnection getBestAvailableConnection(Collection<MoneroRpcConnection> ignoredConnections) { + accountService.checkAccountOpen(); + Set<MoneroRpcConnection> ignoredConnectionsSet = new HashSet<>(ignoredConnections); + addLocalNodeIfIgnored(ignoredConnectionsSet); + return connectionManager.getBestAvailableConnection(ignoredConnectionsSet.toArray(new MoneroRpcConnection[0])); + } + + private void addLocalNodeIfIgnored(Collection<MoneroRpcConnection> ignoredConnections) { + if (xmrLocalNode.shouldBeIgnored() && connectionManager.hasConnection(xmrLocalNode.getUri())) ignoredConnections.add(connectionManager.getConnectionByUri(xmrLocalNode.getUri())); + } + + private void switchToBestConnection() { + if (isFixedConnection() || !connectionManager.getAutoSwitch()) { + log.info("Skipping switch to best Monero connection because connection is fixed or auto switch is disabled"); + return; + } + MoneroRpcConnection bestConnection = getBestAvailableConnection(); + if (bestConnection != null) setConnection(bestConnection); + } + + public synchronized boolean requestSwitchToNextBestConnection() { + return requestSwitchToNextBestConnection(null); + } + + public synchronized boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) { + log.warn("Requesting switch to next best monerod, source monerod={}", sourceConnection == null ? getConnection() == null ? null : getConnection().getUri() : sourceConnection.getUri()); + + // skip if shut down started + if (isShutDownStarted) { + log.warn("Skipping switch to next best Monero connection because shut down has started"); + return false; + } + + // skip if connection is already switched + if (sourceConnection != null && sourceConnection != getConnection()) { + log.warn("Skipping switch to next best Monero connection because source connection is not current connection"); + return false; + } + + // skip if connection is fixed + if (isFixedConnection() || !connectionManager.getAutoSwitch()) { + log.warn("Skipping switch to next best Monero connection because connection is fixed or auto switch is disabled"); + return false; + } + + // skip if last switch was too recent + boolean skipSwitch = System.currentTimeMillis() - lastSwitchTimestamp < SKIP_SWITCH_WITHIN_MS; + if (skipSwitch) { + log.warn("Skipping switch to next best Monero connection because last switch was less than {} seconds ago", SKIP_SWITCH_WITHIN_MS / 1000); + return false; + } + + // skip if too many requests in the last minute + if (numRequestsLastMinute > MAX_SWITCH_REQUESTS_PER_MINUTE) { + log.warn("Skipping switch to next best Monero connection because more than {} requests were made in the last minute", MAX_SWITCH_REQUESTS_PER_MINUTE); + return false; + } + + // increment request count + numRequestsLastMinute++; + UserThread.runAfter(() -> numRequestsLastMinute--, 60); // decrement after one minute + + // exclude current connection + MoneroRpcConnection currentConnection = getConnection(); + if (currentConnection != null) excludedConnections.add(currentConnection); + + // get connection to switch to + MoneroRpcConnection bestConnection = getBestAvailableConnection(excludedConnections); + + // remove from excluded connections after period + UserThread.runAfter(() -> { + if (currentConnection != null) excludedConnections.remove(currentConnection); + }, EXCLUDE_CONNECTION_SECONDS); + + // return if no connection to switch to + if (bestConnection == null) { + log.warn("No connection to switch to"); + return false; + } + + // switch to best connection + lastSwitchTimestamp = System.currentTimeMillis(); + setConnection(bestConnection); + return true; + } + + public void setAutoSwitch(boolean autoSwitch) { + accountService.checkAccountOpen(); + connectionManager.setAutoSwitch(autoSwitch); + connectionList.setAutoSwitch(autoSwitch); + } + + public boolean getAutoSwitch() { + accountService.checkAccountOpen(); + return connectionList.getAutoSwitch(); + } + + public boolean isConnectionLocalHost() { + return isConnectionLocalHost(getConnection()); + } + + public boolean isProxyApplied() { + return isProxyApplied(getConnection()); + } + + public long getRefreshPeriodMs() { + return connectionList.getRefreshPeriod() > 0 ? connectionList.getRefreshPeriod() : getDefaultRefreshPeriodMs(false); + } + + private long getInternalRefreshPeriodMs() { + return connectionList.getRefreshPeriod() > 0 ? connectionList.getRefreshPeriod() : getDefaultRefreshPeriodMs(true); + } + + public void verifyConnection() { + if (daemon == null) throw new RuntimeException("No connection to Monero node"); + if (!Boolean.TRUE.equals(isConnected())) throw new RuntimeException("No connection to Monero node"); + if (!isSyncedWithinTolerance()) throw new RuntimeException("Monero node is not synced"); + } + + public boolean isSyncedWithinTolerance() { + Long targetHeight = getTargetHeight(); + if (targetHeight == null) return false; + if (targetHeight - chainHeight.get() <= 3) return true; // synced if within 3 blocks of target height + return false; + } + + public Long getTargetHeight() { + if (lastInfo == null) return null; + return lastInfo.getTargetHeight() == 0 ? chainHeight.get() : lastInfo.getTargetHeight(); // monerod sync_info's target_height returns 0 when node is fully synced + } + + // ----------------------------- APP METHODS ------------------------------ + + public ReadOnlyIntegerProperty numConnectionsProperty() { + return numConnections; + } + + public ReadOnlyObjectProperty<List<MoneroRpcConnection>> connectionsProperty() { + return connections; + } + + public ReadOnlyObjectProperty<MoneroRpcConnection> connectionProperty() { + return connectionProperty; + } + + public boolean hasSufficientPeersForBroadcast() { + return numConnections.get() >= getMinBroadcastConnections(); + } + + public LongProperty chainHeightProperty() { + return chainHeight; + } + + public ReadOnlyDoubleProperty downloadPercentageProperty() { + return downloadListener.percentageProperty(); + } + + public int getMinBroadcastConnections() { + return MIN_BROADCAST_CONNECTIONS; + } + + public boolean isDownloadComplete() { + return downloadPercentageProperty().get() == 1d; + } + + public ReadOnlyLongProperty numUpdatesProperty() { + return numUpdates; + } + + public void fallbackToBestConnection() { + if (isShutDownStarted) return; + if (xmrNodes.getProvidedXmrNodes().isEmpty()) { + log.warn("Falling back to public nodes"); + preferences.setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.PUBLIC.ordinal()); + } else { + log.warn("Falling back to provided nodes"); + preferences.setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.PROVIDED.ordinal()); + } + fallbackApplied = true; + initializeConnections(); + } + + // ------------------------------- HELPERS -------------------------------- + + private void doneDownload() { + downloadListener.doneDownload(); + } + + private boolean isConnectionLocalHost(MoneroRpcConnection connection) { + return connection != null && HavenoUtils.isLocalHost(connection.getUri()); + } + + private long getDefaultRefreshPeriodMs(boolean internal) { + MoneroRpcConnection connection = getConnection(); + if (connection == null) return XmrLocalNode.REFRESH_PERIOD_LOCAL_MS; + if (isConnectionLocalHost(connection)) { + if (internal) return XmrLocalNode.REFRESH_PERIOD_LOCAL_MS; + if (lastInfo != null && (lastInfo.getHeightWithoutBootstrap() != null && lastInfo.getHeightWithoutBootstrap() > 0 && lastInfo.getHeightWithoutBootstrap() < lastInfo.getHeight())) { + return REFRESH_PERIOD_HTTP_MS; // refresh slower if syncing or bootstrapped + } else { + return XmrLocalNode.REFRESH_PERIOD_LOCAL_MS; // TODO: announce faster refresh after done syncing + } + } else if (isProxyApplied(connection)) { + return REFRESH_PERIOD_ONION_MS; + } else { + return REFRESH_PERIOD_HTTP_MS; + } + } + + private boolean isProxyApplied(MoneroRpcConnection connection) { + if (connection == null) return false; + return connection.isOnion() || (preferences.getUseTorForXmr().isUseTorForXmr() && !HavenoUtils.isPrivateIp(connection.getUri())); + } + + private void initialize() { + + // initialize connections + initializeConnections(); + + // listen for account to be opened or password changed + accountService.addListener(new AccountServiceListener() { + + @Override + public void onAccountOpened() { + try { + log.info(getClass() + ".onAccountOpened() called"); + initialize(); + } catch (Exception e) { + log.error("Error initializing connection service after account opened, error={}\n", e.getMessage(), e); + throw new RuntimeException(e); + } + } + + @Override + public void onPasswordChanged(String oldPassword, String newPassword) { + log.info(getClass() + ".onPasswordChanged({}, {}) called", oldPassword == null ? null : "***", newPassword == null ? null : "***"); + connectionList.changePassword(oldPassword, newPassword); + } + }); + } + + private void initializeConnections() { + synchronized (lock) { + + // reset connection manager + connectionManager.reset(); + connectionManager.setTimeout(REFRESH_PERIOD_HTTP_MS); + + // run once + if (!isInitialized) { + + // register local node listener + xmrLocalNode.addListener(new XmrLocalNodeListener() { + @Override + public void onNodeStarted(MoneroDaemonRpc daemon) { + log.info("Local monero node started, height={}", daemon.getHeight()); + } + + @Override + public void onNodeStopped() { + log.info("Local monero node stopped"); + } + + @Override + public void onConnectionChanged(MoneroRpcConnection connection) { + log.info("Local monerod connection changed: " + connection); + + // skip if ignored + if (isShutDownStarted || !connectionManager.getAutoSwitch() || !accountService.isAccountOpen() || + !connectionManager.hasConnection(connection.getUri()) || xmrLocalNode.shouldBeIgnored()) return; + + // check connection + boolean isConnected = false; + if (xmrLocalNode.isConnected()) { + MoneroRpcConnection conn = connectionManager.getConnectionByUri(connection.getUri()); + conn.checkConnection(connectionManager.getTimeout()); + isConnected = Boolean.TRUE.equals(conn.isConnected()); + } + + // update connection + if (isConnected) { + setConnection(connection.getUri()); + } else if (getConnection() != null && getConnection().getUri().equals(connection.getUri())) { + MoneroRpcConnection bestConnection = getBestAvailableConnection(); + if (bestConnection != null) setConnection(bestConnection); // switch to best connection + } + } + }); + } + + // restore connections + if (!isFixedConnection()) { + + // load previous or default connections + if (coreContext.isApiUser()) { + + // load previous connections + for (MoneroRpcConnection connection : connectionList.getConnections()) connectionManager.addConnection(connection); + log.info("Read " + connectionList.getConnections().size() + " previous connections from disk"); + + // add default connections + for (XmrNode node : xmrNodes.getAllXmrNodes()) { + if (node.hasClearNetAddress()) { + MoneroRpcConnection connection = new MoneroRpcConnection(node.getAddress() + ":" + node.getPort()).setPriority(node.getPriority()); + if (!connectionList.hasConnection(connection.getUri())) addConnection(connection); + } + if (node.hasOnionAddress()) { + MoneroRpcConnection connection = new MoneroRpcConnection(node.getOnionAddress() + ":" + node.getPort()).setPriority(node.getPriority()); + if (!connectionList.hasConnection(connection.getUri())) addConnection(connection); + } + } + } else { + + // add default connections + for (XmrNode node : xmrNodes.selectPreferredNodes(new XmrNodesSetupPreferences(preferences))) { + if (node.hasClearNetAddress()) { + MoneroRpcConnection connection = new MoneroRpcConnection(node.getAddress() + ":" + node.getPort()).setPriority(node.getPriority()); + addConnection(connection); + } + if (node.hasOnionAddress()) { + MoneroRpcConnection connection = new MoneroRpcConnection(node.getOnionAddress() + ":" + node.getPort()).setPriority(node.getPriority()); + addConnection(connection); + } + } + } + + // restore last connection + if (connectionList.getCurrentConnectionUri().isPresent() && connectionManager.hasConnection(connectionList.getCurrentConnectionUri().get())) { + if (!xmrLocalNode.shouldBeIgnored() || !xmrLocalNode.equalsUri(connectionList.getCurrentConnectionUri().get())) { + connectionManager.setConnection(connectionList.getCurrentConnectionUri().get()); + } + } + + // set connection proxies + log.info("TOR proxy URI: " + getProxyUri()); + for (MoneroRpcConnection connection : connectionManager.getConnections()) { + if (isProxyApplied(connection)) connection.setProxyUri(getProxyUri()); + } + + // restore auto switch + if (coreContext.isApiUser()) connectionManager.setAutoSwitch(connectionList.getAutoSwitch()); + else connectionManager.setAutoSwitch(true); // auto switch is always enabled on desktop ui + + // start local node if applicable + maybeStartLocalNode(); + + // update connection + if (connectionManager.getConnection() == null || connectionManager.getAutoSwitch()) { + MoneroRpcConnection bestConnection = getBestAvailableConnection(); + if (bestConnection != null) setConnection(bestConnection); + } + } else if (!isInitialized) { + + // set connection from startup argument if given + connectionManager.setAutoSwitch(false); + MoneroRpcConnection connection = new MoneroRpcConnection(config.xmrNode, config.xmrNodeUsername, config.xmrNodePassword).setPriority(1); + if (isProxyApplied(connection)) connection.setProxyUri(getProxyUri()); + connectionManager.setConnection(connection); + + // start local node if applicable + maybeStartLocalNode(); + } + + // register connection listener + connectionManager.addListener(this::onConnectionChanged); + isInitialized = true; + } + + // notify initial connection + lastRefreshPeriodMs = getRefreshPeriodMs(); + onConnectionChanged(connectionManager.getConnection()); + } + + private void maybeStartLocalNode() { + + // skip if seed node + if (HavenoUtils.isSeedNode()) return; + + // start local node if offline and used as last connection + if (connectionManager.getConnection() != null && xmrLocalNode.equalsUri(connectionManager.getConnection().getUri()) && !xmrLocalNode.isDetected() && !xmrLocalNode.shouldBeIgnored()) { + try { + log.info("Starting local node"); + xmrLocalNode.start(); + } catch (Exception e) { + log.error("Unable to start local monero node, error={}\n", e.getMessage(), e); + } + } + } + + private void onConnectionChanged(MoneroRpcConnection currentConnection) { + if (isShutDownStarted || !accountService.isAccountOpen()) return; + if (currentConnection == null) { + log.warn("Setting daemon connection to null"); + Thread.dumpStack(); + } + synchronized (lock) { + if (currentConnection == null) { + daemon = null; + isConnected = false; + connectionList.setCurrentConnectionUri(null); + } else { + daemon = new MoneroDaemonRpc(currentConnection); + isConnected = currentConnection.isConnected(); + connectionList.removeConnection(currentConnection.getUri()); + connectionList.addConnection(currentConnection); + connectionList.setCurrentConnectionUri(currentConnection.getUri()); + } + + // set connection property on user thread + UserThread.execute(() -> { + connectionProperty.set(currentConnection); + numUpdates.set(numUpdates.get() + 1); + }); + } + + // update polling + doPollDaemon(); + if (currentConnection != getConnection()) return; // polling can change connection + UserThread.runAfter(() -> updatePolling(), getInternalRefreshPeriodMs() / 1000); + + // notify listeners in parallel + log.info("XmrConnectionService.onConnectionChanged() uri={}, connected={}", currentConnection == null ? null : currentConnection.getUri(), currentConnection == null ? "false" : isConnected); + synchronized (listenerLock) { + for (MoneroConnectionManagerListener listener : listeners) { + ThreadUtils.submitToPool(() -> listener.onConnectionChanged(currentConnection)); + } + } + } + + private void updatePolling() { + stopPolling(); + if (connectionList.getRefreshPeriod() >= 0) startPolling(); // 0 means default refresh poll + } + + private void startPolling() { + synchronized (lock) { + if (daemonPollLooper != null) daemonPollLooper.stop(); + daemonPollLooper = new TaskLooper(() -> pollDaemon()); + daemonPollLooper.start(getInternalRefreshPeriodMs()); + } + } + + private void stopPolling() { + synchronized (lock) { + if (daemonPollLooper != null) { + daemonPollLooper.stop(); + daemonPollLooper = null; + } + } + } + + private void pollDaemon() { + if (pollInProgress) return; + doPollDaemon(); + } + + private void doPollDaemon() { + synchronized (pollLock) { + pollInProgress = true; + if (isShutDownStarted) return; + try { + + // poll daemon + if (daemon == null) switchToBestConnection(); + if (daemon == null) throw new RuntimeException("No connection to Monero daemon"); + try { + lastInfo = daemon.getInfo(); + } catch (Exception e) { + + // skip handling if shutting down + if (isShutDownStarted) return; + + // invoke fallback handling on startup error + boolean canFallback = isFixedConnection() || isCustomConnections(); + if (lastInfo == null && canFallback) { + if (!connectionServiceFallbackHandlerActive.get() && (lastFallbackInvocation == null || System.currentTimeMillis() - lastFallbackInvocation > FALLBACK_INVOCATION_PERIOD_MS)) { + log.warn("Failed to fetch daemon info from custom connection on startup: " + e.getMessage()); + lastFallbackInvocation = System.currentTimeMillis(); + connectionServiceFallbackHandlerActive.set(true); + } + return; + } + + // log error message periodically + if (lastLogPollErrorTimestamp == null || System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS) { + log.warn("Failed to fetch daemon info, trying to switch to best connection, error={}", e.getMessage()); + if (DevEnv.isDevMode()) log.error(ExceptionUtils.getStackTrace(e)); + lastLogPollErrorTimestamp = System.currentTimeMillis(); + } + + // switch to best connection + switchToBestConnection(); + lastInfo = daemon.getInfo(); // caught internally if still fails + } + + // connected to daemon + isConnected = true; + + // determine if blockchain is syncing locally + boolean blockchainSyncing = lastInfo.getHeight().equals(lastInfo.getHeightWithoutBootstrap()) || (lastInfo.getTargetHeight().equals(0l) && lastInfo.getHeightWithoutBootstrap().equals(0l)); // blockchain is syncing if height equals height without bootstrap, or target height and height without bootstrap both equal 0 + + // write sync status to preferences + preferences.getXmrNodeSettings().setSyncBlockchain(blockchainSyncing); + + // throttle warnings if daemon not synced + if (!isSyncedWithinTolerance() && System.currentTimeMillis() - lastLogDaemonNotSyncedTimestamp > HavenoUtils.LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS) { + log.warn("Our chain height: {} is out of sync with peer nodes chain height: {}", chainHeight.get(), getTargetHeight()); + lastLogDaemonNotSyncedTimestamp = System.currentTimeMillis(); + } + + // announce connection change if refresh period changes + if (getRefreshPeriodMs() != lastRefreshPeriodMs) { + lastRefreshPeriodMs = getRefreshPeriodMs(); + onConnectionChanged(getConnection()); // causes new poll + return; + } + + // update properties on user thread + UserThread.execute(() -> { + + // set chain height + chainHeight.set(lastInfo.getHeight()); + + // update sync progress + boolean isTestnet = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL; + if (lastInfo.isSynchronized() || isTestnet) doneDownload(); // TODO: skipping synchronized check for testnet because CI tests do not sync 3rd local node, see "Can manage Monero daemon connections" + else if (lastInfo.isBusySyncing()) { + long targetHeight = lastInfo.getTargetHeight(); + long blocksLeft = targetHeight - lastInfo.getHeight(); + if (syncStartHeight == null) syncStartHeight = lastInfo.getHeight(); + double percent = Math.min(1.0, targetHeight == syncStartHeight ? 1.0 : ((double) Math.max(1, lastInfo.getHeight() - syncStartHeight) / (double) (targetHeight - syncStartHeight))); // grant at least 1 block to show progress + downloadListener.progress(percent, blocksLeft, null); + } + + // set available connections + List<MoneroRpcConnection> availableConnections = new ArrayList<>(); + for (MoneroRpcConnection connection : connectionManager.getConnections()) { + if (Boolean.TRUE.equals(connection.isOnline()) && Boolean.TRUE.equals(connection.isAuthenticated())) { + availableConnections.add(connection); + } + } + connections.set(availableConnections); + numConnections.set(availableConnections.size()); + + // notify update + numUpdates.set(numUpdates.get() + 1); + }); + + // handle error recovery + if (lastLogPollErrorTimestamp != null) { + log.info("Successfully fetched daemon info after previous error"); + lastLogPollErrorTimestamp = null; + } + + // clear error message + getConnectionServiceErrorMsg().set(null); + } catch (Exception e) { + + // not connected to daemon + isConnected = false; + + // skip if shut down + if (isShutDownStarted) return; + + // set error message + getConnectionServiceErrorMsg().set(e.getMessage()); + } finally { + pollInProgress = false; + } + } + } + + private boolean isFixedConnection() { + return !"".equals(config.xmrNode) && !fallbackApplied; + } + + private boolean isCustomConnections() { + return preferences.getMoneroNodesOption() == XmrNodes.MoneroNodesOption.CUSTOM; + } +} diff --git a/core/src/main/java/haveno/core/api/LocalMoneroNode.java b/core/src/main/java/haveno/core/api/XmrLocalNode.java similarity index 62% rename from core/src/main/java/haveno/core/api/LocalMoneroNode.java rename to core/src/main/java/haveno/core/api/XmrLocalNode.java index 87d679789c..cd5ed266f1 100644 --- a/core/src/main/java/haveno/core/api/LocalMoneroNode.java +++ b/core/src/main/java/haveno/core/api/XmrLocalNode.java @@ -16,37 +16,46 @@ */ package haveno.core.api; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.BaseCurrencyNetwork; import haveno.common.config.Config; import haveno.common.util.Utilities; import haveno.core.trade.HavenoUtils; import haveno.core.user.Preferences; -import haveno.core.xmr.MoneroNodeSettings; -import lombok.extern.slf4j.Slf4j; -import monero.common.MoneroUtils; -import monero.daemon.MoneroDaemonRpc; -import javax.inject.Inject; -import javax.inject.Singleton; +import haveno.core.xmr.XmrNodeSettings; +import haveno.core.xmr.nodes.XmrNodes; +import haveno.core.xmr.wallet.XmrWalletService; + import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroConnectionManager; +import monero.common.MoneroUtils; +import monero.daemon.MoneroDaemonRpc; + /** * Start and stop or connect to a local Monero node. */ @Slf4j @Singleton -public class LocalMoneroNode { +public class XmrLocalNode { - public static final String MONEROD_DIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? System.getProperty("user.dir") + File.separator + ".localnet" : Config.appDataDir().getAbsolutePath(); + // constants + public static final long REFRESH_PERIOD_LOCAL_MS = 5000; // refresh period for local node public static final String MONEROD_NAME = Utilities.isWindows() ? "monerod.exe" : "monerod"; - public static final String MONEROD_PATH = MONEROD_DIR + File.separator + MONEROD_NAME; - private static final String MONEROD_DATADIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? MONEROD_DIR + File.separator + Config.baseCurrencyNetwork().toString().toLowerCase() + File.separator + "node1" : null; // use default directory unless local + public static final String MONEROD_PATH = XmrWalletService.MONERO_BINS_DIR + File.separator + MONEROD_NAME; + private static final String MONEROD_DATADIR = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_LOCAL ? XmrWalletService.MONERO_BINS_DIR + File.separator + Config.baseCurrencyNetwork().toString().toLowerCase() + File.separator + "node1" : null; // use default directory unless local + // instance fields + private MoneroDaemonRpc daemon; + private MoneroConnectionManager connectionManager; private final Config config; private final Preferences preferences; - private final List<LocalMoneroNodeListener> listeners = new ArrayList<>(); + private final List<XmrLocalNodeListener> listeners = new ArrayList<>(); // required arguments private static final List<String> MONEROD_ARGS = new ArrayList<String>(); @@ -54,24 +63,28 @@ public class LocalMoneroNode { MONEROD_ARGS.add(MONEROD_PATH); MONEROD_ARGS.add("--no-igd"); MONEROD_ARGS.add("--hide-my-port"); + MONEROD_ARGS.add("--p2p-bind-ip"); + MONEROD_ARGS.add(HavenoUtils.LOOPBACK_HOST); if (!Config.baseCurrencyNetwork().isMainnet()) MONEROD_ARGS.add("--" + Config.baseCurrencyNetwork().getNetwork().toLowerCase()); } - // client to the local Monero node - private MoneroDaemonRpc daemon; - private static Integer rpcPort; - static { - if (Config.baseCurrencyNetwork().isMainnet()) rpcPort = 18081; - else if (Config.baseCurrencyNetwork().isTestnet()) rpcPort = 28081; - else if (Config.baseCurrencyNetwork().isStagenet()) rpcPort = 38081; - else throw new RuntimeException("Base network is not local testnet, stagenet, or mainnet"); - } - @Inject - public LocalMoneroNode(Config config, Preferences preferences) { + public XmrLocalNode(Config config, Preferences preferences) { this.config = config; this.preferences = preferences; - this.daemon = new MoneroDaemonRpc("http://" + HavenoUtils.LOOPBACK_HOST + ":" + rpcPort); + this.daemon = new MoneroDaemonRpc(getUri()); + + // initialize connection manager to listen to local connection + this.connectionManager = new MoneroConnectionManager().setConnection(daemon.getRpcConnection()); + this.connectionManager.setTimeout(REFRESH_PERIOD_LOCAL_MS); + this.connectionManager.addListener((connection) -> { + for (var listener : listeners) listener.onConnectionChanged(connection); // notify of connection changes + }); + this.connectionManager.startPolling(REFRESH_PERIOD_LOCAL_MS); + } + + public String getUri() { + return "http://" + HavenoUtils.LOOPBACK_HOST + ":" + HavenoUtils.getDefaultMoneroPort(); } /** @@ -88,14 +101,14 @@ public class LocalMoneroNode { * Returns whether Haveno should ignore a local Monero node even if it is usable. */ public boolean shouldBeIgnored() { - return config.ignoreLocalXmrNode; + return config.ignoreLocalXmrNode || preferences.getMoneroNodesOption() == XmrNodes.MoneroNodesOption.CUSTOM; } - public void addListener(LocalMoneroNodeListener listener) { + public void addListener(XmrLocalNodeListener listener) { listeners.add(listener); } - public boolean removeListener(LocalMoneroNodeListener listener) { + public boolean removeListener(XmrLocalNodeListener listener) { return listeners.remove(listener); } @@ -106,12 +119,8 @@ public class LocalMoneroNode { return daemon; } - private boolean checkConnection() { - return daemon.getRpcConnection().checkConnection(5000); - } - public boolean equalsUri(String uri) { - return HavenoUtils.isLocalHost(uri) && MoneroUtils.parseUri(uri).getPort() == rpcPort; + return HavenoUtils.isLocalHost(uri) && MoneroUtils.parseUri(uri).getPort() == HavenoUtils.getDefaultMoneroPort(); } /** @@ -119,7 +128,7 @@ public class LocalMoneroNode { */ public boolean isDetected() { checkConnection(); - return daemon.getRpcConnection().isOnline(); + return Boolean.TRUE.equals(connectionManager.getConnection().isOnline()); } /** @@ -127,26 +136,30 @@ public class LocalMoneroNode { */ public boolean isConnected() { checkConnection(); - return daemon.getRpcConnection().isConnected(); + return Boolean.TRUE.equals(connectionManager.isConnected()); } - public MoneroNodeSettings getMoneroNodeSettings() { - return preferences.getMoneroNodeSettings(); + private void checkConnection() { + connectionManager.checkConnection(); + } + + public XmrNodeSettings getNodeSettings() { + return preferences.getXmrNodeSettings(); } /** * Start a local Monero node from settings. */ - public void startMoneroNode() throws IOException { - var settings = preferences.getMoneroNodeSettings(); - this.startMoneroNode(settings); + public void start() throws IOException { + var settings = preferences.getXmrNodeSettings(); + this.start(settings); } /** * Start local Monero node. Throws MoneroError if the node cannot be started. * Persist the settings to preferences if the node started successfully. */ - public void startMoneroNode(MoneroNodeSettings settings) throws IOException { + public void start(XmrNodeSettings settings) throws IOException { if (isDetected()) throw new IllegalStateException("Local Monero node already online"); log.info("Starting local Monero node: " + settings); @@ -164,21 +177,26 @@ public class LocalMoneroNode { args.add("--bootstrap-daemon-address=" + bootstrapUrl); } + var syncBlockchain = settings.getSyncBlockchain(); + if (syncBlockchain != null && !syncBlockchain) { + args.add("--no-sync"); + } + var flags = settings.getStartupFlags(); if (flags != null) { args.addAll(flags); } daemon = new MoneroDaemonRpc(args); // start daemon as process and re-assign client - preferences.setMoneroNodeSettings(settings); + preferences.setXmrNodeSettings(settings); for (var listener : listeners) listener.onNodeStarted(daemon); } /** * Stop the current local Monero node if we own its process. - * Does not remove the last MoneroNodeSettings. + * Does not remove the last XmrNodeSettings. */ - public void stopMoneroNode() { + public void stop() { if (!isDetected()) throw new IllegalStateException("Local Monero node is not running"); if (daemon.getProcess() == null || !daemon.getProcess().isAlive()) throw new IllegalStateException("Cannot stop local Monero node because we don't own its process"); // TODO (woodser): remove isAlive() check after monero-java 0.5.4 which nullifies internal process daemon.stopProcess(); diff --git a/core/src/main/java/haveno/core/api/XmrLocalNodeListener.java b/core/src/main/java/haveno/core/api/XmrLocalNodeListener.java new file mode 100644 index 0000000000..dbd70c91c2 --- /dev/null +++ b/core/src/main/java/haveno/core/api/XmrLocalNodeListener.java @@ -0,0 +1,26 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ +package haveno.core.api; + +import monero.common.MoneroRpcConnection; +import monero.daemon.MoneroDaemonRpc; + +public class XmrLocalNodeListener { + public void onNodeStarted(MoneroDaemonRpc daemon) {} + public void onNodeStopped() {} + public void onConnectionChanged(MoneroRpcConnection connection) {} +} diff --git a/core/src/main/java/haveno/core/api/model/AddressBalanceInfo.java b/core/src/main/java/haveno/core/api/model/AddressBalanceInfo.java index 2227478a48..de85c098a5 100644 --- a/core/src/main/java/haveno/core/api/model/AddressBalanceInfo.java +++ b/core/src/main/java/haveno/core/api/model/AddressBalanceInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; diff --git a/core/src/main/java/haveno/core/api/model/ContractInfo.java b/core/src/main/java/haveno/core/api/model/ContractInfo.java index 3774fdb474..98b6652fa7 100644 --- a/core/src/main/java/haveno/core/api/model/ContractInfo.java +++ b/core/src/main/java/haveno/core/api/model/ContractInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; diff --git a/core/src/main/java/haveno/core/api/model/MarketDepthInfo.java b/core/src/main/java/haveno/core/api/model/MarketDepthInfo.java index e307c0ac97..a24a9fdec2 100644 --- a/core/src/main/java/haveno/core/api/model/MarketDepthInfo.java +++ b/core/src/main/java/haveno/core/api/model/MarketDepthInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; diff --git a/core/src/main/java/haveno/core/api/model/MarketPriceInfo.java b/core/src/main/java/haveno/core/api/model/MarketPriceInfo.java index 0190fb0c2e..319841f875 100644 --- a/core/src/main/java/haveno/core/api/model/MarketPriceInfo.java +++ b/core/src/main/java/haveno/core/api/model/MarketPriceInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; diff --git a/core/src/main/java/haveno/core/api/model/OfferInfo.java b/core/src/main/java/haveno/core/api/model/OfferInfo.java index cb8f3d281e..537cc9ab26 100644 --- a/core/src/main/java/haveno/core/api/model/OfferInfo.java +++ b/core/src/main/java/haveno/core/api/model/OfferInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; @@ -52,10 +52,11 @@ public class OfferInfo implements Payload { private final long minAmount; private final String volume; private final String minVolume; - private final long makerFee; - @Nullable - private final long buyerSecurityDeposit; - private final long sellerSecurityDeposit; + private final double makerFeePct; + private final double takerFeePct; + private final double penaltyFeePct; + private final double buyerSecurityDepositPct; + private final double sellerSecurityDepositPct; private final String triggerPrice; private final String paymentAccountId; private final String paymentMethodId; @@ -74,6 +75,11 @@ public class OfferInfo implements Payload { private final int protocolVersion; @Nullable private final String arbitratorSigner; + @Nullable + private final String splitOutputTxHash; + private final long splitOutputTxFee; + private final boolean isPrivateOffer; + private final String challenge; public OfferInfo(OfferInfoBuilder builder) { this.id = builder.getId(); @@ -83,11 +89,13 @@ public class OfferInfo implements Payload { this.marketPriceMarginPct = builder.getMarketPriceMarginPct(); this.amount = builder.getAmount(); this.minAmount = builder.getMinAmount(); + this.makerFeePct = builder.getMakerFeePct(); + this.takerFeePct = builder.getTakerFeePct(); + this.penaltyFeePct = builder.getPenaltyFeePct(); + this.buyerSecurityDepositPct = builder.getBuyerSecurityDepositPct(); + this.sellerSecurityDepositPct = builder.getSellerSecurityDepositPct(); this.volume = builder.getVolume(); this.minVolume = builder.getMinVolume(); - this.makerFee = builder.getMakerFee(); - this.buyerSecurityDeposit = builder.getBuyerSecurityDeposit(); - this.sellerSecurityDeposit = builder.getSellerSecurityDeposit(); this.triggerPrice = builder.getTriggerPrice(); this.paymentAccountId = builder.getPaymentAccountId(); this.paymentMethodId = builder.getPaymentMethodId(); @@ -103,6 +111,10 @@ public class OfferInfo implements Payload { this.versionNumber = builder.getVersionNumber(); this.protocolVersion = builder.getProtocolVersion(); this.arbitratorSigner = builder.getArbitratorSigner(); + this.splitOutputTxHash = builder.getSplitOutputTxHash(); + this.splitOutputTxFee = builder.getSplitOutputTxFee(); + this.isPrivateOffer = builder.isPrivateOffer(); + this.challenge = builder.getChallenge(); } public static OfferInfo toOfferInfo(Offer offer) { @@ -127,6 +139,9 @@ public class OfferInfo implements Payload { .withTriggerPrice(preciseTriggerPrice) .withState(openOffer.getState().name()) .withIsActivated(isActivated) + .withSplitOutputTxHash(openOffer.getSplitOutputTxHash()) + .withSplitOutputTxFee(openOffer.getSplitOutputTxFee()) + .withChallenge(openOffer.getChallenge()) .build(); } @@ -148,11 +163,14 @@ public class OfferInfo implements Payload { .withMarketPriceMarginPct(marketPriceMarginAsPctLiteral) .withAmount(offer.getAmount().longValueExact()) .withMinAmount(offer.getMinAmount().longValueExact()) + .withMakerFeePct(offer.getMakerFeePct()) + .withTakerFeePct(offer.getTakerFeePct()) + .withPenaltyFeePct(offer.getPenaltyFeePct()) + .withSellerSecurityDepositPct(offer.getSellerSecurityDepositPct()) + .withBuyerSecurityDepositPct(offer.getBuyerSecurityDepositPct()) + .withSellerSecurityDepositPct(offer.getSellerSecurityDepositPct()) .withVolume(roundedVolume) .withMinVolume(roundedMinVolume) - .withMakerFee(offer.getMakerFee().longValueExact()) - .withBuyerSecurityDeposit(offer.getBuyerSecurityDeposit().longValueExact()) - .withSellerSecurityDeposit(offer.getSellerSecurityDeposit().longValueExact()) .withPaymentAccountId(offer.getMakerPaymentAccountId()) .withPaymentMethodId(offer.getPaymentMethod().getId()) .withPaymentMethodShortName(offer.getPaymentMethod().getShortName()) @@ -164,7 +182,9 @@ public class OfferInfo implements Payload { .withPubKeyRing(offer.getOfferPayload().getPubKeyRing().toString()) .withVersionNumber(offer.getOfferPayload().getVersionNr()) .withProtocolVersion(offer.getOfferPayload().getProtocolVersion()) - .withArbitratorSigner(offer.getOfferPayload().getArbitratorSigner() == null ? null : offer.getOfferPayload().getArbitratorSigner().getFullAddress()); + .withArbitratorSigner(offer.getOfferPayload().getArbitratorSigner() == null ? null : offer.getOfferPayload().getArbitratorSigner().getFullAddress()) + .withIsPrivateOffer(offer.isPrivateOffer()) + .withChallenge(offer.getChallenge()); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -183,9 +203,11 @@ public class OfferInfo implements Payload { .setMinAmount(minAmount) .setVolume(volume) .setMinVolume(minVolume) - .setMakerFee(makerFee) - .setBuyerSecurityDeposit(buyerSecurityDeposit) - .setSellerSecurityDeposit(sellerSecurityDeposit) + .setMakerFeePct(makerFeePct) + .setTakerFeePct(takerFeePct) + .setPenaltyFeePct(penaltyFeePct) + .setBuyerSecurityDepositPct(buyerSecurityDepositPct) + .setSellerSecurityDepositPct(sellerSecurityDepositPct) .setTriggerPrice(triggerPrice == null ? "0" : triggerPrice) .setPaymentAccountId(paymentAccountId) .setPaymentMethodId(paymentMethodId) @@ -199,8 +221,12 @@ public class OfferInfo implements Payload { .setOwnerNodeAddress(ownerNodeAddress) .setPubKeyRing(pubKeyRing) .setVersionNr(versionNumber) - .setProtocolVersion(protocolVersion); + .setProtocolVersion(protocolVersion) + .setSplitOutputTxFee(splitOutputTxFee) + .setIsPrivateOffer(isPrivateOffer); Optional.ofNullable(arbitratorSigner).ifPresent(builder::setArbitratorSigner); + Optional.ofNullable(splitOutputTxHash).ifPresent(builder::setSplitOutputTxHash); + Optional.ofNullable(challenge).ifPresent(builder::setChallenge); return builder.build(); } @@ -216,9 +242,11 @@ public class OfferInfo implements Payload { .withMinAmount(proto.getMinAmount()) .withVolume(proto.getVolume()) .withMinVolume(proto.getMinVolume()) - .withMakerFee(proto.getMakerFee()) - .withBuyerSecurityDeposit(proto.getBuyerSecurityDeposit()) - .withSellerSecurityDeposit(proto.getSellerSecurityDeposit()) + .withMakerFeePct(proto.getMakerFeePct()) + .withTakerFeePct(proto.getTakerFeePct()) + .withPenaltyFeePct(proto.getPenaltyFeePct()) + .withBuyerSecurityDepositPct(proto.getBuyerSecurityDepositPct()) + .withSellerSecurityDepositPct(proto.getSellerSecurityDepositPct()) .withTriggerPrice(proto.getTriggerPrice()) .withPaymentAccountId(proto.getPaymentAccountId()) .withPaymentMethodId(proto.getPaymentMethodId()) @@ -234,6 +262,10 @@ public class OfferInfo implements Payload { .withVersionNumber(proto.getVersionNr()) .withProtocolVersion(proto.getProtocolVersion()) .withArbitratorSigner(proto.getArbitratorSigner()) + .withSplitOutputTxHash(proto.getSplitOutputTxHash()) + .withSplitOutputTxFee(proto.getSplitOutputTxFee()) + .withIsPrivateOffer(proto.getIsPrivateOffer()) + .withChallenge(proto.getChallenge()) .build(); } } diff --git a/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java b/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java index 5716225b8e..6650265fbb 100644 --- a/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java +++ b/core/src/main/java/haveno/core/api/model/PaymentAccountForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; @@ -73,7 +73,11 @@ public final class PaymentAccountForm implements PersistablePayload { SWIFT, TRANSFERWISE, UPHOLD, - ZELLE; + ZELLE, + AUSTRALIA_PAYID, + CASH_APP, + PAYPAL, + VENMO; public static PaymentAccountForm.FormId fromProto(protobuf.PaymentAccountForm.FormId formId) { return ProtoUtil.enumFromProto(PaymentAccountForm.FormId.class, formId.name()); diff --git a/core/src/main/java/haveno/core/api/model/PaymentAccountFormField.java b/core/src/main/java/haveno/core/api/model/PaymentAccountFormField.java index 07f69fc722..8fb4d5b4ad 100644 --- a/core/src/main/java/haveno/core/api/model/PaymentAccountFormField.java +++ b/core/src/main/java/haveno/core/api/model/PaymentAccountFormField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; @@ -98,7 +98,9 @@ public final class PaymentAccountFormField implements PersistablePayload { SPECIAL_INSTRUCTIONS, STATE, TRADE_CURRENCIES, - USER_NAME; + USERNAME, + EMAIL_OR_MOBILE_NR_OR_USERNAME, + EMAIL_OR_MOBILE_NR_OR_CASHTAG; public static PaymentAccountFormField.FieldId fromProto(protobuf.PaymentAccountFormField.FieldId fieldId) { return ProtoUtil.enumFromProto(PaymentAccountFormField.FieldId.class, fieldId.name()); diff --git a/core/src/main/java/haveno/core/api/model/TradeInfo.java b/core/src/main/java/haveno/core/api/model/TradeInfo.java index bcbc4b2cb3..8df26368ba 100644 --- a/core/src/main/java/haveno/core/api/model/TradeInfo.java +++ b/core/src/main/java/haveno/core/api/model/TradeInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model; @@ -21,6 +21,7 @@ import haveno.common.Payload; import haveno.core.api.model.builder.TradeInfoV1Builder; import haveno.core.trade.Contract; import haveno.core.trade.Trade; +import haveno.core.trade.TradeUtil; import lombok.EqualsAndHashCode; import lombok.Getter; @@ -64,13 +65,20 @@ public class TradeInfo implements Payload { private final String shortId; private final long date; private final String role; - private final long takerFee; private final String makerDepositTxId; private final String takerDepositTxId; private final String payoutTxId; private final long amount; + private final long makerFee; + private final long takerFee; private final long buyerSecurityDeposit; private final long sellerSecurityDeposit; + private final long buyerDepositTxFee; + private final long sellerDepositTxFee; + private final long buyerPayoutTxFee; + private final long sellerPayoutTxFee; + private final long buyerPayoutAmount; + private final long sellerPayoutAmount; private final String price; private final String volume; private final String arbitratorNodeAddress; @@ -98,13 +106,20 @@ public class TradeInfo implements Payload { this.shortId = builder.getShortId(); this.date = builder.getDate(); this.role = builder.getRole(); - this.takerFee = builder.getTakerFee(); this.makerDepositTxId = builder.getMakerDepositTxId(); this.takerDepositTxId = builder.getTakerDepositTxId(); this.payoutTxId = builder.getPayoutTxId(); this.amount = builder.getAmount(); + this.makerFee = builder.getMakerFee(); + this.takerFee = builder.getTakerFee(); this.buyerSecurityDeposit = builder.getBuyerSecurityDeposit(); this.sellerSecurityDeposit = builder.getSellerSecurityDeposit(); + this.buyerDepositTxFee = builder.getBuyerDepositTxFee(); + this.sellerDepositTxFee = builder.getSellerDepositTxFee(); + this.buyerPayoutTxFee = builder.getBuyerPayoutTxFee(); + this.sellerPayoutTxFee = builder.getSellerPayoutTxFee(); + this.buyerPayoutAmount = builder.getBuyerPayoutAmount(); + this.sellerPayoutAmount = builder.getSellerPayoutAmount(); this.price = builder.getPrice(); this.volume = builder.getVolume(); this.arbitratorNodeAddress = builder.getArbitratorNodeAddress(); @@ -128,10 +143,7 @@ public class TradeInfo implements Payload { } public static TradeInfo toTradeInfo(Trade trade) { - return toTradeInfo(trade, null); - } - - public static TradeInfo toTradeInfo(Trade trade, String role) { + String role = TradeUtil.getRole(trade); ContractInfo contractInfo; if (trade.getContract() != null) { Contract contract = trade.getContract(); @@ -154,13 +166,21 @@ public class TradeInfo implements Payload { .withShortId(trade.getShortId()) .withDate(trade.getDate().getTime()) .withRole(role == null ? "" : role) - .withTakerFee(trade.getTakerFee().longValueExact()) .withMakerDepositTxId(trade.getMaker().getDepositTxHash()) .withTakerDepositTxId(trade.getTaker().getDepositTxHash()) .withPayoutTxId(trade.getPayoutTxId()) .withAmount(trade.getAmount().longValueExact()) - .withBuyerSecurityDeposit(trade.getBuyerSecurityDeposit() == null ? -1 : trade.getBuyerSecurityDeposit().longValueExact()) - .withSellerSecurityDeposit(trade.getSellerSecurityDeposit() == null ? -1 : trade.getSellerSecurityDeposit().longValueExact()) + .withMakerFee(trade.getMakerFee().longValueExact()) + .withTakerFee(trade.getTakerFee().longValueExact()) + .withBuyerSecurityDeposit(trade.getBuyer().getSecurityDeposit().longValueExact()) + .withSellerSecurityDeposit(trade.getSeller().getSecurityDeposit().longValueExact()) + .withBuyerDepositTxFee(trade.getBuyer().getDepositTxFee().longValueExact()) + .withSellerDepositTxFee(trade.getSeller().getDepositTxFee().longValueExact()) + .withBuyerPayoutTxFee(trade.getBuyer().getPayoutTxFee().longValueExact()) + .withSellerPayoutTxFee(trade.getSeller().getPayoutTxFee().longValueExact()) + .withBuyerPayoutAmount(trade.getBuyer().getPayoutAmount().longValueExact()) + .withSellerPayoutAmount(trade.getSeller().getPayoutAmount().longValueExact()) + .withTotalTxFee(trade.getTotalTxFee().longValueExact()) .withPrice(toPreciseTradePrice.apply(trade)) .withVolume(toRoundedVolume.apply(trade)) .withArbitratorNodeAddress(toArbitratorNodeAddress.apply(trade)) @@ -197,13 +217,20 @@ public class TradeInfo implements Payload { .setShortId(shortId) .setDate(date) .setRole(role) - .setTakerFee(takerFee) .setMakerDepositTxId(makerDepositTxId == null ? "" : makerDepositTxId) .setTakerDepositTxId(takerDepositTxId == null ? "" : takerDepositTxId) .setPayoutTxId(payoutTxId == null ? "" : payoutTxId) .setAmount(amount) + .setMakerFee(makerFee) + .setTakerFee(takerFee) .setBuyerSecurityDeposit(buyerSecurityDeposit) .setSellerSecurityDeposit(sellerSecurityDeposit) + .setBuyerDepositTxFee(buyerDepositTxFee) + .setSellerDepositTxFee(sellerDepositTxFee) + .setBuyerPayoutTxFee(buyerPayoutTxFee) + .setSellerPayoutTxFee(sellerPayoutTxFee) + .setBuyerPayoutAmount(buyerPayoutAmount) + .setSellerPayoutAmount(sellerPayoutAmount) .setPrice(price) .setTradeVolume(volume) .setArbitratorNodeAddress(arbitratorNodeAddress) @@ -234,13 +261,20 @@ public class TradeInfo implements Payload { .withShortId(proto.getShortId()) .withDate(proto.getDate()) .withRole(proto.getRole()) - .withTakerFee(proto.getTakerFee()) .withMakerDepositTxId(proto.getMakerDepositTxId()) .withTakerDepositTxId(proto.getTakerDepositTxId()) .withPayoutTxId(proto.getPayoutTxId()) .withAmount(proto.getAmount()) + .withMakerFee(proto.getMakerFee()) + .withTakerFee(proto.getTakerFee()) .withBuyerSecurityDeposit(proto.getBuyerSecurityDeposit()) .withSellerSecurityDeposit(proto.getSellerSecurityDeposit()) + .withBuyerDepositTxFee(proto.getBuyerDepositTxFee()) + .withSellerDepositTxFee(proto.getSellerDepositTxFee()) + .withBuyerPayoutTxFee(proto.getBuyerPayoutTxFee()) + .withSellerPayoutTxFee(proto.getSellerPayoutTxFee()) + .withBuyerPayoutAmount(proto.getBuyerPayoutAmount()) + .withSellerPayoutAmount(proto.getSellerPayoutAmount()) .withPrice(proto.getPrice()) .withVolume(proto.getTradeVolume()) .withPeriodState(proto.getPeriodState()) @@ -271,13 +305,20 @@ public class TradeInfo implements Payload { ", shortId='" + shortId + '\'' + "\n" + ", date='" + date + '\'' + "\n" + ", role='" + role + '\'' + "\n" + - ", takerFee='" + takerFee + '\'' + "\n" + ", makerDepositTxId='" + makerDepositTxId + '\'' + "\n" + ", takerDepositTxId='" + takerDepositTxId + '\'' + "\n" + ", payoutTxId='" + payoutTxId + '\'' + "\n" + ", amount='" + amount + '\'' + "\n" + + ", makerFee='" + makerFee + '\'' + "\n" + + ", takerFee='" + takerFee + '\'' + "\n" + ", buyerSecurityDeposit='" + buyerSecurityDeposit + '\'' + "\n" + ", sellerSecurityDeposit='" + sellerSecurityDeposit + '\'' + "\n" + + ", buyerDepositTxFee='" + buyerDepositTxFee + '\'' + "\n" + + ", sellerDepositTxFee='" + sellerDepositTxFee + '\'' + "\n" + + ", buyerPayoutTxFee='" + buyerPayoutTxFee + '\'' + "\n" + + ", sellerPayoutTxFee='" + sellerPayoutTxFee + '\'' + "\n" + + ", buyerPayoutAmount='" + buyerPayoutAmount + '\'' + "\n" + + ", sellerPayoutAmount='" + sellerPayoutAmount + '\'' + "\n" + ", price='" + price + '\'' + "\n" + ", arbitratorNodeAddress='" + arbitratorNodeAddress + '\'' + "\n" + ", tradePeerNodeAddress='" + tradePeerNodeAddress + '\'' + "\n" + diff --git a/core/src/main/java/haveno/core/api/model/XmrBalanceInfo.java b/core/src/main/java/haveno/core/api/model/XmrBalanceInfo.java index 1483e11235..76e661aea6 100644 --- a/core/src/main/java/haveno/core/api/model/XmrBalanceInfo.java +++ b/core/src/main/java/haveno/core/api/model/XmrBalanceInfo.java @@ -1,10 +1,10 @@ package haveno.core.api.model; +import java.math.BigInteger; + import com.google.common.annotations.VisibleForTesting; import haveno.common.Payload; -import lombok.Getter; -@Getter public class XmrBalanceInfo implements Payload { public static final XmrBalanceInfo EMPTY = new XmrBalanceInfo(-1, @@ -19,17 +19,19 @@ public class XmrBalanceInfo implements Payload { private final long pendingBalance; private final long reservedOfferBalance; private final long reservedTradeBalance; + private final long reservedBalance; public XmrBalanceInfo(long balance, long unlockedBalance, - long lockedBalance, + long pendingBalance, long reservedOfferBalance, long reservedTradeBalance) { this.balance = balance; this.availableBalance = unlockedBalance; - this.pendingBalance = lockedBalance; + this.pendingBalance = pendingBalance; this.reservedOfferBalance = reservedOfferBalance; this.reservedTradeBalance = reservedTradeBalance; + this.reservedBalance = reservedOfferBalance + reservedTradeBalance; } @VisibleForTesting @@ -45,6 +47,30 @@ public class XmrBalanceInfo implements Payload { reservedTradeBalance); } + public BigInteger getBalance() { + return BigInteger.valueOf(balance); + } + + public BigInteger getAvailableBalance() { + return BigInteger.valueOf(availableBalance); + } + + public BigInteger getPendingBalance() { + return BigInteger.valueOf(pendingBalance); + } + + public BigInteger getReservedOfferBalance() { + return BigInteger.valueOf(reservedOfferBalance); + } + + public BigInteger getReservedTradeBalance() { + return BigInteger.valueOf(reservedTradeBalance); + } + + public BigInteger getReservedBalance() { + return BigInteger.valueOf(reservedBalance); + } + /////////////////////////////////////////////////////////////////////////////////////////// // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// @@ -72,7 +98,7 @@ public class XmrBalanceInfo implements Payload { public String toString() { return "XmrBalanceInfo{" + "balance=" + balance + - "unlockedBalance=" + availableBalance + + ", unlockedBalance=" + availableBalance + ", lockedBalance=" + pendingBalance + ", reservedOfferBalance=" + reservedOfferBalance + ", reservedTradeBalance=" + reservedTradeBalance + diff --git a/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java b/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java index 2cce4aaa27..36801cdbb6 100644 --- a/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java +++ b/core/src/main/java/haveno/core/api/model/builder/OfferInfoBuilder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model.builder; @@ -38,9 +38,11 @@ public final class OfferInfoBuilder { private long minAmount; private String volume; private String minVolume; - private long makerFee; - private long buyerSecurityDeposit; - private long sellerSecurityDeposit; + private double makerFeePct; + private double takerFeePct; + private double penaltyFeePct; + private double buyerSecurityDepositPct; + private double sellerSecurityDepositPct; private String triggerPrice; private boolean isCurrencyForMakerFeeBtc; private String paymentAccountId; @@ -59,6 +61,10 @@ public final class OfferInfoBuilder { private String versionNumber; private int protocolVersion; private String arbitratorSigner; + private String splitOutputTxHash; + private long splitOutputTxFee; + private boolean isPrivateOffer; + private String challenge; public OfferInfoBuilder withId(String id) { this.id = id; @@ -95,6 +101,31 @@ public final class OfferInfoBuilder { return this; } + public OfferInfoBuilder withMakerFeePct(double makerFeePct) { + this.makerFeePct = makerFeePct; + return this; + } + + public OfferInfoBuilder withTakerFeePct(double takerFeePct) { + this.takerFeePct = takerFeePct; + return this; + } + + public OfferInfoBuilder withPenaltyFeePct(double penaltyFeePct) { + this.penaltyFeePct = penaltyFeePct; + return this; + } + + public OfferInfoBuilder withBuyerSecurityDepositPct(double buyerSecurityDepositPct) { + this.buyerSecurityDepositPct = buyerSecurityDepositPct; + return this; + } + + public OfferInfoBuilder withSellerSecurityDepositPct(double sellerSecurityDepositPct) { + this.sellerSecurityDepositPct = sellerSecurityDepositPct; + return this; + } + public OfferInfoBuilder withVolume(String volume) { this.volume = volume; return this; @@ -105,21 +136,6 @@ public final class OfferInfoBuilder { return this; } - public OfferInfoBuilder withMakerFee(long makerFee) { - this.makerFee = makerFee; - return this; - } - - public OfferInfoBuilder withBuyerSecurityDeposit(long buyerSecurityDeposit) { - this.buyerSecurityDeposit = buyerSecurityDeposit; - return this; - } - - public OfferInfoBuilder withSellerSecurityDeposit(long sellerSecurityDeposit) { - this.sellerSecurityDeposit = sellerSecurityDeposit; - return this; - } - public OfferInfoBuilder withTriggerPrice(String triggerPrice) { this.triggerPrice = triggerPrice; return this; @@ -209,6 +225,26 @@ public final class OfferInfoBuilder { this.arbitratorSigner = arbitratorSigner; return this; } + + public OfferInfoBuilder withSplitOutputTxHash(String splitOutputTxHash) { + this.splitOutputTxHash = splitOutputTxHash; + return this; + } + + public OfferInfoBuilder withSplitOutputTxFee(long splitOutputTxFee) { + this.splitOutputTxFee = splitOutputTxFee; + return this; + } + + public OfferInfoBuilder withIsPrivateOffer(boolean isPrivateOffer) { + this.isPrivateOffer = isPrivateOffer; + return this; + } + + public OfferInfoBuilder withChallenge(String challenge) { + this.challenge = challenge; + return this; + } public OfferInfo build() { return new OfferInfo(this); diff --git a/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java b/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java index 7987061806..dcf40b8a69 100644 --- a/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java +++ b/core/src/main/java/haveno/core/api/model/builder/TradeInfoV1Builder.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.api.model.builder; @@ -38,9 +38,16 @@ public final class TradeInfoV1Builder { private String role; private boolean isCurrencyForTakerFeeBtc; private long totalTxFee; + private long makerFee; private long takerFee; private long buyerSecurityDeposit; private long sellerSecurityDeposit; + private long buyerDepositTxFee; + private long sellerDepositTxFee; + private long buyerPayoutTxFee; + private long sellerPayoutTxFee; + private long buyerPayoutAmount; + private long sellerPayoutAmount; private String makerDepositTxId; private String takerDepositTxId; private String payoutTxId; @@ -102,6 +109,11 @@ public final class TradeInfoV1Builder { return this; } + public TradeInfoV1Builder withMakerFee(long makerFee) { + this.makerFee = makerFee; + return this; + } + public TradeInfoV1Builder withTakerFee(long takerFee) { this.takerFee = takerFee; return this; @@ -117,6 +129,36 @@ public final class TradeInfoV1Builder { return this; } + public TradeInfoV1Builder withBuyerDepositTxFee(long buyerDepositTxFee) { + this.buyerDepositTxFee = buyerDepositTxFee; + return this; + } + + public TradeInfoV1Builder withSellerDepositTxFee(long sellerDepositTxFee) { + this.sellerDepositTxFee = sellerDepositTxFee; + return this; + } + + public TradeInfoV1Builder withBuyerPayoutTxFee(long buyerPayoutTxFee) { + this.buyerPayoutTxFee = buyerPayoutTxFee; + return this; + } + + public TradeInfoV1Builder withSellerPayoutTxFee(long sellerPayoutTxFee) { + this.sellerPayoutTxFee = sellerPayoutTxFee; + return this; + } + + public TradeInfoV1Builder withBuyerPayoutAmount(long buyerPayoutAmount) { + this.buyerPayoutAmount = buyerPayoutAmount; + return this; + } + + public TradeInfoV1Builder withSellerPayoutAmount(long sellerPayoutAmount) { + this.sellerPayoutAmount = sellerPayoutAmount; + return this; + } + public TradeInfoV1Builder withMakerDepositTxId(String makerDepositTxId) { this.makerDepositTxId = makerDepositTxId; return this; diff --git a/core/src/main/java/haveno/core/app/AppStartupState.java b/core/src/main/java/haveno/core/app/AppStartupState.java index 94767beb0e..89fe61576a 100644 --- a/core/src/main/java/haveno/core/app/AppStartupState.java +++ b/core/src/main/java/haveno/core/app/AppStartupState.java @@ -1,24 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; -import haveno.core.api.CoreMoneroConnectionsService; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import haveno.core.api.XmrConnectionService; import haveno.core.api.CoreNotificationService; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.P2PService; import javafx.beans.property.BooleanProperty; @@ -28,9 +31,6 @@ import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.monadic.MonadicBinding; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * We often need to wait until network and wallet is ready or other combination of startup states. * To avoid those repeated checks for the state or setting of listeners on different domains we provide here a @@ -47,40 +47,48 @@ public class AppStartupState { private final BooleanProperty applicationFullyInitialized = new SimpleBooleanProperty(); private final BooleanProperty updatedDataReceived = new SimpleBooleanProperty(); private final BooleanProperty isBlockDownloadComplete = new SimpleBooleanProperty(); + private final BooleanProperty isWalletSynced = new SimpleBooleanProperty(); private final BooleanProperty hasSufficientPeersForBroadcast = new SimpleBooleanProperty(); @Inject public AppStartupState(CoreNotificationService notificationService, - CoreMoneroConnectionsService connectionsService, + XmrConnectionService xmrConnectionService, + XmrWalletService xmrWalletService, P2PService p2PService) { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { updatedDataReceived.set(true); } }); - connectionsService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { - if (connectionsService.isDownloadComplete()) + xmrConnectionService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { + if (xmrConnectionService.isDownloadComplete()) isBlockDownloadComplete.set(true); }); - connectionsService.numPeersProperty().addListener((observable, oldValue, newValue) -> { - if (connectionsService.hasSufficientPeersForBroadcast()) + xmrWalletService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { + if (xmrWalletService.isDownloadComplete()) + isWalletSynced.set(true); + }); + + xmrConnectionService.numConnectionsProperty().addListener((observable, oldValue, newValue) -> { + if (xmrConnectionService.hasSufficientPeersForBroadcast()) hasSufficientPeersForBroadcast.set(true); }); p2pNetworkAndWalletInitialized = EasyBind.combine(updatedDataReceived, isBlockDownloadComplete, + isWalletSynced, hasSufficientPeersForBroadcast, // TODO: consider sufficient number of peers? allDomainServicesInitialized, - (a, b, c, d) -> { - log.info("Combined initialized state = {} = updatedDataReceived={} && isBlockDownloadComplete={} && hasSufficientPeersForBroadcast={} && allDomainServicesInitialized={}", (a && b && c && d), updatedDataReceived.get(), isBlockDownloadComplete.get(), hasSufficientPeersForBroadcast.get(), allDomainServicesInitialized.get()); - if (a && b) { + (a, b, c, d, e) -> { + log.info("Combined initialized state = {} = updatedDataReceived={} && isBlockDownloadComplete={} && isWalletSynced={} && hasSufficientPeersForBroadcast={} && allDomainServicesInitialized={}", (a && b && c && d && e), updatedDataReceived.get(), isBlockDownloadComplete.get(), isWalletSynced.get(), hasSufficientPeersForBroadcast.get(), allDomainServicesInitialized.get()); + if (a && b && c) { walletAndNetworkReady.set(true); } - return a && d; // app fully initialized before daemon connection and wallet by default // TODO: rename variable + return a && e; // app fully initialized before daemon connection and wallet by default }); p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> { if (newValue) { @@ -136,6 +144,10 @@ public class AppStartupState { return isBlockDownloadComplete.get(); } + public boolean isWalletSynced() { + return isWalletSynced.get(); + } + public ReadOnlyBooleanProperty isBlockDownloadCompleteProperty() { return isBlockDownloadComplete; } diff --git a/core/src/main/java/haveno/core/app/AvoidStandbyModeService.java b/core/src/main/java/haveno/core/app/AvoidStandbyModeService.java index d1f1c49369..345f556a33 100644 --- a/core/src/main/java/haveno/core/app/AvoidStandbyModeService.java +++ b/core/src/main/java/haveno/core/app/AvoidStandbyModeService.java @@ -1,37 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.Config; import haveno.common.file.FileUtil; import haveno.common.file.ResourceNotFoundException; import haveno.common.util.Utilities; import haveno.core.user.Preferences; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; -import javax.sound.sampled.AudioSystem; -import javax.sound.sampled.DataLine; -import javax.sound.sampled.LineUnavailableException; -import javax.sound.sampled.SourceDataLine; import java.io.File; import java.io.IOException; import java.nio.file.Paths; @@ -43,6 +35,13 @@ import java.util.concurrent.CountDownLatch; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; +import lombok.extern.slf4j.Slf4j; /** * Prevents that Haveno gets hibernated from the OS. On OSX there is a tool called caffeinate but it seems it does not diff --git a/core/src/main/java/haveno/core/app/ConsoleInput.java b/core/src/main/java/haveno/core/app/ConsoleInput.java index 43045b9e85..f451dcbd14 100644 --- a/core/src/main/java/haveno/core/app/ConsoleInput.java +++ b/core/src/main/java/haveno/core/app/ConsoleInput.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; diff --git a/core/src/main/java/haveno/core/app/ConsoleInputReadTask.java b/core/src/main/java/haveno/core/app/ConsoleInputReadTask.java index 54edd6655b..62511aacfc 100644 --- a/core/src/main/java/haveno/core/app/ConsoleInputReadTask.java +++ b/core/src/main/java/haveno/core/app/ConsoleInputReadTask.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; diff --git a/core/src/main/java/haveno/core/app/CoreModule.java b/core/src/main/java/haveno/core/app/CoreModule.java index c84496ce09..3d36766934 100644 --- a/core/src/main/java/haveno/core/app/CoreModule.java +++ b/core/src/main/java/haveno/core/app/CoreModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; @@ -35,8 +35,8 @@ import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; import haveno.core.util.coin.ImmutableCoinFormatter; -import haveno.core.xmr.MoneroConnectionModule; -import haveno.core.xmr.MoneroModule; +import haveno.core.xmr.XmrConnectionModule; +import haveno.core.xmr.XmrModule; import haveno.network.crypto.EncryptionServiceModule; import haveno.network.p2p.P2PModule; import haveno.network.p2p.network.BanFilter; @@ -88,10 +88,10 @@ public class CoreModule extends AppModule { install(new EncryptionServiceModule(config)); install(new OfferModule(config)); install(new P2PModule(config)); - install(new MoneroModule(config)); + install(new XmrModule(config)); install(new AlertModule(config)); install(new FilterModule(config)); install(new CorePresentationModule(config)); - install(new MoneroConnectionModule(config)); + install(new XmrConnectionModule(config)); } } diff --git a/core/src/main/java/haveno/core/app/DomainInitialisation.java b/core/src/main/java/haveno/core/app/DomainInitialisation.java index 7ab65c70ef..646d80d9dd 100644 --- a/core/src/main/java/haveno/core/app/DomainInitialisation.java +++ b/core/src/main/java/haveno/core/app/DomainInitialisation.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; +import com.google.inject.Inject; import haveno.common.ClockWatcher; import haveno.common.persistence.PersistenceManager; import haveno.core.account.sign.SignedWitnessService; @@ -50,8 +51,6 @@ import haveno.core.user.User; import haveno.core.xmr.Balances; import haveno.network.p2p.P2PService; import haveno.network.p2p.mailbox.MailboxMessageService; - -import javax.inject.Inject; import java.util.List; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -218,7 +217,7 @@ public class DomainInitialisation { revolutAccountsUpdateHandler.accept(user.getPaymentAccountsAsObservable().stream() .filter(paymentAccount -> paymentAccount instanceof RevolutAccount) .map(paymentAccount -> (RevolutAccount) paymentAccount) - .filter(RevolutAccount::userNameNotSet) + .filter(RevolutAccount::usernameNotSet) .collect(Collectors.toList())); } if (amazonGiftCardAccountsUpdateHandler != null && user.getPaymentAccountsAsObservable() != null) { diff --git a/core/src/main/java/haveno/core/app/HavenoExecutable.java b/core/src/main/java/haveno/core/app/HavenoExecutable.java index 3365001841..5f2d14622b 100644 --- a/core/src/main/java/haveno/core/app/HavenoExecutable.java +++ b/core/src/main/java/haveno/core/app/HavenoExecutable.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -19,6 +36,8 @@ package haveno.core.app; import com.google.inject.Guice; import com.google.inject.Injector; + +import haveno.common.ThreadUtils; import haveno.common.UserThread; import haveno.common.app.AppModule; import haveno.common.config.Config; @@ -34,14 +53,14 @@ import haveno.common.setup.UncaughtExceptionHandler; import haveno.common.util.Utilities; import haveno.core.api.AccountServiceListener; import haveno.core.api.CoreAccountService; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.offer.OfferBookService; import haveno.core.offer.OpenOfferManager; import haveno.core.provider.price.PriceFeedService; import haveno.core.setup.CorePersistedDataHost; import haveno.core.setup.CoreSetup; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; -import haveno.core.trade.HavenoUtils; +import haveno.core.trade.TradeManager; import haveno.core.trade.statistics.TradeStatisticsManager; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.BtcWalletService; @@ -63,6 +82,10 @@ import java.util.concurrent.atomic.AtomicInteger; @Slf4j public abstract class HavenoExecutable implements GracefulShutDownHandler, HavenoSetup.HavenoSetupListener, UncaughtExceptionHandler { + // TODO: regular expression is used to parse application name for the flatpak manifest, a more stable approach would be nice + // Don't edit the next line unless you're only editing in between the quotes. + public static final String DEFAULT_APP_NAME = "Haveno"; + public static final int EXIT_SUCCESS = 0; public static final int EXIT_FAILURE = 1; public static final int EXIT_RESTART = 2; @@ -103,7 +126,7 @@ public abstract class HavenoExecutable implements GracefulShutDownHandler, Haven System.exit(EXIT_FAILURE); } catch (Throwable ex) { System.err.println("fault: An unexpected error occurred. " + - "Please file a report at https://haveno.exchange/issues"); + "Please file a report at https://github.com/haveno-dex/haveno/issues"); ex.printStackTrace(System.err); System.exit(EXIT_FAILURE); } @@ -180,8 +203,7 @@ public abstract class HavenoExecutable implements GracefulShutDownHandler, Haven startApplication(); } } catch (InterruptedException | ExecutionException e) { - log.error("An error occurred: {}", e.getMessage()); - e.printStackTrace(); + log.error("An error occurred: {}\n", e.getMessage(), e); } }); } @@ -336,9 +358,15 @@ public abstract class HavenoExecutable implements GracefulShutDownHandler, Haven // notify trade protocols and wallets to prepare for shut down before shutting down Set<Runnable> tasks = new HashSet<Runnable>(); tasks.add(() -> injector.getInstance(XmrWalletService.class).onShutDownStarted()); - tasks.add(() -> injector.getInstance(CoreMoneroConnectionsService.class).onShutDownStarted()); - HavenoUtils.executeTasks(tasks); // notify in parallel + tasks.add(() -> injector.getInstance(XmrConnectionService.class).onShutDownStarted()); + tasks.add(() -> injector.getInstance(TradeManager.class).onShutDownStarted()); + try { + ThreadUtils.awaitTasks(tasks, tasks.size(), 90000l); // run in parallel with timeout + } catch (Exception e) { + log.error("Failed to notify all services to prepare for shutdown: {}\n", e.getMessage(), e); + } + injector.getInstance(TradeManager.class).shutDown(); injector.getInstance(PriceFeedService.class).shutDown(); injector.getInstance(ArbitratorManager.class).shutDown(); injector.getInstance(TradeStatisticsManager.class).shutDown(); @@ -353,23 +381,24 @@ public abstract class HavenoExecutable implements GracefulShutDownHandler, Haven // shut down p2p service injector.getInstance(P2PService.class).shutDown(() -> { - log.info("Done shutting down OpenOfferManager, OfferBookService, and P2PService"); // shut down monero wallets and connections + log.info("Shutting down wallet and connection services"); injector.getInstance(WalletsSetup.class).shutDownComplete.addListener((ov, o, n) -> { + + // done shutting down log.info("Graceful shutdown completed. Exiting now."); module.close(injector); completeShutdown(resultHandler, EXIT_SUCCESS, systemExit); }); injector.getInstance(BtcWalletService.class).shutDown(); injector.getInstance(XmrWalletService.class).shutDown(); - injector.getInstance(CoreMoneroConnectionsService.class).shutDown(); + injector.getInstance(XmrConnectionService.class).shutDown(); injector.getInstance(WalletsSetup.class).shutDown(); }); }); } catch (Throwable t) { - log.error("App shutdown failed with exception {}", t.toString()); - t.printStackTrace(); + log.error("App shutdown failed with exception: {}\n", t.getMessage(), t); completeShutdown(resultHandler, EXIT_FAILURE, systemExit); } } diff --git a/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java b/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java index 73bcccedd2..0cf18224ba 100644 --- a/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java +++ b/core/src/main/java/haveno/core/app/HavenoHeadlessApp.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; @@ -75,9 +75,10 @@ public class HavenoHeadlessApp implements HeadlessApp { log.info("onDisplayTacHandler: We accept the tacs automatically in headless mode"); acceptedHandler.run(); }); + havenoSetup.setDisplayMoneroConnectionFallbackHandler(show -> log.info("onDisplayMoneroConnectionFallbackHandler: show={}", show)); havenoSetup.setDisplayTorNetworkSettingsHandler(show -> log.info("onDisplayTorNetworkSettingsHandler: show={}", show)); havenoSetup.setChainFileLockedExceptionHandler(msg -> log.error("onChainFileLockedExceptionHandler: msg={}", msg)); - havenoSetup.setLockedUpFundsHandler(msg -> log.info("onLockedUpFundsHandler: msg={}", msg)); + tradeManager.setLockedUpFundsHandler(msg -> log.info("onLockedUpFundsHandler: msg={}", msg)); havenoSetup.setShowFirstPopupIfResyncSPVRequestedHandler(() -> log.info("onShowFirstPopupIfResyncSPVRequestedHandler")); havenoSetup.setDisplayUpdateHandler((alert, key) -> log.info("onDisplayUpdateHandler")); havenoSetup.setDisplayAlertHandler(alert -> log.info("onDisplayAlertHandler. alert={}", alert)); @@ -93,7 +94,6 @@ public class HavenoHeadlessApp implements HeadlessApp { lastVersion, Version.VERSION)); havenoSetup.setTorAddressUpgradeHandler(() -> log.info("setTorAddressUpgradeHandler")); corruptedStorageFileHandler.getFiles().ifPresent(files -> log.warn("getCorruptedDatabaseFiles. files={}", files)); - tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> log.error("Error taking offer: " + errorMessage)); } public void stop() { diff --git a/core/src/main/java/haveno/core/app/HavenoHeadlessAppMain.java b/core/src/main/java/haveno/core/app/HavenoHeadlessAppMain.java index cdba5dffb6..c9411faece 100644 --- a/core/src/main/java/haveno/core/app/HavenoHeadlessAppMain.java +++ b/core/src/main/java/haveno/core/app/HavenoHeadlessAppMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; @@ -31,7 +31,7 @@ public class HavenoHeadlessAppMain extends HavenoExecutable { protected HeadlessApp headlessApp; public HavenoHeadlessAppMain() { - super("Haveno Daemon", "havenod", "Haveno", Version.VERSION); + super("Haveno Daemon", "havenod", HavenoExecutable.DEFAULT_APP_NAME, Version.VERSION); } public static void main(String[] args) throws Exception { diff --git a/core/src/main/java/haveno/core/app/HavenoSetup.java b/core/src/main/java/haveno/core/app/HavenoSetup.java index 830952a87e..a291da5001 100644 --- a/core/src/main/java/haveno/core/app/HavenoSetup.java +++ b/core/src/main/java/haveno/core/app/HavenoSetup.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,9 @@ package haveno.core.app; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.app.DevEnv; @@ -33,7 +53,9 @@ import haveno.core.alert.Alert; import haveno.core.alert.AlertManager; import haveno.core.alert.PrivateNotificationManager; import haveno.core.alert.PrivateNotificationPayload; -import haveno.core.api.LocalMoneroNode; +import haveno.core.api.CoreContext; +import haveno.core.api.XmrConnectionService; +import haveno.core.api.XmrLocalNode; import haveno.core.locale.Res; import haveno.core.offer.OpenOfferManager; import haveno.core.payment.AmazonGiftCardAccount; @@ -46,15 +68,12 @@ import haveno.core.support.dispute.mediation.MediationManager; import haveno.core.support.dispute.refund.RefundManager; import haveno.core.trade.HavenoUtils; import haveno.core.trade.TradeManager; -import haveno.core.trade.TradeTxException; import haveno.core.user.Preferences; -import haveno.core.user.User; import haveno.core.user.Preferences.UseTorForXmr; +import haveno.core.user.User; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; -import haveno.core.xmr.model.AddressEntry; import haveno.core.xmr.setup.WalletsSetup; -import haveno.core.xmr.wallet.BtcWalletService; import haveno.core.xmr.wallet.WalletsManager; import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.Socks5ProxyProvider; @@ -62,24 +81,6 @@ import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; import haveno.network.utils.Utils; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.DoubleProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.StringProperty; -import javafx.beans.value.ChangeListener; -import javafx.collections.SetChangeListener; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Coin; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.monadic.MonadicBinding; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; @@ -90,24 +91,37 @@ import java.util.List; import java.util.Objects; import java.util.Random; import java.util.Scanner; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.value.ChangeListener; +import javafx.collections.SetChangeListener; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.monadic.MonadicBinding; @Slf4j @Singleton public class HavenoSetup { private static final String VERSION_FILE_NAME = "version"; - private static final long STARTUP_TIMEOUT_MINUTES = 5; + private static final long STARTUP_TIMEOUT_MINUTES = 4; private final DomainInitialisation domainInitialisation; private final P2PNetworkSetup p2PNetworkSetup; private final WalletAppSetup walletAppSetup; private final WalletsManager walletsManager; private final WalletsSetup walletsSetup; - private final BtcWalletService btcWalletService; + private final XmrConnectionService xmrConnectionService; @Getter private final XmrWalletService xmrWalletService; private final P2PService p2PService; @@ -118,15 +132,19 @@ public class HavenoSetup { private final Preferences preferences; private final User user; private final AlertManager alertManager; + @Getter private final Config config; + @Getter + private final CoreContext coreContext; private final AccountAgeWitnessService accountAgeWitnessService; private final TorSetup torSetup; private final CoinFormatter formatter; - private final LocalMoneroNode localMoneroNode; + private final XmrLocalNode xmrLocalNode; private final AppStartupState appStartupState; private final MediationManager mediationManager; private final RefundManager refundManager; private final ArbitrationManager arbitrationManager; + private final StringProperty topErrorMsg = new SimpleStringProperty(); @Setter @Nullable private Consumer<Runnable> displayTacHandler; @@ -140,6 +158,9 @@ public class HavenoSetup { rejectedTxErrorMessageHandler; @Setter @Nullable + private Consumer<Boolean> displayMoneroConnectionFallbackHandler; + @Setter + @Nullable private Consumer<Boolean> displayTorNetworkSettingsHandler; @Setter @Nullable @@ -181,6 +202,7 @@ public class HavenoSetup { private boolean allBasicServicesInitialized; @SuppressWarnings("FieldCanBeLocal") private MonadicBinding<Boolean> p2pNetworkAndWalletInitialized; + private Timer startupTimeout; private final List<HavenoSetupListener> havenoSetupListeners = new ArrayList<>(); public interface HavenoSetupListener { @@ -202,8 +224,8 @@ public class HavenoSetup { WalletAppSetup walletAppSetup, WalletsManager walletsManager, WalletsSetup walletsSetup, + XmrConnectionService xmrConnectionService, XmrWalletService xmrWalletService, - BtcWalletService btcWalletService, P2PService p2PService, PrivateNotificationManager privateNotificationManager, SignedWitnessStorageService signedWitnessStorageService, @@ -213,10 +235,11 @@ public class HavenoSetup { User user, AlertManager alertManager, Config config, + CoreContext coreContext, AccountAgeWitnessService accountAgeWitnessService, TorSetup torSetup, @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, - LocalMoneroNode localMoneroNode, + XmrLocalNode xmrLocalNode, AppStartupState appStartupState, Socks5ProxyProvider socks5ProxyProvider, MediationManager mediationManager, @@ -227,8 +250,8 @@ public class HavenoSetup { this.walletAppSetup = walletAppSetup; this.walletsManager = walletsManager; this.walletsSetup = walletsSetup; + this.xmrConnectionService = xmrConnectionService; this.xmrWalletService = xmrWalletService; - this.btcWalletService = btcWalletService; this.p2PService = p2PService; this.privateNotificationManager = privateNotificationManager; this.signedWitnessStorageService = signedWitnessStorageService; @@ -238,16 +261,18 @@ public class HavenoSetup { this.user = user; this.alertManager = alertManager; this.config = config; + this.coreContext = coreContext; this.accountAgeWitnessService = accountAgeWitnessService; this.torSetup = torSetup; this.formatter = formatter; - this.localMoneroNode = localMoneroNode; + this.xmrLocalNode = xmrLocalNode; this.appStartupState = appStartupState; this.mediationManager = mediationManager; this.refundManager = refundManager; this.arbitrationManager = arbitrationManager; HavenoUtils.havenoSetup = this; + HavenoUtils.preferences = preferences; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -340,26 +365,28 @@ public class HavenoSetup { private void maybeInstallDependencies() { try { - File monerodFile = new File(LocalMoneroNode.MONEROD_PATH); - String monerodResourcePath = "bin/" + LocalMoneroNode.MONEROD_NAME; + + // install monerod + File monerodFile = new File(XmrLocalNode.MONEROD_PATH); + String monerodResourcePath = "bin/" + XmrLocalNode.MONEROD_NAME; if (!monerodFile.exists() || !FileUtil.resourceEqualToFile(monerodResourcePath, monerodFile)) { log.info("Installing monerod"); monerodFile.getParentFile().mkdirs(); - FileUtil.resourceToFile("bin/" + LocalMoneroNode.MONEROD_NAME, monerodFile); + FileUtil.resourceToFile("bin/" + XmrLocalNode.MONEROD_NAME, monerodFile); monerodFile.setExecutable(true); } - File moneroWalletFile = new File(XmrWalletService.MONERO_WALLET_RPC_PATH); - String moneroWalletResourcePath = "bin/" + XmrWalletService.MONERO_WALLET_RPC_NAME; - if (!moneroWalletFile.exists() || !FileUtil.resourceEqualToFile(moneroWalletResourcePath, moneroWalletFile)) { + // install monero-wallet-rpc + File moneroWalletRpcFile = new File(XmrWalletService.MONERO_WALLET_RPC_PATH); + String moneroWalletRpcResourcePath = "bin/" + XmrWalletService.MONERO_WALLET_RPC_NAME; + if (!moneroWalletRpcFile.exists() || !FileUtil.resourceEqualToFile(moneroWalletRpcResourcePath, moneroWalletRpcFile)) { log.info("Installing monero-wallet-rpc"); - moneroWalletFile.getParentFile().mkdirs(); - FileUtil.resourceToFile(moneroWalletResourcePath, moneroWalletFile); - moneroWalletFile.setExecutable(true); + moneroWalletRpcFile.getParentFile().mkdirs(); + FileUtil.resourceToFile(moneroWalletRpcResourcePath, moneroWalletRpcFile); + moneroWalletRpcFile.setExecutable(true); } } catch (Exception e) { - e.printStackTrace(); - log.error(e.toString()); + log.warn("Failed to install Monero binaries: {}\n", e.getMessage(), e); } } @@ -368,6 +395,26 @@ public class HavenoSetup { p2PService.getP2PDataStorage().readFromResources(postFix, completeHandler); } + private synchronized void resetStartupTimeout() { + if (p2pNetworkAndWalletInitialized != null && p2pNetworkAndWalletInitialized.get()) return; // skip if already initialized + if (startupTimeout != null) startupTimeout.stop(); + startupTimeout = UserThread.runAfter(() -> { + if (p2PNetworkSetup.p2pNetworkFailed.get() || walletsSetup.walletsSetupFailed.get()) { + // Skip this timeout action if the p2p network or wallet setup failed + // since an error prompt will be shown containing the error message + return; + } + log.warn("startupTimeout called"); + if (displayTorNetworkSettingsHandler != null) + displayTorNetworkSettingsHandler.accept(true); + + // log.info("Set log level for org.berndpruenster.netlayer classes to DEBUG to show more details for " + + // "Tor network connection issues"); + // Log.setCustomLogLevel("org.berndpruenster.netlayer", Level.DEBUG); + + }, STARTUP_TIMEOUT_MINUTES, TimeUnit.MINUTES); + } + private void startP2pNetworkAndWallet(Runnable nextStep) { ChangeListener<Boolean> walletInitializedListener = (observable, oldValue, newValue) -> { // TODO that seems to be called too often if Tor takes longer to start up... @@ -375,24 +422,18 @@ public class HavenoSetup { displayTorNetworkSettingsHandler.accept(true); }; - Timer startupTimeout = UserThread.runAfter(() -> { - if (p2PNetworkSetup.p2pNetworkFailed.get() || walletsSetup.walletsSetupFailed.get()) { - // Skip this timeout action if the p2p network or wallet setup failed - // since an error prompt will be shown containing the error message - return; - } - log.warn("startupTimeout called"); - //TODO (niyid) This has a part to play in the display of the password prompt -// if (walletsManager.areWalletsEncrypted()) -// walletInitialized.addListener(walletInitializedListener); - if (displayTorNetworkSettingsHandler != null) - displayTorNetworkSettingsHandler.accept(true); + // start startup timeout + resetStartupTimeout(); - // log.info("Set log level for org.berndpruenster.netlayer classes to DEBUG to show more details for " + - // "Tor network connection issues"); - // Log.setCustomLogLevel("org.berndpruenster.netlayer", Level.DEBUG); + // reset startup timeout on progress + getXmrDaemonSyncProgress().addListener((observable, oldValue, newValue) -> resetStartupTimeout()); + getXmrWalletSyncProgress().addListener((observable, oldValue, newValue) -> resetStartupTimeout()); - }, STARTUP_TIMEOUT_MINUTES, TimeUnit.MINUTES); + // listen for fallback handling + getConnectionServiceFallbackHandlerActive().addListener((observable, oldValue, newValue) -> { + if (displayMoneroConnectionFallbackHandler == null) return; + displayMoneroConnectionFallbackHandler.accept(newValue); + }); log.info("Init P2P network"); havenoSetupListeners.forEach(HavenoSetupListener::onInitP2pNetwork); @@ -421,11 +462,7 @@ public class HavenoSetup { walletAppSetup.init(chainFileLockedExceptionHandler, showFirstPopupIfResyncSPVRequestedHandler, showPopupIfInvalidBtcConfigHandler, - () -> { - if (allBasicServicesInitialized) { - checkForLockedUpFunds(); - } - }, + () -> {}, () -> {}); } @@ -438,10 +475,6 @@ public class HavenoSetup { revolutAccountsUpdateHandler, amazonGiftCardAccountsUpdateHandler); - if (walletsSetup.downloadPercentageProperty().get() == 1) { // TODO: update for XMR - checkForLockedUpFunds(); - } - alertManager.alertMessageProperty().addListener((observable, oldValue, newValue) -> displayAlertIfPresent(newValue, false)); displayAlertIfPresent(alertManager.alertMessageProperty().get(), false); @@ -456,32 +489,6 @@ public class HavenoSetup { // Utils /////////////////////////////////////////////////////////////////////////////////////////// - private void checkForLockedUpFunds() { - // We check if there are locked up funds in failed or closed trades - try { - Set<String> setOfAllTradeIds = tradeManager.getSetOfFailedOrClosedTradeIdsFromLockedInFunds(); - btcWalletService.getAddressEntriesForTrade().stream() - .filter(e -> setOfAllTradeIds.contains(e.getOfferId()) && - e.getContext() == AddressEntry.Context.MULTI_SIG) - .forEach(e -> { - Coin balance = e.getCoinLockedInMultiSigAsCoin(); - if (balance.isPositive()) { - String message = Res.get("popup.warning.lockedUpFunds", - formatter.formatCoinWithCode(balance), e.getAddressString(), e.getOfferId()); - log.warn(message); - if (lockedUpFundsHandler != null) { - lockedUpFundsHandler.accept(message); - } - } - }); - } catch (TradeTxException e) { - log.warn(e.getMessage()); - if (lockedUpFundsHandler != null) { - lockedUpFundsHandler.accept(e.getMessage()); - } - } - } - @Nullable public static String getLastHavenoVersion() { File versionFile = getVersionFile(); @@ -622,7 +629,7 @@ public class HavenoSetup { } private void maybeShowLocalhostRunningInfo() { - maybeTriggerDisplayHandler("moneroLocalhostNode", displayLocalhostHandler, localMoneroNode.shouldBeUsed()); + maybeTriggerDisplayHandler("xmrLocalNode", displayLocalhostHandler, xmrLocalNode.shouldBeUsed()); } private void maybeShowAccountSigningStateInfo() { @@ -715,12 +722,24 @@ public class HavenoSetup { return walletAppSetup.getXmrInfo(); } - public DoubleProperty getXmrSyncProgress() { - return walletAppSetup.getXmrSyncProgress(); + public DoubleProperty getXmrDaemonSyncProgress() { + return walletAppSetup.getXmrDaemonSyncProgress(); } - public StringProperty getWalletServiceErrorMsg() { - return walletAppSetup.getWalletServiceErrorMsg(); + public DoubleProperty getXmrWalletSyncProgress() { + return walletAppSetup.getXmrWalletSyncProgress(); + } + + public StringProperty getConnectionServiceErrorMsg() { + return xmrConnectionService.getConnectionServiceErrorMsg(); + } + + public BooleanProperty getConnectionServiceFallbackHandlerActive() { + return xmrConnectionService.getConnectionServiceFallbackHandlerActive(); + } + + public StringProperty getTopErrorMsg() { + return topErrorMsg; } public StringProperty getXmrSplashSyncIconId() { diff --git a/core/src/main/java/haveno/core/app/HeadlessApp.java b/core/src/main/java/haveno/core/app/HeadlessApp.java index 81a957ddd4..c343161495 100644 --- a/core/src/main/java/haveno/core/app/HeadlessApp.java +++ b/core/src/main/java/haveno/core/app/HeadlessApp.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; diff --git a/core/src/main/java/haveno/core/app/P2PNetworkSetup.java b/core/src/main/java/haveno/core/app/P2PNetworkSetup.java index bd52aab41c..69609a4bba 100644 --- a/core/src/main/java/haveno/core/app/P2PNetworkSetup.java +++ b/core/src/main/java/haveno/core/app/P2PNetworkSetup.java @@ -1,24 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.UserThread; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.locale.Res; import haveno.core.provider.price.PriceFeedService; import haveno.core.user.Preferences; @@ -27,26 +29,23 @@ import haveno.network.p2p.P2PServiceListener; import haveno.network.p2p.network.CloseConnectionReason; import haveno.network.p2p.network.Connection; import haveno.network.p2p.network.ConnectionListener; +import java.util.function.Consumer; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import javax.annotation.Nullable; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.monadic.MonadicBinding; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.function.Consumer; - @Singleton @Slf4j public class P2PNetworkSetup { private final PriceFeedService priceFeedService; private final P2PService p2PService; - private final CoreMoneroConnectionsService connectionService; + private final XmrConnectionService xmrConnectionService; private final Preferences preferences; @SuppressWarnings("FieldCanBeLocal") @@ -72,12 +71,12 @@ public class P2PNetworkSetup { @Inject public P2PNetworkSetup(PriceFeedService priceFeedService, P2PService p2PService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, Preferences preferences) { this.priceFeedService = priceFeedService; this.p2PService = p2PService; - this.connectionService = connectionService; + this.xmrConnectionService = xmrConnectionService; this.preferences = preferences; } @@ -88,7 +87,7 @@ public class P2PNetworkSetup { BooleanProperty initialP2PNetworkDataReceived = new SimpleBooleanProperty(); p2PNetworkInfoBinding = EasyBind.combine(bootstrapState, bootstrapWarning, p2PService.getNumConnectedPeers(), - connectionService.numPeersProperty(), hiddenServicePublished, initialP2PNetworkDataReceived, + xmrConnectionService.numConnectionsProperty(), hiddenServicePublished, initialP2PNetworkDataReceived, (state, warning, numP2pPeers, numXmrPeers, hiddenService, dataReceived) -> { String result; int p2pPeers = (int) numP2pPeers; diff --git a/core/src/main/java/haveno/core/app/TorSetup.java b/core/src/main/java/haveno/core/app/TorSetup.java index 8976a10e04..c28e509ecc 100644 --- a/core/src/main/java/haveno/core/app/TorSetup.java +++ b/core/src/main/java/haveno/core/app/TorSetup.java @@ -1,36 +1,37 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.file.FileUtil; import haveno.common.handlers.ErrorMessageHandler; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; +import static haveno.common.util.Preconditions.checkDir; import java.io.File; import java.io.IOException; import java.nio.file.Paths; +import javax.annotation.Nullable; -import static haveno.common.util.Preconditions.checkDir; +import org.apache.commons.lang3.exception.ExceptionUtils; + +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton @@ -50,8 +51,7 @@ public class TorSetup { if (resultHandler != null) resultHandler.run(); } catch (IOException e) { - e.printStackTrace(); - log.error(e.toString()); + log.error(ExceptionUtils.getStackTrace(e)); if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage(e.toString()); } diff --git a/core/src/main/java/haveno/core/app/WalletAppSetup.java b/core/src/main/java/haveno/core/app/WalletAppSetup.java index cd2efe34a7..d17c7ba366 100644 --- a/core/src/main/java/haveno/core/app/WalletAppSetup.java +++ b/core/src/main/java/haveno/core/app/WalletAppSetup.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,10 +34,12 @@ package haveno.core.app; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.core.api.CoreContext; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.locale.Res; import haveno.core.offer.OpenOfferManager; import haveno.core.trade.TradeManager; @@ -31,29 +50,25 @@ import haveno.core.xmr.exceptions.InvalidHostException; import haveno.core.xmr.exceptions.RejectedTxException; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.WalletsManager; +import haveno.core.xmr.wallet.XmrWalletService; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleDoubleProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; +import javax.annotation.Nullable; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import monero.daemon.model.MoneroDaemonInfo; - +import monero.common.MoneroUtils; import org.bitcoinj.core.RejectMessage; -import org.bitcoinj.core.VersionMessage; import org.bitcoinj.store.BlockStoreException; import org.bitcoinj.store.ChainFileLockedException; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.monadic.MonadicBinding; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; - @Slf4j @Singleton public class WalletAppSetup { @@ -61,7 +76,8 @@ public class WalletAppSetup { private final CoreContext coreContext; private final WalletsManager walletsManager; private final WalletsSetup walletsSetup; - private final CoreMoneroConnectionsService connectionService; + private final XmrConnectionService xmrConnectionService; + private final XmrWalletService xmrWalletService; private final Config config; private final Preferences preferences; @@ -69,9 +85,9 @@ public class WalletAppSetup { private MonadicBinding<String> xmrInfoBinding; @Getter - private final DoubleProperty xmrSyncProgress = new SimpleDoubleProperty(-1); + private final DoubleProperty xmrDaemonSyncProgress = new SimpleDoubleProperty(-1); @Getter - private final StringProperty walletServiceErrorMsg = new SimpleStringProperty(); + private final DoubleProperty xmrWalletSyncProgress = new SimpleDoubleProperty(-1); @Getter private final StringProperty xmrSplashSyncIconId = new SimpleStringProperty(); @Getter @@ -85,13 +101,15 @@ public class WalletAppSetup { public WalletAppSetup(CoreContext coreContext, WalletsManager walletsManager, WalletsSetup walletsSetup, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, + XmrWalletService xmrWalletService, Config config, Preferences preferences) { this.coreContext = coreContext; this.walletsManager = walletsManager; this.walletsSetup = walletsSetup; - this.connectionService = connectionService; + this.xmrConnectionService = xmrConnectionService; + this.xmrWalletService = xmrWalletService; this.config = config; this.preferences = preferences; this.useTorForXmr.set(preferences.getUseTorForXmr()); @@ -102,57 +120,73 @@ public class WalletAppSetup { @Nullable Runnable showPopupIfInvalidBtcConfigHandler, Runnable downloadCompleteHandler, Runnable walletInitializedHandler) { - log.info("Initialize WalletAppSetup with BitcoinJ version {} and hash of BitcoinJ commit {}", - VersionMessage.BITCOINJ_VERSION, "2a80db4"); + log.info("Initialize WalletAppSetup with monero-java v{}", MoneroUtils.getVersion()); ObjectProperty<Throwable> walletServiceException = new SimpleObjectProperty<>(); - xmrInfoBinding = EasyBind.combine(connectionService.downloadPercentageProperty(), // TODO (woodser): update to XMR - connectionService.chainHeightProperty(), + xmrInfoBinding = EasyBind.combine( + xmrConnectionService.numUpdatesProperty(), // receives notification of any connection update + xmrWalletService.downloadPercentageProperty(), + xmrWalletService.walletHeightProperty(), walletServiceException, - getWalletServiceErrorMsg(), - (downloadPercentage, chainHeight, exception, errorMsg) -> { + xmrConnectionService.getConnectionServiceErrorMsg(), + (numConnectionUpdates, walletDownloadPercentage, walletHeight, exception, errorMsg) -> { String result; if (exception == null && errorMsg == null) { - double percentage = (double) downloadPercentage; - xmrSyncProgress.set(percentage); - MoneroDaemonInfo lastInfo = connectionService.getLastInfo(); - Long bestChainHeight = lastInfo == null ? null : lastInfo.getHeight(); - String chainHeightAsString = bestChainHeight != null && bestChainHeight > 0 ? - String.valueOf(bestChainHeight) : - ""; - if (percentage == 1) { - String synchronizedWith = Res.get("mainView.footer.xmrInfo.synchronizedWith", - getXmrNetworkAsString(), chainHeightAsString); - String feeInfo = ""; // TODO: feeService.isFeeAvailable() returns true, disable - result = Res.get("mainView.footer.xmrInfo", synchronizedWith, feeInfo); - getXmrSplashSyncIconId().set("image-connection-synced"); - downloadCompleteHandler.run(); - } else if (percentage > 0.0) { - String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingWith", - getXmrNetworkAsString(), chainHeightAsString, - FormattingUtils.formatToPercentWithSymbol(percentage)); - result = Res.get("mainView.footer.xmrInfo", synchronizingWith, ""); + + // update daemon sync progress + double chainDownloadPercentageD = xmrConnectionService.downloadPercentageProperty().doubleValue(); + Long bestChainHeight = xmrConnectionService.chainHeightProperty().get(); + String chainHeightAsString = bestChainHeight != null && bestChainHeight > 0 ? String.valueOf(bestChainHeight) : ""; + if (chainDownloadPercentageD < 1) { + xmrDaemonSyncProgress.set(chainDownloadPercentageD); + if (chainDownloadPercentageD > 0.0) { + String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingWith", getXmrDaemonNetworkAsString(), chainHeightAsString, FormattingUtils.formatToRoundedPercentWithSymbol(chainDownloadPercentageD)); + result = Res.get("mainView.footer.xmrInfo", synchronizingWith, ""); + } else { + result = Res.get("mainView.footer.xmrInfo", + Res.get("mainView.footer.xmrInfo.connectingTo"), + getXmrDaemonNetworkAsString()); + } } else { - result = Res.get("mainView.footer.xmrInfo", - Res.get("mainView.footer.xmrInfo.connectingTo"), - getXmrNetworkAsString()); + + // update wallet sync progress + double walletDownloadPercentageD = (double) walletDownloadPercentage; + xmrWalletSyncProgress.set(walletDownloadPercentageD); + Long bestWalletHeight = walletHeight == null ? null : (Long) walletHeight; + String walletHeightAsString = bestWalletHeight != null && bestWalletHeight > 0 ? String.valueOf(bestWalletHeight) : ""; + if (walletDownloadPercentageD == 1) { + String synchronizedWith = Res.get("mainView.footer.xmrInfo.syncedWith", getXmrWalletNetworkAsString(), walletHeightAsString); + String feeInfo = ""; // TODO: feeService.isFeeAvailable() returns true, disable + result = Res.get("mainView.footer.xmrInfo", synchronizedWith, feeInfo); + getXmrSplashSyncIconId().set("image-connection-synced"); + downloadCompleteHandler.run(); + } else if (walletDownloadPercentageD >= 0) { + String synchronizingWith = Res.get("mainView.footer.xmrInfo.synchronizingWalletWith", getXmrWalletNetworkAsString(), walletHeightAsString, FormattingUtils.formatToRoundedPercentWithSymbol(walletDownloadPercentageD)); + result = Res.get("mainView.footer.xmrInfo", synchronizingWith, ""); + getXmrSplashSyncIconId().set(""); // clear synced icon + } else { + String synchronizedWith = Res.get("mainView.footer.xmrInfo.connectedTo", getXmrDaemonNetworkAsString(), chainHeightAsString); + String feeInfo = ""; // TODO: feeService.isFeeAvailable() returns true, disable + result = Res.get("mainView.footer.xmrInfo", synchronizedWith, feeInfo); + getXmrSplashSyncIconId().set("image-connection-synced"); + } } } else { result = Res.get("mainView.footer.xmrInfo", Res.get("mainView.footer.xmrInfo.connectionFailed"), - getXmrNetworkAsString()); + getXmrDaemonNetworkAsString()); if (exception != null) { if (exception instanceof TimeoutException) { - getWalletServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.timeout")); + xmrConnectionService.getConnectionServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.timeout")); } else if (exception.getCause() instanceof BlockStoreException) { if (exception.getCause().getCause() instanceof ChainFileLockedException && chainFileLockedExceptionHandler != null) { chainFileLockedExceptionHandler.accept(Res.get("popup.warning.startupFailed.twoInstances")); } } else if (exception instanceof RejectedTxException) { rejectedTxException.set((RejectedTxException) exception); - getWalletServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.rejectedTxException", exception.getMessage())); + xmrConnectionService.getConnectionServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.rejectedTxException", exception.getMessage())); } else { - getWalletServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.connectionError", exception.getMessage())); + xmrConnectionService.getConnectionServiceErrorMsg().set(Res.get("mainView.walletServiceErrorMsg.connectionError", exception.getMessage())); } } } @@ -234,14 +268,25 @@ public class WalletAppSetup { }); } - private String getXmrNetworkAsString() { + private String getXmrDaemonNetworkAsString() { String postFix; - if (config.ignoreLocalXmrNode) - postFix = " " + Res.get("mainView.footer.localhostBitcoinNode"); - else if (preferences.getUseTorForXmr().isUseTorForXmr()) + if (xmrConnectionService.isConnectionLocalHost()) + postFix = " " + Res.get("mainView.footer.localhostMoneroNode"); + else if (xmrConnectionService.isProxyApplied()) postFix = " " + Res.get("mainView.footer.usingTor"); else postFix = ""; return Res.get(config.baseCurrencyNetwork.name()) + postFix; } + + private String getXmrWalletNetworkAsString() { + String postFix; + if (xmrConnectionService.isConnectionLocalHost()) + postFix = " " + Res.get("mainView.footer.localhostMoneroNode"); + else if (xmrWalletService.isProxyApplied()) + postFix = " " + Res.get("mainView.footer.usingTor"); + else + postFix = " " + Res.get("mainView.footer.clearnet"); + return Res.get(config.baseCurrencyNetwork.name()) + postFix; + } } diff --git a/core/src/main/java/haveno/core/app/misc/AppSetup.java b/core/src/main/java/haveno/core/app/misc/AppSetup.java index 8ba2e88326..9e10884522 100644 --- a/core/src/main/java/haveno/core/app/misc/AppSetup.java +++ b/core/src/main/java/haveno/core/app/misc/AppSetup.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app.misc; +import com.google.inject.Inject; import haveno.common.app.Version; import haveno.common.config.Config; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; - @Slf4j public abstract class AppSetup { protected final Config config; diff --git a/core/src/main/java/haveno/core/app/misc/AppSetupWithP2P.java b/core/src/main/java/haveno/core/app/misc/AppSetupWithP2P.java index 87e1100b90..b5553a926f 100644 --- a/core/src/main/java/haveno/core/app/misc/AppSetupWithP2P.java +++ b/core/src/main/java/haveno/core/app/misc/AppSetupWithP2P.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app.misc; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; import haveno.common.proto.persistable.PersistedDataHost; @@ -31,13 +32,11 @@ import haveno.network.p2p.network.Connection; import haveno.network.p2p.network.ConnectionListener; import haveno.network.p2p.peers.PeerManager; import haveno.network.p2p.storage.P2PDataStorage; +import java.util.ArrayList; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import java.util.ArrayList; - @Slf4j public class AppSetupWithP2P extends AppSetup { protected final P2PService p2PService; diff --git a/core/src/main/java/haveno/core/app/misc/AppSetupWithP2PAndDAO.java b/core/src/main/java/haveno/core/app/misc/AppSetupWithP2PAndDAO.java deleted file mode 100644 index 292085ecc8..0000000000 --- a/core/src/main/java/haveno/core/app/misc/AppSetupWithP2PAndDAO.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.core.app.misc; - -import haveno.common.config.Config; -import haveno.core.account.sign.SignedWitnessService; -import haveno.core.account.witness.AccountAgeWitnessService; -import haveno.core.filter.FilterManager; -import haveno.core.trade.statistics.TradeStatisticsManager; -import haveno.network.p2p.P2PService; -import haveno.network.p2p.peers.PeerManager; -import haveno.network.p2p.storage.P2PDataStorage; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; - -@Slf4j -public class AppSetupWithP2PAndDAO extends AppSetupWithP2P { - - @Inject - public AppSetupWithP2PAndDAO(P2PService p2PService, - P2PDataStorage p2PDataStorage, - PeerManager peerManager, - TradeStatisticsManager tradeStatisticsManager, - AccountAgeWitnessService accountAgeWitnessService, - SignedWitnessService signedWitnessService, - FilterManager filterManager, - Config config) { - super(p2PService, - p2PDataStorage, - peerManager, - tradeStatisticsManager, - accountAgeWitnessService, - signedWitnessService, - filterManager, - config); - - - } - - @Override - protected void onBasicServicesInitialized() { - super.onBasicServicesInitialized(); - } -} diff --git a/core/src/main/java/haveno/core/app/misc/ExecutableForAppWithP2p.java b/core/src/main/java/haveno/core/app/misc/ExecutableForAppWithP2p.java index f6f7331d9e..725ccd877c 100644 --- a/core/src/main/java/haveno/core/app/misc/ExecutableForAppWithP2p.java +++ b/core/src/main/java/haveno/core/app/misc/ExecutableForAppWithP2p.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,6 +35,8 @@ package haveno.core.app.misc; import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import haveno.common.ThreadUtils; import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.config.Config; @@ -26,12 +45,15 @@ import haveno.common.handlers.ResultHandler; import haveno.common.persistence.PersistenceManager; import haveno.common.setup.GracefulShutDownHandler; import haveno.common.util.Profiler; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; +import haveno.core.app.AvoidStandbyModeService; import haveno.core.app.HavenoExecutable; import haveno.core.offer.OfferBookService; import haveno.core.offer.OpenOfferManager; +import haveno.core.provider.price.PriceFeedService; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; -import haveno.core.trade.HavenoUtils; +import haveno.core.trade.TradeManager; +import haveno.core.trade.statistics.TradeStatisticsManager; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.BtcWalletService; import haveno.core.xmr.wallet.XmrWalletService; @@ -93,14 +115,23 @@ public abstract class ExecutableForAppWithP2p extends HavenoExecutable { try { if (injector != null) { - // notify trade protocols and wallets to prepare for shut down before shutting down + // notify trade protocols and wallets to prepare for shut down Set<Runnable> tasks = new HashSet<Runnable>(); tasks.add(() -> injector.getInstance(XmrWalletService.class).onShutDownStarted()); - tasks.add(() -> injector.getInstance(CoreMoneroConnectionsService.class).onShutDownStarted()); - HavenoUtils.executeTasks(tasks); // notify in parallel + tasks.add(() -> injector.getInstance(XmrConnectionService.class).onShutDownStarted()); + tasks.add(() -> injector.getInstance(TradeManager.class).onShutDownStarted()); + try { + ThreadUtils.awaitTasks(tasks, tasks.size(), 120000l); // run in parallel with timeout + } catch (Exception e) { + log.error("Error awaiting tasks to complete: {}\n", e.getMessage(), e); + } JsonFileManager.shutDownAllInstances(); + injector.getInstance(TradeManager.class).shutDown(); + injector.getInstance(PriceFeedService.class).shutDown(); injector.getInstance(ArbitratorManager.class).shutDown(); + injector.getInstance(TradeStatisticsManager.class).shutDown(); + injector.getInstance(AvoidStandbyModeService.class).shutDown(); // shut down open offer manager log.info("Shutting down OpenOfferManager, OfferBookService, and P2PService"); @@ -111,20 +142,22 @@ public abstract class ExecutableForAppWithP2p extends HavenoExecutable { // shut down p2p service injector.getInstance(P2PService.class).shutDown(() -> { - log.info("Done shutting down OpenOfferManager, OfferBookService, and P2PService"); // shut down monero wallets and connections + log.info("Shutting down wallet and connection services"); injector.getInstance(WalletsSetup.class).shutDownComplete.addListener((ov, o, n) -> { module.close(injector); PersistenceManager.flushAllDataToDiskAtShutdown(() -> { - resultHandler.handleResult(); + + // done shutting down log.info("Graceful shutdown completed. Exiting now."); + resultHandler.handleResult(); UserThread.runAfter(() -> System.exit(HavenoExecutable.EXIT_SUCCESS), 1); }); }); injector.getInstance(BtcWalletService.class).shutDown(); injector.getInstance(XmrWalletService.class).shutDown(); - injector.getInstance(CoreMoneroConnectionsService.class).shutDown(); + injector.getInstance(XmrConnectionService.class).shutDown(); injector.getInstance(WalletsSetup.class).shutDown(); }); }); @@ -144,8 +177,7 @@ public abstract class ExecutableForAppWithP2p extends HavenoExecutable { }, 1); } } catch (Throwable t) { - log.debug("App shutdown failed with exception"); - t.printStackTrace(); + log.info("App shutdown failed with exception: {}\n", t.getMessage(), t); PersistenceManager.flushAllDataToDiskAtShutdown(() -> { resultHandler.handleResult(); log.info("Graceful shutdown resulted in an error. Exiting now."); diff --git a/core/src/main/java/haveno/core/app/misc/ModuleForAppWithP2p.java b/core/src/main/java/haveno/core/app/misc/ModuleForAppWithP2p.java index 7bef375dc4..e2c1c1f634 100644 --- a/core/src/main/java/haveno/core/app/misc/ModuleForAppWithP2p.java +++ b/core/src/main/java/haveno/core/app/misc/ModuleForAppWithP2p.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app.misc; @@ -36,8 +36,8 @@ import haveno.core.proto.persistable.CorePersistenceProtoResolver; import haveno.core.trade.TradeModule; import haveno.core.user.Preferences; import haveno.core.user.User; -import haveno.core.xmr.MoneroConnectionModule; -import haveno.core.xmr.MoneroModule; +import haveno.core.xmr.XmrConnectionModule; +import haveno.core.xmr.XmrModule; import haveno.network.crypto.EncryptionServiceModule; import haveno.network.p2p.P2PModule; import haveno.network.p2p.network.BanFilter; @@ -92,9 +92,9 @@ public class ModuleForAppWithP2p extends AppModule { install(new EncryptionServiceModule(config)); install(new OfferModule(config)); install(new P2PModule(config)); - install(new MoneroModule(config)); + install(new XmrModule(config)); install(new AlertModule(config)); install(new FilterModule(config)); - install(new MoneroConnectionModule(config)); + install(new XmrConnectionModule(config)); } } diff --git a/core/src/main/java/haveno/core/exceptions/TradePriceOutOfToleranceException.java b/core/src/main/java/haveno/core/exceptions/TradePriceOutOfToleranceException.java index 3f6283d3e3..3b6f3a3d4b 100644 --- a/core/src/main/java/haveno/core/exceptions/TradePriceOutOfToleranceException.java +++ b/core/src/main/java/haveno/core/exceptions/TradePriceOutOfToleranceException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.exceptions; diff --git a/core/src/main/java/haveno/core/filter/Filter.java b/core/src/main/java/haveno/core/filter/Filter.java index ae6602639f..3b930f42ea 100644 --- a/core/src/main/java/haveno/core/filter/Filter.java +++ b/core/src/main/java/haveno/core/filter/Filter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.filter; diff --git a/core/src/main/java/haveno/core/filter/FilterManager.java b/core/src/main/java/haveno/core/filter/FilterManager.java index 4b84549f40..cb7e0e9b21 100644 --- a/core/src/main/java/haveno/core/filter/FilterManager.java +++ b/core/src/main/java/haveno/core/filter/FilterManager.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.filter; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.app.DevEnv; import haveno.common.app.Version; import haveno.common.config.Config; @@ -35,16 +38,6 @@ import haveno.network.p2p.P2PServiceListener; import haveno.network.p2p.network.BanFilter; import haveno.network.p2p.storage.HashMapChangedListener; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.ECKey; -import org.bitcoinj.core.Sha256Hash; -import org.bouncycastle.util.encoders.Base64; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; import java.lang.reflect.Method; import java.math.BigInteger; import java.nio.charset.StandardCharsets; @@ -58,9 +51,14 @@ import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Consumer; - -import static com.google.common.base.Preconditions.checkNotNull; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.ECKey; +import org.bitcoinj.core.Sha256Hash; import static org.bitcoinj.core.Utils.HEX; +import org.bouncycastle.util.encoders.Base64; /** * We only support one active filter, if we receive multiple we use the one with the more recent creationDate. diff --git a/core/src/main/java/haveno/core/filter/FilterModule.java b/core/src/main/java/haveno/core/filter/FilterModule.java index 2a0e8897a9..c2bbd533f4 100644 --- a/core/src/main/java/haveno/core/filter/FilterModule.java +++ b/core/src/main/java/haveno/core/filter/FilterModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.filter; diff --git a/core/src/main/java/haveno/core/filter/PaymentAccountFilter.java b/core/src/main/java/haveno/core/filter/PaymentAccountFilter.java index 75a11b5a61..94b2d06766 100644 --- a/core/src/main/java/haveno/core/filter/PaymentAccountFilter.java +++ b/core/src/main/java/haveno/core/filter/PaymentAccountFilter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.filter; diff --git a/core/src/main/java/haveno/core/locale/BankUtil.java b/core/src/main/java/haveno/core/locale/BankUtil.java index ac901102b6..3583959f37 100644 --- a/core/src/main/java/haveno/core/locale/BankUtil.java +++ b/core/src/main/java/haveno/core/locale/BankUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/Country.java b/core/src/main/java/haveno/core/locale/Country.java index 4b54f83c44..ce0eb5163c 100644 --- a/core/src/main/java/haveno/core/locale/Country.java +++ b/core/src/main/java/haveno/core/locale/Country.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/CountryUtil.java b/core/src/main/java/haveno/core/locale/CountryUtil.java index 54836d585b..bf2faccceb 100644 --- a/core/src/main/java/haveno/core/locale/CountryUtil.java +++ b/core/src/main/java/haveno/core/locale/CountryUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/CryptoCurrency.java b/core/src/main/java/haveno/core/locale/CryptoCurrency.java index 52fdb50dc3..6c46c9d2b3 100644 --- a/core/src/main/java/haveno/core/locale/CryptoCurrency.java +++ b/core/src/main/java/haveno/core/locale/CryptoCurrency.java @@ -1,28 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; import com.google.protobuf.Message; -import lombok.EqualsAndHashCode; import lombok.Getter; -@EqualsAndHashCode(callSuper = true) public final class CryptoCurrency extends TradeCurrency { // http://boschista.deviantart.com/journal/Cool-ASCII-Symbols-214218618 private final static String PREFIX = "✦ "; diff --git a/core/src/main/java/haveno/core/locale/CurrencyTuple.java b/core/src/main/java/haveno/core/locale/CurrencyTuple.java index 25ffcc0b03..b0e061a7e9 100644 --- a/core/src/main/java/haveno/core/locale/CurrencyTuple.java +++ b/core/src/main/java/haveno/core/locale/CurrencyTuple.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/CurrencyUtil.java b/core/src/main/java/haveno/core/locale/CurrencyUtil.java index 870a17c8c7..570333a2f9 100644 --- a/core/src/main/java/haveno/core/locale/CurrencyUtil.java +++ b/core/src/main/java/haveno/core/locale/CurrencyUtil.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -56,14 +73,6 @@ public class CurrencyUtil { private static String baseCurrencyCode = "XMR"; - private static List<TraditionalCurrency> getTraditionalNonFiatCurrencies() { - return Arrays.asList( - new TraditionalCurrency("XAG", "Gold"), - new TraditionalCurrency("XAU", "Silver"), - new TraditionalCurrency("XGB", "Goldback") - ); - } - // Calls to isTraditionalCurrency and isCryptoCurrency are very frequent so we use a cache of the results. // The main improvement was already achieved with using memoize for the source maps, but // the caching still reduces performance costs by about 20% for isCryptoCurrency (1752 ms vs 2121 ms) and about 50% @@ -107,6 +116,14 @@ public class CurrencyUtil { return new ArrayList<>(traditionalCurrencyMapSupplier.get().values()); } + public static List<TraditionalCurrency> getTraditionalNonFiatCurrencies() { + return Arrays.asList( + new TraditionalCurrency("XAG", "Silver"), + new TraditionalCurrency("XAU", "Gold"), + new TraditionalCurrency("XGB", "Goldback") + ); + } + public static Collection<TraditionalCurrency> getAllSortedTraditionalCurrencies(Comparator comparator) { return (List<TraditionalCurrency>) getAllSortedTraditionalCurrencies().stream() .sorted(comparator) @@ -183,6 +200,8 @@ public class CurrencyUtil { result.add(new CryptoCurrency("BCH", "Bitcoin Cash")); result.add(new CryptoCurrency("ETH", "Ether")); result.add(new CryptoCurrency("LTC", "Litecoin")); + result.add(new CryptoCurrency("USDT-ERC20", "Tether USD (ERC20)")); + result.add(new CryptoCurrency("USDC-ERC20", "USD Coin (ERC20)")); result.add(new CryptoCurrency("WOW", "Wownero")); result.sort(TradeCurrency::compareTo); return result; @@ -279,6 +298,9 @@ public class CurrencyUtil { if (currencyCode != null && isCryptoCurrencyMap.containsKey(currencyCode.toUpperCase())) { return isCryptoCurrencyMap.get(currencyCode.toUpperCase()); } + if (isCryptoCurrencyBase(currencyCode)) { + return true; + } boolean isCryptoCurrency; if (currencyCode == null) { @@ -305,6 +327,20 @@ public class CurrencyUtil { return isCryptoCurrency; } + private static boolean isCryptoCurrencyBase(String currencyCode) { + if (currencyCode == null) return false; + currencyCode = currencyCode.toUpperCase(); + return currencyCode.equals("USDT") || currencyCode.equals("USDC"); + } + + public static String getCurrencyCodeBase(String currencyCode) { + if (currencyCode == null) return null; + currencyCode = currencyCode.toUpperCase(); + if (currencyCode.contains("USDT")) return "USDT"; + if (currencyCode.contains("USDC")) return "USDC"; + return currencyCode; + } + public static Optional<CryptoCurrency> getCryptoCurrency(String currencyCode) { return Optional.ofNullable(cryptoCurrencyMapSupplier.get().get(currencyCode)); } diff --git a/core/src/main/java/haveno/core/locale/GlobalSettings.java b/core/src/main/java/haveno/core/locale/GlobalSettings.java index 0a215860f9..7dcaedfa64 100644 --- a/core/src/main/java/haveno/core/locale/GlobalSettings.java +++ b/core/src/main/java/haveno/core/locale/GlobalSettings.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/LanguageUtil.java b/core/src/main/java/haveno/core/locale/LanguageUtil.java index 565f9bc46e..d3e7415a43 100644 --- a/core/src/main/java/haveno/core/locale/LanguageUtil.java +++ b/core/src/main/java/haveno/core/locale/LanguageUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; @@ -44,14 +44,14 @@ public class LanguageUtil { "fa", // Persian "it", // Italian "cs", // Czech - "pl" // Polish + "pl", // Polish + "tr" // Turkish /* // not translated yet "el", // Greek "sr-Latn-RS", // Serbian [Latin] (Serbia) "hu", // Hungarian "ro", // Romanian - "tr" // Turkish "iw", // Hebrew "hi", // Hindi "ko", // Korean diff --git a/core/src/main/java/haveno/core/locale/LocaleUtil.java b/core/src/main/java/haveno/core/locale/LocaleUtil.java index 8d67e05b0d..23ab2ef689 100644 --- a/core/src/main/java/haveno/core/locale/LocaleUtil.java +++ b/core/src/main/java/haveno/core/locale/LocaleUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/Region.java b/core/src/main/java/haveno/core/locale/Region.java index 3e31e9ebde..aefc6bef4e 100644 --- a/core/src/main/java/haveno/core/locale/Region.java +++ b/core/src/main/java/haveno/core/locale/Region.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/main/java/haveno/core/locale/Res.java b/core/src/main/java/haveno/core/locale/Res.java index 494eb035c9..e44092561f 100644 --- a/core/src/main/java/haveno/core/locale/Res.java +++ b/core/src/main/java/haveno/core/locale/Res.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; @@ -109,9 +109,9 @@ public class Res { public static String get(String key) { try { return resourceBundle.getString(key) - .replace("BTC", baseCurrencyCode) - .replace("Bitcoin", baseCurrencyName) - .replace("bitcoin", baseCurrencyNameLowerCase); + .replace("XMR", baseCurrencyCode) + .replace("Monero", baseCurrencyName) + .replace("monero", baseCurrencyNameLowerCase); } catch (MissingResourceException e) { log.warn("Missing resource for key: {}", key); if (DevEnv.isDevMode()) { diff --git a/core/src/main/java/haveno/core/locale/TradeCurrency.java b/core/src/main/java/haveno/core/locale/TradeCurrency.java index 954b3fac8b..b60abf5e88 100644 --- a/core/src/main/java/haveno/core/locale/TradeCurrency.java +++ b/core/src/main/java/haveno/core/locale/TradeCurrency.java @@ -1,37 +1,34 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; import haveno.common.proto.ProtobufferRuntimeException; import haveno.common.proto.persistable.PersistablePayload; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -@EqualsAndHashCode @ToString @Getter @Slf4j public abstract class TradeCurrency implements PersistablePayload, Comparable<TradeCurrency> { protected final String code; - @EqualsAndHashCode.Exclude protected final String name; public TradeCurrency(String code, String name) { @@ -82,4 +79,23 @@ public abstract class TradeCurrency implements PersistablePayload, Comparable<Tr return this.name.compareTo(other.name); } + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (obj == this) { + return true; + } + if (obj instanceof TradeCurrency) { + TradeCurrency other = (TradeCurrency) obj; + return code.equals(other.code); + } + return false; + } + + @Override + public int hashCode() { + return code.hashCode(); + } } diff --git a/core/src/main/java/haveno/core/locale/TraditionalCurrency.java b/core/src/main/java/haveno/core/locale/TraditionalCurrency.java index 32dca91764..1ab491467e 100644 --- a/core/src/main/java/haveno/core/locale/TraditionalCurrency.java +++ b/core/src/main/java/haveno/core/locale/TraditionalCurrency.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -19,14 +36,12 @@ package haveno.core.locale; import com.google.protobuf.Message; -import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; import java.util.Currency; import java.util.Locale; -@EqualsAndHashCode(callSuper = true) @ToString @Getter public final class TraditionalCurrency extends TradeCurrency { diff --git a/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java b/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java index 8ccd63c329..0e4777488a 100644 --- a/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java +++ b/core/src/main/java/haveno/core/monetary/CryptoExchangeRate.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; diff --git a/core/src/main/java/haveno/core/monetary/CryptoMoney.java b/core/src/main/java/haveno/core/monetary/CryptoMoney.java index dfb8471630..b2581eba5d 100644 --- a/core/src/main/java/haveno/core/monetary/CryptoMoney.java +++ b/core/src/main/java/haveno/core/monetary/CryptoMoney.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; diff --git a/core/src/main/java/haveno/core/monetary/MonetaryWrapper.java b/core/src/main/java/haveno/core/monetary/MonetaryWrapper.java index 67f39534af..c9a4ea9f37 100644 --- a/core/src/main/java/haveno/core/monetary/MonetaryWrapper.java +++ b/core/src/main/java/haveno/core/monetary/MonetaryWrapper.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; diff --git a/core/src/main/java/haveno/core/monetary/Price.java b/core/src/main/java/haveno/core/monetary/Price.java index 98703aaebd..8dccd0608d 100644 --- a/core/src/main/java/haveno/core/monetary/Price.java +++ b/core/src/main/java/haveno/core/monetary/Price.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; @@ -49,7 +49,7 @@ public class Price extends MonetaryWrapper implements Comparable<Price> { } /** - * Parse the Bitcoin {@code Price} given a {@code currencyCode} and {@code inputValue}. + * Parse the Monero {@code Price} given a {@code currencyCode} and {@code inputValue}. * * @param currencyCode The currency code to parse, e.g "USD" or "LTC". * @param input The input value to parse as a String, e.g "2.54" or "-0.0001". @@ -64,7 +64,7 @@ public class Price extends MonetaryWrapper implements Comparable<Price> { } /** - * Parse the Bitcoin {@code Price} given a {@code currencyCode} and {@code inputValue}. + * Parse the Monero {@code Price} given a {@code currencyCode} and {@code inputValue}. * * @param currencyCode The currency code to parse, e.g "USD" or "LTC". * @param value The value to parse. @@ -94,7 +94,7 @@ public class Price extends MonetaryWrapper implements Comparable<Price> { else if (monetary instanceof CryptoMoney && this.monetary instanceof CryptoMoney) return HavenoUtils.coinToAtomicUnits(new CryptoExchangeRate((CryptoMoney) this.monetary).cryptoToCoin((CryptoMoney) monetary)); else - return BigInteger.valueOf(0); + return BigInteger.ZERO; } public String getCurrencyCode() { diff --git a/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java b/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java index a1a9e03b3e..976d3fa2ec 100644 --- a/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java +++ b/core/src/main/java/haveno/core/monetary/TraditionalExchangeRate.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; diff --git a/core/src/main/java/haveno/core/monetary/Volume.java b/core/src/main/java/haveno/core/monetary/Volume.java index 55ffcf4d4f..f777ab5aff 100644 --- a/core/src/main/java/haveno/core/monetary/Volume.java +++ b/core/src/main/java/haveno/core/monetary/Volume.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; diff --git a/core/src/main/java/haveno/core/network/CoreBanFilter.java b/core/src/main/java/haveno/core/network/CoreBanFilter.java index ef4406d114..f27fdb49b2 100644 --- a/core/src/main/java/haveno/core/network/CoreBanFilter.java +++ b/core/src/main/java/haveno/core/network/CoreBanFilter.java @@ -1,33 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.network.BanFilter; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Named; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.function.Predicate; +import lombok.extern.slf4j.Slf4j; @Slf4j public class CoreBanFilter implements BanFilter { diff --git a/core/src/main/java/haveno/core/network/MessageState.java b/core/src/main/java/haveno/core/network/MessageState.java index 34f3e63c25..c4ae7f8f40 100644 --- a/core/src/main/java/haveno/core/network/MessageState.java +++ b/core/src/main/java/haveno/core/network/MessageState.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestHandler.java b/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestHandler.java index 7d343a179d..1e2ad15e7b 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestHandler.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory; @@ -20,6 +20,8 @@ package haveno.core.network.p2p.inventory; import com.google.common.base.Enums; import com.google.common.base.Joiner; import com.google.common.base.Optional; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.app.Version; import haveno.common.config.Config; import haveno.common.proto.network.NetworkEnvelope; @@ -37,13 +39,10 @@ import haveno.network.p2p.network.Statistic; import haveno.network.p2p.peers.PeerManager; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Named; import java.lang.management.ManagementFactory; import java.util.HashMap; import java.util.Map; +import lombok.extern.slf4j.Slf4j; @Slf4j public class GetInventoryRequestHandler implements MessageListener { diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestManager.java b/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestManager.java index 6b109c89bc..dc33e8fe53 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestManager.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequestManager.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory; +import com.google.inject.Inject; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.network.p2p.inventory.model.InventoryItem; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.network.NetworkNode; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.HashMap; import java.util.Map; import java.util.function.Consumer; +import lombok.extern.slf4j.Slf4j; @Slf4j public class GetInventoryRequestManager { diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequester.java b/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequester.java index 9d939fed3e..ca87adbe9d 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequester.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/GetInventoryRequester.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryRequest.java b/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryRequest.java index 9fcc9a15b8..fd359a8b16 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryRequest.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.messages; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryResponse.java b/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryResponse.java index 1ae090d44f..c53611988d 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryResponse.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/messages/GetInventoryResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.messages; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/Average.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/Average.java index d1a5970b3d..d112c268f2 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/Average.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/Average.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByIntegerDiff.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByIntegerDiff.java index 3e7cb145ce..3fe90eb838 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByIntegerDiff.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByIntegerDiff.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByPercentage.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByPercentage.java index 388ae3812d..c58ef5c5af 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByPercentage.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationByPercentage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationOfHashes.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationOfHashes.java index 3eb76d2fc9..02357e3252 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationOfHashes.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationOfHashes.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationSeverity.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationSeverity.java index ac09419ae2..b69f03cd93 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationSeverity.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationSeverity.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationType.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationType.java index fb887fb1cf..e0ea00169b 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationType.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/DeviationType.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/InventoryItem.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/InventoryItem.java index bd9d1a2544..783cd1e1df 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/InventoryItem.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/InventoryItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/inventory/model/RequestInfo.java b/core/src/main/java/haveno/core/network/p2p/inventory/model/RequestInfo.java index 26ad6b377a..4fddcac0aa 100644 --- a/core/src/main/java/haveno/core/network/p2p/inventory/model/RequestInfo.java +++ b/core/src/main/java/haveno/core/network/p2p/inventory/model/RequestInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.inventory.model; diff --git a/core/src/main/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepository.java b/core/src/main/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepository.java index ce2e1be653..c8d9c33d07 100644 --- a/core/src/main/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepository.java +++ b/core/src/main/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepository.java @@ -1,29 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.seed; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.Config; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.seed.SeedNodeRepository; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -35,6 +33,7 @@ import java.util.Optional; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; // If a new BaseCurrencyNetwork type gets added we need to add the resource file for it as well! @Slf4j diff --git a/core/src/main/java/haveno/core/notifications/MobileMessage.java b/core/src/main/java/haveno/core/notifications/MobileMessage.java index 445e13c3f9..b81c99ad86 100644 --- a/core/src/main/java/haveno/core/notifications/MobileMessage.java +++ b/core/src/main/java/haveno/core/notifications/MobileMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; diff --git a/core/src/main/java/haveno/core/notifications/MobileMessageEncryption.java b/core/src/main/java/haveno/core/notifications/MobileMessageEncryption.java index a2afc95e37..02fd428215 100644 --- a/core/src/main/java/haveno/core/notifications/MobileMessageEncryption.java +++ b/core/src/main/java/haveno/core/notifications/MobileMessageEncryption.java @@ -1,33 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; import com.google.common.base.Charsets; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Base64; - +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.security.NoSuchAlgorithmException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; @Slf4j @Singleton diff --git a/core/src/main/java/haveno/core/notifications/MobileMessageType.java b/core/src/main/java/haveno/core/notifications/MobileMessageType.java index a3ecc4f4d4..bfd86a8422 100644 --- a/core/src/main/java/haveno/core/notifications/MobileMessageType.java +++ b/core/src/main/java/haveno/core/notifications/MobileMessageType.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; diff --git a/core/src/main/java/haveno/core/notifications/MobileModel.java b/core/src/main/java/haveno/core/notifications/MobileModel.java index 6adf318db1..040e260c24 100644 --- a/core/src/main/java/haveno/core/notifications/MobileModel.java +++ b/core/src/main/java/haveno/core/notifications/MobileModel.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; import com.google.common.annotations.VisibleForTesting; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.util.Arrays; +import javax.annotation.Nullable; import lombok.Data; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Arrays; - @Data @Slf4j @Singleton diff --git a/core/src/main/java/haveno/core/notifications/MobileNotificationService.java b/core/src/main/java/haveno/core/notifications/MobileNotificationService.java index c222f3b704..ab80da8b1e 100644 --- a/core/src/main/java/haveno/core/notifications/MobileNotificationService.java +++ b/core/src/main/java/haveno/core/notifications/MobileNotificationService.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -25,12 +27,15 @@ import com.google.common.util.concurrent.MoreExecutors; import com.google.gson.Gson; import com.google.inject.Inject; import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.app.Version; import haveno.common.config.Config; import haveno.common.util.Utilities; import haveno.core.user.Preferences; import haveno.network.http.HttpClient; +import java.util.UUID; +import java.util.function.Consumer; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import lombok.Getter; @@ -38,13 +43,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Hex; import org.jetbrains.annotations.NotNull; -import javax.inject.Named; -import java.util.UUID; -import java.util.function.Consumer; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - @Slf4j @Singleton public class MobileNotificationService { diff --git a/core/src/main/java/haveno/core/notifications/MobileNotificationValidator.java b/core/src/main/java/haveno/core/notifications/MobileNotificationValidator.java index 0004defa41..c084b0e42e 100644 --- a/core/src/main/java/haveno/core/notifications/MobileNotificationValidator.java +++ b/core/src/main/java/haveno/core/notifications/MobileNotificationValidator.java @@ -1,27 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; +import com.google.inject.Inject; +import com.google.inject.Singleton; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; - @Slf4j @Singleton public class MobileNotificationValidator { diff --git a/core/src/main/java/haveno/core/notifications/alerts/DisputeMsgEvents.java b/core/src/main/java/haveno/core/notifications/alerts/DisputeMsgEvents.java index 41e890edbd..60a7e60ba0 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/DisputeMsgEvents.java +++ b/core/src/main/java/haveno/core/notifications/alerts/DisputeMsgEvents.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.locale.Res; import haveno.core.notifications.MobileMessage; import haveno.core.notifications.MobileMessageType; @@ -27,14 +29,11 @@ import haveno.core.support.dispute.mediation.MediationManager; import haveno.core.support.dispute.refund.RefundManager; import haveno.core.support.messages.ChatMessage; import haveno.network.p2p.P2PService; +import java.util.UUID; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.UUID; - @Slf4j @Singleton public class DisputeMsgEvents { @@ -115,16 +114,18 @@ public class DisputeMsgEvents { // We check at every new message if it might be a message sent after the dispute had been closed. If that is the // case we revert the isClosed flag so that the UI can reopen the dispute and indicate that a new dispute // message arrived. - ObservableList<ChatMessage> chatMessages = dispute.getChatMessages(); - // If last message is not a result message we re-open as we might have received a new message from the - // trader/mediator/arbitrator who has reopened the case - if (dispute.isClosed() && !chatMessages.isEmpty() && !chatMessages.get(chatMessages.size() - 1).isResultMessage(dispute)) { - dispute.reOpen(); - if (dispute.getSupportType() == SupportType.MEDIATION) { - mediationManager.requestPersistence(); - } else if (dispute.getSupportType() == SupportType.REFUND) { - refundManager.requestPersistence(); + synchronized (dispute.getChatMessages()) { + ObservableList<ChatMessage> chatMessages = dispute.getChatMessages(); + // If last message is not a result message we re-open as we might have received a new message from the + // trader/mediator/arbitrator who has reopened the case + if (dispute.isClosed() && !chatMessages.isEmpty() && !chatMessages.get(chatMessages.size() - 1).isResultMessage(dispute)) { + dispute.reOpen(); + if (dispute.getSupportType() == SupportType.MEDIATION) { + mediationManager.requestPersistence(); + } else if (dispute.getSupportType() == SupportType.REFUND) { + refundManager.requestPersistence(); + } } - } + } } } diff --git a/core/src/main/java/haveno/core/notifications/alerts/MyOfferTakenEvents.java b/core/src/main/java/haveno/core/notifications/alerts/MyOfferTakenEvents.java index 1424be3ef1..25886213f1 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/MyOfferTakenEvents.java +++ b/core/src/main/java/haveno/core/notifications/alerts/MyOfferTakenEvents.java @@ -1,35 +1,34 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.locale.Res; import haveno.core.notifications.MobileMessage; import haveno.core.notifications.MobileMessageType; import haveno.core.notifications.MobileNotificationService; import haveno.core.offer.OpenOffer; import haveno.core.offer.OpenOfferManager; +import java.util.UUID; import javafx.collections.ListChangeListener; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.UUID; - @Slf4j @Singleton public class MyOfferTakenEvents { diff --git a/core/src/main/java/haveno/core/notifications/alerts/TradeEvents.java b/core/src/main/java/haveno/core/notifications/alerts/TradeEvents.java index aa9d8eeb69..0dd6fe58ac 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/TradeEvents.java +++ b/core/src/main/java/haveno/core/notifications/alerts/TradeEvents.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.PubKeyRingProvider; import haveno.core.locale.Res; import haveno.core.notifications.MobileMessage; @@ -24,14 +26,11 @@ import haveno.core.notifications.MobileMessageType; import haveno.core.notifications.MobileNotificationService; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; -import javafx.collections.ListChangeListener; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import javafx.collections.ListChangeListener; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton @@ -84,8 +83,6 @@ public class TradeEvents { if (trade.getContract() != null && pubKeyRingProvider.get().equals(trade.getContract().getBuyerPubKeyRing())) msg = Res.get("account.notifications.trade.message.msg.completed", shortId); break; - case COMPLETED: - break; } if (msg != null) { MobileMessage message = new MobileMessage(Res.get("account.notifications.trade.message.title"), diff --git a/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlertFilter.java b/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlertFilter.java index eb83458e28..81b4ba69ed 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlertFilter.java +++ b/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlertFilter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts.market; diff --git a/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java b/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java index 07fc7fb848..af2434dd22 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java +++ b/core/src/main/java/haveno/core/notifications/alerts/market/MarketAlerts.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts.market; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.common.util.MathUtils; import haveno.core.locale.CurrencyUtil; @@ -34,12 +36,9 @@ import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; import haveno.core.user.User; import haveno.core.util.FormattingUtils; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.List; import java.util.UUID; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton diff --git a/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlert.java b/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlert.java index 684533a498..afe695b281 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlert.java +++ b/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlert.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts.price; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.util.MathUtils; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -31,9 +33,6 @@ import haveno.core.user.User; import haveno.core.util.FormattingUtils; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; - @Slf4j @Singleton public class PriceAlert { diff --git a/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlertFilter.java b/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlertFilter.java index 61534bed28..40502aff7a 100644 --- a/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlertFilter.java +++ b/core/src/main/java/haveno/core/notifications/alerts/price/PriceAlertFilter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications.alerts.price; diff --git a/core/src/main/java/haveno/core/offer/AvailabilityResult.java b/core/src/main/java/haveno/core/offer/AvailabilityResult.java index 48094580fc..6ca73bc1bb 100644 --- a/core/src/main/java/haveno/core/offer/AvailabilityResult.java +++ b/core/src/main/java/haveno/core/offer/AvailabilityResult.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; diff --git a/core/src/main/java/haveno/core/offer/CreateOfferService.java b/core/src/main/java/haveno/core/offer/CreateOfferService.java index 2b53a4f871..407953b05f 100644 --- a/core/src/main/java/haveno/core/offer/CreateOfferService.java +++ b/core/src/main/java/haveno/core/offer/CreateOfferService.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.app.Version; import haveno.common.crypto.PubKeyRingProvider; import haveno.common.util.Utilities; @@ -31,22 +33,17 @@ import haveno.core.provider.price.PriceFeedService; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import haveno.core.trade.HavenoUtils; import haveno.core.trade.statistics.TradeStatisticsManager; -import haveno.core.user.Preferences; import haveno.core.user.User; import haveno.core.util.coin.CoinUtil; -import haveno.core.xmr.wallet.Restrictions; import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.math.BigInteger; import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton @@ -103,9 +100,10 @@ public class CreateOfferService { Price fixedPrice, boolean useMarketBasedPrice, double marketPriceMargin, - double buyerSecurityDepositAsDouble, - PaymentAccount paymentAccount) { - + double securityDepositPct, + PaymentAccount paymentAccount, + boolean isPrivateOffer, + boolean buyerAsTakerWithoutDeposit) { log.info("create and get offer with offerId={}, " + "currencyCode={}, " + "direction={}, " + @@ -114,7 +112,9 @@ public class CreateOfferService { "marketPriceMargin={}, " + "amount={}, " + "minAmount={}, " + - "buyerSecurityDeposit={}", + "securityDepositPct={}, " + + "isPrivateOffer={}, " + + "buyerAsTakerWithoutDeposit={}", offerId, currencyCode, direction, @@ -123,7 +123,16 @@ public class CreateOfferService { marketPriceMargin, amount, minAmount, - buyerSecurityDepositAsDouble); + securityDepositPct, + isPrivateOffer, + buyerAsTakerWithoutDeposit); + + + // verify buyer as taker security deposit + boolean isBuyerMaker = offerUtil.isBuyOffer(direction); + if (!isBuyerMaker && !isPrivateOffer && buyerAsTakerWithoutDeposit) { + throw new IllegalArgumentException("Buyer as taker deposit is required for public offers"); + } // verify fixed price xor market price with margin if (fixedPrice != null) { @@ -144,10 +153,17 @@ public class CreateOfferService { } // adjust amount and min amount for fixed-price offer - long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction); if (fixedPrice != null) { - amount = CoinUtil.getRoundedAmount(amount, fixedPrice, maxTradeLimit, currencyCode, paymentAccount.getPaymentMethod().getId()); - minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, maxTradeLimit, currencyCode, paymentAccount.getPaymentMethod().getId()); + amount = CoinUtil.getRoundedAmount(amount, fixedPrice, null, currencyCode, paymentAccount.getPaymentMethod().getId()); + minAmount = CoinUtil.getRoundedAmount(minAmount, fixedPrice, null, currencyCode, paymentAccount.getPaymentMethod().getId()); + } + + // generate one-time challenge for private offer + String challenge = null; + String challengeHash = null; + if (isPrivateOffer) { + challenge = HavenoUtils.generateChallenge(); + challengeHash = HavenoUtils.getChallengeHash(challenge); } long priceAsLong = fixedPrice != null ? fixedPrice.getValue() : 0L; @@ -161,29 +177,19 @@ public class CreateOfferService { List<String> acceptedCountryCodes = PaymentAccountUtil.getAcceptedCountryCodes(paymentAccount); String bankId = PaymentAccountUtil.getBankId(paymentAccount); List<String> acceptedBanks = PaymentAccountUtil.getAcceptedBanks(paymentAccount); - double sellerSecurityDepositAsDouble = getSellerSecurityDepositAsDouble(buyerSecurityDepositAsDouble); - BigInteger makerFee = HavenoUtils.getMakerFee(amount); - BigInteger buyerSecurityDeposit = getBuyerSecurityDeposit(amount, buyerSecurityDepositAsDouble); - BigInteger sellerSecurityDeposit = getSellerSecurityDeposit(amount, sellerSecurityDepositAsDouble); long maxTradePeriod = paymentAccount.getMaxTradePeriod(); - - // reserved for future use cases - // Use null values if not set - boolean isPrivateOffer = false; + boolean hasBuyerAsTakerWithoutDeposit = !isBuyerMaker && isPrivateOffer && buyerAsTakerWithoutDeposit; + long maxTradeLimit = offerUtil.getMaxTradeLimit(paymentAccount, currencyCode, direction, hasBuyerAsTakerWithoutDeposit); boolean useAutoClose = false; boolean useReOpenAfterAutoClose = false; long lowerClosePrice = 0; long upperClosePrice = 0; - String hashOfChallenge = null; - Map<String, String> extraDataMap = offerUtil.getExtraDataMap(paymentAccount, - currencyCode, - direction); + Map<String, String> extraDataMap = offerUtil.getExtraDataMap(paymentAccount, currencyCode, direction); offerUtil.validateOfferData( - buyerSecurityDepositAsDouble, + securityDepositPct, paymentAccount, - currencyCode, - makerFee); + currencyCode); OfferPayload offerPayload = new OfferPayload(offerId, creationTime, @@ -195,6 +201,11 @@ public class CreateOfferService { useMarketBasedPriceValue, amountAsLong, minAmountAsLong, + hasBuyerAsTakerWithoutDeposit ? HavenoUtils.MAKER_FEE_FOR_TAKER_WITHOUT_DEPOSIT_PCT : HavenoUtils.MAKER_FEE_PCT, + hasBuyerAsTakerWithoutDeposit ? 0d : HavenoUtils.TAKER_FEE_PCT, + HavenoUtils.PENALTY_FEE_PCT, + hasBuyerAsTakerWithoutDeposit ? 0d : securityDepositPct, // buyer as taker security deposit is optional for private offers + securityDepositPct, baseCurrencyCode, counterCurrencyCode, paymentAccount.getPaymentMethod().getId(), @@ -204,10 +215,7 @@ public class CreateOfferService { bankId, acceptedBanks, Version.VERSION, - xmrWalletService.getWallet().getHeight(), - makerFee.longValueExact(), - buyerSecurityDeposit.longValueExact(), - sellerSecurityDeposit.longValueExact(), + xmrWalletService.getHeight(), maxTradeLimit, maxTradePeriod, useAutoClose, @@ -215,7 +223,7 @@ public class CreateOfferService { upperClosePrice, lowerClosePrice, isPrivateOffer, - hashOfChallenge, + challengeHash, extraDataMap, Version.TRADE_PROTOCOL_VERSION, null, @@ -223,38 +231,10 @@ public class CreateOfferService { null); Offer offer = new Offer(offerPayload); offer.setPriceFeedService(priceFeedService); + offer.setChallenge(challenge); return offer; } - public BigInteger getReservedFundsForOffer(OfferDirection direction, - BigInteger amount, - double buyerSecurityDeposit, - double sellerSecurityDeposit) { - - BigInteger reservedFundsForOffer = getSecurityDeposit(direction, - amount, - buyerSecurityDeposit, - sellerSecurityDeposit); - if (!offerUtil.isBuyOffer(direction)) - reservedFundsForOffer = reservedFundsForOffer.add(amount); - - return reservedFundsForOffer; - } - - public BigInteger getSecurityDeposit(OfferDirection direction, - BigInteger amount, - double buyerSecurityDeposit, - double sellerSecurityDeposit) { - return offerUtil.isBuyOffer(direction) ? - getBuyerSecurityDeposit(amount, buyerSecurityDeposit) : - getSellerSecurityDeposit(amount, sellerSecurityDeposit); - } - - public double getSellerSecurityDepositAsDouble(double buyerSecurityDeposit) { - return Preferences.USE_SYMMETRIC_SECURITY_DEPOSIT ? buyerSecurityDeposit : - Restrictions.getSellerSecurityDepositAsPercent(); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Private /////////////////////////////////////////////////////////////////////////////////////////// @@ -263,26 +243,4 @@ public class CreateOfferService { MarketPrice marketPrice = priceFeedService.getMarketPrice(currencyCode); return marketPrice != null && marketPrice.isExternallyProvidedPrice(); } - - private BigInteger getBuyerSecurityDeposit(BigInteger amount, double buyerSecurityDeposit) { - BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(buyerSecurityDeposit, amount); - return getBoundedBuyerSecurityDeposit(percentOfAmount); - } - - private BigInteger getSellerSecurityDeposit(BigInteger amount, double sellerSecurityDeposit) { - BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(sellerSecurityDeposit, amount); - return getBoundedSellerSecurityDeposit(percentOfAmount); - } - - private BigInteger getBoundedBuyerSecurityDeposit(BigInteger value) { - // We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the - // MinBuyerSecurityDeposit from Restrictions. - return Restrictions.getMinBuyerSecurityDeposit().max(value); - } - - private BigInteger getBoundedSellerSecurityDeposit(BigInteger value) { - // We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the - // MinSellerSecurityDeposit from Restrictions. - return Restrictions.getMinSellerSecurityDeposit().max(value); - } } diff --git a/core/src/main/java/haveno/core/offer/MarketPriceNotAvailableException.java b/core/src/main/java/haveno/core/offer/MarketPriceNotAvailableException.java index c30929e3d7..1e528f11ca 100644 --- a/core/src/main/java/haveno/core/offer/MarketPriceNotAvailableException.java +++ b/core/src/main/java/haveno/core/offer/MarketPriceNotAvailableException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; diff --git a/core/src/main/java/haveno/core/offer/Offer.java b/core/src/main/java/haveno/core/offer/Offer.java index 08a9e59197..3dc566b308 100644 --- a/core/src/main/java/haveno/core/offer/Offer.java +++ b/core/src/main/java/haveno/core/offer/Offer.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; +import haveno.common.ThreadUtils; +import haveno.common.UserThread; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; import haveno.common.handlers.ErrorMessageHandler; @@ -37,6 +39,7 @@ import haveno.core.offer.availability.OfferAvailabilityProtocol; import haveno.core.payment.payload.PaymentMethod; import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; +import haveno.core.trade.HavenoUtils; import haveno.core.util.VolumeUtil; import haveno.network.p2p.NodeAddress; import javafx.beans.property.ObjectProperty; @@ -78,7 +81,8 @@ public class Offer implements NetworkPayload, PersistablePayload { AVAILABLE, NOT_AVAILABLE, REMOVED, - MAKER_OFFLINE + MAKER_OFFLINE, + INVALID } /////////////////////////////////////////////////////////////////////////////////////////// @@ -111,6 +115,12 @@ public class Offer implements NetworkPayload, PersistablePayload { @Setter transient private boolean isReservedFundsSpent; + @JsonExclude + @Getter + @Setter + @Nullable + transient private String challenge; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -152,7 +162,9 @@ public class Offer implements NetworkPayload, PersistablePayload { log.error(errorMessage); errorMessageHandler.handleErrorMessage(errorMessage); }); - availabilityProtocol.sendOfferAvailabilityRequest(); + ThreadUtils.submitToPool((() -> { + availabilityProtocol.sendOfferAvailabilityRequest(); + })); } public void cancelAvailabilityRequest() { @@ -204,23 +216,23 @@ public class Offer implements NetworkPayload, PersistablePayload { return offerPayload.getPrice(); } - public void verifyTakersTradePrice(long takersTradePrice) throws TradePriceOutOfToleranceException, + public void verifyTradePrice(long price) throws TradePriceOutOfToleranceException, MarketPriceNotAvailableException, IllegalArgumentException { if (!isUseMarketBasedPrice()) { - checkArgument(takersTradePrice == getFixedPrice(), + checkArgument(price == getFixedPrice(), "Takers price does not match offer price. " + - "Takers price=" + takersTradePrice + "; offer price=" + getFixedPrice()); + "Takers price=" + price + "; offer price=" + getFixedPrice()); return; } - Price tradePrice = Price.valueOf(getCurrencyCode(), takersTradePrice); + Price tradePrice = Price.valueOf(getCurrencyCode(), price); Price offerPrice = getPrice(); if (offerPrice == null) throw new MarketPriceNotAvailableException("Market price required for calculating trade price is not available."); - checkArgument(takersTradePrice > 0, "takersTradePrice must be positive"); + checkArgument(price > 0, "takersTradePrice must be positive"); - double relation = (double) takersTradePrice / (double) offerPrice.getValue(); + double relation = (double) price / (double) offerPrice.getValue(); // We allow max. 2 % difference between own offerPayload price calculation and takers calculation. // Market price might be different at maker's and takers side so we need a bit of tolerance. // The tolerance will get smaller once we have multiple price feeds avoiding fast price fluctuations @@ -228,7 +240,7 @@ public class Offer implements NetworkPayload, PersistablePayload { double deviation = Math.abs(1 - relation); log.info("Price at take-offer time: id={}, currency={}, takersPrice={}, makersPrice={}, deviation={}", - getShortId(), getCurrencyCode(), takersTradePrice, offerPrice.getValue(), + getShortId(), getCurrencyCode(), price, offerPrice.getValue(), deviation * 100 + "%"); if (deviation > PRICE_TOLERANCE) { String msg = "Taker's trade price is too far away from our calculated price based on the market price.\n" + @@ -261,7 +273,7 @@ public class Offer implements NetworkPayload, PersistablePayload { /////////////////////////////////////////////////////////////////////////////////////////// public void setState(Offer.State state) { - stateProperty().set(state); + stateProperty.set(state); } public ObjectProperty<Offer.State> stateProperty() { @@ -269,7 +281,7 @@ public class Offer implements NetworkPayload, PersistablePayload { } public void setErrorMessage(String errorMessage) { - this.errorMessageProperty.set(errorMessage); + UserThread.await(() -> errorMessageProperty.set(errorMessage)); } @@ -277,24 +289,70 @@ public class Offer implements NetworkPayload, PersistablePayload { // Getter /////////////////////////////////////////////////////////////////////////////////////////// - // get the amount needed for the maker to reserve the offer - public BigInteger getReserveAmount() { - BigInteger reserveAmount = getDirection() == OfferDirection.BUY ? getBuyerSecurityDeposit() : getSellerSecurityDeposit(); - if (getDirection() == OfferDirection.SELL) reserveAmount = reserveAmount.add(getAmount()); - reserveAmount = reserveAmount.add(getMakerFee()); - return reserveAmount; + // amount needed for the maker to reserve the offer + public BigInteger getAmountNeeded() { + BigInteger amountNeeded = getDirection() == OfferDirection.BUY ? getMaxBuyerSecurityDeposit() : getMaxSellerSecurityDeposit(); + if (getDirection() == OfferDirection.SELL) amountNeeded = amountNeeded.add(getAmount()); + amountNeeded = amountNeeded.add(getMaxMakerFee()); + return amountNeeded; } - public BigInteger getMakerFee() { - return BigInteger.valueOf(offerPayload.getMakerFee()); + // amount reserved for offer + public BigInteger getReservedAmount() { + if (offerPayload.getReserveTxKeyImages() == null) return null; + return HavenoUtils.xmrWalletService.getOutputsAmount(offerPayload.getReserveTxKeyImages()); } - public BigInteger getBuyerSecurityDeposit() { - return BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit()); + public BigInteger getMaxMakerFee() { + return offerPayload.getMaxMakerFee(); } - public BigInteger getSellerSecurityDeposit() { - return BigInteger.valueOf(offerPayload.getSellerSecurityDeposit()); + public BigInteger getMaxBuyerSecurityDeposit() { + return offerPayload.getMaxBuyerSecurityDeposit(); + } + + public BigInteger getMaxSellerSecurityDeposit() { + return offerPayload.getMaxSellerSecurityDeposit(); + } + + public double getMakerFeePct() { + return offerPayload.getMakerFeePct(); + } + + public double getTakerFeePct() { + return offerPayload.getTakerFeePct(); + } + + public double getPenaltyFeePct() { + return offerPayload.getPenaltyFeePct(); + } + + public BigInteger getMakerFee(BigInteger tradeAmount) { + return HavenoUtils.multiply(tradeAmount, getMakerFeePct()); + } + + public BigInteger getTakerFee(BigInteger tradeAmount) { + return HavenoUtils.multiply(tradeAmount, getTakerFeePct()); + } + + public double getBuyerSecurityDepositPct() { + return offerPayload.getBuyerSecurityDepositPct(); + } + + public double getSellerSecurityDepositPct() { + return offerPayload.getSellerSecurityDepositPct(); + } + + public boolean isPrivateOffer() { + return offerPayload.isPrivateOffer(); + } + + public String getChallengeHash() { + return offerPayload.getChallengeHash(); + } + + public boolean hasBuyerAsTakerWithoutDeposit() { + return getDirection() == OfferDirection.SELL && getBuyerSecurityDepositPct() == 0; } public BigInteger getMaxTradeLimit() { @@ -368,6 +426,12 @@ public class Offer implements NetworkPayload, PersistablePayload { return getExtraDataMap().get(OfferPayload.F2F_EXTRA_INFO); else if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.PAY_BY_MAIL_EXTRA_INFO)) return getExtraDataMap().get(OfferPayload.PAY_BY_MAIL_EXTRA_INFO); + else if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.AUSTRALIA_PAYID_EXTRA_INFO)) + return getExtraDataMap().get(OfferPayload.AUSTRALIA_PAYID_EXTRA_INFO); + else if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.PAYPAL_EXTRA_INFO)) + return getExtraDataMap().get(OfferPayload.PAYPAL_EXTRA_INFO); + else if (getExtraDataMap() != null && getExtraDataMap().containsKey(OfferPayload.CASHAPP_EXTRA_INFO)) + return getExtraDataMap().get(OfferPayload.CASHAPP_EXTRA_INFO); else return ""; } diff --git a/core/src/main/java/haveno/core/offer/OfferBookService.java b/core/src/main/java/haveno/core/offer/OfferBookService.java index 42f07ad71c..7698aeb1ca 100644 --- a/core/src/main/java/haveno/core/offer/OfferBookService.java +++ b/core/src/main/java/haveno/core/offer/OfferBookService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,32 +34,25 @@ package haveno.core.offer; -import common.utils.GenUtils; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.common.file.JsonFileManager; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.filter.FilterManager; import haveno.core.locale.Res; import haveno.core.provider.price.PriceFeedService; +import haveno.core.trade.HavenoUtils; import haveno.core.util.JsonUtil; -import haveno.core.xmr.wallet.MoneroKeyImageListener; -import haveno.core.xmr.wallet.MoneroKeyImagePoller; +import haveno.core.xmr.wallet.XmrKeyImageListener; +import haveno.core.xmr.wallet.XmrKeyImagePoller; import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.P2PService; import haveno.network.p2p.storage.HashMapChangedListener; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import monero.common.MoneroConnectionManagerListener; -import monero.common.MoneroRpcConnection; -import monero.daemon.model.MoneroKeyImageSpentStatus; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; import java.io.File; import java.util.Collection; import java.util.LinkedList; @@ -50,23 +60,24 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import monero.daemon.model.MoneroKeyImageSpentStatus; /** * Handles storage and retrieval of offers. * Uses an invalidation flag to only request the full offer map in case there was a change (anyone has added or removed an offer). */ public class OfferBookService { - private static final Logger log = LoggerFactory.getLogger(OfferBookService.class); private final P2PService p2PService; private final PriceFeedService priceFeedService; private final List<OfferBookChangedListener> offerBookChangedListeners = new LinkedList<>(); private final FilterManager filterManager; private final JsonFileManager jsonFileManager; - private final CoreMoneroConnectionsService connectionsService; + private final XmrConnectionService xmrConnectionService; // poll key images of offers - private MoneroKeyImagePoller keyImagePoller; + private XmrKeyImagePoller keyImagePoller; private static final long KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL = 20000; // 20 seconds private static final long KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE = 300000; // 5 minutes @@ -84,70 +95,67 @@ public class OfferBookService { public OfferBookService(P2PService p2PService, PriceFeedService priceFeedService, FilterManager filterManager, - CoreMoneroConnectionsService connectionsService, + XmrConnectionService xmrConnectionService, @Named(Config.STORAGE_DIR) File storageDir, @Named(Config.DUMP_STATISTICS) boolean dumpStatistics) { this.p2PService = p2PService; this.priceFeedService = priceFeedService; this.filterManager = filterManager; - this.connectionsService = connectionsService; + this.xmrConnectionService = xmrConnectionService; jsonFileManager = new JsonFileManager(storageDir); // listen for connection changes to monerod - connectionsService.addConnectionListener(new MoneroConnectionManagerListener() { - @Override - public void onConnectionChanged(MoneroRpcConnection connection) { - maybeInitializeKeyImagePoller(); - keyImagePoller.setDaemon(connectionsService.getDaemon()); - keyImagePoller.setRefreshPeriodMs(getKeyImageRefreshPeriodMs()); - } + xmrConnectionService.addConnectionListener((connection) -> { + maybeInitializeKeyImagePoller(); + keyImagePoller.setDaemon(xmrConnectionService.getDaemon()); + keyImagePoller.setRefreshPeriodMs(getKeyImageRefreshPeriodMs()); }); // listen for offers p2PService.addHashSetChangedListener(new HashMapChangedListener() { @Override public void onAdded(Collection<ProtectedStorageEntry> protectedStorageEntries) { + UserThread.execute(() -> { protectedStorageEntries.forEach(protectedStorageEntry -> { - synchronized (offerBookChangedListeners) { - offerBookChangedListeners.forEach(listener -> { - if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) { - OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload(); - maybeInitializeKeyImagePoller(); - keyImagePoller.addKeyImages(offerPayload.getReserveTxKeyImages()); - Offer offer = new Offer(offerPayload); - offer.setPriceFeedService(priceFeedService); - setReservedFundsSpent(offer); - listener.onAdded(offer); - } - }); + if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) { + OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload(); + maybeInitializeKeyImagePoller(); + keyImagePoller.addKeyImages(offerPayload.getReserveTxKeyImages()); + Offer offer = new Offer(offerPayload); + offer.setPriceFeedService(priceFeedService); + setReservedFundsSpent(offer); + synchronized (offerBookChangedListeners) { + offerBookChangedListeners.forEach(listener -> listener.onAdded(offer)); + } } }); + }); } @Override public void onRemoved(Collection<ProtectedStorageEntry> protectedStorageEntries) { + UserThread.execute(() -> { protectedStorageEntries.forEach(protectedStorageEntry -> { - synchronized (offerBookChangedListeners) { - offerBookChangedListeners.forEach(listener -> { - if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) { - OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload(); - maybeInitializeKeyImagePoller(); - keyImagePoller.removeKeyImages(offerPayload.getReserveTxKeyImages()); - Offer offer = new Offer(offerPayload); - offer.setPriceFeedService(priceFeedService); - setReservedFundsSpent(offer); - listener.onRemoved(offer); - } - }); + if (protectedStorageEntry.getProtectedStoragePayload() instanceof OfferPayload) { + OfferPayload offerPayload = (OfferPayload) protectedStorageEntry.getProtectedStoragePayload(); + maybeInitializeKeyImagePoller(); + keyImagePoller.removeKeyImages(offerPayload.getReserveTxKeyImages()); + Offer offer = new Offer(offerPayload); + offer.setPriceFeedService(priceFeedService); + setReservedFundsSpent(offer); + synchronized (offerBookChangedListeners) { + offerBookChangedListeners.forEach(listener -> listener.onRemoved(offer)); + } } }); + }); } }); if (dumpStatistics) { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { addOfferBookChangedListener(new OfferBookChangedListener() { @Override public void onAdded(Offer offer) { @@ -268,28 +276,30 @@ public class OfferBookService { private synchronized void maybeInitializeKeyImagePoller() { if (keyImagePoller != null) return; - keyImagePoller = new MoneroKeyImagePoller(connectionsService.getDaemon(), getKeyImageRefreshPeriodMs()); + keyImagePoller = new XmrKeyImagePoller(xmrConnectionService.getDaemon(), getKeyImageRefreshPeriodMs()); // handle when key images spent - keyImagePoller.addListener(new MoneroKeyImageListener() { + keyImagePoller.addListener(new XmrKeyImageListener() { @Override public void onSpentStatusChanged(Map<String, MoneroKeyImageSpentStatus> spentStatuses) { - for (String keyImage : spentStatuses.keySet()) { - updateAffectedOffers(keyImage); - } + UserThread.execute(() -> { + for (String keyImage : spentStatuses.keySet()) { + updateAffectedOffers(keyImage); + } + }); } }); // first poll after 20s // TODO: remove? new Thread(() -> { - GenUtils.waitFor(20000); + HavenoUtils.waitFor(20000); keyImagePoller.poll(); }).start(); } private long getKeyImageRefreshPeriodMs() { - return connectionsService.isConnectionLocal() ? KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL : KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE; + return xmrConnectionService.isConnectionLocalHost() ? KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL : KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE; } private void updateAffectedOffers(String keyImage) { @@ -297,12 +307,8 @@ public class OfferBookService { if (offer.getOfferPayload().getReserveTxKeyImages().contains(keyImage)) { synchronized (offerBookChangedListeners) { offerBookChangedListeners.forEach(listener -> { - - // notify off thread to avoid deadlocking - new Thread(() -> { - listener.onRemoved(offer); - listener.onAdded(offer); - }).start(); + listener.onRemoved(offer); + listener.onAdded(offer); }); } } diff --git a/core/src/main/java/haveno/core/offer/OfferDirection.java b/core/src/main/java/haveno/core/offer/OfferDirection.java index d1b9a6a148..a91ba59725 100644 --- a/core/src/main/java/haveno/core/offer/OfferDirection.java +++ b/core/src/main/java/haveno/core/offer/OfferDirection.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; diff --git a/core/src/main/java/haveno/core/offer/OfferFilterService.java b/core/src/main/java/haveno/core/offer/OfferFilterService.java index f9816582ca..e64a1ee6eb 100644 --- a/core/src/main/java/haveno/core/offer/OfferFilterService.java +++ b/core/src/main/java/haveno/core/offer/OfferFilterService.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.app.Version; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.filter.FilterManager; @@ -26,21 +28,15 @@ import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.trade.HavenoUtils; import haveno.core.user.Preferences; import haveno.core.user.User; -import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; import javafx.collections.SetChangeListener; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.Coin; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - @Slf4j @Singleton public class OfferFilterService { @@ -205,7 +201,7 @@ public class OfferFilterService { accountAgeWitnessService); long myTradeLimit = accountOptional .map(paymentAccount -> accountAgeWitnessService.getMyTradeLimit(paymentAccount, - offer.getCurrencyCode(), offer.getMirroredDirection())) + offer.getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit())) .orElse(0L); long offerMinAmount = offer.getMinAmount().longValueExact(); log.debug("isInsufficientTradeLimit accountOptional={}, myTradeLimit={}, offerMinAmount={}, ", @@ -219,7 +215,7 @@ public class OfferFilterService { return result; } - public boolean hasValidSignature(Offer offer) { + private boolean hasValidSignature(Offer offer) { // get accepted arbitrator by address Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(offer.getOfferPayload().getArbitratorSigner()); @@ -229,11 +225,14 @@ public class OfferFilterService { Arbitrator thisArbitrator = user.getRegisteredArbitrator(); if (thisArbitrator != null && thisArbitrator.getNodeAddress().equals(offer.getOfferPayload().getArbitratorSigner())) { if (thisArbitrator.getNodeAddress().equals(p2PService.getNetworkNode().getNodeAddress())) arbitrator = thisArbitrator; // TODO: unnecessary to compare arbitrator and p2pservice address? + } else { + + // // otherwise log warning that arbitrator is unregistered + // List<NodeAddress> arbitratorAddresses = user.getAcceptedArbitrators().stream().map(Arbitrator::getNodeAddress).collect(Collectors.toList()); + // if (!arbitratorAddresses.isEmpty()) { + // log.warn("No arbitrator is registered with offer's signer. offerId={}, arbitrator signer={}, accepted arbitrators={}", offer.getId(), offer.getOfferPayload().getArbitratorSigner(), arbitratorAddresses); + // } } - - // otherwise log warning - List<NodeAddress> arbitratorAddresses = user.getAcceptedArbitrators().stream().map(Arbitrator::getNodeAddress).collect(Collectors.toList()); - log.warn("No arbitrator is registered with offer's signer. offerId={}, arbitrator signer={}, accepted arbitrators={}", offer.getId(), offer.getOfferPayload().getArbitratorSigner(), arbitratorAddresses); } if (arbitrator == null) return false; // invalid arbitrator diff --git a/core/src/main/java/haveno/core/offer/OfferForJson.java b/core/src/main/java/haveno/core/offer/OfferForJson.java index eb347ed9a3..caebcdc3dd 100644 --- a/core/src/main/java/haveno/core/offer/OfferForJson.java +++ b/core/src/main/java/haveno/core/offer/OfferForJson.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; diff --git a/core/src/main/java/haveno/core/offer/OfferModule.java b/core/src/main/java/haveno/core/offer/OfferModule.java index 39a166462b..d6143a99de 100644 --- a/core/src/main/java/haveno/core/offer/OfferModule.java +++ b/core/src/main/java/haveno/core/offer/OfferModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; diff --git a/core/src/main/java/haveno/core/offer/OfferPayload.java b/core/src/main/java/haveno/core/offer/OfferPayload.java index ae8296e107..0dadf882ba 100644 --- a/core/src/main/java/haveno/core/offer/OfferPayload.java +++ b/core/src/main/java/haveno/core/offer/OfferPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; @@ -28,6 +28,8 @@ import haveno.common.util.CollectionUtils; import haveno.common.util.Hex; import haveno.common.util.JsonExclude; import haveno.common.util.Utilities; +import haveno.core.trade.HavenoUtils; +import haveno.core.xmr.wallet.Restrictions; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.storage.payload.ExpirablePayload; import haveno.network.p2p.storage.payload.ProtectedStoragePayload; @@ -39,6 +41,7 @@ import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; import java.lang.reflect.Type; +import java.math.BigInteger; import java.security.PublicKey; import java.util.ArrayList; import java.util.List; @@ -52,7 +55,7 @@ import java.util.concurrent.TimeUnit; @Getter @Slf4j public final class OfferPayload implements ProtectedStoragePayload, ExpirablePayload, RequiresOwnerIsOnlinePayload { - public static final long TTL = TimeUnit.MINUTES.toMillis(9); + public static final long TTL = TimeUnit.MINUTES.toMillis(11); protected final String id; protected final long date; @@ -91,11 +94,14 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay // Keys for extra map // Only set for traditional offers public static final String ACCOUNT_AGE_WITNESS_HASH = "accountAgeWitnessHash"; + public static final String CASHAPP_EXTRA_INFO = "cashAppExtraInfo"; public static final String REFERRAL_ID = "referralId"; // Only used in payment method F2F public static final String F2F_CITY = "f2fCity"; public static final String F2F_EXTRA_INFO = "f2fExtraInfo"; public static final String PAY_BY_MAIL_EXTRA_INFO = "payByMailExtraInfo"; + public static final String AUSTRALIA_PAYID_EXTRA_INFO = "australiaPayidExtraInfo"; + public static final String PAYPAL_EXTRA_INFO = "payPalExtraInfo"; // Comma separated list of ordinal of a haveno.common.app.Capability. E.g. ordinal of // Capability.SIGNED_ACCOUNT_AGE_WITNESS is 11 and Capability.MEDIATION is 12 so if we want to signal that maker @@ -129,9 +135,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay @Nullable private final List<String> acceptedBankIds; private final long blockHeightAtOfferCreation; - private final long makerFee; - private final long buyerSecurityDeposit; - private final long sellerSecurityDeposit; + private final double makerFeePct; + private final double takerFeePct; + private final double penaltyFeePct; + private final double buyerSecurityDepositPct; + private final double sellerSecurityDepositPct; private final long maxTradeLimit; private final long maxTradePeriod; @@ -148,7 +156,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay // Reserved for possible future use to support private trades where the taker needs to have an accessKey private final boolean isPrivateOffer; @Nullable - private final String hashOfChallenge; + private final String challengeHash; /////////////////////////////////////////////////////////////////////////////////////////// @@ -165,6 +173,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay boolean useMarketBasedPrice, long amount, long minAmount, + double makerFeePct, + double takerFeePct, + double penaltyFeePct, + double buyerSecurityDepositPct, + double sellerSecurityDepositPct, String baseCurrencyCode, String counterCurrencyCode, String paymentMethodId, @@ -175,9 +188,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay @Nullable List<String> acceptedBankIds, String versionNr, long blockHeightAtOfferCreation, - long makerFee, - long buyerSecurityDeposit, - long sellerSecurityDeposit, long maxTradeLimit, long maxTradePeriod, boolean useAutoClose, @@ -185,7 +195,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay long lowerClosePrice, long upperClosePrice, boolean isPrivateOffer, - @Nullable String hashOfChallenge, + @Nullable String challengeHash, @Nullable Map<String, String> extraDataMap, int protocolVersion, @Nullable NodeAddress arbitratorSigner, @@ -201,6 +211,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay this.price = price; this.amount = amount; this.minAmount = minAmount; + this.makerFeePct = makerFeePct; + this.takerFeePct = takerFeePct; + this.penaltyFeePct = penaltyFeePct; + this.buyerSecurityDepositPct = buyerSecurityDepositPct; + this.sellerSecurityDepositPct = sellerSecurityDepositPct; this.paymentMethodId = paymentMethodId; this.makerPaymentAccountId = makerPaymentAccountId; this.extraDataMap = extraDataMap; @@ -216,9 +231,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay this.bankId = bankId; this.acceptedBankIds = acceptedBankIds; this.blockHeightAtOfferCreation = blockHeightAtOfferCreation; - this.makerFee = makerFee; - this.buyerSecurityDeposit = buyerSecurityDeposit; - this.sellerSecurityDeposit = sellerSecurityDeposit; this.maxTradeLimit = maxTradeLimit; this.maxTradePeriod = maxTradePeriod; this.useAutoClose = useAutoClose; @@ -226,7 +238,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay this.lowerClosePrice = lowerClosePrice; this.upperClosePrice = upperClosePrice; this.isPrivateOffer = isPrivateOffer; - this.hashOfChallenge = hashOfChallenge; + this.challengeHash = challengeHash; } public byte[] getHash() { @@ -250,6 +262,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay false, amount, minAmount, + makerFeePct, + takerFeePct, + penaltyFeePct, + buyerSecurityDepositPct, + sellerSecurityDepositPct, baseCurrencyCode, counterCurrencyCode, paymentMethodId, @@ -260,9 +277,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay acceptedBankIds, versionNr, blockHeightAtOfferCreation, - makerFee, - buyerSecurityDeposit, - sellerSecurityDeposit, maxTradeLimit, maxTradePeriod, useAutoClose, @@ -270,7 +284,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay lowerClosePrice, upperClosePrice, isPrivateOffer, - hashOfChallenge, + challengeHash, extraDataMap, protocolVersion, arbitratorSigner, @@ -300,6 +314,33 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay return getBaseCurrencyCode().equals("XMR") ? getCounterCurrencyCode() : getBaseCurrencyCode(); } + public BigInteger getMaxMakerFee() { + return HavenoUtils.multiply(BigInteger.valueOf(getAmount()), getMakerFeePct()); + } + + public BigInteger getMaxBuyerSecurityDeposit() { + return getBuyerSecurityDepositForTradeAmount(BigInteger.valueOf(getAmount())); + } + + public BigInteger getMaxSellerSecurityDeposit() { + return getSellerSecurityDepositForTradeAmount(BigInteger.valueOf(getAmount())); + } + + public BigInteger getBuyerSecurityDepositForTradeAmount(BigInteger tradeAmount) { + BigInteger securityDepositUnadjusted = HavenoUtils.multiply(tradeAmount, getBuyerSecurityDepositPct()); + boolean isBuyerTaker = getDirection() == OfferDirection.SELL; + if (isPrivateOffer() && isBuyerTaker) { + return securityDepositUnadjusted; + } else { + return Restrictions.getMinSecurityDeposit().max(securityDepositUnadjusted); + } + } + + public BigInteger getSellerSecurityDepositForTradeAmount(BigInteger tradeAmount) { + BigInteger securityDepositUnadjusted = HavenoUtils.multiply(tradeAmount, getSellerSecurityDepositPct()); + return Restrictions.getMinSecurityDeposit().max(securityDepositUnadjusted); + } + /////////////////////////////////////////////////////////////////////////////////////////// // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// @@ -316,15 +357,17 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay .setUseMarketBasedPrice(useMarketBasedPrice) .setAmount(amount) .setMinAmount(minAmount) + .setMakerFeePct(makerFeePct) + .setTakerFeePct(takerFeePct) + .setPenaltyFeePct(penaltyFeePct) + .setBuyerSecurityDepositPct(buyerSecurityDepositPct) + .setSellerSecurityDepositPct(sellerSecurityDepositPct) .setBaseCurrencyCode(baseCurrencyCode) .setCounterCurrencyCode(counterCurrencyCode) .setPaymentMethodId(paymentMethodId) .setMakerPaymentAccountId(makerPaymentAccountId) .setVersionNr(versionNr) .setBlockHeightAtOfferCreation(blockHeightAtOfferCreation) - .setMakerFee(makerFee) - .setBuyerSecurityDeposit(buyerSecurityDeposit) - .setSellerSecurityDeposit(sellerSecurityDeposit) .setMaxTradeLimit(maxTradeLimit) .setMaxTradePeriod(maxTradePeriod) .setUseAutoClose(useAutoClose) @@ -338,7 +381,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay Optional.ofNullable(bankId).ifPresent(builder::setBankId); Optional.ofNullable(acceptedBankIds).ifPresent(builder::addAllAcceptedBankIds); Optional.ofNullable(acceptedCountryCodes).ifPresent(builder::addAllAcceptedCountryCodes); - Optional.ofNullable(hashOfChallenge).ifPresent(builder::setHashOfChallenge); + Optional.ofNullable(challengeHash).ifPresent(builder::setChallengeHash); Optional.ofNullable(extraDataMap).ifPresent(builder::putAllExtraData); Optional.ofNullable(arbitratorSigner).ifPresent(e -> builder.setArbitratorSigner(arbitratorSigner.toProtoMessage())); Optional.ofNullable(arbitratorSignature).ifPresent(e -> builder.setArbitratorSignature(ByteString.copyFrom(e))); @@ -352,7 +395,9 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay null : new ArrayList<>(proto.getAcceptedBankIdsList()); List<String> acceptedCountryCodes = proto.getAcceptedCountryCodesList().isEmpty() ? null : new ArrayList<>(proto.getAcceptedCountryCodesList()); - String hashOfChallenge = ProtoUtil.stringOrNullFromProto(proto.getHashOfChallenge()); + List<String> reserveTxKeyImages = proto.getReserveTxKeyImagesList().isEmpty() ? + null : new ArrayList<>(proto.getReserveTxKeyImagesList()); + String challengeHash = ProtoUtil.stringOrNullFromProto(proto.getChallengeHash()); Map<String, String> extraDataMapMap = CollectionUtils.isEmpty(proto.getExtraDataMap()) ? null : proto.getExtraDataMap(); @@ -366,6 +411,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay proto.getUseMarketBasedPrice(), proto.getAmount(), proto.getMinAmount(), + proto.getMakerFeePct(), + proto.getTakerFeePct(), + proto.getPenaltyFeePct(), + proto.getBuyerSecurityDepositPct(), + proto.getSellerSecurityDepositPct(), proto.getBaseCurrencyCode(), proto.getCounterCurrencyCode(), proto.getPaymentMethodId(), @@ -376,9 +426,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay acceptedBankIds, proto.getVersionNr(), proto.getBlockHeightAtOfferCreation(), - proto.getMakerFee(), - proto.getBuyerSecurityDeposit(), - proto.getSellerSecurityDeposit(), proto.getMaxTradeLimit(), proto.getMaxTradePeriod(), proto.getUseAutoClose(), @@ -386,12 +433,12 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay proto.getLowerClosePrice(), proto.getUpperClosePrice(), proto.getIsPrivateOffer(), - hashOfChallenge, + challengeHash, extraDataMapMap, proto.getProtocolVersion(), proto.hasArbitratorSigner() ? NodeAddress.fromProto(proto.getArbitratorSigner()) : null, ProtoUtil.byteArrayOrNullFromProto(proto.getArbitratorSignature()), - proto.getReserveTxKeyImagesList() == null ? null : new ArrayList<String>(proto.getReserveTxKeyImagesList())); + reserveTxKeyImages); } @Override @@ -404,6 +451,11 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n price=" + price + ",\r\n amount=" + amount + ",\r\n minAmount=" + minAmount + + ",\r\n makerFeePct=" + makerFeePct + + ",\r\n takerFeePct=" + takerFeePct + + ",\r\n penaltyFeePct=" + penaltyFeePct + + ",\r\n buyerSecurityDepositPct=" + buyerSecurityDepositPct + + ",\r\n sellerSecurityDeposiPct=" + sellerSecurityDepositPct + ",\r\n paymentMethodId='" + paymentMethodId + '\'' + ",\r\n makerPaymentAccountId='" + makerPaymentAccountId + '\'' + ",\r\n ownerNodeAddress=" + ownerNodeAddress + @@ -421,9 +473,6 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n bankId='" + bankId + '\'' + ",\r\n acceptedBankIds=" + acceptedBankIds + ",\r\n blockHeightAtOfferCreation=" + blockHeightAtOfferCreation + - ",\r\n makerFee=" + makerFee + - ",\r\n buyerSecurityDeposit=" + buyerSecurityDeposit + - ",\r\n sellerSecurityDeposit=" + sellerSecurityDeposit + ",\r\n maxTradeLimit=" + maxTradeLimit + ",\r\n maxTradePeriod=" + maxTradePeriod + ",\r\n useAutoClose=" + useAutoClose + @@ -431,7 +480,7 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay ",\r\n lowerClosePrice=" + lowerClosePrice + ",\r\n upperClosePrice=" + upperClosePrice + ",\r\n isPrivateOffer=" + isPrivateOffer + - ",\r\n hashOfChallenge='" + hashOfChallenge + '\'' + + ",\r\n challengeHash='" + challengeHash + '\'' + ",\r\n arbitratorSigner=" + arbitratorSigner + ",\r\n arbitratorSignature=" + Utilities.bytesAsHexString(arbitratorSignature) + "\r\n} "; @@ -453,15 +502,17 @@ public final class OfferPayload implements ProtectedStoragePayload, ExpirablePay object.add("useMarketBasedPrice", context.serialize(offerPayload.isUseMarketBasedPrice())); object.add("amount", context.serialize(offerPayload.getAmount())); object.add("minAmount", context.serialize(offerPayload.getMinAmount())); + object.add("makerFeePct", context.serialize(offerPayload.getMakerFeePct())); + object.add("takerFeePct", context.serialize(offerPayload.getTakerFeePct())); + object.add("penaltyFeePct", context.serialize(offerPayload.getPenaltyFeePct())); + object.add("buyerSecurityDepositPct", context.serialize(offerPayload.getBuyerSecurityDepositPct())); + object.add("sellerSecurityDepositPct", context.serialize(offerPayload.getSellerSecurityDepositPct())); object.add("baseCurrencyCode", context.serialize(offerPayload.getBaseCurrencyCode())); object.add("counterCurrencyCode", context.serialize(offerPayload.getCounterCurrencyCode())); object.add("paymentMethodId", context.serialize(offerPayload.getPaymentMethodId())); object.add("makerPaymentAccountId", context.serialize(offerPayload.getMakerPaymentAccountId())); object.add("versionNr", context.serialize(offerPayload.getVersionNr())); object.add("blockHeightAtOfferCreation", context.serialize(offerPayload.getBlockHeightAtOfferCreation())); - object.add("makerFee", context.serialize(offerPayload.getMakerFee())); - object.add("buyerSecurityDeposit", context.serialize(offerPayload.getBuyerSecurityDeposit())); - object.add("sellerSecurityDeposit", context.serialize(offerPayload.getSellerSecurityDeposit())); object.add("maxTradeLimit", context.serialize(offerPayload.getMaxTradeLimit())); object.add("maxTradePeriod", context.serialize(offerPayload.getMaxTradePeriod())); object.add("useAutoClose", context.serialize(offerPayload.isUseAutoClose())); diff --git a/core/src/main/java/haveno/core/offer/OfferRestrictions.java b/core/src/main/java/haveno/core/offer/OfferRestrictions.java index 03e66fc86e..30a3ea4b66 100644 --- a/core/src/main/java/haveno/core/offer/OfferRestrictions.java +++ b/core/src/main/java/haveno/core/offer/OfferRestrictions.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; @@ -37,7 +37,7 @@ public class OfferRestrictions { return new Date().after(REQUIRE_TOR_NODE_ADDRESS_V3_DATE) && Config.baseCurrencyNetwork().isMainnet(); } - public static BigInteger TOLERATED_SMALL_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(2.0); + public static BigInteger TOLERATED_SMALL_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(3); static boolean hasOfferMandatoryCapability(Offer offer, Capability mandatoryCapability) { Map<String, String> extraDataMap = offer.getExtraDataMap(); diff --git a/core/src/main/java/haveno/core/offer/OfferUtil.java b/core/src/main/java/haveno/core/offer/OfferUtil.java index ac8779777f..3d4c1c376e 100644 --- a/core/src/main/java/haveno/core/offer/OfferUtil.java +++ b/core/src/main/java/haveno/core/offer/OfferUtil.java @@ -1,25 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.app.Capabilities; import haveno.common.app.Version; import haveno.common.util.MathUtils; +import static haveno.common.util.MathUtils.roundDoubleToLong; +import static haveno.common.util.MathUtils.scaleUpByPowerOf10; import haveno.common.util.Utilities; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.filter.FilterManager; @@ -28,8 +34,23 @@ import haveno.core.locale.Res; import haveno.core.monetary.Price; import haveno.core.monetary.TraditionalMoney; import haveno.core.monetary.Volume; -import haveno.core.payment.PayByMailAccount; +import static haveno.core.offer.OfferPayload.ACCOUNT_AGE_WITNESS_HASH; +import static haveno.core.offer.OfferPayload.AUSTRALIA_PAYID_EXTRA_INFO; +import static haveno.core.offer.OfferPayload.CAPABILITIES; +import static haveno.core.offer.OfferPayload.CASHAPP_EXTRA_INFO; +import static haveno.core.offer.OfferPayload.F2F_CITY; +import static haveno.core.offer.OfferPayload.F2F_EXTRA_INFO; +import static haveno.core.offer.OfferPayload.PAY_BY_MAIL_EXTRA_INFO; +import static haveno.core.offer.OfferPayload.PAYPAL_EXTRA_INFO; +import static haveno.core.offer.OfferPayload.REFERRAL_ID; +import static haveno.core.offer.OfferPayload.XMR_AUTO_CONF; +import static haveno.core.offer.OfferPayload.XMR_AUTO_CONF_ENABLED_VALUE; + +import haveno.core.payment.AustraliaPayidAccount; +import haveno.core.payment.CashAppAccount; import haveno.core.payment.F2FAccount; +import haveno.core.payment.PayByMailAccount; +import haveno.core.payment.PayPalAccount; import haveno.core.payment.PaymentAccount; import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; @@ -37,31 +58,15 @@ import haveno.core.trade.statistics.ReferralIdService; import haveno.core.user.AutoConfirmSettings; import haveno.core.user.Preferences; import haveno.core.util.coin.CoinFormatter; +import static haveno.core.xmr.wallet.Restrictions.getMaxSecurityDepositAsPercent; +import static haveno.core.xmr.wallet.Restrictions.getMinSecurityDepositAsPercent; import haveno.network.p2p.P2PService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.UUID; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.common.util.MathUtils.roundDoubleToLong; -import static haveno.common.util.MathUtils.scaleUpByPowerOf10; -import static haveno.core.offer.OfferPayload.ACCOUNT_AGE_WITNESS_HASH; -import static haveno.core.offer.OfferPayload.CAPABILITIES; -import static haveno.core.offer.OfferPayload.PAY_BY_MAIL_EXTRA_INFO; -import static haveno.core.offer.OfferPayload.F2F_CITY; -import static haveno.core.offer.OfferPayload.F2F_EXTRA_INFO; -import static haveno.core.offer.OfferPayload.REFERRAL_ID; -import static haveno.core.offer.OfferPayload.XMR_AUTO_CONF; -import static haveno.core.offer.OfferPayload.XMR_AUTO_CONF_ENABLED_VALUE; -import static haveno.core.xmr.wallet.Restrictions.getMaxBuyerSecurityDepositAsPercent; -import static haveno.core.xmr.wallet.Restrictions.getMinBuyerSecurityDepositAsPercent; +import lombok.extern.slf4j.Slf4j; /** * This class holds utility methods for creating, editing and taking an Offer. @@ -115,9 +120,10 @@ public class OfferUtil { public long getMaxTradeLimit(PaymentAccount paymentAccount, String currencyCode, - OfferDirection direction) { + OfferDirection direction, + boolean buyerAsTakerWithoutDeposit) { return paymentAccount != null - ? accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction) + ? accountAgeWitnessService.getMyTradeLimit(paymentAccount, currencyCode, direction, buyerAsTakerWithoutDeposit) : 0; } @@ -143,9 +149,9 @@ public class OfferUtil { public BigInteger getBalanceShortage(BigInteger cost, BigInteger balance) { if (cost != null) { BigInteger shortage = cost.subtract(balance); - return shortage.compareTo(BigInteger.valueOf(0)) < 0 ? BigInteger.valueOf(0) : shortage; + return shortage.compareTo(BigInteger.ZERO) < 0 ? BigInteger.ZERO : shortage; } else { - return BigInteger.valueOf(0); + return BigInteger.ZERO; } } @@ -199,6 +205,18 @@ public class OfferUtil { extraDataMap.put(PAY_BY_MAIL_EXTRA_INFO, ((PayByMailAccount) paymentAccount).getExtraInfo()); } + if (paymentAccount instanceof PayPalAccount) { + extraDataMap.put(PAYPAL_EXTRA_INFO, ((PayPalAccount) paymentAccount).getExtraInfo()); + } + + if (paymentAccount instanceof CashAppAccount) { + extraDataMap.put(CASHAPP_EXTRA_INFO, ((CashAppAccount) paymentAccount).getExtraInfo()); + } + + if (paymentAccount instanceof AustraliaPayidAccount) { + extraDataMap.put(AUSTRALIA_PAYID_EXTRA_INFO, ((AustraliaPayidAccount) paymentAccount).getExtraInfo()); + } + extraDataMap.put(CAPABILITIES, Capabilities.app.toStringList()); if (currencyCode.equals("XMR") && direction == OfferDirection.SELL) { @@ -211,18 +229,16 @@ public class OfferUtil { return extraDataMap.isEmpty() ? null : extraDataMap; } - public void validateOfferData(double buyerSecurityDeposit, + public void validateOfferData(double securityDeposit, PaymentAccount paymentAccount, - String currencyCode, - BigInteger makerFee) { - checkNotNull(makerFee, "makerFee must not be null"); + String currencyCode) { checkNotNull(p2PService.getAddress(), "Address must not be null"); - checkArgument(buyerSecurityDeposit <= getMaxBuyerSecurityDepositAsPercent(), + checkArgument(securityDeposit <= getMaxSecurityDepositAsPercent(), "securityDeposit must not exceed " + - getMaxBuyerSecurityDepositAsPercent()); - checkArgument(buyerSecurityDeposit >= getMinBuyerSecurityDepositAsPercent(), + getMaxSecurityDepositAsPercent()); + checkArgument(securityDeposit >= getMinSecurityDepositAsPercent(), "securityDeposit must not be less than " + - getMinBuyerSecurityDepositAsPercent()); + getMinSecurityDepositAsPercent() + " but was " + securityDeposit); checkArgument(!filterManager.isCurrencyBanned(currencyCode), Res.get("offerbook.warning.currencyBanned")); checkArgument(!filterManager.isPaymentMethodBanned(paymentAccount.getPaymentMethod()), diff --git a/core/src/main/java/haveno/core/offer/OpenOffer.java b/core/src/main/java/haveno/core/offer/OpenOffer.java index 0811cb7b01..1f177959f3 100644 --- a/core/src/main/java/haveno/core/offer/OpenOffer.java +++ b/core/src/main/java/haveno/core/offer/OpenOffer.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,8 +34,6 @@ package haveno.core.offer; -import haveno.common.Timer; -import haveno.common.UserThread; import haveno.common.proto.ProtoUtil; import haveno.core.trade.Tradable; import javafx.beans.property.ObjectProperty; @@ -27,7 +42,6 @@ import javafx.beans.property.SimpleObjectProperty; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; -import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; import java.util.ArrayList; @@ -36,14 +50,10 @@ import java.util.List; import java.util.Optional; @EqualsAndHashCode -@Slf4j public final class OpenOffer implements Tradable { - // Timeout for offer reservation during takeoffer process. If deposit tx is not completed in that time we reset the offer to AVAILABLE state. - private static final long TIMEOUT = 60; - transient private Timer timeoutTimer; public enum State { - SCHEDULED, + PENDING, AVAILABLE, RESERVED, CLOSED, @@ -70,6 +80,9 @@ public final class OpenOffer implements Tradable { @Getter @Nullable String splitOutputTxHash; + @Getter + @Setter + long splitOutputTxFee; @Nullable @Setter @Getter @@ -83,12 +96,20 @@ public final class OpenOffer implements Tradable { @Getter private String reserveTxKey; @Getter + @Setter + private String challenge; + @Getter private final long triggerPrice; @Getter @Setter transient private long mempoolStatus = -1; transient final private ObjectProperty<State> stateProperty = new SimpleObjectProperty<>(state); - + @Getter + @Setter + transient boolean isProcessing = false; + @Getter + @Setter + transient int numProcessingAttempts = 0; public OpenOffer(Offer offer) { this(offer, 0, false); } @@ -101,7 +122,8 @@ public final class OpenOffer implements Tradable { this.offer = offer; this.triggerPrice = triggerPrice; this.reserveExactAmount = reserveExactAmount; - state = State.SCHEDULED; + this.challenge = offer.getChallenge(); + state = State.PENDING; } public OpenOffer(Offer offer, long triggerPrice, OpenOffer openOffer) { @@ -114,9 +136,11 @@ public final class OpenOffer implements Tradable { this.scheduledAmount = openOffer.scheduledAmount; this.scheduledTxHashes = openOffer.scheduledTxHashes == null ? null : new ArrayList<String>(openOffer.scheduledTxHashes); this.splitOutputTxHash = openOffer.splitOutputTxHash; + this.splitOutputTxFee = openOffer.splitOutputTxFee; this.reserveTxHash = openOffer.reserveTxHash; this.reserveTxHex = openOffer.reserveTxHex; this.reserveTxKey = openOffer.reserveTxKey; + this.challenge = openOffer.challenge; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -130,21 +154,25 @@ public final class OpenOffer implements Tradable { @Nullable String scheduledAmount, @Nullable List<String> scheduledTxHashes, String splitOutputTxHash, + long splitOutputTxFee, @Nullable String reserveTxHash, @Nullable String reserveTxHex, - @Nullable String reserveTxKey) { + @Nullable String reserveTxKey, + @Nullable String challenge) { this.offer = offer; this.state = state; this.triggerPrice = triggerPrice; this.reserveExactAmount = reserveExactAmount; this.scheduledTxHashes = scheduledTxHashes; this.splitOutputTxHash = splitOutputTxHash; + this.splitOutputTxFee = splitOutputTxFee; this.reserveTxHash = reserveTxHash; this.reserveTxHex = reserveTxHex; this.reserveTxKey = reserveTxKey; + this.challenge = challenge; - if (this.state == State.RESERVED) - setState(State.AVAILABLE); + // reset reserved state to available + if (this.state == State.RESERVED) setState(State.AVAILABLE); } @Override @@ -153,6 +181,7 @@ public final class OpenOffer implements Tradable { .setOffer(offer.toProtoMessage()) .setTriggerPrice(triggerPrice) .setState(protobuf.OpenOffer.State.valueOf(state.name())) + .setSplitOutputTxFee(splitOutputTxFee) .setReserveExactAmount(reserveExactAmount); Optional.ofNullable(scheduledAmount).ifPresent(e -> builder.setScheduledAmount(scheduledAmount)); @@ -161,6 +190,7 @@ public final class OpenOffer implements Tradable { Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash)); Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex)); Optional.ofNullable(reserveTxKey).ifPresent(e -> builder.setReserveTxKey(reserveTxKey)); + Optional.ofNullable(challenge).ifPresent(e -> builder.setChallenge(challenge)); return protobuf.Tradable.newBuilder().setOpenOffer(builder).build(); } @@ -173,9 +203,11 @@ public final class OpenOffer implements Tradable { proto.getScheduledAmount(), proto.getScheduledTxHashesList(), ProtoUtil.stringOrNullFromProto(proto.getSplitOutputTxHash()), - proto.getReserveTxHash(), - proto.getReserveTxHex(), - proto.getReserveTxKey()); + proto.getSplitOutputTxFee(), + ProtoUtil.stringOrNullFromProto(proto.getReserveTxHash()), + ProtoUtil.stringOrNullFromProto(proto.getReserveTxHex()), + ProtoUtil.stringOrNullFromProto(proto.getReserveTxKey()), + ProtoUtil.stringOrNullFromProto(proto.getChallenge())); return openOffer; } @@ -202,21 +234,14 @@ public final class OpenOffer implements Tradable { public void setState(State state) { this.state = state; stateProperty.set(state); - - // We keep it reserved for a limited time, if trade preparation fails we revert to available state - if (this.state == State.RESERVED) { // TODO (woodser): remove this? - startTimeout(); - } else { - stopTimeout(); - } } public ReadOnlyObjectProperty<State> stateProperty() { return stateProperty; } - public boolean isScheduled() { - return state == State.SCHEDULED; + public boolean isPending() { + return state == State.PENDING; } public boolean isAvailable() { @@ -227,32 +252,19 @@ public final class OpenOffer implements Tradable { return state == State.DEACTIVATED; } - private void startTimeout() { - stopTimeout(); - - timeoutTimer = UserThread.runAfter(() -> { - log.debug("Timeout for resetting State.RESERVED reached"); - if (state == State.RESERVED) { - // we do not need to persist that as at startup any RESERVED state would be reset to AVAILABLE anyway - setState(State.AVAILABLE); - } - }, TIMEOUT); + public boolean isCanceled() { + return state == State.CANCELED; } - private void stopTimeout() { - if (timeoutTimer != null) { - timeoutTimer.stop(); - timeoutTimer = null; - } - } - - @Override public String toString() { return "OpenOffer{" + ",\n offer=" + offer + ",\n state=" + state + ",\n triggerPrice=" + triggerPrice + + ",\n reserveExactAmount=" + reserveExactAmount + + ",\n scheduledAmount=" + scheduledAmount + + ",\n splitOutputTxFee=" + splitOutputTxFee + "\n}"; } } diff --git a/core/src/main/java/haveno/core/offer/OpenOfferManager.java b/core/src/main/java/haveno/core/offer/OpenOfferManager.java index a792a41798..86f45566dd 100644 --- a/core/src/main/java/haveno/core/offer/OpenOfferManager.java +++ b/core/src/main/java/haveno/core/offer/OpenOfferManager.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,7 +34,9 @@ package haveno.core.offer; -import common.utils.GenUtils; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import haveno.common.ThreadUtils; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.app.Capabilities; @@ -33,7 +52,7 @@ import haveno.common.proto.persistable.PersistedDataHost; import haveno.common.util.Tuple2; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.api.CoreContext; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.exceptions.TradePriceOutOfToleranceException; import haveno.core.filter.FilterManager; import haveno.core.offer.OfferBookService.OfferBookChangedListener; @@ -43,6 +62,7 @@ import haveno.core.offer.messages.SignOfferRequest; import haveno.core.offer.messages.SignOfferResponse; import haveno.core.offer.placeoffer.PlaceOfferModel; import haveno.core.offer.placeoffer.PlaceOfferProtocol; +import haveno.core.offer.placeoffer.tasks.ValidateOffer; import haveno.core.provider.price.PriceFeedService; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; @@ -51,6 +71,7 @@ import haveno.core.trade.ClosedTradableManager; import haveno.core.trade.HavenoUtils; import haveno.core.trade.TradableList; import haveno.core.trade.handlers.TransactionResultHandler; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.trade.statistics.TradeStatisticsManager; import haveno.core.user.Preferences; import haveno.core.user.User; @@ -58,8 +79,9 @@ import haveno.core.util.JsonUtil; import haveno.core.util.Validator; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.BtcWalletService; -import haveno.core.xmr.wallet.MoneroKeyImageListener; -import haveno.core.xmr.wallet.MoneroKeyImagePoller; +import haveno.core.xmr.wallet.Restrictions; +import haveno.core.xmr.wallet.XmrKeyImageListener; +import haveno.core.xmr.wallet.XmrKeyImagePoller; import haveno.core.xmr.wallet.TradeWalletService; import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessage; @@ -72,30 +94,11 @@ import haveno.network.p2p.P2PService; import haveno.network.p2p.SendDirectMessageListener; import haveno.network.p2p.peers.Broadcaster; import haveno.network.p2p.peers.PeerManager; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import lombok.Getter; -import monero.common.MoneroConnectionManagerListener; -import monero.common.MoneroRpcConnection; -import monero.daemon.model.MoneroKeyImageSpentStatus; -import monero.daemon.model.MoneroTx; -import monero.wallet.model.MoneroIncomingTransfer; -import monero.wallet.model.MoneroOutputQuery; -import monero.wallet.model.MoneroTransferQuery; -import monero.wallet.model.MoneroTxConfig; -import monero.wallet.model.MoneroTxQuery; -import monero.wallet.model.MoneroTxWallet; -import monero.wallet.model.MoneroWalletListener; -import org.jetbrains.annotations.NotNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import javax.inject.Inject; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -105,23 +108,43 @@ import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javax.annotation.Nullable; +import lombok.Getter; +import monero.common.MoneroRpcConnection; +import monero.daemon.model.MoneroKeyImageSpentStatus; +import monero.daemon.model.MoneroTx; +import monero.wallet.model.MoneroIncomingTransfer; +import monero.wallet.model.MoneroOutputQuery; +import monero.wallet.model.MoneroOutputWallet; +import monero.wallet.model.MoneroTransferQuery; +import monero.wallet.model.MoneroTxConfig; +import monero.wallet.model.MoneroTxQuery; +import monero.wallet.model.MoneroTxWallet; +import monero.wallet.model.MoneroWalletListener; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMessageListener, PersistedDataHost { private static final Logger log = LoggerFactory.getLogger(OpenOfferManager.class); + private static final String THREAD_ID = OpenOfferManager.class.getSimpleName(); private static final long RETRY_REPUBLISH_DELAY_SEC = 10; private static final long REPUBLISH_AGAIN_AT_STARTUP_DELAY_SEC = 30; - private static final long REPUBLISH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(40); - private static final long REFRESH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(6); + private static final long REPUBLISH_INTERVAL_MS = TimeUnit.MINUTES.toMillis(30); + private static final long REFRESH_INTERVAL_MS = OfferPayload.TTL / 2; + private static final int NUM_ATTEMPTS_THRESHOLD = 5; // process pending offer only on republish cycle after this many attempts private final CoreContext coreContext; private final KeyRing keyRing; private final User user; private final P2PService p2PService; - private final CoreMoneroConnectionsService connectionsService; + @Getter + private final XmrConnectionService xmrConnectionService; private final BtcWalletService btcWalletService; + @Getter private final XmrWalletService xmrWalletService; private final TradeWalletService tradeWalletService; private final OfferBookService offerBookService; @@ -139,7 +162,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private final SignedOfferList signedOffers = new SignedOfferList(); private final PersistenceManager<SignedOfferList> signedOfferPersistenceManager; private final Map<String, PlaceOfferProtocol> placeOfferProtocols = new HashMap<String, PlaceOfferProtocol>(); - private BigInteger lastUnlockedBalance; private boolean stopped; private Timer periodicRepublishOffersTimer, periodicRefreshOffersTimer, retryRepublishOffersTimer; @Getter @@ -148,7 +170,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe private final AccountAgeWitnessService accountAgeWitnessService; // poll key images of signed offers - private MoneroKeyImagePoller signedOfferKeyImagePoller; + private XmrKeyImagePoller signedOfferKeyImagePoller; + private static final long SHUTDOWN_TIMEOUT_MS = 60000; private static final long KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL = 20000; // 20 seconds private static final long KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE = 300000; // 5 minutes @@ -164,7 +187,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe KeyRing keyRing, User user, P2PService p2PService, - CoreMoneroConnectionsService connectionsService, + XmrConnectionService xmrConnectionService, BtcWalletService btcWalletService, XmrWalletService xmrWalletService, TradeWalletService tradeWalletService, @@ -184,7 +207,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe this.keyRing = keyRing; this.user = user; this.p2PService = p2PService; - this.connectionsService = connectionsService; + this.xmrConnectionService = xmrConnectionService; this.btcWalletService = btcWalletService; this.xmrWalletService = xmrWalletService; this.tradeWalletService = tradeWalletService; @@ -200,25 +223,24 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe this.persistenceManager = persistenceManager; this.signedOfferPersistenceManager = signedOfferPersistenceManager; this.accountAgeWitnessService = accountAgeWitnessService; + HavenoUtils.openOfferManager = this; this.persistenceManager.initialize(openOffers, "OpenOffers", PersistenceManager.Source.PRIVATE); this.signedOfferPersistenceManager.initialize(signedOffers, "SignedOffers", PersistenceManager.Source.PRIVATE); // arbitrator stores reserve tx for signed offers // listen for connection changes to monerod - connectionsService.addConnectionListener(new MoneroConnectionManagerListener() { - @Override - public void onConnectionChanged(MoneroRpcConnection connection) { - maybeInitializeKeyImagePoller(); - } - }); + xmrConnectionService.addConnectionListener((connection) -> maybeInitializeKeyImagePoller()); // close open offer if reserved funds spent offerBookService.addOfferBookChangedListener(new OfferBookChangedListener() { @Override public void onAdded(Offer offer) { + + // cancel offer if reserved funds spent Optional<OpenOffer> openOfferOptional = getOpenOfferById(offer.getId()); if (openOfferOptional.isPresent() && openOfferOptional.get().getState() != OpenOffer.State.RESERVED && offer.isReservedFundsSpent()) { - closeOpenOffer(offer); + log.warn("Canceling open offer because reserved funds have been spent, offerId={}, state={}", offer.getId(), openOfferOptional.get().getState()); + cancelOpenOffer(openOfferOptional.get(), null, null); } } @Override @@ -233,25 +255,25 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // read open offers persistenceManager.readPersisted(persisted -> { - openOffers.setAll(persisted.getList()); - openOffers.forEach(openOffer -> openOffer.getOffer().setPriceFeedService(priceFeedService)); + openOffers.setAll(persisted.getList()); + openOffers.forEach(openOffer -> openOffer.getOffer().setPriceFeedService(priceFeedService)); - // read signed offers - signedOfferPersistenceManager.readPersisted(signedOfferPersisted -> { - signedOffers.setAll(signedOfferPersisted.getList()); - completeHandler.run(); - }, - completeHandler); - }, - completeHandler); + // read signed offers + signedOfferPersistenceManager.readPersisted(signedOfferPersisted -> { + signedOffers.setAll(signedOfferPersisted.getList()); + completeHandler.run(); + }, + completeHandler); + }, + completeHandler); } private synchronized void maybeInitializeKeyImagePoller() { if (signedOfferKeyImagePoller != null) return; - signedOfferKeyImagePoller = new MoneroKeyImagePoller(connectionsService.getDaemon(), getKeyImageRefreshPeriodMs()); + signedOfferKeyImagePoller = new XmrKeyImagePoller(xmrConnectionService.getDaemon(), getKeyImageRefreshPeriodMs()); // handle when key images confirmed spent - signedOfferKeyImagePoller.addListener(new MoneroKeyImageListener() { + signedOfferKeyImagePoller.addListener(new XmrKeyImageListener() { @Override public void onSpentStatusChanged(Map<String, MoneroKeyImageSpentStatus> spentStatuses) { for (Entry<String, MoneroKeyImageSpentStatus> entry : spentStatuses.entrySet()) { @@ -265,13 +287,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // first poll in 5s // TODO: remove? new Thread(() -> { - GenUtils.waitFor(5000); + HavenoUtils.waitFor(5000); signedOfferKeyImagePoller.poll(); }).start(); } private long getKeyImageRefreshPeriodMs() { - return connectionsService.isConnectionLocal() ? KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL : KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE; + return xmrConnectionService.isConnectionLocalHost() ? KEY_IMAGE_REFRESH_PERIOD_MS_LOCAL : KEY_IMAGE_REFRESH_PERIOD_MS_REMOTE; } public void onAllServicesInitialized() { @@ -282,7 +304,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { onBootstrapComplete(); } }); @@ -319,24 +341,43 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe int size = openOffers.size(); log.info("Remove open offers at shutDown. Number of open offers: {}", size); if (offerBookService.isBootstrapped() && size > 0) { - UserThread.execute(() -> { - openOffers.forEach(openOffer -> offerBookService.removeOfferAtShutDown(openOffer.getOffer().getOfferPayload())); + ThreadUtils.execute(() -> { + + // remove offers from offer book + synchronized (openOffers) { + openOffers.forEach(openOffer -> { + if (openOffer.getState() == OpenOffer.State.AVAILABLE) { + offerBookService.removeOfferAtShutDown(openOffer.getOffer().getOfferPayload()); + } + }); + } // Force broadcaster to send out immediately, otherwise we could have a 2 sec delay until the // bundled messages sent out. broadcaster.flush(); - - if (completeHandler != null) { - // For typical number of offers we are tolerant with delay to give enough time to broadcast. - // If number of offers is very high we limit to 3 sec. to not delay other shutdown routines. - int delay = Math.min(3000, size * 200 + 500); - UserThread.runAfter(completeHandler, delay, TimeUnit.MILLISECONDS); - } - }); + // For typical number of offers we are tolerant with delay to give enough time to broadcast. + // If number of offers is very high we limit to 3 sec. to not delay other shutdown routines. + long delayMs = Math.min(3000, size * 200 + 500); + HavenoUtils.waitFor(delayMs); + }, THREAD_ID); } else { broadcaster.flush(); - if (completeHandler != null) - completeHandler.run(); + } + + // shut down thread pool off main thread + ThreadUtils.submitToPool(() -> { + shutDownThreadPool(); + + // invoke completion handler + if (completeHandler != null) completeHandler.run(); + }); + } + + private void shutDownThreadPool() { + try { + ThreadUtils.shutDown(THREAD_ID, SHUTDOWN_TIMEOUT_MS); + } catch (Exception e) { + log.error("Error shutting down OpenOfferManager thread pool", e); } } @@ -401,56 +442,65 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe maybeUpdatePersistedOffers(); - // Republish means we send the complete offer object - republishOffers(); - startPeriodicRepublishOffersTimer(); + // run off user thread so app is not blocked from starting + ThreadUtils.submitToPool(() -> { - // Refresh is started once we get a success from republish + // wait for prices to be available + priceFeedService.awaitExternalPrices(); - // We republish after a bit as it might be that our connected node still has the offer in the data map - // but other peers have it already removed because of expired TTL. - // Those other not directly connected peers would not get the broadcast of the new offer, as the first - // connected peer (seed node) does not broadcast if it has the data in the map. - // To update quickly to the whole network we repeat the republishOffers call after a few seconds when we - // are better connected to the network. There is no guarantee that all peers will receive it but we also - // have our periodic timer, so after that longer interval the offer should be available to all peers. - if (retryRepublishOffersTimer == null) - retryRepublishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, - REPUBLISH_AGAIN_AT_STARTUP_DELAY_SEC); + // process open offers on dedicated thread + ThreadUtils.execute(() -> { - p2PService.getPeerManager().addListener(this); + // Republish means we send the complete offer object + republishOffers(); + startPeriodicRepublishOffersTimer(); - // TODO: add to invalid offers on failure -// openOffers.stream() -// .forEach(openOffer -> OfferUtil.getInvalidMakerFeeTxErrorMessage(openOffer.getOffer(), btcWalletService) -// .ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg)))); + // Refresh is started once we get a success from republish - // process scheduled offers - processScheduledOffers((transaction) -> {}, (errorMessage) -> { - log.warn("Error processing unposted offers: " + errorMessage); - }); + // We republish after a bit as it might be that our connected node still has the offer in the data map + // but other peers have it already removed because of expired TTL. + // Those other not directly connected peers would not get the broadcast of the new offer, as the first + // connected peer (seed node) does not broadcast if it has the data in the map. + // To update quickly to the whole network we repeat the republishOffers call after a few seconds when we + // are better connected to the network. There is no guarantee that all peers will receive it but we also + // have our periodic timer, so after that longer interval the offer should be available to all peers. + if (retryRepublishOffersTimer == null) + retryRepublishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, + REPUBLISH_AGAIN_AT_STARTUP_DELAY_SEC); - // register to process unposted offers when unlocked balance increases - if (xmrWalletService.getWallet() != null) lastUnlockedBalance = xmrWalletService.getWallet().getUnlockedBalance(0); - xmrWalletService.addWalletListener(new MoneroWalletListener() { - @Override - public void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) { - if (lastUnlockedBalance == null || lastUnlockedBalance.compareTo(newUnlockedBalance) < 0) { - processScheduledOffers((transaction) -> {}, (errorMessage) -> { - log.warn("Error processing unposted offers on new unlocked balance: " + errorMessage); // TODO: popup to notify user that offer did not post - }); + p2PService.getPeerManager().addListener(this); + + // TODO: add to invalid offers on failure + // openOffers.stream() + // .forEach(openOffer -> OfferUtil.getInvalidMakerFeeTxErrorMessage(openOffer.getOffer(), btcWalletService) + // .ifPresent(errorMsg -> invalidOffers.add(new Tuple2<>(openOffer, errorMsg)))); + + // process pending offers + processPendingOffers(false, (transaction) -> {}, (errorMessage) -> { + log.warn("Error processing pending offers on bootstrap: " + errorMessage); + }); + + // register to process pending offers on new block + xmrWalletService.addWalletListener(new MoneroWalletListener() { + @Override + public void onNewBlock(long height) { + + // process each pending offer on new block a few times, then rely on period republish + processPendingOffers(true, (transaction) -> {}, (errorMessage) -> { + log.warn("Error processing pending offers on new block {}: {}", height, errorMessage); + }); + } + }); + + // initialize key image poller for signed offers + maybeInitializeKeyImagePoller(); + + // poll spent status of key images + for (SignedOffer signedOffer : signedOffers.getList()) { + signedOfferKeyImagePoller.addKeyImages(signedOffer.getReserveTxKeyImages()); } - lastUnlockedBalance = newUnlockedBalance; - } + }, THREAD_ID); }); - - // initialize key image poller for signed offers - maybeInitializeKeyImagePoller(); - - // poll spent status of key images - for (SignedOffer signedOffer : signedOffers.getList()) { - signedOfferKeyImagePoller.addKeyImages(signedOffer.getReserveTxKeyImages()); - } } @@ -493,32 +543,33 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe boolean useSavingsWallet, long triggerPrice, boolean reserveExactAmount, + boolean resetAddressEntriesOnError, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - checkNotNull(offer.getMakerFee(), "makerFee must not be null"); // create open offer OpenOffer openOffer = new OpenOffer(offer, triggerPrice, reserveExactAmount); // schedule or post offer - new Thread(() -> { + ThreadUtils.execute(() -> { synchronized (processOffersLock) { CountDownLatch latch = new CountDownLatch(1); - processUnpostedOffer(getOpenOffers(), openOffer, (transaction) -> { - addOpenOffer(openOffer); + addOpenOffer(openOffer); + processPendingOffer(getOpenOffers(), openOffer, (transaction) -> { requestPersistence(); latch.countDown(); resultHandler.handleResult(transaction); }, (errorMessage) -> { - log.warn("Error processing unposted offer {}: {}", openOffer.getId(), errorMessage); - onCancelled(openOffer); - offer.setErrorMessage(errorMessage); + if (!openOffer.isCanceled()) { + log.warn("Error processing pending offer {}: {}", openOffer.getId(), errorMessage); + doCancelOffer(openOffer, resetAddressEntriesOnError); + } latch.countDown(); errorMessageHandler.handleErrorMessage(errorMessage); }); HavenoUtils.awaitLatch(latch); } - }).start(); + }, THREAD_ID); } // Remove from offerbook @@ -536,9 +587,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe public void activateOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - if (openOffer.isScheduled()) { - resultHandler.handleResult(); // ignore if scheduled - } else if (!offersToBeEdited.containsKey(openOffer.getId())) { + if (openOffer.isPending()) { + resultHandler.handleResult(); // ignore if pending + } else if (offersToBeEdited.containsKey(openOffer.getId())) { + errorMessageHandler.handleErrorMessage("You can't activate an offer that is currently edited."); + } else { Offer offer = openOffer.getOffer(); offerBookService.activateOffer(offer, () -> { @@ -548,8 +601,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe resultHandler.handleResult(); }, errorMessageHandler); - } else { - errorMessageHandler.handleErrorMessage("You can't activate an offer that is currently edited."); } } @@ -574,16 +625,27 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe public void cancelOpenOffer(OpenOffer openOffer, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + log.info("Canceling open offer: {}", openOffer.getId()); if (!offersToBeEdited.containsKey(openOffer.getId())) { - if (openOffer.isDeactivated()) { - onCancelled(openOffer); - } else { + if (openOffer.isAvailable()) { + openOffer.setState(OpenOffer.State.CANCELED); offerBookService.removeOffer(openOffer.getOffer().getOfferPayload(), - () -> onCancelled(openOffer), + () -> { + ThreadUtils.submitToPool(() -> { // TODO: this runs off thread and then shows popup when done. should show overlay spinner until done + doCancelOffer(openOffer); + if (resultHandler != null) resultHandler.handleResult(); + }); + }, errorMessageHandler); + } else { + openOffer.setState(OpenOffer.State.CANCELED); + ThreadUtils.submitToPool(() -> { + doCancelOffer(openOffer); + if (resultHandler != null) resultHandler.handleResult(); + }); } } else { - errorMessageHandler.handleErrorMessage("You can't remove an offer that is currently edited."); + if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage("You can't remove an offer that is currently edited."); } } @@ -630,7 +692,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe addOpenOffer(editedOpenOffer); if (editedOpenOffer.isAvailable()) - republishOffer(editedOpenOffer); + maybeRepublishOffer(editedOpenOffer); offersToBeEdited.remove(openOffer.getId()); requestPersistence(); @@ -656,20 +718,20 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } } + private void doCancelOffer(OpenOffer openOffer) { + doCancelOffer(openOffer, true); + } + // remove open offer which thaws its key images - private void onCancelled(@NotNull OpenOffer openOffer) { + private void doCancelOffer(@NotNull OpenOffer openOffer, boolean resetAddressEntries) { Offer offer = openOffer.getOffer(); - if (offer.getOfferPayload().getReserveTxKeyImages() != null) { - xmrWalletService.thawOutputs(offer.getOfferPayload().getReserveTxKeyImages()); - xmrWalletService.saveMainWallet(); - } offer.setState(Offer.State.REMOVED); openOffer.setState(OpenOffer.State.CANCELED); - removeOpenOffer(openOffer); - closedTradableManager.add(openOffer); - xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId()); - log.info("onRemoved offerId={}", offer.getId()); + removeOpenOffer(openOffer); + closedTradableManager.add(openOffer); // TODO: don't add these to closed tradables? + if (resetAddressEntries) xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId()); requestPersistence(); + xmrWalletService.thawOutputs(offer.getOfferPayload().getReserveTxKeyImages()); } // close open offer after key images spent @@ -743,6 +805,10 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } } + public boolean hasOpenOffer(String offerId) { + return getOpenOfferById(offerId).isPresent(); + } + public Optional<SignedOffer> getSignedOfferById(String offerId) { synchronized (signedOffers) { return signedOffers.stream().filter(e -> e.getOfferId().equals(offerId)).findFirst(); @@ -750,19 +816,25 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } private void addOpenOffer(OpenOffer openOffer) { + log.info("Adding open offer {}", openOffer.getId()); synchronized (openOffers) { openOffers.add(openOffer); } } private void removeOpenOffer(OpenOffer openOffer) { + log.info("Removing open offer {}", openOffer.getId()); synchronized (openOffers) { openOffers.remove(openOffer); } + synchronized (placeOfferProtocols) { + PlaceOfferProtocol protocol = placeOfferProtocols.remove(openOffer.getId()); + if (protocol != null) protocol.cancelOffer(); + } } private void addSignedOffer(SignedOffer signedOffer) { - log.info("Adding SignedOffer offer for offer {}", signedOffer.getOfferId()); + log.info("Adding SignedOffer for offer {}", signedOffer.getOfferId()); synchronized (signedOffers) { // remove signed offers with common key images @@ -792,41 +864,69 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } } - public boolean hasAvailableOutput(BigInteger amount) { - return findSplitOutputFundingTx(getOpenOffers(), null, amount, null) != null; - } - /////////////////////////////////////////////////////////////////////////////////////////// // Place offer helpers /////////////////////////////////////////////////////////////////////////////////////////// - - private void processScheduledOffers(TransactionResultHandler resultHandler, // TODO (woodser): transaction not needed with result handler + private void processPendingOffers(boolean skipOffersWithTooManyAttempts, + TransactionResultHandler resultHandler, // TODO (woodser): transaction not needed with result handler ErrorMessageHandler errorMessageHandler) { - new Thread(() -> { + ThreadUtils.execute(() -> { + List<String> errorMessages = new ArrayList<String>(); synchronized (processOffersLock) { - List<String> errorMessages = new ArrayList<String>(); List<OpenOffer> openOffers = getOpenOffers(); - for (OpenOffer scheduledOffer : openOffers) { - if (scheduledOffer.getState() != OpenOffer.State.SCHEDULED) continue; + for (OpenOffer pendingOffer : openOffers) { + if (pendingOffer.getState() != OpenOffer.State.PENDING) continue; + if (skipOffersWithTooManyAttempts && pendingOffer.getNumProcessingAttempts() > NUM_ATTEMPTS_THRESHOLD) continue; // skip offers with too many attempts CountDownLatch latch = new CountDownLatch(1); - processUnpostedOffer(openOffers, scheduledOffer, (transaction) -> { + processPendingOffer(openOffers, pendingOffer, (transaction) -> { latch.countDown(); }, errorMessage -> { - log.warn("Error processing unposted offer {}: {}", scheduledOffer.getId(), errorMessage); - onCancelled(scheduledOffer); - errorMessages.add(errorMessage); + if (!pendingOffer.isCanceled()) { + String warnMessage = "Error processing pending offer, offerId=" + pendingOffer.getId() + ", attempt=" + pendingOffer.getNumProcessingAttempts() + ": " + errorMessage; + errorMessages.add(warnMessage); + + // cancel offer if invalid + if (pendingOffer.getOffer().getState() == Offer.State.INVALID) { + log.warn("Canceling offer because it's invalid: {}", pendingOffer.getId()); + doCancelOffer(pendingOffer); + } + } latch.countDown(); }); HavenoUtils.awaitLatch(latch); } - requestPersistence(); - if (errorMessages.size() > 0) errorMessageHandler.handleErrorMessage(errorMessages.toString()); - else resultHandler.handleResult(null); } - }).start(); + requestPersistence(); + if (errorMessages.isEmpty()) { + if (resultHandler != null) resultHandler.handleResult(null); + } else { + if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage(errorMessages.toString()); + } + }, THREAD_ID); } - private void processUnpostedOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + private void processPendingOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + + // skip if already processing + if (openOffer.isProcessing()) { + resultHandler.handleResult(null); + return; + } + + // process offer + openOffer.setProcessing(true); + doProcessPendingOffer(openOffers, openOffer, (transaction) -> { + openOffer.setProcessing(false); + resultHandler.handleResult(transaction); + }, (errorMsg) -> { + openOffer.setProcessing(false); + openOffer.setNumProcessingAttempts(openOffer.getNumProcessingAttempts() + 1); + openOffer.getOffer().setErrorMessage(errorMsg); + errorMessageHandler.handleErrorMessage(errorMsg); + }); + } + + private void doProcessPendingOffer(List<OpenOffer> openOffers, OpenOffer openOffer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { new Thread(() -> { try { @@ -836,45 +936,69 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe return; } - // get offer reserve amount - BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount(); - + // validate offer + try { + ValidateOffer.validateOffer(openOffer.getOffer(), accountAgeWitnessService, user); + } catch (Exception e) { + errorMessageHandler.handleErrorMessage("Failed to validate offer: " + e.getMessage()); + return; + } + + // cancel offer if scheduled txs unavailable + if (openOffer.getScheduledTxHashes() != null) { + boolean scheduledTxsAvailable = true; + for (MoneroTxWallet tx : xmrWalletService.getTxs(openOffer.getScheduledTxHashes())) { + if (!tx.isLocked() && !isOutputsAvailable(tx)) { + scheduledTxsAvailable = false; + break; + } + } + if (!scheduledTxsAvailable) { + log.warn("Canceling offer {} because scheduled txs are no longer available", openOffer.getId()); + doCancelOffer(openOffer); + resultHandler.handleResult(null); + return; + } + } + + // get amount needed to reserve offer + BigInteger amountNeeded = openOffer.getOffer().getAmountNeeded(); + // handle split output offer if (openOffer.isReserveExactAmount()) { // find tx with exact input amount - MoneroTxWallet splitOutputTx = findSplitOutputFundingTx(openOffers, openOffer); - if (splitOutputTx != null && openOffer.getScheduledTxHashes() == null) { - openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash())); - openOffer.setScheduledAmount(offerReserveAmount.toString()); - openOffer.setState(OpenOffer.State.SCHEDULED); + MoneroTxWallet splitOutputTx = getSplitOutputFundingTx(openOffers, openOffer); + if (splitOutputTx != null && openOffer.getSplitOutputTxHash() == null) { + setSplitOutputTx(openOffer, splitOutputTx); } // if not found, create tx to split exact output if (splitOutputTx == null) { - splitOrSchedule(openOffers, openOffer, offerReserveAmount); + if (openOffer.getSplitOutputTxHash() != null) { + log.warn("Split output tx unexpectedly unavailable for offer, offerId={}, split output tx={}", openOffer.getId(), openOffer.getSplitOutputTxHash()); + setSplitOutputTx(openOffer, null); + } + try { + splitOrSchedule(openOffers, openOffer, amountNeeded); + } catch (Exception e) { + log.warn("Unable to split or schedule funds for offer {}: {}", openOffer.getId(), e.getMessage()); + openOffer.getOffer().setState(Offer.State.INVALID); + errorMessageHandler.handleErrorMessage(e.getMessage()); + return; + } } else if (!splitOutputTx.isLocked()) { // otherwise sign and post offer if split output available - signAndPostOffer(openOffer, true, resultHandler, (errMsg) -> { - - // on error, create split output tx if not already created - if (openOffer.getSplitOutputTxHash() == null) { - int offerSubaddress = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).getSubaddressIndex(); - log.warn("Splitting new output because spending scheduled output(s) failed for offer {}. Split output tx subaddresses={}. Offer funding subadress={}", openOffer.getId(), splitOutputTx.getOutgoingTransfer().getSubaddressIndices(), offerSubaddress); - splitOrSchedule(openOffers, openOffer, offerReserveAmount); - resultHandler.handleResult(null); - } else { - errorMessageHandler.handleErrorMessage(errMsg); - } - }); + signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler); return; } } else { - // handle sufficient balance - boolean hasSufficientBalance = xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0; - if (hasSufficientBalance) { + // sign and post offer if enough funds + boolean hasFundsReserved = openOffer.getReserveTxHash() != null; + boolean hasSufficientBalance = xmrWalletService.getAvailableBalance().compareTo(amountNeeded) >= 0; + if (hasFundsReserved || hasSufficientBalance) { signAndPostOffer(openOffer, true, resultHandler, errorMessageHandler); return; } else if (openOffer.getScheduledTxHashes() == null) { @@ -885,107 +1009,104 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // handle result resultHandler.handleResult(null); } catch (Exception e) { - e.printStackTrace(); + if (!openOffer.isCanceled()) log.error("Error processing pending offer: {}\n", e.getMessage(), e); errorMessageHandler.handleErrorMessage(e.getMessage()); } }).start(); } - private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer) { + private MoneroTxWallet getSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer) { XmrAddressEntry addressEntry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); - return findSplitOutputFundingTx(openOffers, openOffer, openOffer.getOffer().getReserveAmount(), addressEntry.getSubaddressIndex()); + return getSplitOutputFundingTx(openOffers, openOffer, openOffer.getOffer().getAmountNeeded(), addressEntry.getSubaddressIndex()); } - private MoneroTxWallet findSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger reserveAmount, Integer preferredSubaddressIndex) { - List<MoneroTxWallet> fundingTxs = new ArrayList<>(); - MoneroTxWallet earliestUnscheduledTx = null; + private MoneroTxWallet getSplitOutputFundingTx(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger reserveAmount, Integer preferredSubaddressIndex) { // return split output tx if already assigned if (openOffer != null && openOffer.getSplitOutputTxHash() != null) { - return xmrWalletService.getWallet().getTx(openOffer.getSplitOutputTxHash()); - } - // return earliest tx with exact amount to offer's subaddress if available - if (preferredSubaddressIndex != null) { + // get recorded split output tx + MoneroTxWallet splitOutputTx = xmrWalletService.getTx(openOffer.getSplitOutputTxHash()); - // get txs with exact output amount - fundingTxs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery() - .setIsConfirmed(true) - .setOutputQuery(new MoneroOutputQuery() - .setAccountIndex(0) - .setSubaddressIndex(preferredSubaddressIndex) - .setAmount(reserveAmount) - .setIsSpent(false) - .setIsFrozen(false))); - - // return earliest tx if available - earliestUnscheduledTx = getEarliestUnscheduledTx(openOffers, fundingTxs); - if (earliestUnscheduledTx != null) return earliestUnscheduledTx; - } - - // return scheduled tx if already assigned - if (openOffer.getScheduledTxHashes() != null) { - return xmrWalletService.getWallet().getTx(openOffer.getScheduledTxHashes().get(0)); - } - - // cache all transactions including from pool - List<MoneroTxWallet> allTxs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery().setIncludeOutputs(true)); - - if (preferredSubaddressIndex != null) { - - // return earliest tx with exact incoming transfer to fund offer's subaddress if available (since outputs are not available until confirmed) - fundingTxs.clear(); - for (MoneroTxWallet tx : allTxs) { - boolean hasExactTransfer = tx.getTransfers(new MoneroTransferQuery() - .setIsIncoming(true) - .setAccountIndex(0) - .setSubaddressIndex(preferredSubaddressIndex) - .setAmount(reserveAmount)).size() > 0; - if (hasExactTransfer) fundingTxs.add(tx); + // check if split output tx is available for offer + if (splitOutputTx.isLocked()) return splitOutputTx; + else { + boolean isAvailable = true; + for (MoneroOutputWallet output : splitOutputTx.getOutputsWallet()) { + if (output.isSpent() || output.isFrozen()) { + isAvailable = false; + break; + } + } + if (isAvailable || isReservedByOffer(openOffer, splitOutputTx)) return splitOutputTx; + else log.warn("Split output tx is no longer available for offer {}", openOffer.getId()); } - earliestUnscheduledTx = getEarliestUnscheduledTx(openOffers, fundingTxs); + } + + // get split output tx to offer's preferred subaddress + if (preferredSubaddressIndex != null) { + List<MoneroTxWallet> fundingTxs = getSplitOutputFundingTxs(reserveAmount, preferredSubaddressIndex); + MoneroTxWallet earliestUnscheduledTx = getEarliestUnscheduledTx(openOffers, openOffer, fundingTxs); if (earliestUnscheduledTx != null) return earliestUnscheduledTx; } - // return earliest tx with exact confirmed output to any subaddress if available - fundingTxs.clear(); - for (MoneroTxWallet tx : allTxs) { - boolean hasExactOutput = tx.getOutputsWallet(new MoneroOutputQuery() - .setAccountIndex(0) - .setAmount(reserveAmount) - .setIsSpent(false) - .setIsFrozen(false)).size() > 0; - if (hasExactOutput) fundingTxs.add(tx); - } - earliestUnscheduledTx = getEarliestUnscheduledTx(openOffers, fundingTxs); - if (earliestUnscheduledTx != null) return earliestUnscheduledTx; - - // return earliest tx with exact incoming transfer to any subaddress if available (since outputs are not available until confirmed) - fundingTxs.clear(); - for (MoneroTxWallet tx : allTxs) { - boolean hasExactTransfer = tx.getTransfers(new MoneroTransferQuery() - .setIsIncoming(true) - .setAccountIndex(0) - .setAmount(reserveAmount)).size() > 0; - if (hasExactTransfer) fundingTxs.add(tx); - } - return getEarliestUnscheduledTx(openOffers, fundingTxs); + // get split output tx to any subaddress + List<MoneroTxWallet> fundingTxs = getSplitOutputFundingTxs(reserveAmount, null); + return getEarliestUnscheduledTx(openOffers, openOffer, fundingTxs); } - private MoneroTxWallet getEarliestUnscheduledTx(List<OpenOffer> openOffers, List<MoneroTxWallet> txs) { + private boolean isReservedByOffer(OpenOffer openOffer, MoneroTxWallet tx) { + if (openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() == null) return false; + Set<String> offerKeyImages = new HashSet<String>(openOffer.getOffer().getOfferPayload().getReserveTxKeyImages()); + for (MoneroOutputWallet output : tx.getOutputsWallet()) { + if (offerKeyImages.contains(output.getKeyImage().getHex())) return true; + } + return false; + } + + private List<MoneroTxWallet> getSplitOutputFundingTxs(BigInteger reserveAmount, Integer preferredSubaddressIndex) { + List<MoneroTxWallet> splitOutputTxs = xmrWalletService.getTxs(new MoneroTxQuery().setIsIncoming(true).setIsFailed(false)); + Set<MoneroTxWallet> removeTxs = new HashSet<MoneroTxWallet>(); + for (MoneroTxWallet tx : splitOutputTxs) { + if (tx.getOutputs() != null) { // outputs not available until first confirmation + for (MoneroOutputWallet output : tx.getOutputsWallet()) { + if (output.isSpent() || output.isFrozen()) removeTxs.add(tx); + } + } + if (!hasExactAmount(tx, reserveAmount, preferredSubaddressIndex)) removeTxs.add(tx); + } + splitOutputTxs.removeAll(removeTxs); + return splitOutputTxs; + } + + private boolean hasExactAmount(MoneroTxWallet tx, BigInteger amount, Integer preferredSubaddressIndex) { + boolean hasExactOutput = (tx.getOutputsWallet(new MoneroOutputQuery() + .setAccountIndex(0) + .setSubaddressIndex(preferredSubaddressIndex) + .setAmount(amount)).size() > 0); + if (hasExactOutput) return true; + boolean hasExactTransfer = (tx.getTransfers(new MoneroTransferQuery() + .setAccountIndex(0) + .setSubaddressIndex(preferredSubaddressIndex) + .setAmount(amount)).size() > 0); + return hasExactTransfer; + } + + private MoneroTxWallet getEarliestUnscheduledTx(List<OpenOffer> openOffers, OpenOffer excludeOpenOffer, List<MoneroTxWallet> txs) { MoneroTxWallet earliestUnscheduledTx = null; for (MoneroTxWallet tx : txs) { - if (isTxScheduled(openOffers, tx.getHash())) continue; + if (isTxScheduledByOtherOffer(openOffers, excludeOpenOffer, tx.getHash())) continue; if (earliestUnscheduledTx == null || (earliestUnscheduledTx.getNumConfirmations() < tx.getNumConfirmations())) earliestUnscheduledTx = tx; } return earliestUnscheduledTx; } private void splitOrSchedule(List<OpenOffer> openOffers, OpenOffer openOffer, BigInteger offerReserveAmount) { - + // handle sufficient available balance to split output - boolean sufficientAvailableBalance = xmrWalletService.getWallet().getUnlockedBalance(0).compareTo(offerReserveAmount) >= 0; - if (sufficientAvailableBalance) { + boolean sufficientAvailableBalance = xmrWalletService.getAvailableBalance().compareTo(offerReserveAmount) >= 0; + if (sufficientAvailableBalance && openOffer.getSplitOutputTxHash() == null) { + log.info("Splitting and scheduling outputs for offer {}", openOffer.getShortId()); splitAndSchedule(openOffer); } else if (openOffer.getScheduledTxHashes() == null) { scheduleWithEarliestTxs(openOffers, openOffer); @@ -993,63 +1114,100 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } private MoneroTxWallet splitAndSchedule(OpenOffer openOffer) { - BigInteger reserveAmount = openOffer.getOffer().getReserveAmount(); + BigInteger reserveAmount = openOffer.getOffer().getAmountNeeded(); xmrWalletService.swapAddressEntryToAvailable(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); // change funding subaddress in case funded with unsuitable output(s) - XmrAddressEntry entry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); - log.info("Creating split output tx to fund offer {} at subaddress {}", openOffer.getId(), entry.getSubaddressIndex()); - MoneroTxWallet splitOutputTx = xmrWalletService.getWallet().createTx(new MoneroTxConfig() - .setAccountIndex(0) - .setAddress(entry.getAddressString()) - .setAmount(reserveAmount) - .setRelay(true) - .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); - log.info("Done creating split output tx to fund offer {}", openOffer.getId()); + MoneroTxWallet splitOutputTx = null; + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { + XmrAddressEntry entry = xmrWalletService.getOrCreateAddressEntry(openOffer.getId(), XmrAddressEntry.Context.OFFER_FUNDING); + synchronized (HavenoUtils.getWalletFunctionLock()) { + long startTime = System.currentTimeMillis(); + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + log.info("Creating split output tx to fund offer {} at subaddress {}", openOffer.getShortId(), entry.getSubaddressIndex()); + splitOutputTx = xmrWalletService.createTx(new MoneroTxConfig() + .setAccountIndex(0) + .setAddress(entry.getAddressString()) + .setAmount(reserveAmount) + .setRelay(true) + .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); + break; + } catch (Exception e) { + if (e.getMessage().contains("not enough")) throw e; // do not retry if not enough funds + log.warn("Error creating split output tx to fund offer, offerId={}, subaddress={}, attempt={}/{}, error={}", openOffer.getShortId(), entry.getSubaddressIndex(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + xmrWalletService.handleWalletError(e, sourceConnection); + if (stopped || i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } + log.info("Done creating split output tx to fund offer {} in {} ms", openOffer.getId(), System.currentTimeMillis() - startTime); + } + } - // schedule txs - openOffer.setScheduledTxHashes(Arrays.asList(splitOutputTx.getHash())); - openOffer.setSplitOutputTxHash(splitOutputTx.getHash()); - openOffer.setScheduledAmount(openOffer.getOffer().getReserveAmount().toString()); - openOffer.setState(OpenOffer.State.SCHEDULED); + // set split tx + setSplitOutputTx(openOffer, splitOutputTx); return splitOutputTx; } + private void setSplitOutputTx(OpenOffer openOffer, MoneroTxWallet splitOutputTx) { + openOffer.setSplitOutputTxHash(splitOutputTx == null ? null : splitOutputTx.getHash()); + openOffer.setSplitOutputTxFee(splitOutputTx == null ? 0l : splitOutputTx.getFee().longValueExact()); + openOffer.setScheduledTxHashes(splitOutputTx == null ? null : Arrays.asList(splitOutputTx.getHash())); + openOffer.setScheduledAmount(splitOutputTx == null ? null : openOffer.getOffer().getAmountNeeded().toString()); + if (!openOffer.isCanceled()) openOffer.setState(OpenOffer.State.PENDING); + } + private void scheduleWithEarliestTxs(List<OpenOffer> openOffers, OpenOffer openOffer) { // check for sufficient balance - scheduled offers amount - BigInteger offerReserveAmount = openOffer.getOffer().getReserveAmount(); - if (xmrWalletService.getWallet().getBalance(0).subtract(getScheduledAmount(openOffers)).compareTo(offerReserveAmount) < 0) { + BigInteger offerReserveAmount = openOffer.getOffer().getAmountNeeded(); + if (xmrWalletService.getBalance().subtract(getScheduledAmount(openOffers)).compareTo(offerReserveAmount) < 0) { throw new RuntimeException("Not enough money in Haveno wallet"); } - // get locked txs - List<MoneroTxWallet> lockedTxs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery().setIsLocked(true)); + // get earliest available or pending txs with sufficient incoming amount + BigInteger scheduledAmount = BigInteger.ZERO; + Set<MoneroTxWallet> scheduledTxs = new HashSet<MoneroTxWallet>(); + for (MoneroTxWallet tx : xmrWalletService.getTxs()) { - // get earliest unscheduled txs with sufficient incoming amount - List<String> scheduledTxHashes = new ArrayList<String>(); - BigInteger scheduledAmount = BigInteger.valueOf(0); - for (MoneroTxWallet lockedTx : lockedTxs) { - if (isTxScheduled(openOffers, lockedTx.getHash())) continue; - if (lockedTx.getIncomingTransfers() == null || lockedTx.getIncomingTransfers().isEmpty()) continue; - scheduledTxHashes.add(lockedTx.getHash()); - for (MoneroIncomingTransfer transfer : lockedTx.getIncomingTransfers()) { - if (transfer.getAccountIndex() == 0) scheduledAmount = scheduledAmount.add(transfer.getAmount()); + // skip if no funds available + BigInteger sentToSelfAmount = xmrWalletService.getAmountSentToSelf(tx); // amount sent to self always shows 0, so compute from destinations manually + if (sentToSelfAmount.equals(BigInteger.ZERO) && (tx.getIncomingTransfers() == null || tx.getIncomingTransfers().isEmpty())) continue; + if (!isOutputsAvailable(tx)) continue; + if (isTxScheduledByOtherOffer(openOffers, openOffer, tx.getHash())) continue; + + // schedule transaction if funds sent to self, because they are not included in incoming transfers // TODO: fix in libraries? + if (sentToSelfAmount.compareTo(BigInteger.ZERO) > 0) { + scheduledAmount = scheduledAmount.add(sentToSelfAmount); + scheduledTxs.add(tx); + } else if (tx.getIncomingTransfers() != null) { + + // schedule transaction if incoming tranfers to account 0 + for (MoneroIncomingTransfer transfer : tx.getIncomingTransfers()) { + if (transfer.getAccountIndex() == 0) { + scheduledAmount = scheduledAmount.add(transfer.getAmount()); + scheduledTxs.add(tx); + } + } } + + // break if sufficient funds if (scheduledAmount.compareTo(offerReserveAmount) >= 0) break; } if (scheduledAmount.compareTo(offerReserveAmount) < 0) throw new RuntimeException("Not enough funds to schedule offer"); // schedule txs - openOffer.setScheduledTxHashes(scheduledTxHashes); + openOffer.setScheduledTxHashes(scheduledTxs.stream().map(tx -> tx.getHash()).collect(Collectors.toList())); openOffer.setScheduledAmount(scheduledAmount.toString()); - openOffer.setState(OpenOffer.State.SCHEDULED); + openOffer.setState(OpenOffer.State.PENDING); } private BigInteger getScheduledAmount(List<OpenOffer> openOffers) { - BigInteger scheduledAmount = BigInteger.valueOf(0); + BigInteger scheduledAmount = BigInteger.ZERO; for (OpenOffer openOffer : openOffers) { - if (openOffer.getState() != OpenOffer.State.SCHEDULED) continue; + if (openOffer.getState() != OpenOffer.State.PENDING) continue; if (openOffer.getScheduledTxHashes() == null) continue; - List<MoneroTxWallet> fundingTxs = xmrWalletService.getWallet().getTxs(openOffer.getScheduledTxHashes()); + List<MoneroTxWallet> fundingTxs = xmrWalletService.getTxs(openOffer.getScheduledTxHashes()); for (MoneroTxWallet fundingTx : fundingTxs) { if (fundingTx.getIncomingTransfers() != null) { for (MoneroIncomingTransfer transfer : fundingTx.getIncomingTransfers()) { @@ -1061,17 +1219,28 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe return scheduledAmount; } - private boolean isTxScheduled(List<OpenOffer> openOffers, String txHash) { - for (OpenOffer openOffer : openOffers) { - if (openOffer.getState() != OpenOffer.State.SCHEDULED) continue; - if (openOffer.getScheduledTxHashes() == null) continue; - for (String scheduledTxHash : openOffer.getScheduledTxHashes()) { - if (txHash.equals(scheduledTxHash)) return true; + private boolean isTxScheduledByOtherOffer(List<OpenOffer> openOffers, OpenOffer openOffer, String txHash) { + for (OpenOffer otherOffer : openOffers) { + if (otherOffer == openOffer) continue; + if (otherOffer.getState() != OpenOffer.State.PENDING) continue; + if (txHash.equals(otherOffer.getSplitOutputTxHash())) return true; + if (otherOffer.getScheduledTxHashes() != null) { + for (String scheduledTxHash : otherOffer.getScheduledTxHashes()) { + if (txHash.equals(scheduledTxHash)) return true; + } } } return false; } + private boolean isOutputsAvailable(MoneroTxWallet tx) { + if (tx.getOutputsWallet() == null) return false; + for (MoneroOutputWallet output : tx.getOutputsWallet()) { + if (output.isSpent() || output.isFrozen()) return false; + } + return true; + } + private void signAndPostOffer(OpenOffer openOffer, boolean useSavingsWallet, // TODO: remove this? TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { @@ -1079,7 +1248,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // create model PlaceOfferModel model = new PlaceOfferModel(openOffer, - openOffer.getOffer().getReserveAmount(), + openOffer.getOffer().getAmountNeeded(), useSavingsWallet, p2PService, btcWalletService, @@ -1092,17 +1261,13 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe user, keyRing, filterManager, - accountAgeWitnessService); + accountAgeWitnessService, + this); // create protocol PlaceOfferProtocol placeOfferProtocol = new PlaceOfferProtocol(model, transaction -> { - // set reserve tx on open offer - openOffer.setReserveTxHash(model.getReserveTx().getHash()); - openOffer.setReserveTxHex(model.getReserveTx().getFullHex()); - openOffer.setReserveTxKey(model.getReserveTx().getKey()); - // set offer state openOffer.setState(OpenOffer.State.AVAILABLE); openOffer.setScheduledTxHashes(null); @@ -1143,7 +1308,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe NodeAddress thisAddress = p2PService.getNetworkNode().getNodeAddress(); if (thisArbitrator == null || !thisArbitrator.getNodeAddress().equals(thisAddress)) { errorMessage = "Cannot sign offer because we are not a registered arbitrator"; - log.info(errorMessage); + log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; } @@ -1151,28 +1316,116 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // verify arbitrator is signer of offer payload if (!thisAddress.equals(request.getOfferPayload().getArbitratorSigner())) { errorMessage = "Cannot sign offer because offer payload is for a different arbitrator"; - log.info(errorMessage); + log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; } - // verify maker's trade fee + // private offers must have challenge hash Offer offer = new Offer(request.getOfferPayload()); - BigInteger tradeFee = HavenoUtils.getMakerFee(offer.getAmount()); - if (!tradeFee.equals(offer.getMakerFee())) { - errorMessage = "Wrong trade fee for offer " + request.offerId; - log.info(errorMessage); + if (offer.isPrivateOffer() && (offer.getChallengeHash() == null || offer.getChallengeHash().length() == 0)) { + errorMessage = "Private offer must have challenge hash for offer " + request.offerId; + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify maker and taker fees + boolean hasBuyerAsTakerWithoutDeposit = offer.getDirection() == OfferDirection.SELL && offer.isPrivateOffer() && offer.getChallengeHash() != null && offer.getChallengeHash().length() > 0 && offer.getTakerFeePct() == 0; + if (hasBuyerAsTakerWithoutDeposit) { + + // verify maker's trade fee + if (offer.getMakerFeePct() != HavenoUtils.MAKER_FEE_FOR_TAKER_WITHOUT_DEPOSIT_PCT) { + errorMessage = "Wrong maker fee for offer " + request.offerId; + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify taker's trade fee + if (offer.getTakerFeePct() != 0) { + errorMessage = "Wrong taker fee for offer " + request.offerId + ". Expected 0 but got " + offer.getTakerFeePct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify maker security deposit + if (offer.getSellerSecurityDepositPct() != Restrictions.MIN_SECURITY_DEPOSIT_PCT) { + errorMessage = "Wrong seller security deposit for offer " + request.offerId + ". Expected " + Restrictions.MIN_SECURITY_DEPOSIT_PCT + " but got " + offer.getSellerSecurityDepositPct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify taker's security deposit + if (offer.getBuyerSecurityDepositPct() != 0) { + errorMessage = "Wrong buyer security deposit for offer " + request.offerId + ". Expected 0 but got " + offer.getBuyerSecurityDepositPct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + } else { + + // verify maker's trade fee + if (offer.getMakerFeePct() != HavenoUtils.MAKER_FEE_PCT) { + errorMessage = "Wrong maker fee for offer " + request.offerId; + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify taker's trade fee + if (offer.getTakerFeePct() != HavenoUtils.TAKER_FEE_PCT) { + errorMessage = "Wrong taker fee for offer " + request.offerId + ". Expected " + HavenoUtils.TAKER_FEE_PCT + " but got " + offer.getTakerFeePct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify seller's security deposit + if (offer.getSellerSecurityDepositPct() < Restrictions.MIN_SECURITY_DEPOSIT_PCT) { + errorMessage = "Insufficient seller security deposit for offer " + request.offerId + ". Expected at least " + Restrictions.MIN_SECURITY_DEPOSIT_PCT + " but got " + offer.getSellerSecurityDepositPct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // verify buyer's security deposit + if (offer.getBuyerSecurityDepositPct() < Restrictions.MIN_SECURITY_DEPOSIT_PCT) { + errorMessage = "Insufficient buyer security deposit for offer " + request.offerId + ". Expected at least " + Restrictions.MIN_SECURITY_DEPOSIT_PCT + " but got " + offer.getBuyerSecurityDepositPct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + + // security deposits must be equal + if (offer.getBuyerSecurityDepositPct() != offer.getSellerSecurityDepositPct()) { + errorMessage = "Buyer and seller security deposits are not equal for offer " + request.offerId + ": " + offer.getSellerSecurityDepositPct() + " vs " + offer.getBuyerSecurityDepositPct(); + log.warn(errorMessage); + sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); + return; + } + } + + // verify penalty fee + if (offer.getPenaltyFeePct() != HavenoUtils.PENALTY_FEE_PCT) { + errorMessage = "Wrong penalty fee for offer " + request.offerId; + log.warn(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); return; } // verify maker's reserve tx (double spend, trade fee, trade amount, mining fee) - BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount(); - BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); - Tuple2<MoneroTx, BigInteger> txResult = xmrWalletService.verifyTradeTx( + BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), HavenoUtils.PENALTY_FEE_PCT); + BigInteger maxTradeFee = HavenoUtils.multiply(offer.getAmount(), hasBuyerAsTakerWithoutDeposit ? HavenoUtils.MAKER_FEE_FOR_TAKER_WITHOUT_DEPOSIT_PCT : HavenoUtils.MAKER_FEE_PCT); + BigInteger sendTradeAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.ZERO : offer.getAmount(); + BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit(); + MoneroTx verifiedTx = xmrWalletService.verifyReserveTx( offer.getId(), - tradeFee, - sendAmount, + penaltyFee, + maxTradeFee, + sendTradeAmount, securityDeposit, request.getPayoutAddress(), request.getReserveTxHash(), @@ -1191,11 +1444,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe signedOfferPayload.getPubKeyRing().hashCode(), // trader id signedOfferPayload.getId(), offer.getAmount().longValueExact(), - tradeFee.longValueExact(), + maxTradeFee.longValueExact(), request.getReserveTxHash(), request.getReserveTxHex(), request.getReserveTxKeyImages(), - txResult.first.getFee().longValueExact(), + verifiedTx.getFee().longValueExact(), signature); // TODO (woodser): no need for signature to be part of SignedOffer? addSignedOffer(signedOffer); requestPersistence(); @@ -1228,9 +1481,8 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe }); result = true; } catch (Exception e) { - e.printStackTrace(); errorMessage = "Exception at handleSignOfferRequest " + e.getMessage(); - log.error(errorMessage); + log.error(errorMessage + "\n", e); } finally { sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), result, errorMessage); } @@ -1273,7 +1525,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } // Don't allow trade start if Monero node is not fully synced - if (!connectionsService.isSyncedWithinTolerance()) { + if (!xmrConnectionService.isSyncedWithinTolerance()) { errorMessage = "We got a handleOfferAvailabilityRequest but our chain is not synced."; log.info(errorMessage); sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), false, errorMessage); @@ -1317,7 +1569,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe // Check also tradePrice to avoid failures after taker fee is paid caused by a too big difference // in trade price between the peers. Also here poor connectivity might cause market price API connection // losses and therefore an outdated market price. - offer.verifyTakersTradePrice(request.getTakersTradePrice()); + offer.verifyTradePrice(request.getTakersTradePrice()); availabilityResult = AvailabilityResult.AVAILABLE; } catch (TradePriceOutOfToleranceException e) { log.warn("Trade price check failed because takers price is outside out tolerance."); @@ -1382,8 +1634,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe result = true; } catch (Throwable t) { errorMessage = "Exception at handleRequestIsOfferAvailableMessage " + t.getMessage(); - log.error(errorMessage); - t.printStackTrace(); + log.error(errorMessage + "\n", t); } finally { sendAckMessage(request.getClass(), peer, request.getPubKeyRing(), request.getOfferId(), request.getUid(), result, errorMessage); } @@ -1500,6 +1751,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe originalOfferPayload.isUseMarketBasedPrice(), originalOfferPayload.getAmount(), originalOfferPayload.getMinAmount(), + originalOfferPayload.getMakerFeePct(), + originalOfferPayload.getTakerFeePct(), + originalOfferPayload.getPenaltyFeePct(), + originalOfferPayload.getBuyerSecurityDepositPct(), + originalOfferPayload.getSellerSecurityDepositPct(), originalOfferPayload.getBaseCurrencyCode(), originalOfferPayload.getCounterCurrencyCode(), originalOfferPayload.getPaymentMethodId(), @@ -1510,9 +1766,6 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe originalOfferPayload.getAcceptedBankIds(), originalOfferPayload.getVersionNr(), originalOfferPayload.getBlockHeightAtOfferCreation(), - originalOfferPayload.getMakerFee(), - originalOfferPayload.getBuyerSecurityDeposit(), - originalOfferPayload.getSellerSecurityDeposit(), originalOfferPayload.getMaxTradeLimit(), originalOfferPayload.getMaxTradePeriod(), originalOfferPayload.isUseAutoClose(), @@ -1520,7 +1773,7 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe originalOfferPayload.getLowerClosePrice(), originalOfferPayload.getUpperClosePrice(), originalOfferPayload.isPrivateOffer(), - originalOfferPayload.getHashOfChallenge(), + originalOfferPayload.getChallengeHash(), updatedExtraDataMap, protocolVersion, originalOfferPayload.getArbitratorSigner(), @@ -1563,7 +1816,9 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe stopPeriodicRefreshOffersTimer(); - processListForRepublishOffers(getOpenOffers()); + ThreadUtils.execute(() -> { + processListForRepublishOffers(getOpenOffers()); + }, THREAD_ID); } private void processListForRepublishOffers(List<OpenOffer> list) { @@ -1576,11 +1831,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe synchronized (openOffers) { contained = openOffers.contains(openOffer); } - if (contained && openOffer.isAvailable()) { + if (contained) { // TODO It is not clear yet if it is better for the node and the network to send out all add offer // messages in one go or to spread it over a delay. With power users who have 100-200 offers that can have // some significant impact to user experience and the network - republishOffer(openOffer, () -> processListForRepublishOffers(list)); + maybeRepublishOffer(openOffer, () -> processListForRepublishOffers(list)); /* republishOffer(openOffer, () -> UserThread.runAfter(() -> processListForRepublishOffers(list), @@ -1592,67 +1847,95 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe } } - private void republishOffer(OpenOffer openOffer) { - republishOffer(openOffer, null); + private void maybeRepublishOffer(OpenOffer openOffer) { + maybeRepublishOffer(openOffer, null); } - private void republishOffer(OpenOffer openOffer, @Nullable Runnable completeHandler) { + private void maybeRepublishOffer(OpenOffer openOffer, @Nullable Runnable completeHandler) { + ThreadUtils.execute(() -> { - // re-add to offer book if signature is valid - Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(openOffer.getOffer().getOfferPayload().getArbitratorSigner()); - boolean isValid = arbitrator != null && HavenoUtils.isArbitratorSignatureValid(openOffer.getOffer().getOfferPayload(), arbitrator); - if (isValid) { - offerBookService.addOffer(openOffer.getOffer(), - () -> { - if (!stopped) { - - // refresh means we send only the data needed to refresh the TTL (hash, signature and sequence no.) - if (periodicRefreshOffersTimer == null) { - startPeriodicRefreshOffersTimer(); - } - if (completeHandler != null) { - completeHandler.run(); - } - } - }, - errorMessage -> { - if (!stopped) { - log.error("Adding offer to P2P network failed. " + errorMessage); - stopRetryRepublishOffersTimer(); - retryRepublishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, - RETRY_REPUBLISH_DELAY_SEC); - if (completeHandler != null) completeHandler.run(); - } - }); - return; - } - - // cancel and recreate offer - log.warn("Offer {} has invalid arbitrator signature, reposting", openOffer.getId()); - onCancelled(openOffer); - Offer updatedOffer = new Offer(openOffer.getOffer().getOfferPayload()); - updatedOffer.setPriceFeedService(priceFeedService); - OpenOffer updatedOpenOffer = new OpenOffer(updatedOffer, openOffer.getTriggerPrice()); - - // repost offer - new Thread(() -> { - synchronized (processOffersLock) { - CountDownLatch latch = new CountDownLatch(1); - processUnpostedOffer(getOpenOffers(), updatedOpenOffer, (transaction) -> { - addOpenOffer(updatedOpenOffer); - requestPersistence(); - latch.countDown(); - if (completeHandler != null) completeHandler.run(); - }, (errorMessage) -> { - log.warn("Error reposting offer {} with invalid signature: {}", updatedOpenOffer.getId(), errorMessage); - onCancelled(updatedOpenOffer); - updatedOffer.setErrorMessage(errorMessage); - latch.countDown(); - if (completeHandler != null) completeHandler.run(); - }); - HavenoUtils.awaitLatch(latch); + // skip if prevented from publishing + if (preventedFromPublishing(openOffer)) { + if (completeHandler != null) completeHandler.run(); + return; } - }).start(); + + // determine if offer is valid + boolean isValid = true; + Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(openOffer.getOffer().getOfferPayload().getArbitratorSigner()); + if (arbitrator == null) { + log.warn("Offer {} signed by unavailable arbitrator, reposting", openOffer.getId()); + isValid = false; + } else if (!HavenoUtils.isArbitratorSignatureValid(openOffer.getOffer().getOfferPayload(), arbitrator)) { + log.warn("Offer {} has invalid arbitrator signature, reposting", openOffer.getId()); + isValid = false; + } + if ((openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() != null || openOffer.getOffer().getOfferPayload().getReserveTxKeyImages().isEmpty()) && (openOffer.getReserveTxHash() == null || openOffer.getReserveTxHash().isEmpty())) { + log.warn("Offer {} is missing reserve tx hash but has reserved key images, reposting", openOffer.getId()); + isValid = false; + } + + // if valid, re-add offer to book + if (isValid) { + offerBookService.addOffer(openOffer.getOffer(), + () -> { + if (!stopped) { + + // refresh means we send only the data needed to refresh the TTL (hash, signature and sequence no.) + if (periodicRefreshOffersTimer == null) { + startPeriodicRefreshOffersTimer(); + } + if (completeHandler != null) { + completeHandler.run(); + } + } + }, + errorMessage -> { + if (!stopped) { + log.error("Adding offer to P2P network failed. " + errorMessage); + stopRetryRepublishOffersTimer(); + retryRepublishOffersTimer = UserThread.runAfter(OpenOfferManager.this::republishOffers, + RETRY_REPUBLISH_DELAY_SEC); + if (completeHandler != null) completeHandler.run(); + } + }); + } else { + + // reset offer state to pending + openOffer.getOffer().getOfferPayload().setArbitratorSignature(null); + openOffer.getOffer().getOfferPayload().setArbitratorSigner(null); + openOffer.getOffer().setState(Offer.State.UNKNOWN); + openOffer.setState(OpenOffer.State.PENDING); + + // republish offer + synchronized (processOffersLock) { + CountDownLatch latch = new CountDownLatch(1); + processPendingOffer(getOpenOffers(), openOffer, (transaction) -> { + requestPersistence(); + latch.countDown(); + if (completeHandler != null) completeHandler.run(); + }, (errorMessage) -> { + if (!openOffer.isCanceled()) { + log.warn("Error republishing offer {}: {}", openOffer.getId(), errorMessage); + openOffer.getOffer().setErrorMessage(errorMessage); + + // cancel offer if invalid + if (openOffer.getOffer().getState() == Offer.State.INVALID) { + log.warn("Canceling offer because it's invalid: {}", openOffer.getId()); + doCancelOffer(openOffer); + } + } + latch.countDown(); + if (completeHandler != null) completeHandler.run(); + }); + HavenoUtils.awaitLatch(latch); + } + } + }, THREAD_ID); + } + + private boolean preventedFromPublishing(OpenOffer openOffer) { + return openOffer.isDeactivated() || openOffer.isCanceled() || openOffer.getOffer().getOfferPayload().getArbitratorSigner() == null; } private void startPeriodicRepublishOffersTimer() { @@ -1687,8 +1970,11 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe final OpenOffer openOffer = openOffersList.get(i); UserThread.runAfterRandomDelay(() -> { // we need to check if in the meantime the offer has been removed - if (openOffers.contains(openOffer) && openOffer.isAvailable()) - refreshOffer(openOffer); + boolean contained = false; + synchronized (openOffers) { + contained = openOffers.contains(openOffer); + } + if (contained) maybeRefreshOffer(openOffer, 0, 1); }, minDelay, maxDelay, TimeUnit.MILLISECONDS); } } else { @@ -1701,10 +1987,16 @@ public class OpenOfferManager implements PeerManager.Listener, DecryptedDirectMe log.trace("periodicRefreshOffersTimer already stated"); } - private void refreshOffer(OpenOffer openOffer) { + private void maybeRefreshOffer(OpenOffer openOffer, int numAttempts, int maxAttempts) { + if (preventedFromPublishing(openOffer)) return; offerBookService.refreshTTL(openOffer.getOffer().getOfferPayload(), () -> log.debug("Successful refreshed TTL for offer"), - log::warn); + (errorMessage) -> { + log.warn(errorMessage); + if (numAttempts + 1 < maxAttempts) { + UserThread.runAfter(() -> maybeRefreshOffer(openOffer, numAttempts + 1, maxAttempts), 10); + } + }); } private void restart() { diff --git a/core/src/main/java/haveno/core/offer/SignedOfferList.java b/core/src/main/java/haveno/core/offer/SignedOfferList.java index 14ef6ff1f7..a77d0402d9 100644 --- a/core/src/main/java/haveno/core/offer/SignedOfferList.java +++ b/core/src/main/java/haveno/core/offer/SignedOfferList.java @@ -1,3 +1,20 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.offer; import com.google.protobuf.Message; diff --git a/core/src/main/java/haveno/core/offer/TriggerPriceService.java b/core/src/main/java/haveno/core/offer/TriggerPriceService.java index 8e323406e0..59705de064 100644 --- a/core/src/main/java/haveno/core/offer/TriggerPriceService.java +++ b/core/src/main/java/haveno/core/offer/TriggerPriceService.java @@ -1,23 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.util.MathUtils; +import static haveno.common.util.MathUtils.roundDoubleToLong; +import static haveno.common.util.MathUtils.scaleUpByPowerOf10; import haveno.core.locale.CurrencyUtil; import haveno.core.monetary.CryptoMoney; import haveno.core.monetary.Price; @@ -26,20 +30,14 @@ import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.P2PService; -import javafx.collections.ListChangeListener; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; - -import static haveno.common.util.MathUtils.roundDoubleToLong; -import static haveno.common.util.MathUtils.scaleUpByPowerOf10; +import javafx.collections.ListChangeListener; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton @@ -64,7 +62,7 @@ public class TriggerPriceService { } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { onBootstrapComplete(); } }); diff --git a/core/src/main/java/haveno/core/offer/availability/DisputeAgentSelection.java b/core/src/main/java/haveno/core/offer/availability/DisputeAgentSelection.java index 4f30e99d86..b09750ead4 100644 --- a/core/src/main/java/haveno/core/offer/availability/DisputeAgentSelection.java +++ b/core/src/main/java/haveno/core/offer/availability/DisputeAgentSelection.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.availability; diff --git a/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java b/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java index c4fa1caecf..7aa8675de3 100644 --- a/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java +++ b/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.availability; diff --git a/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityProtocol.java b/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityProtocol.java index c7da58aa52..27a94d5bf4 100644 --- a/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityProtocol.java +++ b/core/src/main/java/haveno/core/offer/availability/OfferAvailabilityProtocol.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.availability; diff --git a/core/src/main/java/haveno/core/offer/availability/tasks/ProcessOfferAvailabilityResponse.java b/core/src/main/java/haveno/core/offer/availability/tasks/ProcessOfferAvailabilityResponse.java index ace9dce02b..d5bc581477 100644 --- a/core/src/main/java/haveno/core/offer/availability/tasks/ProcessOfferAvailabilityResponse.java +++ b/core/src/main/java/haveno/core/offer/availability/tasks/ProcessOfferAvailabilityResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.availability.tasks; @@ -23,7 +23,6 @@ import haveno.core.offer.AvailabilityResult; import haveno.core.offer.Offer; import haveno.core.offer.availability.OfferAvailabilityModel; import haveno.core.offer.messages.OfferAvailabilityResponse; -import haveno.core.trade.HavenoUtils; import lombok.extern.slf4j.Slf4j; import static com.google.common.base.Preconditions.checkArgument; @@ -52,13 +51,6 @@ public class ProcessOfferAvailabilityResponse extends Task<OfferAvailabilityMode return; } - // verify maker signature for trade request - if (!HavenoUtils.isMakerSignatureValid(model.getTradeRequest(), offerAvailabilityResponse.getMakerSignature(), offer.getPubKeyRing())) { - offer.setState(Offer.State.NOT_AVAILABLE); - failed("Take offer attempt failed because maker signature is invalid"); - return; - } - offer.setState(Offer.State.AVAILABLE); model.setMakerSignature(offerAvailabilityResponse.getMakerSignature()); checkNotNull(model.getMakerSignature()); diff --git a/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java b/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java index 9429649d97..d6080e61e3 100644 --- a/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java +++ b/core/src/main/java/haveno/core/offer/availability/tasks/SendOfferAvailabilityRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.availability.tasks; @@ -26,6 +26,7 @@ import haveno.core.offer.availability.OfferAvailabilityModel; import haveno.core.offer.messages.OfferAvailabilityRequest; import haveno.core.trade.HavenoUtils; import haveno.core.trade.messages.InitTradeRequest; +import haveno.core.trade.messages.TradeProtocolVersion; import haveno.core.user.User; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.XmrWalletService; @@ -53,8 +54,9 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> { User user = model.getUser(); P2PService p2PService = model.getP2PService(); XmrWalletService walletService = model.getXmrWalletService(); - String paymentAccountId = model.getPaymentAccountId(); - String paymentMethodId = user.getPaymentAccount(paymentAccountId).getPaymentAccountPayload().getPaymentMethodId(); + String makerPaymentAccountId = offer.getOfferPayload().getMakerPaymentAccountId(); + String takerPaymentAccountId = model.getPaymentAccountId(); + String paymentMethodId = user.getPaymentAccount(takerPaymentAccountId).getPaymentAccountPayload().getPaymentMethodId(); String payoutAddress = walletService.getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); // taker signs offer using offer id as nonce to avoid challenge protocol @@ -66,15 +68,16 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> { // send InitTradeRequest to maker to sign InitTradeRequest tradeRequest = new InitTradeRequest( + TradeProtocolVersion.MULTISIG_2_3, // TODO: replace with first of their accepted protocols offer.getId(), - P2PService.getMyNodeAddress(), - p2PService.getKeyRing().getPubKeyRing(), model.getTradeAmount().longValueExact(), price.getValue(), - HavenoUtils.getTakerFee(model.getTradeAmount()).longValueExact(), - user.getAccountId(), - paymentAccountId, paymentMethodId, + null, + user.getAccountId(), + makerPaymentAccountId, + takerPaymentAccountId, + p2PService.getKeyRing().getPubKeyRing(), UUID.randomUUID().toString(), Version.getP2PMessageVersion(), sig, @@ -86,7 +89,7 @@ public class SendOfferAvailabilityRequest extends Task<OfferAvailabilityModel> { null, null, payoutAddress, - null); + null); // challenge is required when offer taken // save trade request to later send to arbitrator model.setTradeRequest(tradeRequest); diff --git a/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityRequest.java b/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityRequest.java index 6060bd01f6..0c5537e225 100644 --- a/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityRequest.java +++ b/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.messages; diff --git a/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java b/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java index 6731b0f87f..0227aed4fb 100644 --- a/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java +++ b/core/src/main/java/haveno/core/offer/messages/OfferAvailabilityResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.messages; diff --git a/core/src/main/java/haveno/core/offer/messages/OfferMessage.java b/core/src/main/java/haveno/core/offer/messages/OfferMessage.java index f9e3dbfc3c..d702310fb9 100644 --- a/core/src/main/java/haveno/core/offer/messages/OfferMessage.java +++ b/core/src/main/java/haveno/core/offer/messages/OfferMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.messages; diff --git a/core/src/main/java/haveno/core/offer/messages/SignOfferRequest.java b/core/src/main/java/haveno/core/offer/messages/SignOfferRequest.java index 630ff98ddf..241abc86f2 100644 --- a/core/src/main/java/haveno/core/offer/messages/SignOfferRequest.java +++ b/core/src/main/java/haveno/core/offer/messages/SignOfferRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.messages; diff --git a/core/src/main/java/haveno/core/offer/messages/SignOfferResponse.java b/core/src/main/java/haveno/core/offer/messages/SignOfferResponse.java index f2bf409527..257c7391d7 100644 --- a/core/src/main/java/haveno/core/offer/messages/SignOfferResponse.java +++ b/core/src/main/java/haveno/core/offer/messages/SignOfferResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.messages; diff --git a/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferModel.java b/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferModel.java index 30c4b2233c..65aed8aa9d 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferModel.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer; @@ -23,6 +23,7 @@ import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.filter.FilterManager; import haveno.core.offer.OfferBookService; import haveno.core.offer.OpenOffer; +import haveno.core.offer.OpenOfferManager; import haveno.core.offer.messages.SignOfferResponse; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import haveno.core.support.dispute.mediation.mediator.MediatorManager; @@ -35,7 +36,6 @@ import haveno.network.p2p.P2PService; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import monero.wallet.model.MoneroTxWallet; import org.bitcoinj.core.Transaction; import java.math.BigInteger; @@ -61,6 +61,8 @@ public class PlaceOfferModel implements Model { private final FilterManager filterManager; @Getter private final AccountAgeWitnessService accountAgeWitnessService; + @Getter + private final OpenOfferManager openOfferManager; // Mutable @Setter @@ -68,9 +70,10 @@ public class PlaceOfferModel implements Model { @Setter private Transaction transaction; @Setter - private MoneroTxWallet reserveTx; - @Setter private SignOfferResponse signOfferResponse; + @Setter + @Getter + protected PlaceOfferProtocol protocol; public PlaceOfferModel(OpenOffer openOffer, BigInteger reservedFundsForOffer, @@ -86,7 +89,8 @@ public class PlaceOfferModel implements Model { User user, KeyRing keyRing, FilterManager filterManager, - AccountAgeWitnessService accountAgeWitnessService) { + AccountAgeWitnessService accountAgeWitnessService, + OpenOfferManager openOfferManager) { this.openOffer = openOffer; this.reservedFundsForOffer = reservedFundsForOffer; this.useSavingsWallet = useSavingsWallet; @@ -102,6 +106,7 @@ public class PlaceOfferModel implements Model { this.keyRing = keyRing; this.filterManager = filterManager; this.accountAgeWitnessService = accountAgeWitnessService; + this.openOfferManager = openOfferManager; } @Override diff --git a/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferProtocol.java b/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferProtocol.java index 3875b5cc8e..0b22d9e40e 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferProtocol.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/PlaceOfferProtocol.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer; @@ -41,6 +41,7 @@ public class PlaceOfferProtocol { private Timer timeoutTimer; private final TransactionResultHandler resultHandler; private final ErrorMessageHandler errorMessageHandler; + private TaskRunner<PlaceOfferModel> taskRunner; /////////////////////////////////////////////////////////////////////////////////////////// @@ -51,6 +52,7 @@ public class PlaceOfferProtocol { TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { this.model = model; + this.model.setProtocol(this); this.resultHandler = resultHandler; this.errorMessageHandler = errorMessageHandler; } @@ -62,12 +64,13 @@ public class PlaceOfferProtocol { public void placeOffer() { - timeoutTimer = UserThread.runAfter(() -> { - handleError(Res.get("createOffer.timeoutAtPublishing")); - }, TradeProtocol.TRADE_TIMEOUT); + startTimeoutTimer(); - TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model, + taskRunner = new TaskRunner<>(model, () -> { + + // reset timer if response not yet received + if (model.getSignOfferResponse() == null) startTimeoutTimer(); }, (errorMessage) -> { handleError(errorMessage); @@ -81,53 +84,68 @@ public class PlaceOfferProtocol { taskRunner.run(); } + + public void cancelOffer() { + handleError("Offer was canceled: " + model.getOpenOffer().getOffer().getId()); // cancel is treated as error for callers to handle + } // TODO (woodser): switch to fluent public void handleSignOfferResponse(SignOfferResponse response, NodeAddress sender) { - log.debug("handleSignOfferResponse() " + model.getOpenOffer().getOffer().getId()); - model.setSignOfferResponse(response); + log.debug("handleSignOfferResponse() " + model.getOpenOffer().getOffer().getId()); + model.setSignOfferResponse(response); - if (!model.getOpenOffer().getOffer().getOfferPayload().getArbitratorSigner().equals(sender)) { - log.warn("Ignoring sign offer response from different sender"); - return; - } + // ignore if unexpected signer + if (!model.getOpenOffer().getOffer().getOfferPayload().getArbitratorSigner().equals(sender)) { + log.warn("Ignoring sign offer response from different sender"); + return; + } - // ignore if timer already stopped - if (timeoutTimer == null) { - log.warn("Ignoring sign offer response from arbitrator because timeout has expired for offer " + model.getOpenOffer().getOffer().getId()); - return; - } + // ignore if payloads have different timestamps + if (model.getOpenOffer().getOffer().getOfferPayload().getDate() != response.getSignedOfferPayload().getDate()) { + log.warn("Ignoring sign offer response from arbitrator for offer payload with different timestamp"); + return; + } - // reset timer - stopTimeoutTimer(); - timeoutTimer = UserThread.runAfter(() -> { - handleError(Res.get("createOffer.timeoutAtPublishing")); - }, TradeProtocol.TRADE_TIMEOUT); + // ignore if timer already stopped + if (timeoutTimer == null) { + log.warn("Ignoring sign offer response from arbitrator because timeout has expired for offer " + model.getOpenOffer().getOffer().getId()); + return; + } - TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model, - () -> { - log.debug("sequence at handleSignOfferResponse completed"); - stopTimeoutTimer(); - resultHandler.handleResult(model.getTransaction()); // TODO (woodser): XMR transaction instead - }, - (errorMessage) -> { - if (model.isOfferAddedToOfferBook()) { - model.getOfferBookService().removeOffer(model.getOpenOffer().getOffer().getOfferPayload(), - () -> { - model.setOfferAddedToOfferBook(false); - log.debug("OfferPayload removed from offer book."); - }, - log::error); - } - handleError(errorMessage); - } - ); - taskRunner.addTasks( - MakerProcessSignOfferResponse.class, - AddToOfferBook.class - ); + // reset timer + startTimeoutTimer(); - taskRunner.run(); + TaskRunner<PlaceOfferModel> taskRunner = new TaskRunner<>(model, + () -> { + log.debug("sequence at handleSignOfferResponse completed"); + stopTimeoutTimer(); + resultHandler.handleResult(model.getTransaction()); // TODO (woodser): XMR transaction instead + }, + (errorMessage) -> { + if (model.isOfferAddedToOfferBook()) { + model.getOfferBookService().removeOffer(model.getOpenOffer().getOffer().getOfferPayload(), + () -> { + model.setOfferAddedToOfferBook(false); + log.debug("OfferPayload removed from offer book."); + }, + log::error); + } + handleError(errorMessage); + } + ); + taskRunner.addTasks( + MakerProcessSignOfferResponse.class, + AddToOfferBook.class + ); + + taskRunner.run(); + } + + public void startTimeoutTimer() { + stopTimeoutTimer(); + timeoutTimer = UserThread.runAfter(() -> { + handleError(Res.get("createOffer.timeoutAtPublishing")); + }, TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS); } private void stopTimeoutTimer() { @@ -139,9 +157,11 @@ public class PlaceOfferProtocol { private void handleError(String errorMessage) { if (timeoutTimer != null) { - log.error(errorMessage); + taskRunner.cancel(); + if (!model.getOpenOffer().isCanceled()) { + model.getOpenOffer().getOffer().setErrorMessage(errorMessage); + } stopTimeoutTimer(); - model.getOpenOffer().getOffer().setErrorMessage(errorMessage); errorMessageHandler.handleErrorMessage(errorMessage); } } diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/AddToOfferBook.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/AddToOfferBook.java index 3c4325dc74..c5c3cf4f46 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/AddToOfferBook.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/AddToOfferBook.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer.tasks; diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/CreateMakerFeeTx.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/CreateMakerFeeTx.java deleted file mode 100644 index 5f0402937e..0000000000 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/CreateMakerFeeTx.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.core.offer.placeoffer.tasks; - -//import haveno.core.util.FeeReceiverSelector; - -import haveno.common.taskrunner.Task; -import haveno.common.taskrunner.TaskRunner; -import haveno.core.offer.Offer; -import haveno.core.offer.placeoffer.PlaceOfferModel; -import haveno.core.xmr.model.AddressEntry; -import haveno.core.xmr.wallet.BtcWalletService; -import haveno.core.xmr.wallet.TradeWalletService; -import org.bitcoinj.core.Address; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class CreateMakerFeeTx extends Task<PlaceOfferModel> { - private static final Logger log = LoggerFactory.getLogger(CreateMakerFeeTx.class); - - @SuppressWarnings({"unused"}) - public CreateMakerFeeTx(TaskRunner<PlaceOfferModel> taskHandler, PlaceOfferModel model) { - super(taskHandler, model); - } - - @Override - protected void run() { - Offer offer = model.getOpenOffer().getOffer(); - - try { - runInterceptHook(); - - String id = offer.getId(); - BtcWalletService walletService = model.getWalletService(); - - Address fundingAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.OFFER_FUNDING).getAddress(); - Address reservedForTradeAddress = walletService.getOrCreateAddressEntry(id, AddressEntry.Context.RESERVED_FOR_TRADE).getAddress(); - Address changeAddress = walletService.getFreshAddressEntry().getAddress(); - - TradeWalletService tradeWalletService = model.getTradeWalletService(); - throw new RuntimeException("CreateMakerFeeTx not used for XMR"); - } catch (Throwable t) { - offer.setErrorMessage("An error occurred.\n" + - "Error message:\n" - + t.getMessage()); - - failed(t); - } - } -} diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerProcessSignOfferResponse.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerProcessSignOfferResponse.java index ecd6ea1f79..f8baf8a400 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerProcessSignOfferResponse.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerProcessSignOfferResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer.tasks; @@ -42,11 +42,14 @@ public class MakerProcessSignOfferResponse extends Task<PlaceOfferModel> { // validate arbitrator signature if (!HavenoUtils.isArbitratorSignatureValid(model.getSignOfferResponse().getSignedOfferPayload(), arbitrator)) { - throw new RuntimeException("Offer payload has invalid arbitrator signature"); + throw new RuntimeException("Arbitrator's offer payload has invalid signature, offerId=" + offer.getId()); } // set arbitrator signature for maker's offer offer.getOfferPayload().setArbitratorSignature(model.getSignOfferResponse().getSignedOfferPayload().getArbitratorSignature()); + if (!HavenoUtils.isArbitratorSignatureValid(offer.getOfferPayload(), arbitrator)) { + throw new RuntimeException("Maker's offer payload has invalid signature, offerId=" + offer.getId()); + } offer.setState(Offer.State.AVAILABLE); complete(); } catch (Exception e) { diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java index d0a992f25b..4b44a8102d 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerReserveOfferFunds.java @@ -1,36 +1,40 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer.tasks; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + import haveno.common.taskrunner.Task; import haveno.common.taskrunner.TaskRunner; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; +import haveno.core.offer.OpenOffer; import haveno.core.offer.placeoffer.PlaceOfferModel; +import haveno.core.trade.HavenoUtils; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroRpcConnection; import monero.daemon.model.MoneroOutput; import monero.wallet.model.MoneroTxWallet; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; - @Slf4j public class MakerReserveOfferFunds extends Task<PlaceOfferModel> { @@ -41,36 +45,83 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> { @Override protected void run() { - Offer offer = model.getOpenOffer().getOffer(); + OpenOffer openOffer = model.getOpenOffer(); + Offer offer = openOffer.getOffer(); try { runInterceptHook(); - // verify monero connection - model.getXmrWalletService().getConnectionsService().verifyConnection(); - - // create reserve tx - BigInteger makerFee = offer.getMakerFee(); - BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.valueOf(0) : offer.getAmount(); - BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); - String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); - XmrAddressEntry fundingEntry = model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).orElse(null); - Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex(); - MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(makerFee, sendAmount, securityDeposit, returnAddress, model.getOpenOffer().isReserveExactAmount(), preferredSubaddressIndex); - - // check for error in case creating reserve tx exceeded timeout - // TODO: better way? - if (!model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).isPresent()) { - throw new RuntimeException("An error has occurred posting offer " + offer.getId() + " causing its subaddress entry to be deleted"); + // skip if reserve tx already created + if (openOffer.getReserveTxHash() != null && !openOffer.getReserveTxHash().isEmpty()) { + log.info("Reserve tx already created for offerId={}", openOffer.getShortId()); + complete(); + return; } - // collect reserved key images - List<String> reservedKeyImages = new ArrayList<String>(); - for (MoneroOutput input : reserveTx.getInputs()) reservedKeyImages.add(input.getKeyImage().getHex()); + // verify monero connection + model.getXmrWalletService().getXmrConnectionService().verifyConnection(); - // save offer state - model.setReserveTx(reserveTx); - offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages); + // create reserve tx + MoneroTxWallet reserveTx = null; + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { + + // reset protocol timeout + verifyPending(); + model.getProtocol().startTimeoutTimer(); + + // collect relevant info + BigInteger penaltyFee = HavenoUtils.multiply(offer.getAmount(), offer.getPenaltyFeePct()); + BigInteger makerFee = offer.getMaxMakerFee(); + BigInteger sendAmount = offer.getDirection() == OfferDirection.BUY ? BigInteger.ZERO : offer.getAmount(); + BigInteger securityDeposit = offer.getDirection() == OfferDirection.BUY ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit(); + String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); + XmrAddressEntry fundingEntry = model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.OFFER_FUNDING).orElse(null); + Integer preferredSubaddressIndex = fundingEntry == null ? null : fundingEntry.getSubaddressIndex(); + + // attempt creating reserve tx + try { + synchronized (HavenoUtils.getWalletFunctionLock()) { + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = model.getXmrWalletService().getXmrConnectionService().getConnection(); + try { + //if (true) throw new RuntimeException("Pretend error"); + reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, makerFee, sendAmount, securityDeposit, returnAddress, openOffer.isReserveExactAmount(), preferredSubaddressIndex); + } catch (Exception e) { + log.warn("Error creating reserve tx, offerId={}, attempt={}/{}, error={}", openOffer.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + model.getXmrWalletService().handleWalletError(e, sourceConnection); + verifyPending(); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + model.getProtocol().startTimeoutTimer(); // reset protocol timeout + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + + // verify still open + verifyPending(); + if (reserveTx != null) break; + } + } + } catch (Exception e) { + + // reset state with wallet lock + model.getXmrWalletService().resetAddressEntriesForOpenOffer(offer.getId()); + if (reserveTx != null) model.getXmrWalletService().thawOutputs(HavenoUtils.getInputKeyImages(reserveTx)); + offer.getOfferPayload().setReserveTxKeyImages(null); + throw e; + } + + // reset protocol timeout + model.getProtocol().startTimeoutTimer(); + + // collect reserved key images + List<String> reservedKeyImages = new ArrayList<String>(); + for (MoneroOutput input : reserveTx.getInputs()) reservedKeyImages.add(input.getKeyImage().getHex()); + + // update offer state + openOffer.setReserveTxHash(reserveTx.getHash()); + openOffer.setReserveTxHex(reserveTx.getFullHex()); + openOffer.setReserveTxKey(reserveTx.getKey()); + offer.getOfferPayload().setReserveTxKeyImages(reservedKeyImages); + } complete(); } catch (Throwable t) { offer.setErrorMessage("An error occurred.\n" + @@ -79,4 +130,12 @@ public class MakerReserveOfferFunds extends Task<PlaceOfferModel> { failed(t); } } + + private boolean isPending() { + return model.getOpenOffer().isPending(); + } + + private void verifyPending() { + if (!isPending()) throw new RuntimeException("Offer " + model.getOpenOffer().getOffer().getId() + " is canceled"); + } } diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java index 4aaf31f262..2037b51d09 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/MakerSendSignOfferRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer.tasks; @@ -24,10 +24,12 @@ import haveno.common.handlers.ResultHandler; import haveno.common.taskrunner.Task; import haveno.common.taskrunner.TaskRunner; import haveno.core.offer.Offer; +import haveno.core.offer.OpenOffer; import haveno.core.offer.availability.DisputeAgentSelection; import haveno.core.offer.messages.SignOfferRequest; import haveno.core.offer.placeoffer.PlaceOfferModel; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; +import haveno.core.trade.HavenoUtils; import haveno.core.xmr.model.XmrAddressEntry; import haveno.network.p2p.AckMessage; import haveno.network.p2p.DecryptedDirectMessageListener; @@ -46,8 +48,6 @@ import java.util.UUID; public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { private static final Logger log = LoggerFactory.getLogger(MakerSendSignOfferRequest.class); - private boolean failed = false; - @SuppressWarnings({"unused"}) public MakerSendSignOfferRequest(TaskRunner taskHandler, PlaceOfferModel model) { super(taskHandler, model); @@ -55,7 +55,8 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { @Override protected void run() { - Offer offer = model.getOpenOffer().getOffer(); + OpenOffer openOffer = model.getOpenOffer(); + Offer offer = openOffer.getOffer(); try { runInterceptHook(); @@ -70,9 +71,9 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { UUID.randomUUID().toString(), Version.getP2PMessageVersion(), new Date().getTime(), - model.getReserveTx().getHash(), - model.getReserveTx().getFullHex(), - model.getReserveTx().getKey(), + openOffer.getReserveTxHash(), + openOffer.getReserveTxHex(), + openOffer.getReserveTxKey(), offer.getOfferPayload().getReserveTxKeyImages(), returnAddress); @@ -80,8 +81,7 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { sendSignOfferRequests(request, () -> { complete(); }, (errorMessage) -> { - appendToErrorMessage("Error signing offer " + request.getOfferId() + ": " + errorMessage); - failed(errorMessage); + failed("Error signing offer " + request.getOfferId() + ": " + errorMessage); }); } catch (Throwable t) { offer.setErrorMessage("An error occurred.\n" + @@ -116,9 +116,10 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { model.getOpenOffer().getOffer().getOfferPayload().setArbitratorSigner(arbitratorNodeAddress); model.getOpenOffer().getOffer().setState(Offer.State.OFFER_FEE_RESERVED); resultHandler.handleResult(); - } else { - errorMessageHandler.handleErrorMessage("Arbitrator nacked SignOfferRequest for offer " + request.getOfferId() + ": " + ackMessage.getErrorMessage()); - } + } else { + model.getOpenOffer().getOffer().setState(Offer.State.INVALID); + errorMessageHandler.handleErrorMessage("Arbitrator nacked SignOfferRequest for offer " + request.getOfferId() + ": " + ackMessage.getErrorMessage()); + } } }; model.getP2PService().addDecryptedDirectMessageListener(ackListener); @@ -128,19 +129,31 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { @Override public void onArrived() { log.info("{} arrived at arbitrator: offerId={}", request.getClass().getSimpleName(), model.getOpenOffer().getId()); + model.getProtocol().startTimeoutTimer(); // reset timeout } // if unavailable, try alternative arbitrator @Override public void onFault(String errorMessage) { - log.warn("Arbitrator {} unavailable: {}", arbitratorNodeAddress, errorMessage); + log.warn("Arbitrator unavailable: address={}, error={}", arbitratorNodeAddress, errorMessage); excludedArbitrators.add(arbitratorNodeAddress); + + // check if offer still pending + if (!model.getOpenOffer().isPending()) { + errorMessageHandler.handleErrorMessage("Offer is no longer pending, offerId=" + model.getOpenOffer().getId()); + return; + } + + // get alternative arbitrator Arbitrator altArbitrator = DisputeAgentSelection.getRandomArbitrator(model.getArbitratorManager(), excludedArbitrators); if (altArbitrator == null) { errorMessageHandler.handleErrorMessage("Offer " + request.getOfferId() + " could not be signed by any arbitrator"); return; } + + // send request to alternative arbitrator log.info("Using alternative arbitrator {}", altArbitrator.getNodeAddress()); + model.getProtocol().startTimeoutTimer(); // reset timeout sendSignOfferRequests(request, altArbitrator.getNodeAddress(), excludedArbitrators, resultHandler, errorMessageHandler); } }); @@ -159,7 +172,8 @@ public class MakerSendSignOfferRequest extends Task<PlaceOfferModel> { arbitratorNodeAddress, arbitrator.getPubKeyRing(), request, - listener + listener, + HavenoUtils.ARBITRATOR_ACK_TIMEOUT_SECONDS ); } } diff --git a/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java b/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java index fdf397f97d..3b1a01beeb 100644 --- a/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java +++ b/core/src/main/java/haveno/core/offer/placeoffer/tasks/ValidateOffer.java @@ -1,28 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.placeoffer.tasks; import haveno.common.taskrunner.Task; import haveno.common.taskrunner.TaskRunner; +import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.offer.Offer; +import haveno.core.offer.OfferDirection; import haveno.core.offer.placeoffer.PlaceOfferModel; import haveno.core.trade.HavenoUtils; import haveno.core.trade.messages.TradeMessage; +import haveno.core.user.User; import org.bitcoinj.core.Coin; import java.math.BigInteger; @@ -41,55 +44,7 @@ public class ValidateOffer extends Task<PlaceOfferModel> { try { runInterceptHook(); - // Coins - checkBINotNullOrZero(offer.getAmount(), "Amount"); - checkBINotNullOrZero(offer.getMinAmount(), "MinAmount"); - checkBINotNullOrZero(offer.getMakerFee(), "MakerFee"); - checkBINotNullOrZero(offer.getBuyerSecurityDeposit(), "buyerSecurityDeposit"); - checkBINotNullOrZero(offer.getSellerSecurityDeposit(), "sellerSecurityDeposit"); - //checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model - checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit"); - - // We remove those checks to be more flexible with future changes. - /*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value, - "createOfferFee must not be less than FeeService.MIN_CREATE_OFFER_FEE_IN_BTC. " + - "MakerFee=" + offer.getMakerFee().toFriendlyString());*/ - /*checkArgument(offer.getBuyerSecurityDeposit().value >= ProposalConsensus.getMinBuyerSecurityDeposit().value, - "buyerSecurityDeposit must not be less than ProposalConsensus.MIN_BUYER_SECURITY_DEPOSIT. " + - "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); - checkArgument(offer.getBuyerSecurityDeposit().value <= ProposalConsensus.getMaxBuyerSecurityDeposit().value, - "buyerSecurityDeposit must not be larger than ProposalConsensus.MAX_BUYER_SECURITY_DEPOSIT. " + - "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); - checkArgument(offer.getSellerSecurityDeposit().value == ProposalConsensus.getSellerSecurityDeposit().value, - "sellerSecurityDeposit must be equal to ProposalConsensus.SELLER_SECURITY_DEPOSIT. " + - "sellerSecurityDeposit=" + offer.getSellerSecurityDeposit().toFriendlyString());*/ - /*checkArgument(offer.getMinAmount().compareTo(ProposalConsensus.getMinTradeAmount()) >= 0, - "MinAmount is less than " + ProposalConsensus.getMinTradeAmount().toFriendlyString());*/ - - long maxAmount = model.getAccountAgeWitnessService().getMyTradeLimit(model.getUser().getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection()); - checkArgument(offer.getAmount().longValueExact() <= maxAmount, - "Amount is larger than " + HavenoUtils.atomicUnitsToXmr(offer.getPaymentMethod().getMaxTradeLimit(offer.getCurrencyCode())) + " XMR"); - checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount"); - - checkNotNull(offer.getPrice(), "Price is null"); - if (!offer.isUseMarketBasedPrice()) checkArgument(offer.getPrice().isPositive(), - "Price must be positive unless using market based price. price=" + offer.getPrice().toFriendlyString()); - - checkArgument(offer.getDate().getTime() > 0, - "Date must not be 0. date=" + offer.getDate().toString()); - - checkNotNull(offer.getCurrencyCode(), "Currency is null"); - checkNotNull(offer.getDirection(), "Direction is null"); - checkNotNull(offer.getId(), "Id is null"); - checkNotNull(offer.getPubKeyRing(), "pubKeyRing is null"); - checkNotNull(offer.getMinAmount(), "MinAmount is null"); - checkNotNull(offer.getPrice(), "Price is null"); - checkNotNull(offer.getMakerFee(), "MakerFee is null"); - checkNotNull(offer.getVersionNr(), "VersionNr is null"); - checkArgument(offer.getMaxTradePeriod() > 0, - "maxTradePeriod must be positive. maxTradePeriod=" + offer.getMaxTradePeriod()); - // TODO check upper and lower bounds for fiat - // TODO check rest of new parameters + validateOffer(offer, model.getAccountAgeWitnessService(), model.getUser()); complete(); } catch (Exception e) { @@ -100,42 +55,108 @@ public class ValidateOffer extends Task<PlaceOfferModel> { } } - public static void checkBINotNullOrZero(BigInteger value, String name) { + public static void validateOffer(Offer offer, AccountAgeWitnessService accountAgeWitnessService, User user) { + + // Coins + checkBINotNullOrZero(offer.getAmount(), "Amount"); + checkBINotNullOrZero(offer.getMinAmount(), "MinAmount"); + //checkCoinNotNullOrZero(offer.getTxFee(), "txFee"); // TODO: remove from data model + checkBINotNullOrZero(offer.getMaxTradeLimit(), "MaxTradeLimit"); + if (offer.getMakerFeePct() < 0) throw new IllegalArgumentException("Maker fee must be >= 0% but was " + offer.getMakerFeePct()); + if (offer.getTakerFeePct() < 0) throw new IllegalArgumentException("Taker fee must be >= 0% but was " + offer.getTakerFeePct()); + offer.isPrivateOffer(); + if (offer.isPrivateOffer()) { + boolean isBuyerMaker = offer.getDirection() == OfferDirection.BUY; + if (isBuyerMaker) { + if (offer.getBuyerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Buyer security deposit percent must be positive but was " + offer.getBuyerSecurityDepositPct()); + if (offer.getSellerSecurityDepositPct() < 0) throw new IllegalArgumentException("Seller security deposit percent must be >= 0% but was " + offer.getSellerSecurityDepositPct()); + } else { + if (offer.getBuyerSecurityDepositPct() < 0) throw new IllegalArgumentException("Buyer security deposit percent must be >= 0% but was " + offer.getBuyerSecurityDepositPct()); + if (offer.getSellerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Seller security deposit percent must be positive but was " + offer.getSellerSecurityDepositPct()); + } + } else { + if (offer.getBuyerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Buyer security deposit percent must be positive but was " + offer.getBuyerSecurityDepositPct()); + if (offer.getSellerSecurityDepositPct() <= 0) throw new IllegalArgumentException("Seller security deposit percent must be positive but was " + offer.getSellerSecurityDepositPct()); + } + + + // We remove those checks to be more flexible with future changes. + /*checkArgument(offer.getMakerFee().value >= FeeService.getMinMakerFee(offer.isCurrencyForMakerFeeBtc()).value, + "createOfferFee must not be less than FeeService.MIN_CREATE_OFFER_FEE_IN_BTC. " + + "MakerFee=" + offer.getMakerFee().toFriendlyString());*/ + /*checkArgument(offer.getBuyerSecurityDeposit().value >= ProposalConsensus.getMinBuyerSecurityDeposit().value, + "buyerSecurityDeposit must not be less than ProposalConsensus.MIN_BUYER_SECURITY_DEPOSIT. " + + "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); + checkArgument(offer.getBuyerSecurityDeposit().value <= ProposalConsensus.getMaxBuyerSecurityDeposit().value, + "buyerSecurityDeposit must not be larger than ProposalConsensus.MAX_BUYER_SECURITY_DEPOSIT. " + + "buyerSecurityDeposit=" + offer.getBuyerSecurityDeposit().toFriendlyString()); + checkArgument(offer.getSellerSecurityDeposit().value == ProposalConsensus.getSellerSecurityDeposit().value, + "sellerSecurityDeposit must be equal to ProposalConsensus.SELLER_SECURITY_DEPOSIT. " + + "sellerSecurityDeposit=" + offer.getSellerSecurityDeposit().toFriendlyString());*/ + /*checkArgument(offer.getMinAmount().compareTo(ProposalConsensus.getMinTradeAmount()) >= 0, + "MinAmount is less than " + ProposalConsensus.getMinTradeAmount().toFriendlyString());*/ + + long maxAmount = accountAgeWitnessService.getMyTradeLimit(user.getPaymentAccount(offer.getMakerPaymentAccountId()), offer.getCurrencyCode(), offer.getDirection(), offer.hasBuyerAsTakerWithoutDeposit()); + checkArgument(offer.getAmount().longValueExact() <= maxAmount, + "Amount is larger than " + HavenoUtils.atomicUnitsToXmr(maxAmount) + " XMR"); + checkArgument(offer.getAmount().compareTo(offer.getMinAmount()) >= 0, "MinAmount is larger than Amount"); + + checkNotNull(offer.getPrice(), "Price is null"); + if (!offer.isUseMarketBasedPrice()) checkArgument(offer.getPrice().isPositive(), + "Price must be positive unless using market based price. price=" + offer.getPrice().toFriendlyString()); + + checkArgument(offer.getDate().getTime() > 0, + "Date must not be 0. date=" + offer.getDate().toString()); + + checkNotNull(offer.getCurrencyCode(), "Currency is null"); + checkNotNull(offer.getDirection(), "Direction is null"); + checkNotNull(offer.getId(), "Id is null"); + checkNotNull(offer.getPubKeyRing(), "pubKeyRing is null"); + checkNotNull(offer.getMinAmount(), "MinAmount is null"); + checkNotNull(offer.getPrice(), "Price is null"); + checkNotNull(offer.getVersionNr(), "VersionNr is null"); + checkArgument(offer.getMaxTradePeriod() > 0, + "maxTradePeriod must be positive. maxTradePeriod=" + offer.getMaxTradePeriod()); + // TODO check upper and lower bounds for fiat + // TODO check rest of new parameters + } + + private static void checkBINotNullOrZero(BigInteger value, String name) { checkNotNull(value, name + " is null"); - checkArgument(value.compareTo(BigInteger.valueOf(0)) > 0, + checkArgument(value.compareTo(BigInteger.ZERO) > 0, name + " must be positive. " + name + "=" + value); } - public static void checkCoinNotNullOrZero(Coin value, String name) { + private static void checkCoinNotNullOrZero(Coin value, String name) { checkNotNull(value, name + " is null"); checkArgument(value.isPositive(), name + " must be positive. " + name + "=" + value.toFriendlyString()); } - public static String nonEmptyStringOf(String value) { + private static String nonEmptyStringOf(String value) { checkNotNull(value); checkArgument(value.length() > 0); return value; } - public static long nonNegativeLongOf(long value) { + private static long nonNegativeLongOf(long value) { checkArgument(value >= 0); return value; } - public static Coin nonZeroCoinOf(Coin value) { + private static Coin nonZeroCoinOf(Coin value) { checkNotNull(value); checkArgument(!value.isZero()); return value; } - public static Coin positiveCoinOf(Coin value) { + private static Coin positiveCoinOf(Coin value) { checkNotNull(value); checkArgument(value.isPositive()); return value; } - public static void checkTradeId(String tradeId, TradeMessage tradeMessage) { - checkArgument(tradeId.equals(tradeMessage.getTradeId())); + private static void checkTradeId(String tradeId, TradeMessage tradeMessage) { + checkArgument(tradeId.equals(tradeMessage.getOfferId())); } } diff --git a/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java b/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java index f97839c944..49c6da12e9 100644 --- a/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java +++ b/core/src/main/java/haveno/core/offer/takeoffer/TakeOfferModel.java @@ -1,47 +1,45 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.takeoffer; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; import haveno.common.taskrunner.Model; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.monetary.Price; import haveno.core.monetary.Volume; import haveno.core.offer.Offer; +import static haveno.core.offer.OfferDirection.SELL; import haveno.core.offer.OfferUtil; import haveno.core.payment.PaymentAccount; import haveno.core.provider.price.PriceFeedService; import haveno.core.trade.HavenoUtils; import haveno.core.util.VolumeUtil; import haveno.core.xmr.model.XmrAddressEntry; +import static haveno.core.xmr.model.XmrAddressEntry.Context.OFFER_FUNDING; import haveno.core.xmr.wallet.XmrWalletService; +import java.math.BigInteger; +import java.util.Objects; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; -import java.math.BigInteger; -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.core.offer.OfferDirection.SELL; -import static haveno.core.xmr.model.XmrAddressEntry.Context.OFFER_FUNDING; - @Slf4j public class TakeOfferModel implements Model { // Immutable @@ -66,7 +64,7 @@ public class TakeOfferModel implements Model { @Getter private BigInteger totalToPay; @Getter - private BigInteger missingCoin = BigInteger.valueOf(0); + private BigInteger missingCoin = BigInteger.ZERO; @Getter private BigInteger totalAvailableBalance; @Getter @@ -100,9 +98,9 @@ public class TakeOfferModel implements Model { this.useSavingsWallet = useSavingsWallet; this.amount = tradeAmount.min(BigInteger.valueOf(getMaxTradeLimit())); this.securityDeposit = offer.getDirection() == SELL - ? offer.getBuyerSecurityDeposit() - : offer.getSellerSecurityDeposit(); - this.takerFee = HavenoUtils.getTakerFee(amount); + ? offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(amount) + : offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(amount); + this.takerFee = HavenoUtils.multiply(amount, offer.getTakerFeePct()); calculateVolume(); calculateTotalToPay(); @@ -150,13 +148,14 @@ public class TakeOfferModel implements Model { private long getMaxTradeLimit() { return accountAgeWitnessService.getMyTradeLimit(paymentAccount, offer.getCurrencyCode(), - offer.getMirroredDirection()); + offer.getMirroredDirection(), + offer.hasBuyerAsTakerWithoutDeposit()); } @NotNull public BigInteger getFundsNeededForTrade() { // If taking a buy offer, taker needs to reserve the offer.amt too. - return securityDeposit.add(offer.isBuyOffer() ? amount : BigInteger.valueOf(0)); + return securityDeposit.add(offer.isBuyOffer() ? amount : BigInteger.ZERO); } private void validateModelInputs() { @@ -173,7 +172,7 @@ public class TakeOfferModel implements Model { this.amount = null; this.availableBalance = null; this.isXmrWalletFunded = false; - this.missingCoin = BigInteger.valueOf(0); + this.missingCoin = BigInteger.ZERO; this.offer = null; this.paymentAccount = null; this.securityDeposit = null; diff --git a/core/src/main/java/haveno/core/payment/AchTransferAccount.java b/core/src/main/java/haveno/core/payment/AchTransferAccount.java index 104a036af5..9f04e4e076 100644 --- a/core/src/main/java/haveno/core/payment/AchTransferAccount.java +++ b/core/src/main/java/haveno/core/payment/AchTransferAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/AdvancedCashAccount.java b/core/src/main/java/haveno/core/payment/AdvancedCashAccount.java index d9fe54750d..1dce0bd4c8 100644 --- a/core/src/main/java/haveno/core/payment/AdvancedCashAccount.java +++ b/core/src/main/java/haveno/core/payment/AdvancedCashAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -42,7 +42,6 @@ public final class AdvancedCashAccount extends PaymentAccount { public AdvancedCashAccount() { super(PaymentMethod.ADVANCED_CASH); - tradeCurrencies.addAll(SUPPORTED_CURRENCIES); } @Override diff --git a/core/src/main/java/haveno/core/payment/AliPayAccount.java b/core/src/main/java/haveno/core/payment/AliPayAccount.java index 70f8584fbb..b6f93b364d 100644 --- a/core/src/main/java/haveno/core/payment/AliPayAccount.java +++ b/core/src/main/java/haveno/core/payment/AliPayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/AmazonGiftCardAccount.java b/core/src/main/java/haveno/core/payment/AmazonGiftCardAccount.java index 3c381c4774..cb3eb35c70 100644 --- a/core/src/main/java/haveno/core/payment/AmazonGiftCardAccount.java +++ b/core/src/main/java/haveno/core/payment/AmazonGiftCardAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/AssetAccount.java b/core/src/main/java/haveno/core/payment/AssetAccount.java index 2009dc1971..43aefb1c99 100644 --- a/core/src/main/java/haveno/core/payment/AssetAccount.java +++ b/core/src/main/java/haveno/core/payment/AssetAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/AustraliaPayidAccount.java b/core/src/main/java/haveno/core/payment/AustraliaPayidAccount.java index 60e9fe03f5..bc1d7b3ada 100644 --- a/core/src/main/java/haveno/core/payment/AustraliaPayidAccount.java +++ b/core/src/main/java/haveno/core/payment/AustraliaPayidAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -36,6 +36,14 @@ public final class AustraliaPayidAccount extends PaymentAccount { setSingleTradeCurrency(SUPPORTED_CURRENCIES.get(0)); } + private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of( + PaymentAccountFormField.FieldId.BANK_ACCOUNT_NAME, + PaymentAccountFormField.FieldId.PAYID, + PaymentAccountFormField.FieldId.EXTRA_INFO, + PaymentAccountFormField.FieldId.ACCOUNT_NAME, + PaymentAccountFormField.FieldId.SALT + ); + @Override protected PaymentAccountPayload createPayload() { return new AustraliaPayidAccountPayload(paymentMethod.getId(), id); @@ -48,7 +56,7 @@ public final class AustraliaPayidAccount extends PaymentAccount { @Override public @NonNull List<PaymentAccountFormField.FieldId> getInputFieldIds() { - throw new RuntimeException("Not implemented"); + return INPUT_FIELD_IDS; } public String getPayid() { @@ -68,4 +76,12 @@ public final class AustraliaPayidAccount extends PaymentAccount { if (bankAccountName == null) bankAccountName = ""; ((AustraliaPayidAccountPayload) paymentAccountPayload).setBankAccountName(bankAccountName); } + + public void setExtraInfo(String extraInfo) { + ((AustraliaPayidAccountPayload) paymentAccountPayload).setExtraInfo(extraInfo); + } + + public String getExtraInfo() { + return ((AustraliaPayidAccountPayload) paymentAccountPayload).getExtraInfo(); + } } diff --git a/core/src/main/java/haveno/core/payment/BankAccount.java b/core/src/main/java/haveno/core/payment/BankAccount.java index bb91c85bb4..9b20637720 100644 --- a/core/src/main/java/haveno/core/payment/BankAccount.java +++ b/core/src/main/java/haveno/core/payment/BankAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/BankNameRestrictedBankAccount.java b/core/src/main/java/haveno/core/payment/BankNameRestrictedBankAccount.java index 0eaac8c243..01ef3c4000 100644 --- a/core/src/main/java/haveno/core/payment/BankNameRestrictedBankAccount.java +++ b/core/src/main/java/haveno/core/payment/BankNameRestrictedBankAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/BizumAccount.java b/core/src/main/java/haveno/core/payment/BizumAccount.java index 3b782276c2..04757ecd5a 100644 --- a/core/src/main/java/haveno/core/payment/BizumAccount.java +++ b/core/src/main/java/haveno/core/payment/BizumAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/CapitualAccount.java b/core/src/main/java/haveno/core/payment/CapitualAccount.java index 36e5329d13..28b47859e7 100644 --- a/core/src/main/java/haveno/core/payment/CapitualAccount.java +++ b/core/src/main/java/haveno/core/payment/CapitualAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -40,7 +40,6 @@ public final class CapitualAccount extends PaymentAccount { public CapitualAccount() { super(PaymentMethod.CAPITUAL); - tradeCurrencies.addAll(SUPPORTED_CURRENCIES); } @Override diff --git a/core/src/main/java/haveno/core/payment/CashAppAccount.java b/core/src/main/java/haveno/core/payment/CashAppAccount.java index c4ae77137e..250f1c5779 100644 --- a/core/src/main/java/haveno/core/payment/CashAppAccount.java +++ b/core/src/main/java/haveno/core/payment/CashAppAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -28,17 +28,22 @@ import lombok.NonNull; import java.util.List; -// Removed due too high chargeback risk -// Cannot be deleted as it would break old trade history entries -@Deprecated @EqualsAndHashCode(callSuper = true) public final class CashAppAccount extends PaymentAccount { - public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of(new TraditionalCurrency("USD")); + public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of( + new TraditionalCurrency("USD"), + new TraditionalCurrency("GBP")); + + private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of( + PaymentAccountFormField.FieldId.EMAIL_OR_MOBILE_NR_OR_CASHTAG, + PaymentAccountFormField.FieldId.TRADE_CURRENCIES, + PaymentAccountFormField.FieldId.ACCOUNT_NAME, + PaymentAccountFormField.FieldId.EXTRA_INFO, + PaymentAccountFormField.FieldId.SALT); public CashAppAccount() { super(PaymentMethod.CASH_APP); - setSingleTradeCurrency(SUPPORTED_CURRENCIES.get(0)); } @Override @@ -53,14 +58,22 @@ public final class CashAppAccount extends PaymentAccount { @Override public @NonNull List<PaymentAccountFormField.FieldId> getInputFieldIds() { - throw new RuntimeException("Not implemented"); + return INPUT_FIELD_IDS; } - public void setCashTag(String cashTag) { - ((CashAppAccountPayload) paymentAccountPayload).setCashTag(cashTag); + public void setEmailOrMobileNrOrCashtag(String emailOrMobileNrOrCashtag) { + ((CashAppAccountPayload) paymentAccountPayload).setEmailOrMobileNrOrCashtag(emailOrMobileNrOrCashtag); } - public String getCashTag() { - return ((CashAppAccountPayload) paymentAccountPayload).getCashTag(); + public String getEmailOrMobileNrOrCashtag() { + return ((CashAppAccountPayload) paymentAccountPayload).getEmailOrMobileNrOrCashtag(); + } + + public void setExtraInfo(String extraInfo) { + ((CashAppAccountPayload) paymentAccountPayload).setExtraInfo(extraInfo); + } + + public String getExtraInfo() { + return ((CashAppAccountPayload) paymentAccountPayload).getExtraInfo(); } } diff --git a/core/src/main/java/haveno/core/payment/CashAtAtmAccount.java b/core/src/main/java/haveno/core/payment/CashAtAtmAccount.java index 60d64205b2..25ab730a64 100644 --- a/core/src/main/java/haveno/core/payment/CashAtAtmAccount.java +++ b/core/src/main/java/haveno/core/payment/CashAtAtmAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/CashDepositAccount.java b/core/src/main/java/haveno/core/payment/CashDepositAccount.java index e4d952f6f1..b263c906df 100644 --- a/core/src/main/java/haveno/core/payment/CashDepositAccount.java +++ b/core/src/main/java/haveno/core/payment/CashDepositAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/CelPayAccount.java b/core/src/main/java/haveno/core/payment/CelPayAccount.java index 1221870356..a21ca3e0e3 100644 --- a/core/src/main/java/haveno/core/payment/CelPayAccount.java +++ b/core/src/main/java/haveno/core/payment/CelPayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/ChargeBackRisk.java b/core/src/main/java/haveno/core/payment/ChargeBackRisk.java index ec35030b73..29726ac354 100644 --- a/core/src/main/java/haveno/core/payment/ChargeBackRisk.java +++ b/core/src/main/java/haveno/core/payment/ChargeBackRisk.java @@ -1,26 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; +import com.google.inject.Singleton; import haveno.core.payment.payload.PaymentMethod; -import javax.inject.Singleton; - @Singleton public class ChargeBackRisk { public boolean hasChargebackRisk(String id, String currencyCode) { diff --git a/core/src/main/java/haveno/core/payment/ChaseQuickPayAccount.java b/core/src/main/java/haveno/core/payment/ChaseQuickPayAccount.java index d481b6ddd9..808c6abe0b 100644 --- a/core/src/main/java/haveno/core/payment/ChaseQuickPayAccount.java +++ b/core/src/main/java/haveno/core/payment/ChaseQuickPayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/CountryBasedPaymentAccount.java b/core/src/main/java/haveno/core/payment/CountryBasedPaymentAccount.java index dcf22904c9..6fd86aafde 100644 --- a/core/src/main/java/haveno/core/payment/CountryBasedPaymentAccount.java +++ b/core/src/main/java/haveno/core/payment/CountryBasedPaymentAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/CryptoCurrencyAccount.java b/core/src/main/java/haveno/core/payment/CryptoCurrencyAccount.java index ac41b95c4e..fffb69a937 100644 --- a/core/src/main/java/haveno/core/payment/CryptoCurrencyAccount.java +++ b/core/src/main/java/haveno/core/payment/CryptoCurrencyAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/DomesticWireTransferAccount.java b/core/src/main/java/haveno/core/payment/DomesticWireTransferAccount.java index bebe18d88a..0707db411e 100644 --- a/core/src/main/java/haveno/core/payment/DomesticWireTransferAccount.java +++ b/core/src/main/java/haveno/core/payment/DomesticWireTransferAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/F2FAccount.java b/core/src/main/java/haveno/core/payment/F2FAccount.java index 93c8acd828..b75718ec68 100644 --- a/core/src/main/java/haveno/core/payment/F2FAccount.java +++ b/core/src/main/java/haveno/core/payment/F2FAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/FasterPaymentsAccount.java b/core/src/main/java/haveno/core/payment/FasterPaymentsAccount.java index 995943cae8..ceeb3eaf44 100644 --- a/core/src/main/java/haveno/core/payment/FasterPaymentsAccount.java +++ b/core/src/main/java/haveno/core/payment/FasterPaymentsAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/HalCashAccount.java b/core/src/main/java/haveno/core/payment/HalCashAccount.java index 88f949b8af..f2de687fe0 100644 --- a/core/src/main/java/haveno/core/payment/HalCashAccount.java +++ b/core/src/main/java/haveno/core/payment/HalCashAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/IfscBasedAccount.java b/core/src/main/java/haveno/core/payment/IfscBasedAccount.java index 28b43f198d..5326a7b814 100644 --- a/core/src/main/java/haveno/core/payment/IfscBasedAccount.java +++ b/core/src/main/java/haveno/core/payment/IfscBasedAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/ImpsAccount.java b/core/src/main/java/haveno/core/payment/ImpsAccount.java index 4eb66f8e60..42dd116668 100644 --- a/core/src/main/java/haveno/core/payment/ImpsAccount.java +++ b/core/src/main/java/haveno/core/payment/ImpsAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/InstantCryptoCurrencyAccount.java b/core/src/main/java/haveno/core/payment/InstantCryptoCurrencyAccount.java index 332b2d70ca..767c850e60 100644 --- a/core/src/main/java/haveno/core/payment/InstantCryptoCurrencyAccount.java +++ b/core/src/main/java/haveno/core/payment/InstantCryptoCurrencyAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/InteracETransferAccount.java b/core/src/main/java/haveno/core/payment/InteracETransferAccount.java index 61918a0351..579167c276 100644 --- a/core/src/main/java/haveno/core/payment/InteracETransferAccount.java +++ b/core/src/main/java/haveno/core/payment/InteracETransferAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/JapanBankAccount.java b/core/src/main/java/haveno/core/payment/JapanBankAccount.java index 3a7a47a915..51c15ea931 100644 --- a/core/src/main/java/haveno/core/payment/JapanBankAccount.java +++ b/core/src/main/java/haveno/core/payment/JapanBankAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/JapanBankData.java b/core/src/main/java/haveno/core/payment/JapanBankData.java index c3c01449dd..9181e0f48a 100644 --- a/core/src/main/java/haveno/core/payment/JapanBankData.java +++ b/core/src/main/java/haveno/core/payment/JapanBankData.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/MoneseAccount.java b/core/src/main/java/haveno/core/payment/MoneseAccount.java index 5e7a46007e..e7fe518bc9 100644 --- a/core/src/main/java/haveno/core/payment/MoneseAccount.java +++ b/core/src/main/java/haveno/core/payment/MoneseAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/MoneyBeamAccount.java b/core/src/main/java/haveno/core/payment/MoneyBeamAccount.java index 5873dc33c4..97fbcccf3b 100644 --- a/core/src/main/java/haveno/core/payment/MoneyBeamAccount.java +++ b/core/src/main/java/haveno/core/payment/MoneyBeamAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/MoneyGramAccount.java b/core/src/main/java/haveno/core/payment/MoneyGramAccount.java index 7634a94102..9bd633e72e 100644 --- a/core/src/main/java/haveno/core/payment/MoneyGramAccount.java +++ b/core/src/main/java/haveno/core/payment/MoneyGramAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -100,7 +100,6 @@ public final class MoneyGramAccount extends PaymentAccount { public MoneyGramAccount() { super(PaymentMethod.MONEY_GRAM); - tradeCurrencies.addAll(SUPPORTED_CURRENCIES); } @Override diff --git a/core/src/main/java/haveno/core/payment/NationalBankAccount.java b/core/src/main/java/haveno/core/payment/NationalBankAccount.java index 7a7b1ee0a1..16b2633689 100644 --- a/core/src/main/java/haveno/core/payment/NationalBankAccount.java +++ b/core/src/main/java/haveno/core/payment/NationalBankAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/NeftAccount.java b/core/src/main/java/haveno/core/payment/NeftAccount.java index 45321df025..4f4a2a4deb 100644 --- a/core/src/main/java/haveno/core/payment/NeftAccount.java +++ b/core/src/main/java/haveno/core/payment/NeftAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/NequiAccount.java b/core/src/main/java/haveno/core/payment/NequiAccount.java index 39d8344d4a..d74f509319 100644 --- a/core/src/main/java/haveno/core/payment/NequiAccount.java +++ b/core/src/main/java/haveno/core/payment/NequiAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/OKPayAccount.java b/core/src/main/java/haveno/core/payment/OKPayAccount.java index ebbf400c15..b1bac24383 100644 --- a/core/src/main/java/haveno/core/payment/OKPayAccount.java +++ b/core/src/main/java/haveno/core/payment/OKPayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -61,8 +61,6 @@ public final class OKPayAccount extends PaymentAccount { public OKPayAccount() { super(PaymentMethod.OK_PAY); - - tradeCurrencies.addAll(SUPPORTED_CURRENCIES); } @Override diff --git a/core/src/main/java/haveno/core/payment/PaxumAccount.java b/core/src/main/java/haveno/core/payment/PaxumAccount.java index e7c663905d..1f8b9e934d 100644 --- a/core/src/main/java/haveno/core/payment/PaxumAccount.java +++ b/core/src/main/java/haveno/core/payment/PaxumAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PayByMailAccount.java b/core/src/main/java/haveno/core/payment/PayByMailAccount.java index ffbb5c8919..e202472db6 100644 --- a/core/src/main/java/haveno/core/payment/PayByMailAccount.java +++ b/core/src/main/java/haveno/core/payment/PayByMailAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PayPalAccount.java b/core/src/main/java/haveno/core/payment/PayPalAccount.java new file mode 100644 index 0000000000..c7ec15183a --- /dev/null +++ b/core/src/main/java/haveno/core/payment/PayPalAccount.java @@ -0,0 +1,103 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.payment; + +import haveno.core.api.model.PaymentAccountFormField; +import haveno.core.locale.TraditionalCurrency; +import haveno.core.locale.TradeCurrency; +import haveno.core.payment.payload.PaymentAccountPayload; +import haveno.core.payment.payload.PaymentMethod; +import haveno.core.payment.payload.PayPalAccountPayload; +import lombok.EqualsAndHashCode; +import lombok.NonNull; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +public final class PayPalAccount extends PaymentAccount { + + // https://developer.paypal.com/docs/reports/reference/paypal-supported-currencies/ + public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of( + new TraditionalCurrency("AUD"), + new TraditionalCurrency("BRL"), + new TraditionalCurrency("CAD"), + new TraditionalCurrency("CNY"), + new TraditionalCurrency("CZK"), + new TraditionalCurrency("DKK"), + new TraditionalCurrency("EUR"), + new TraditionalCurrency("HKD"), + new TraditionalCurrency("HUF"), + new TraditionalCurrency("ILS"), + new TraditionalCurrency("JPY"), + new TraditionalCurrency("MYR"), + new TraditionalCurrency("MXN"), + new TraditionalCurrency("TWD"), + new TraditionalCurrency("NZD"), + new TraditionalCurrency("NOK"), + new TraditionalCurrency("PHP"), + new TraditionalCurrency("PLN"), + new TraditionalCurrency("GBP"), + new TraditionalCurrency("SGD"), + new TraditionalCurrency("SEK"), + new TraditionalCurrency("CHF"), + new TraditionalCurrency("THB"), + new TraditionalCurrency("USD")); + + private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of( + PaymentAccountFormField.FieldId.EMAIL_OR_MOBILE_NR_OR_USERNAME, + PaymentAccountFormField.FieldId.TRADE_CURRENCIES, + PaymentAccountFormField.FieldId.ACCOUNT_NAME, + PaymentAccountFormField.FieldId.EXTRA_INFO, + PaymentAccountFormField.FieldId.SALT); + + public PayPalAccount() { + super(PaymentMethod.PAYPAL); + } + + @Override + protected PaymentAccountPayload createPayload() { + return new PayPalAccountPayload(paymentMethod.getId(), id); + } + + @Override + public @NonNull List<TradeCurrency> getSupportedCurrencies() { + return SUPPORTED_CURRENCIES; + } + + @Override + public @NonNull List<PaymentAccountFormField.FieldId> getInputFieldIds() { + return INPUT_FIELD_IDS; + } + + public void setEmailOrMobileNrOrUsername(String emailOrMobileNrOrUsername) { + ((PayPalAccountPayload) paymentAccountPayload) + .setEmailOrMobileNrOrUsername(emailOrMobileNrOrUsername); + } + + public String getEmailOrMobileNrOrUsername() { + return ((PayPalAccountPayload) paymentAccountPayload).getEmailOrMobileNrOrUsername(); + } + + public void setExtraInfo(String extraInfo) { + ((PayPalAccountPayload) paymentAccountPayload).setExtraInfo(extraInfo); + } + + public String getExtraInfo() { + return ((PayPalAccountPayload) paymentAccountPayload).getExtraInfo(); + } +} diff --git a/core/src/main/java/haveno/core/payment/PaymentAccount.java b/core/src/main/java/haveno/core/payment/PaymentAccount.java index 123b9e1770..a9e03d8016 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccount.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccount.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -122,6 +139,10 @@ public abstract class PaymentAccount implements PersistablePayload { return getSingleTradeCurrency() == null || CurrencyUtil.isFiatCurrency(getSingleTradeCurrency().getCode()); // TODO: check if trade currencies contain fiat } + public boolean isCryptoCurrency() { + return getSingleTradeCurrency() != null && CurrencyUtil.isCryptoCurrency(getSingleTradeCurrency().getCode()); + } + /////////////////////////////////////////////////////////////////////////////////////////// // PROTO BUFFER @@ -399,7 +420,8 @@ public abstract class PaymentAccount implements PersistablePayload { case ANSWER: throw new IllegalArgumentException("Not implemented"); case BANK_ACCOUNT_NAME: - throw new IllegalArgumentException("Not implemented"); + processValidationResult(new LengthValidator(2, 100).validate(value)); + break; case BANK_ACCOUNT_NUMBER: throw new IllegalArgumentException("Not implemented"); case BANK_ACCOUNT_TYPE: @@ -498,7 +520,8 @@ public abstract class PaymentAccount implements PersistablePayload { case NATIONAL_ACCOUNT_ID: throw new IllegalArgumentException("Not implemented"); case PAYID: - throw new IllegalArgumentException("Not implemented"); + processValidationResult(new LengthValidator(2, 100).validate(value)); + break; case PIX_KEY: throw new IllegalArgumentException("Not implemented"); case POSTAL_ADDRESS: @@ -533,7 +556,13 @@ public abstract class PaymentAccount implements PersistablePayload { Optional<List<TradeCurrency>> tradeCurrencies = CurrencyUtil.getTradeCurrenciesInList(currencyCodes, getSupportedCurrencies()); if (!tradeCurrencies.isPresent()) throw new IllegalArgumentException("No trade currencies were found in the " + getPaymentMethod().getDisplayString() + " account form"); break; - case USER_NAME: + case USERNAME: + processValidationResult(new LengthValidator(3, 100).validate(value)); + break; + case EMAIL_OR_MOBILE_NR_OR_USERNAME: + processValidationResult(new LengthValidator(3, 100).validate(value)); + break; + case EMAIL_OR_MOBILE_NR_OR_CASHTAG: processValidationResult(new LengthValidator(3, 100).validate(value)); break; case ADDRESS: @@ -579,7 +608,11 @@ public abstract class PaymentAccount implements PersistablePayload { case ANSWER: throw new IllegalArgumentException("Not implemented"); case BANK_ACCOUNT_NAME: - throw new IllegalArgumentException("Not implemented"); + field.setComponent(PaymentAccountFormField.Component.TEXT); + field.setLabel(Res.get("payment.account.owner")); + field.setMinLength(2); + field.setMaxLength(100); + break; case BANK_ACCOUNT_NUMBER: throw new IllegalArgumentException("Not implemented"); case BANK_ACCOUNT_TYPE: @@ -707,7 +740,9 @@ public abstract class PaymentAccount implements PersistablePayload { case NATIONAL_ACCOUNT_ID: throw new IllegalArgumentException("Not implemented"); case PAYID: - throw new IllegalArgumentException("Not implemented"); + field.setComponent(PaymentAccountFormField.Component.TEXT); + field.setLabel(Res.get("payment.email.mobile")); + break; case PIX_KEY: throw new IllegalArgumentException("Not implemented"); case POSTAL_ADDRESS: @@ -743,9 +778,21 @@ public abstract class PaymentAccount implements PersistablePayload { field.setSupportedCurrencies(getSupportedCurrencies()); field.setValue(String.join(",", getSupportedCurrencies().stream().map(TradeCurrency::getCode).collect(Collectors.toList()))); break; - case USER_NAME: + case USERNAME: field.setComponent(PaymentAccountFormField.Component.TEXT); - field.setLabel(Res.get("payment.account.userName")); + field.setLabel(Res.get("payment.account.username")); + field.setMinLength(3); + field.setMaxLength(100); + break; + case EMAIL_OR_MOBILE_NR_OR_USERNAME: + field.setComponent(PaymentAccountFormField.Component.TEXT); + field.setLabel(Res.get("payment.email.mobile.username")); + field.setMinLength(3); + field.setMaxLength(100); + break; + case EMAIL_OR_MOBILE_NR_OR_CASHTAG: + field.setComponent(PaymentAccountFormField.Component.TEXT); + field.setLabel(Res.get("payment.email.mobile.cashtag")); field.setMinLength(3); field.setMaxLength(100); break; diff --git a/core/src/main/java/haveno/core/payment/PaymentAccountFactory.java b/core/src/main/java/haveno/core/payment/PaymentAccountFactory.java index 109cbfb19f..64c8bdbc52 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccountFactory.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccountFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -86,6 +86,8 @@ public class PaymentAccountFactory { return new TransferwiseAccount(); case PaymentMethod.TRANSFERWISE_USD_ID: return new TransferwiseUsdAccount(); + case PaymentMethod.PAYPAL_ID: + return new PayPalAccount(); case PaymentMethod.PAYSERA_ID: return new PayseraAccount(); case PaymentMethod.PAXUM_ID: @@ -130,15 +132,14 @@ public class PaymentAccountFactory { return new AchTransferAccount(); case PaymentMethod.DOMESTIC_WIRE_TRANSFER_ID: return new DomesticWireTransferAccount(); - - // Cannot be deleted as it would break old trade history entries - case PaymentMethod.OK_PAY_ID: - return new OKPayAccount(); case PaymentMethod.CASH_APP_ID: return new CashAppAccount(); case PaymentMethod.VENMO_ID: return new VenmoAccount(); + // Cannot be deleted as it would break old trade history entries + case PaymentMethod.OK_PAY_ID: + return new OKPayAccount(); default: throw new RuntimeException("Not supported PaymentMethod: " + paymentMethod); } diff --git a/core/src/main/java/haveno/core/payment/PaymentAccountList.java b/core/src/main/java/haveno/core/payment/PaymentAccountList.java index d12e8c02c0..f9045241f2 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccountList.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccountList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PaymentAccountTypeAdapter.java b/core/src/main/java/haveno/core/payment/PaymentAccountTypeAdapter.java index f7766e2202..0160a1a736 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccountTypeAdapter.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccountTypeAdapter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java b/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java index d4c8fe8bda..11575aeb62 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccountUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -66,6 +66,7 @@ import static haveno.core.payment.payload.PaymentMethod.NATIONAL_BANK_ID; import static haveno.core.payment.payload.PaymentMethod.NEFT_ID; import static haveno.core.payment.payload.PaymentMethod.NEQUI_ID; import static haveno.core.payment.payload.PaymentMethod.PAXUM_ID; +import static haveno.core.payment.payload.PaymentMethod.PAYPAL_ID; import static haveno.core.payment.payload.PaymentMethod.PAYSERA_ID; import static haveno.core.payment.payload.PaymentMethod.PAYTM_ID; import static haveno.core.payment.payload.PaymentMethod.PERFECT_MONEY_ID; @@ -123,7 +124,7 @@ public class PaymentAccountUtil { AccountAgeWitnessService accountAgeWitnessService) { boolean hasChargebackRisk = hasChargebackRisk(offer.getPaymentMethod(), offer.getCurrencyCode()); boolean hasValidAccountAgeWitness = accountAgeWitnessService.getMyTradeLimit(paymentAccount, - offer.getCurrencyCode(), offer.getMirroredDirection()) >= offer.getMinAmount().longValueExact(); + offer.getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()) >= offer.getMinAmount().longValueExact(); return !hasChargebackRisk || hasValidAccountAgeWitness; } @@ -214,6 +215,8 @@ public class PaymentAccountUtil { return USPostalMoneyOrderAccount.SUPPORTED_CURRENCIES; case VENMO_ID: return VenmoAccount.SUPPORTED_CURRENCIES; + case PAYPAL_ID: + return PayPalAccount.SUPPORTED_CURRENCIES; case JAPAN_BANK_ID: return JapanBankAccount.SUPPORTED_CURRENCIES; case WECHAT_PAY_ID: diff --git a/core/src/main/java/haveno/core/payment/PaymentAccounts.java b/core/src/main/java/haveno/core/payment/PaymentAccounts.java index a77a05cc2d..975a2403b2 100644 --- a/core/src/main/java/haveno/core/payment/PaymentAccounts.java +++ b/core/src/main/java/haveno/core/payment/PaymentAccounts.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PayseraAccount.java b/core/src/main/java/haveno/core/payment/PayseraAccount.java index 2250dd1a18..0254cd7c71 100644 --- a/core/src/main/java/haveno/core/payment/PayseraAccount.java +++ b/core/src/main/java/haveno/core/payment/PayseraAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PaytmAccount.java b/core/src/main/java/haveno/core/payment/PaytmAccount.java index 3aaf727a1a..e434179137 100644 --- a/core/src/main/java/haveno/core/payment/PaytmAccount.java +++ b/core/src/main/java/haveno/core/payment/PaytmAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PerfectMoneyAccount.java b/core/src/main/java/haveno/core/payment/PerfectMoneyAccount.java index 014c2a4eef..84a51bff02 100644 --- a/core/src/main/java/haveno/core/payment/PerfectMoneyAccount.java +++ b/core/src/main/java/haveno/core/payment/PerfectMoneyAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PixAccount.java b/core/src/main/java/haveno/core/payment/PixAccount.java index df456d9c96..c0e3b72c82 100644 --- a/core/src/main/java/haveno/core/payment/PixAccount.java +++ b/core/src/main/java/haveno/core/payment/PixAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PopmoneyAccount.java b/core/src/main/java/haveno/core/payment/PopmoneyAccount.java index a233a32ba6..22fd446257 100644 --- a/core/src/main/java/haveno/core/payment/PopmoneyAccount.java +++ b/core/src/main/java/haveno/core/payment/PopmoneyAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/PromptPayAccount.java b/core/src/main/java/haveno/core/payment/PromptPayAccount.java index 1094993c25..026a643fba 100644 --- a/core/src/main/java/haveno/core/payment/PromptPayAccount.java +++ b/core/src/main/java/haveno/core/payment/PromptPayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/ReceiptPredicates.java b/core/src/main/java/haveno/core/payment/ReceiptPredicates.java index 720d36a5c5..a56fa4491b 100644 --- a/core/src/main/java/haveno/core/payment/ReceiptPredicates.java +++ b/core/src/main/java/haveno/core/payment/ReceiptPredicates.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/ReceiptValidator.java b/core/src/main/java/haveno/core/payment/ReceiptValidator.java index 827453ac9a..c2d9409e63 100644 --- a/core/src/main/java/haveno/core/payment/ReceiptValidator.java +++ b/core/src/main/java/haveno/core/payment/ReceiptValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/RevolutAccount.java b/core/src/main/java/haveno/core/payment/RevolutAccount.java index 93b6ab6c38..f268a0d0d0 100644 --- a/core/src/main/java/haveno/core/payment/RevolutAccount.java +++ b/core/src/main/java/haveno/core/payment/RevolutAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -32,7 +32,7 @@ import java.util.List; public final class RevolutAccount extends PaymentAccount { private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of( - PaymentAccountFormField.FieldId.USER_NAME, + PaymentAccountFormField.FieldId.USERNAME, PaymentAccountFormField.FieldId.TRADE_CURRENCIES, PaymentAccountFormField.FieldId.ACCOUNT_NAME, PaymentAccountFormField.FieldId.SALT @@ -74,7 +74,6 @@ public final class RevolutAccount extends PaymentAccount { public RevolutAccount() { super(PaymentMethod.REVOLUT); - tradeCurrencies.addAll(getSupportedCurrencies()); } @Override @@ -82,16 +81,16 @@ public final class RevolutAccount extends PaymentAccount { return new RevolutAccountPayload(paymentMethod.getId(), id); } - public void setUserName(String userName) { - revolutAccountPayload().setUserName(userName); + public void setUsername(String userame) { + revolutAccountPayload().setUserName(userame); } - public String getUserName() { - return (revolutAccountPayload()).getUserName(); + public String getUsername() { + return (revolutAccountPayload()).getUsername(); } - public boolean userNameNotSet() { - return (revolutAccountPayload()).userNameNotSet(); + public boolean usernameNotSet() { + return (revolutAccountPayload()).usernameNotSet(); } private RevolutAccountPayload revolutAccountPayload() { diff --git a/core/src/main/java/haveno/core/payment/RtgsAccount.java b/core/src/main/java/haveno/core/payment/RtgsAccount.java index 3a6a90ec50..e7bc4831b2 100644 --- a/core/src/main/java/haveno/core/payment/RtgsAccount.java +++ b/core/src/main/java/haveno/core/payment/RtgsAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SameBankAccount.java b/core/src/main/java/haveno/core/payment/SameBankAccount.java index c5d9316efa..3a2af39946 100644 --- a/core/src/main/java/haveno/core/payment/SameBankAccount.java +++ b/core/src/main/java/haveno/core/payment/SameBankAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SameCountryRestrictedBankAccount.java b/core/src/main/java/haveno/core/payment/SameCountryRestrictedBankAccount.java index e0d464ea53..ea2f3bd33c 100644 --- a/core/src/main/java/haveno/core/payment/SameCountryRestrictedBankAccount.java +++ b/core/src/main/java/haveno/core/payment/SameCountryRestrictedBankAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SatispayAccount.java b/core/src/main/java/haveno/core/payment/SatispayAccount.java index 6fee6781de..2a93ceed4c 100644 --- a/core/src/main/java/haveno/core/payment/SatispayAccount.java +++ b/core/src/main/java/haveno/core/payment/SatispayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SepaAccount.java b/core/src/main/java/haveno/core/payment/SepaAccount.java index 5697eca2dc..1ad984458c 100644 --- a/core/src/main/java/haveno/core/payment/SepaAccount.java +++ b/core/src/main/java/haveno/core/payment/SepaAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SepaInstantAccount.java b/core/src/main/java/haveno/core/payment/SepaInstantAccount.java index fa5454f85a..d006aa84b7 100644 --- a/core/src/main/java/haveno/core/payment/SepaInstantAccount.java +++ b/core/src/main/java/haveno/core/payment/SepaInstantAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SpecificBanksAccount.java b/core/src/main/java/haveno/core/payment/SpecificBanksAccount.java index 4f1879577b..d74fd36a15 100644 --- a/core/src/main/java/haveno/core/payment/SpecificBanksAccount.java +++ b/core/src/main/java/haveno/core/payment/SpecificBanksAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/StrikeAccount.java b/core/src/main/java/haveno/core/payment/StrikeAccount.java index 56579281b9..d0e0c930e7 100644 --- a/core/src/main/java/haveno/core/payment/StrikeAccount.java +++ b/core/src/main/java/haveno/core/payment/StrikeAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SwiftAccount.java b/core/src/main/java/haveno/core/payment/SwiftAccount.java index 2ffa7cea59..c084c28af7 100644 --- a/core/src/main/java/haveno/core/payment/SwiftAccount.java +++ b/core/src/main/java/haveno/core/payment/SwiftAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/SwishAccount.java b/core/src/main/java/haveno/core/payment/SwishAccount.java index de9517ed8a..a726a9a14a 100644 --- a/core/src/main/java/haveno/core/payment/SwishAccount.java +++ b/core/src/main/java/haveno/core/payment/SwishAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/TikkieAccount.java b/core/src/main/java/haveno/core/payment/TikkieAccount.java index bcacabe730..123b2a0d58 100644 --- a/core/src/main/java/haveno/core/payment/TikkieAccount.java +++ b/core/src/main/java/haveno/core/payment/TikkieAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/TradeLimits.java b/core/src/main/java/haveno/core/payment/TradeLimits.java index e41ec8423f..92ac29b0a8 100644 --- a/core/src/main/java/haveno/core/payment/TradeLimits.java +++ b/core/src/main/java/haveno/core/payment/TradeLimits.java @@ -1,37 +1,38 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; import com.google.common.annotations.VisibleForTesting; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.util.MathUtils; import haveno.core.trade.HavenoUtils; +import java.math.BigInteger; +import javax.annotation.Nullable; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.math.BigInteger; - @Slf4j @Singleton public class TradeLimits { - private static final BigInteger MAX_TRADE_LIMIT = HavenoUtils.xmrToAtomicUnits(20.0); // max trade limit for lowest risk payment method. Others will get derived from that. + private static final BigInteger MAX_TRADE_LIMIT = HavenoUtils.xmrToAtomicUnits(528); // max trade limit for lowest risk payment method. Others will get derived from that. + private static final BigInteger MAX_TRADE_LIMIT_WITHOUT_BUYER_AS_TAKER_DEPOSIT = HavenoUtils.xmrToAtomicUnits(1); // max trade limit without deposit from buyer + @Nullable @Getter private static TradeLimits INSTANCE; @@ -58,6 +59,15 @@ public class TradeLimits { return MAX_TRADE_LIMIT; } + /** + * The maximum trade limit without a buyer deposit. + * + * @return the maximum trade limit for a buyer without a deposit + */ + public BigInteger getMaxTradeLimitBuyerAsTakerWithoutDeposit() { + return MAX_TRADE_LIMIT_WITHOUT_BUYER_AS_TAKER_DEPOSIT; + } + // We possibly rounded value for the first month gets multiplied by 4 to get the trade limit after the account // age witness is not considered anymore (> 2 months). diff --git a/core/src/main/java/haveno/core/payment/TransferwiseAccount.java b/core/src/main/java/haveno/core/payment/TransferwiseAccount.java index 15029a157b..398eaaf1bf 100644 --- a/core/src/main/java/haveno/core/payment/TransferwiseAccount.java +++ b/core/src/main/java/haveno/core/payment/TransferwiseAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/TransferwiseUsdAccount.java b/core/src/main/java/haveno/core/payment/TransferwiseUsdAccount.java index 8ab90f13bb..94491ddbf0 100644 --- a/core/src/main/java/haveno/core/payment/TransferwiseUsdAccount.java +++ b/core/src/main/java/haveno/core/payment/TransferwiseUsdAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/USPostalMoneyOrderAccount.java b/core/src/main/java/haveno/core/payment/USPostalMoneyOrderAccount.java index 9265f6e670..41667563cf 100644 --- a/core/src/main/java/haveno/core/payment/USPostalMoneyOrderAccount.java +++ b/core/src/main/java/haveno/core/payment/USPostalMoneyOrderAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/UpholdAccount.java b/core/src/main/java/haveno/core/payment/UpholdAccount.java index 967647d9ef..e4db1d514d 100644 --- a/core/src/main/java/haveno/core/payment/UpholdAccount.java +++ b/core/src/main/java/haveno/core/payment/UpholdAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -69,7 +69,6 @@ public final class UpholdAccount extends PaymentAccount { public UpholdAccount() { super(PaymentMethod.UPHOLD); - tradeCurrencies.addAll(SUPPORTED_CURRENCIES); } @Override diff --git a/core/src/main/java/haveno/core/payment/UpiAccount.java b/core/src/main/java/haveno/core/payment/UpiAccount.java index 204bc87790..1042e9d0e3 100644 --- a/core/src/main/java/haveno/core/payment/UpiAccount.java +++ b/core/src/main/java/haveno/core/payment/UpiAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/VenmoAccount.java b/core/src/main/java/haveno/core/payment/VenmoAccount.java index de62562cc6..870438b38c 100644 --- a/core/src/main/java/haveno/core/payment/VenmoAccount.java +++ b/core/src/main/java/haveno/core/payment/VenmoAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; @@ -28,14 +28,16 @@ import lombok.NonNull; import java.util.List; -// Removed due too high chargeback risk -// Cannot be deleted as it would break old trade history entries -@Deprecated @EqualsAndHashCode(callSuper = true) public final class VenmoAccount extends PaymentAccount { public static final List<TradeCurrency> SUPPORTED_CURRENCIES = List.of(new TraditionalCurrency("USD")); + private static final List<PaymentAccountFormField.FieldId> INPUT_FIELD_IDS = List.of( + PaymentAccountFormField.FieldId.EMAIL_OR_MOBILE_NR_OR_USERNAME, + PaymentAccountFormField.FieldId.ACCOUNT_NAME, + PaymentAccountFormField.FieldId.SALT); + public VenmoAccount() { super(PaymentMethod.VENMO); setSingleTradeCurrency(SUPPORTED_CURRENCIES.get(0)); @@ -53,22 +55,15 @@ public final class VenmoAccount extends PaymentAccount { @Override public @NonNull List<PaymentAccountFormField.FieldId> getInputFieldIds() { - throw new RuntimeException("Not implemented"); + return INPUT_FIELD_IDS; } - public void setVenmoUserName(String venmoUserName) { - ((VenmoAccountPayload) paymentAccountPayload).setVenmoUserName(venmoUserName); + public void setNameOrUsernameOrEmailOrMobileNr(String usernameOrEmailOrMobileNr) { + ((VenmoAccountPayload) paymentAccountPayload) + .setEmailOrMobileNrOrUsername(usernameOrEmailOrMobileNr); } - public String getVenmoUserName() { - return ((VenmoAccountPayload) paymentAccountPayload).getVenmoUserName(); - } - - public void setHolderName(String holderName) { - ((VenmoAccountPayload) paymentAccountPayload).setHolderName(holderName); - } - - public String getHolderName() { - return ((VenmoAccountPayload) paymentAccountPayload).getHolderName(); + public String getNameOrUsernameOrEmailOrMobileNr() { + return ((VenmoAccountPayload) paymentAccountPayload).getEmailOrMobileNrOrUsername(); } } diff --git a/core/src/main/java/haveno/core/payment/VerseAccount.java b/core/src/main/java/haveno/core/payment/VerseAccount.java index d6ea99e6a0..f45015a77a 100644 --- a/core/src/main/java/haveno/core/payment/VerseAccount.java +++ b/core/src/main/java/haveno/core/payment/VerseAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/WeChatPayAccount.java b/core/src/main/java/haveno/core/payment/WeChatPayAccount.java index ed07689718..e7099879ea 100644 --- a/core/src/main/java/haveno/core/payment/WeChatPayAccount.java +++ b/core/src/main/java/haveno/core/payment/WeChatPayAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/WesternUnionAccount.java b/core/src/main/java/haveno/core/payment/WesternUnionAccount.java index e4846b62f1..64f18c205b 100644 --- a/core/src/main/java/haveno/core/payment/WesternUnionAccount.java +++ b/core/src/main/java/haveno/core/payment/WesternUnionAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/ZelleAccount.java b/core/src/main/java/haveno/core/payment/ZelleAccount.java index 46638b935e..4415f4ed42 100644 --- a/core/src/main/java/haveno/core/payment/ZelleAccount.java +++ b/core/src/main/java/haveno/core/payment/ZelleAccount.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/main/java/haveno/core/payment/payload/AchTransferAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/AchTransferAccountPayload.java index 634bad2bcd..7ed9d23c4d 100644 --- a/core/src/main/java/haveno/core/payment/payload/AchTransferAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/AchTransferAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/AdvancedCashAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/AdvancedCashAccountPayload.java index 6d5c85b922..727e60d3f3 100644 --- a/core/src/main/java/haveno/core/payment/payload/AdvancedCashAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/AdvancedCashAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/AliPayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/AliPayAccountPayload.java index 959248b3a6..d44c185208 100644 --- a/core/src/main/java/haveno/core/payment/payload/AliPayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/AliPayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/AmazonGiftCardAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/AmazonGiftCardAccountPayload.java index 5fa75e039e..266e08e946 100644 --- a/core/src/main/java/haveno/core/payment/payload/AmazonGiftCardAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/AmazonGiftCardAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/AssetAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/AssetAccountPayload.java index 8eb49c02c2..7fd19215e5 100644 --- a/core/src/main/java/haveno/core/payment/payload/AssetAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/AssetAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/AustraliaPayidAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/AustraliaPayidAccountPayload.java index 28f2106e53..6620e8a22a 100644 --- a/core/src/main/java/haveno/core/payment/payload/AustraliaPayidAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/AustraliaPayidAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -38,6 +38,7 @@ import java.util.Map; public final class AustraliaPayidAccountPayload extends PaymentAccountPayload { private String payid = ""; private String bankAccountName = ""; + private String extraInfo = ""; public AustraliaPayidAccountPayload(String paymentMethod, String id) { super(paymentMethod, id); @@ -52,6 +53,7 @@ public final class AustraliaPayidAccountPayload extends PaymentAccountPayload { String id, String payid, String bankAccountName, + String extraInfo, long maxTradePeriod, Map<String, String> excludeFromJsonDataMap) { super(paymentMethod, @@ -61,6 +63,7 @@ public final class AustraliaPayidAccountPayload extends PaymentAccountPayload { this.payid = payid; this.bankAccountName = bankAccountName; + this.extraInfo = extraInfo; } @Override @@ -70,6 +73,7 @@ public final class AustraliaPayidAccountPayload extends PaymentAccountPayload { protobuf.AustraliaPayidPayload.newBuilder() .setPayid(payid) .setBankAccountName(bankAccountName) + .setExtraInfo(extraInfo) ).build(); } @@ -79,6 +83,7 @@ public final class AustraliaPayidAccountPayload extends PaymentAccountPayload { proto.getId(), AustraliaPayidPayload.getPayid(), AustraliaPayidPayload.getBankAccountName(), + AustraliaPayidPayload.getExtraInfo(), proto.getMaxTradePeriod(), CollectionUtils.isEmpty(proto.getExcludeFromJsonDataMap()) ? null : new HashMap<>(proto.getExcludeFromJsonDataMap())); } @@ -97,7 +102,8 @@ public final class AustraliaPayidAccountPayload extends PaymentAccountPayload { public String getPaymentDetailsForTradePopup() { return Res.get("payment.australia.payid") + ": " + payid + "\n" + - Res.get("payment.account.owner") + ": " + bankAccountName; + Res.get("payment.account.owner") + ": " + bankAccountName + "\n" + + Res.get("payment.shared.extraInfo") + ": " + extraInfo; } diff --git a/core/src/main/java/haveno/core/payment/payload/BankAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/BankAccountPayload.java index 1c7225e15f..d0c48c577e 100644 --- a/core/src/main/java/haveno/core/payment/payload/BankAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/BankAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/BizumAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/BizumAccountPayload.java index 70378858ed..b8081a7227 100644 --- a/core/src/main/java/haveno/core/payment/payload/BizumAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/BizumAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/CapitualAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CapitualAccountPayload.java index d8776f3e58..8195ac7fe4 100644 --- a/core/src/main/java/haveno/core/payment/payload/CapitualAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CapitualAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/CashAppAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CashAppAccountPayload.java index 32148d68d1..bec0f340e5 100644 --- a/core/src/main/java/haveno/core/payment/payload/CashAppAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CashAppAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -29,29 +29,27 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -// Cannot be deleted as it would break old trade history entries -// Removed due too high chargeback risk -@Deprecated @EqualsAndHashCode(callSuper = true) @ToString @Setter @Getter @Slf4j public final class CashAppAccountPayload extends PaymentAccountPayload { - private String cashTag = ""; + private String emailOrMobileNrOrCashtag = ""; + private String extraInfo = ""; public CashAppAccountPayload(String paymentMethod, String id) { super(paymentMethod, id); } - /////////////////////////////////////////////////////////////////////////////////////////// // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// private CashAppAccountPayload(String paymentMethod, String id, - String cashTag, + String emailOrMobileNrOrCashtag, + String extraInfo, long maxTradePeriod, Map<String, String> excludeFromJsonDataMap) { super(paymentMethod, @@ -59,21 +57,24 @@ public final class CashAppAccountPayload extends PaymentAccountPayload { maxTradePeriod, excludeFromJsonDataMap); - this.cashTag = cashTag; + this.emailOrMobileNrOrCashtag = emailOrMobileNrOrCashtag; + this.extraInfo = extraInfo; } @Override public Message toProtoMessage() { return getPaymentAccountPayloadBuilder() .setCashAppAccountPayload(protobuf.CashAppAccountPayload.newBuilder() - .setCashTag(cashTag)) + .setExtraInfo(extraInfo) + .setEmailOrMobileNrOrCashtag(emailOrMobileNrOrCashtag)) .build(); } public static CashAppAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { return new CashAppAccountPayload(proto.getPaymentMethodId(), proto.getId(), - proto.getCashAppAccountPayload().getCashTag(), + proto.getCashAppAccountPayload().getEmailOrMobileNrOrCashtag(), + proto.getCashAppAccountPayload().getExtraInfo(), proto.getMaxTradePeriod(), new HashMap<>(proto.getExcludeFromJsonDataMap())); } @@ -85,7 +86,10 @@ public final class CashAppAccountPayload extends PaymentAccountPayload { @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account") + " " + cashTag; + return Res.get(paymentMethodId) + " - " + + Res.getWithCol("payment.email.mobile.cashtag") + + " " + emailOrMobileNrOrCashtag + "\n" + + Res.getWithCol("payment.shared.extraInfo") + " " + extraInfo+ "\n"; } @Override @@ -95,6 +99,6 @@ public final class CashAppAccountPayload extends PaymentAccountPayload { @Override public byte[] getAgeWitnessInputData() { - return super.getAgeWitnessInputData(cashTag.getBytes(StandardCharsets.UTF_8)); + return super.getAgeWitnessInputData(emailOrMobileNrOrCashtag.getBytes(StandardCharsets.UTF_8)); } } diff --git a/core/src/main/java/haveno/core/payment/payload/CashAtAtmAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CashAtAtmAccountPayload.java index b77f3875b1..b51086bd78 100644 --- a/core/src/main/java/haveno/core/payment/payload/CashAtAtmAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CashAtAtmAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/CashDepositAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CashDepositAccountPayload.java index f476bc4486..13d4c462fd 100644 --- a/core/src/main/java/haveno/core/payment/payload/CashDepositAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CashDepositAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/CelPayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CelPayAccountPayload.java index 5c973f8a02..5dbc267e83 100644 --- a/core/src/main/java/haveno/core/payment/payload/CelPayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CelPayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/ChaseQuickPayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/ChaseQuickPayAccountPayload.java index 5634de7a11..19f56a44ac 100644 --- a/core/src/main/java/haveno/core/payment/payload/ChaseQuickPayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/ChaseQuickPayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/CountryBasedPaymentAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CountryBasedPaymentAccountPayload.java index fd093478ea..94ce063097 100644 --- a/core/src/main/java/haveno/core/payment/payload/CountryBasedPaymentAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CountryBasedPaymentAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/CryptoCurrencyAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/CryptoCurrencyAccountPayload.java index ef0fc3380f..c77918bdf7 100644 --- a/core/src/main/java/haveno/core/payment/payload/CryptoCurrencyAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/CryptoCurrencyAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/DomesticWireTransferAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/DomesticWireTransferAccountPayload.java index ce4336642f..8112929cf7 100644 --- a/core/src/main/java/haveno/core/payment/payload/DomesticWireTransferAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/DomesticWireTransferAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/F2FAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/F2FAccountPayload.java index 10934f825b..d25a4ac6e2 100644 --- a/core/src/main/java/haveno/core/payment/payload/F2FAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/F2FAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/FasterPaymentsAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/FasterPaymentsAccountPayload.java index ca729a2b0e..50eb246579 100644 --- a/core/src/main/java/haveno/core/payment/payload/FasterPaymentsAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/FasterPaymentsAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/HalCashAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/HalCashAccountPayload.java index 2ce1dc8ff9..8603b4ca25 100644 --- a/core/src/main/java/haveno/core/payment/payload/HalCashAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/HalCashAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/ImpsAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/ImpsAccountPayload.java index 0dc4b082e9..0f17f8dbc9 100644 --- a/core/src/main/java/haveno/core/payment/payload/ImpsAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/ImpsAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/InstantCryptoCurrencyPayload.java b/core/src/main/java/haveno/core/payment/payload/InstantCryptoCurrencyPayload.java index 599ff08f80..b13c272e0c 100644 --- a/core/src/main/java/haveno/core/payment/payload/InstantCryptoCurrencyPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/InstantCryptoCurrencyPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java index f396cfde5c..26105e7478 100644 --- a/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/InteracETransferAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/JapanBankAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/JapanBankAccountPayload.java index be9ce2c9f2..6e46660226 100644 --- a/core/src/main/java/haveno/core/payment/payload/JapanBankAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/JapanBankAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/MoneseAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/MoneseAccountPayload.java index 0d5e12633f..02ef13eb6a 100644 --- a/core/src/main/java/haveno/core/payment/payload/MoneseAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/MoneseAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -77,7 +77,7 @@ public final class MoneseAccountPayload extends PaymentAccountPayload { @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + holderName; + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.username") + " " + holderName; } @Override diff --git a/core/src/main/java/haveno/core/payment/payload/MoneyBeamAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/MoneyBeamAccountPayload.java index 5c18c2d16f..156780d1af 100644 --- a/core/src/main/java/haveno/core/payment/payload/MoneyBeamAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/MoneyBeamAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/MoneyGramAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/MoneyGramAccountPayload.java index dcdfada744..07b08b6f9e 100644 --- a/core/src/main/java/haveno/core/payment/payload/MoneyGramAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/MoneyGramAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/NationalBankAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/NationalBankAccountPayload.java index 4f61382f09..f181edbdd0 100644 --- a/core/src/main/java/haveno/core/payment/payload/NationalBankAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/NationalBankAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/NeftAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/NeftAccountPayload.java index ba6d525483..55592fe58b 100644 --- a/core/src/main/java/haveno/core/payment/payload/NeftAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/NeftAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/NequiAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/NequiAccountPayload.java index 0c044e87f1..ae7e90f74d 100644 --- a/core/src/main/java/haveno/core/payment/payload/NequiAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/NequiAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/OKPayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/OKPayAccountPayload.java index 28ef97d28e..5b6a938d69 100644 --- a/core/src/main/java/haveno/core/payment/payload/OKPayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/OKPayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PaxumAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PaxumAccountPayload.java index 90262c8c5e..91123cba25 100644 --- a/core/src/main/java/haveno/core/payment/payload/PaxumAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PaxumAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PayByMailAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PayByMailAccountPayload.java index 49cd1b6dcc..7cf544c687 100644 --- a/core/src/main/java/haveno/core/payment/payload/PayByMailAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PayByMailAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PayPalAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PayPalAccountPayload.java new file mode 100644 index 0000000000..76e4f87814 --- /dev/null +++ b/core/src/main/java/haveno/core/payment/payload/PayPalAccountPayload.java @@ -0,0 +1,101 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.payment.payload; + +import com.google.protobuf.Message; +import haveno.core.locale.Res; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +@EqualsAndHashCode(callSuper = true) +@ToString +@Setter +@Getter +@Slf4j +public final class PayPalAccountPayload extends PaymentAccountPayload { + private String emailOrMobileNrOrUsername = ""; + private String extraInfo = ""; + + public PayPalAccountPayload(String paymentMethod, String id) { + super(paymentMethod, id); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTO BUFFER + /////////////////////////////////////////////////////////////////////////////////////////// + + private PayPalAccountPayload(String paymentMethod, + String id, + String emailOrMobileNrOrUsername, + String extraInfo, + long maxTradePeriod, + Map<String, String> excludeFromJsonDataMap) { + super(paymentMethod, + id, + maxTradePeriod, + excludeFromJsonDataMap); + + this.emailOrMobileNrOrUsername = emailOrMobileNrOrUsername; + this.extraInfo = extraInfo; + } + + @Override + public Message toProtoMessage() { + return getPaymentAccountPayloadBuilder() + .setPaypalAccountPayload(protobuf.PayPalAccountPayload.newBuilder() + .setExtraInfo(extraInfo) + .setEmailOrMobileNrOrUsername(emailOrMobileNrOrUsername)) + .build(); + } + + public static PayPalAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { + return new PayPalAccountPayload(proto.getPaymentMethodId(), + proto.getId(), + proto.getPaypalAccountPayload().getEmailOrMobileNrOrUsername(), + proto.getPaypalAccountPayload().getExtraInfo(), + proto.getMaxTradePeriod(), + new HashMap<>(proto.getExcludeFromJsonDataMap())); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // API + /////////////////////////////////////////////////////////////////////////////////////////// + + @Override + public String getPaymentDetails() { + return Res.getWithCol("payment.email.mobile.username") + " "+ emailOrMobileNrOrUsername + "\n" + + Res.getWithCol("payment.shared.extraInfo") + " " + extraInfo+ "\n"; + } + + @Override + public String getPaymentDetailsForTradePopup() { + return getPaymentDetails(); + } + + @Override + public byte[] getAgeWitnessInputData() { + return super.getAgeWitnessInputData(emailOrMobileNrOrUsername.getBytes(StandardCharsets.UTF_8)); + } +} diff --git a/core/src/main/java/haveno/core/payment/payload/PayloadWithHolderName.java b/core/src/main/java/haveno/core/payment/payload/PayloadWithHolderName.java index 9d6e8cea01..977ac0501f 100644 --- a/core/src/main/java/haveno/core/payment/payload/PayloadWithHolderName.java +++ b/core/src/main/java/haveno/core/payment/payload/PayloadWithHolderName.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PaymentAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PaymentAccountPayload.java index d4e737fb47..0d3439d086 100644 --- a/core/src/main/java/haveno/core/payment/payload/PaymentAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PaymentAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java b/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java index 532142059f..49302f610a 100644 --- a/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java +++ b/core/src/main/java/haveno/core/payment/payload/PaymentMethod.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -23,7 +40,6 @@ import haveno.common.proto.persistable.PersistablePayload; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.locale.TradeCurrency; -import haveno.core.offer.OfferRestrictions; import haveno.core.payment.AchTransferAccount; import haveno.core.payment.AdvancedCashAccount; import haveno.core.payment.AliPayAccount; @@ -31,8 +47,10 @@ import haveno.core.payment.AmazonGiftCardAccount; import haveno.core.payment.AustraliaPayidAccount; import haveno.core.payment.BizumAccount; import haveno.core.payment.CapitualAccount; +import haveno.core.payment.CashAppAccount; import haveno.core.payment.CashAtAtmAccount; import haveno.core.payment.PayByMailAccount; +import haveno.core.payment.PayPalAccount; import haveno.core.payment.CashDepositAccount; import haveno.core.payment.CelPayAccount; import haveno.core.payment.ZelleAccount; @@ -73,6 +91,7 @@ import haveno.core.payment.TransferwiseUsdAccount; import haveno.core.payment.USPostalMoneyOrderAccount; import haveno.core.payment.UpholdAccount; import haveno.core.payment.UpiAccount; +import haveno.core.payment.VenmoAccount; import haveno.core.payment.VerseAccount; import haveno.core.payment.WeChatPayAccount; import haveno.core.payment.WesternUnionAccount; @@ -105,13 +124,8 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_STAGENET ? TimeUnit.MINUTES.toMillis(30) : TimeUnit.DAYS.toMillis(1); - // Default trade limits. - // We initialize very early before reading persisted data. We will apply later the limit from - // the DAO param (Param.MAX_TRADE_LIMIT) but that can be only done after the dao is initialized. - // The default values will be used for deriving the - // risk factor so the relation between the risk categories stays the same as with the default values. - // We must not change those values as it could lead to invalid offers if amount becomes lower then new trade limit. - // Increasing might be ok, but needs more thought as well... + // These values are not used except to derive the associated risk factor. + private static final BigInteger DEFAULT_TRADE_LIMIT_CRYPTO = HavenoUtils.xmrToAtomicUnits(200); private static final BigInteger DEFAULT_TRADE_LIMIT_VERY_LOW_RISK = HavenoUtils.xmrToAtomicUnits(100); private static final BigInteger DEFAULT_TRADE_LIMIT_LOW_RISK = HavenoUtils.xmrToAtomicUnits(50); private static final BigInteger DEFAULT_TRADE_LIMIT_MID_RISK = HavenoUtils.xmrToAtomicUnits(25); @@ -174,14 +188,11 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme public static final String SWIFT_ID = "SWIFT"; public static final String ACH_TRANSFER_ID = "ACH_TRANSFER"; public static final String DOMESTIC_WIRE_TRANSFER_ID = "DOMESTIC_WIRE_TRANSFER"; - - // Cannot be deleted as it would break old trade history entries @Deprecated - public static final String OK_PAY_ID = "OK_PAY"; - @Deprecated - public static final String CASH_APP_ID = "CASH_APP"; // Removed due too high chargeback risk - @Deprecated - public static final String VENMO_ID = "VENMO"; // Removed due too high chargeback risk + public static final String OK_PAY_ID = "OK_PAY"; // Cannot be deleted as it would break old trade history entries + public static final String CASH_APP_ID = "CASH_APP"; + public static final String VENMO_ID = "VENMO"; + public static final String PAYPAL_ID = "PAYPAL"; public static PaymentMethod UPHOLD; public static PaymentMethod MONEY_BEAM; @@ -238,14 +249,13 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme public static PaymentMethod ACH_TRANSFER; public static PaymentMethod DOMESTIC_WIRE_TRANSFER; public static PaymentMethod BSQ_SWAP; + public static PaymentMethod PAYPAL; + public static PaymentMethod CASH_APP; + public static PaymentMethod VENMO; // Cannot be deleted as it would break old trade history entries @Deprecated public static PaymentMethod OK_PAY = getDummyPaymentMethod(OK_PAY_ID); - @Deprecated - public static PaymentMethod CASH_APP = getDummyPaymentMethod(CASH_APP_ID); // Removed due too high chargeback risk - @Deprecated - public static PaymentMethod VENMO = getDummyPaymentMethod(VENMO_ID); // Removed due too high chargeback risk // The limit and duration assignment must not be changed as that could break old offers (if amount would be higher // than new trade limit) and violate the maker expectation when he created the offer (duration). @@ -264,16 +274,16 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme // US ZELLE = new PaymentMethod(ZELLE_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(ZelleAccount.SUPPORTED_CURRENCIES)), - POPMONEY = new PaymentMethod(POPMONEY_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PopmoneyAccount.SUPPORTED_CURRENCIES)), US_POSTAL_MONEY_ORDER = new PaymentMethod(US_POSTAL_MONEY_ORDER_ID, 8 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(USPostalMoneyOrderAccount.SUPPORTED_CURRENCIES)), + VENMO = new PaymentMethod(VENMO_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(VenmoAccount.SUPPORTED_CURRENCIES)), // Canada INTERAC_E_TRANSFER = new PaymentMethod(INTERAC_E_TRANSFER_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(InteracETransferAccount.SUPPORTED_CURRENCIES)), // Global CASH_DEPOSIT = new PaymentMethod(CASH_DEPOSIT_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CashDepositAccount.SUPPORTED_CURRENCIES)), - PAY_BY_MAIL = new PaymentMethod(PAY_BY_MAIL_ID, 8 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PayByMailAccount.SUPPORTED_CURRENCIES)), + PAY_BY_MAIL = new PaymentMethod(PAY_BY_MAIL_ID, 8 * DAY, DEFAULT_TRADE_LIMIT_LOW_RISK, getAssetCodes(PayByMailAccount.SUPPORTED_CURRENCIES)), CASH_AT_ATM = new PaymentMethod(CASH_AT_ATM_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CashAtAtmAccount.SUPPORTED_CURRENCIES)), MONEY_GRAM = new PaymentMethod(MONEY_GRAM_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_MID_RISK, getAssetCodes(MoneyGramAccount.SUPPORTED_CURRENCIES)), WESTERN_UNION = new PaymentMethod(WESTERN_UNION_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_MID_RISK, getAssetCodes(WesternUnionAccount.SUPPORTED_CURRENCIES)), @@ -292,24 +302,26 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme TRANSFERWISE_USD = new PaymentMethod(TRANSFERWISE_USD_ID, 4 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(TransferwiseUsdAccount.SUPPORTED_CURRENCIES)), PAYSERA = new PaymentMethod(PAYSERA_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PayseraAccount.SUPPORTED_CURRENCIES)), PAXUM = new PaymentMethod(PAXUM_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PaxumAccount.SUPPORTED_CURRENCIES)), - NEFT = new PaymentMethod(NEFT_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.02), getAssetCodes(NeftAccount.SUPPORTED_CURRENCIES)), + NEFT = new PaymentMethod(NEFT_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(NeftAccount.SUPPORTED_CURRENCIES)), RTGS = new PaymentMethod(RTGS_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(RtgsAccount.SUPPORTED_CURRENCIES)), IMPS = new PaymentMethod(IMPS_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(ImpsAccount.SUPPORTED_CURRENCIES)), - UPI = new PaymentMethod(UPI_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(UpiAccount.SUPPORTED_CURRENCIES)), - PAYTM = new PaymentMethod(PAYTM_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(PaytmAccount.SUPPORTED_CURRENCIES)), + UPI = new PaymentMethod(UPI_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(UpiAccount.SUPPORTED_CURRENCIES)), + PAYTM = new PaymentMethod(PAYTM_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PaytmAccount.SUPPORTED_CURRENCIES)), NEQUI = new PaymentMethod(NEQUI_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(NequiAccount.SUPPORTED_CURRENCIES)), - BIZUM = new PaymentMethod(BIZUM_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.04), getAssetCodes(BizumAccount.SUPPORTED_CURRENCIES)), + BIZUM = new PaymentMethod(BIZUM_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(BizumAccount.SUPPORTED_CURRENCIES)), PIX = new PaymentMethod(PIX_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PixAccount.SUPPORTED_CURRENCIES)), CAPITUAL = new PaymentMethod(CAPITUAL_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CapitualAccount.SUPPORTED_CURRENCIES)), CELPAY = new PaymentMethod(CELPAY_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CelPayAccount.SUPPORTED_CURRENCIES)), MONESE = new PaymentMethod(MONESE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(MoneseAccount.SUPPORTED_CURRENCIES)), SATISPAY = new PaymentMethod(SATISPAY_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(SatispayAccount.SUPPORTED_CURRENCIES)), - TIKKIE = new PaymentMethod(TIKKIE_ID, DAY, HavenoUtils.xmrToAtomicUnits(0.05), getAssetCodes(TikkieAccount.SUPPORTED_CURRENCIES)), + TIKKIE = new PaymentMethod(TIKKIE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(TikkieAccount.SUPPORTED_CURRENCIES)), VERSE = new PaymentMethod(VERSE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(VerseAccount.SUPPORTED_CURRENCIES)), STRIKE = new PaymentMethod(STRIKE_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(StrikeAccount.SUPPORTED_CURRENCIES)), SWIFT = new PaymentMethod(SWIFT_ID, 7 * DAY, DEFAULT_TRADE_LIMIT_MID_RISK, getAssetCodes(SwiftAccount.SUPPORTED_CURRENCIES)), ACH_TRANSFER = new PaymentMethod(ACH_TRANSFER_ID, 5 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(AchTransferAccount.SUPPORTED_CURRENCIES)), DOMESTIC_WIRE_TRANSFER = new PaymentMethod(DOMESTIC_WIRE_TRANSFER_ID, 3 * DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(DomesticWireTransferAccount.SUPPORTED_CURRENCIES)), + PAYPAL = new PaymentMethod(PAYPAL_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(PayPalAccount.SUPPORTED_CURRENCIES)), + CASH_APP = new PaymentMethod(CASH_APP_ID, DAY, DEFAULT_TRADE_LIMIT_HIGH_RISK, getAssetCodes(CashAppAccount.SUPPORTED_CURRENCIES)), // Japan JAPAN_BANK = new PaymentMethod(JAPAN_BANK_ID, DAY, DEFAULT_TRADE_LIMIT_LOW_RISK, getAssetCodes(JapanBankAccount.SUPPORTED_CURRENCIES)), @@ -325,9 +337,10 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme PROMPT_PAY = new PaymentMethod(PROMPT_PAY_ID, DAY, DEFAULT_TRADE_LIMIT_LOW_RISK, getAssetCodes(PromptPayAccount.SUPPORTED_CURRENCIES)), // Cryptos - BLOCK_CHAINS = new PaymentMethod(BLOCK_CHAINS_ID, DAY, DEFAULT_TRADE_LIMIT_VERY_LOW_RISK, Arrays.asList()), + BLOCK_CHAINS = new PaymentMethod(BLOCK_CHAINS_ID, DAY, DEFAULT_TRADE_LIMIT_CRYPTO, Arrays.asList()), + // Cryptos with 1 hour trade period - BLOCK_CHAINS_INSTANT = new PaymentMethod(BLOCK_CHAINS_INSTANT_ID, TimeUnit.HOURS.toMillis(1), DEFAULT_TRADE_LIMIT_VERY_LOW_RISK, Arrays.asList()) + BLOCK_CHAINS_INSTANT = new PaymentMethod(BLOCK_CHAINS_INSTANT_ID, TimeUnit.HOURS.toMillis(1), DEFAULT_TRADE_LIMIT_CRYPTO, Arrays.asList()) ); // TODO: delete this override method, which overrides the paymentMethods variable, when all payment methods supported using structured form api, and make paymentMethods private @@ -347,7 +360,11 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme SWIFT_ID, TRANSFERWISE_ID, UPHOLD_ID, - ZELLE_ID); + ZELLE_ID, + AUSTRALIA_PAYID_ID, + CASH_APP_ID, + PAYPAL_ID, + VENMO_ID); return paymentMethods.stream().filter(paymentMethod -> paymentMethodIds.contains(paymentMethod.getId())).collect(Collectors.toList()); } @@ -368,7 +385,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme } public static PaymentMethod getDummyPaymentMethod(String id) { - return new PaymentMethod(id, 0, BigInteger.valueOf(0), Arrays.asList()); + return new PaymentMethod(id, 0, BigInteger.ZERO, Arrays.asList()); } @@ -418,7 +435,7 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme // Used for dummy entries in payment methods list (SHOW_ALL) private PaymentMethod(String id) { - this(id, 0, BigInteger.valueOf(0), new ArrayList<String>()); + this(id, 0, BigInteger.ZERO, new ArrayList<String>()); } @@ -475,17 +492,21 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme } // We use the class field maxTradeLimit only for mapping the risk factor. + // The actual trade limit is calculated by dividing TradeLimits.MAX_TRADE_LIMIT by the + // risk factor, and then further decreasing by chargeback risk, account signing, and age. long riskFactor; - if (maxTradeLimit == DEFAULT_TRADE_LIMIT_VERY_LOW_RISK.longValueExact()) + if (maxTradeLimit == DEFAULT_TRADE_LIMIT_CRYPTO.longValueExact()) riskFactor = 1; - else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_LOW_RISK.longValueExact()) - riskFactor = 2; - else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_MID_RISK.longValueExact()) + else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_VERY_LOW_RISK.longValueExact()) riskFactor = 4; + else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_LOW_RISK.longValueExact()) + riskFactor = 11; + else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_MID_RISK.longValueExact()) + riskFactor = 22; else if (maxTradeLimit == DEFAULT_TRADE_LIMIT_HIGH_RISK.longValueExact()) - riskFactor = 8; + riskFactor = 44; else { - riskFactor = 8; + riskFactor = 44; log.warn("maxTradeLimit is not matching one of our default values. We use highest risk factor. " + "maxTradeLimit={}. PaymentMethod={}", maxTradeLimit, this); } @@ -494,13 +515,6 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme TradeLimits tradeLimits = new TradeLimits(); long maxTradeLimit = tradeLimits.getMaxTradeLimit().longValueExact(); long riskBasedTradeLimit = tradeLimits.getRoundedRiskBasedTradeLimit(maxTradeLimit, riskFactor); - - // if traditional and stagenet, cap offer amounts to avoid offers which cannot be taken - boolean isTraditional = CurrencyUtil.isTraditionalCurrency(currencyCode); - boolean isStagenet = Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_STAGENET; - if (isTraditional && isStagenet && riskBasedTradeLimit > OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) { - riskBasedTradeLimit = OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact(); - } return BigInteger.valueOf(riskBasedTradeLimit); } @@ -554,9 +568,11 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme } public static boolean hasChargebackRisk(String id, String currencyCode) { - if (CurrencyUtil.getMatureMarketCurrencies().stream() - .noneMatch(c -> c.getCode().equals(currencyCode))) - return false; + + // TODO: bisq indicates no chargeback risk for non-"mature" currencies, but they have chargeback risk too, so we disable + // if (CurrencyUtil.getMatureMarketCurrencies().stream() + // .noneMatch(c -> c.getCode().equals(currencyCode))) + // return false; return id.equals(PaymentMethod.SEPA_ID) || id.equals(PaymentMethod.SEPA_INSTANT_ID) || @@ -569,7 +585,10 @@ public final class PaymentMethod implements PersistablePayload, Comparable<Payme id.equals(PaymentMethod.CHASE_QUICK_PAY_ID) || id.equals(PaymentMethod.POPMONEY_ID) || id.equals(PaymentMethod.MONEY_BEAM_ID) || - id.equals(PaymentMethod.UPHOLD_ID); + id.equals(PaymentMethod.UPHOLD_ID) || + id.equals(PaymentMethod.CASH_APP_ID) || + id.equals(PaymentMethod.PAYPAL_ID) || + id.equals(PaymentMethod.VENMO_ID); } public static boolean isRoundedForAtmCash(String id) { diff --git a/core/src/main/java/haveno/core/payment/payload/PayseraAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PayseraAccountPayload.java index 8b8dbce639..df6daf43dd 100644 --- a/core/src/main/java/haveno/core/payment/payload/PayseraAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PayseraAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PaytmAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PaytmAccountPayload.java index 6b46fd95b1..ebad4ddff4 100644 --- a/core/src/main/java/haveno/core/payment/payload/PaytmAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PaytmAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PerfectMoneyAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PerfectMoneyAccountPayload.java index 494ac75616..ddb0f906ad 100644 --- a/core/src/main/java/haveno/core/payment/payload/PerfectMoneyAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PerfectMoneyAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PixAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PixAccountPayload.java index ff0b86cfae..2646b581ce 100644 --- a/core/src/main/java/haveno/core/payment/payload/PixAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PixAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PopmoneyAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PopmoneyAccountPayload.java index ed9a497d3a..aecebb906d 100644 --- a/core/src/main/java/haveno/core/payment/payload/PopmoneyAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PopmoneyAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/PromptPayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/PromptPayAccountPayload.java index dd342df5c2..1d124cea89 100644 --- a/core/src/main/java/haveno/core/payment/payload/PromptPayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/PromptPayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/RevolutAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/RevolutAccountPayload.java index 8a0a8f1d08..e8bd06ac60 100644 --- a/core/src/main/java/haveno/core/payment/payload/RevolutAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/RevolutAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -40,16 +40,16 @@ public final class RevolutAccountPayload extends PaymentAccountPayload { // Was added in 1.3.8 // To not break signed accounts we keep accountId as internal id used for signing. - // Old accounts get a popup to add the new required field userName but accountId is - // left unchanged. Newly created accounts fill accountId with the value of userName. - // In the UI we only use userName. + // Old accounts get a popup to add the new required field username but accountId is + // left unchanged. Newly created accounts fill accountId with the value of username. + // In the UI we only use username. // For backward compatibility we need to exclude the new field for the contract json. // We can remove that after a while when risk that users with pre 1.3.8 version trade with updated // users is very low. @JsonExclude @Getter - private String userName = ""; + private String username = ""; public RevolutAccountPayload(String paymentMethod, String id) { super(paymentMethod, id); @@ -62,7 +62,7 @@ public final class RevolutAccountPayload extends PaymentAccountPayload { private RevolutAccountPayload(String paymentMethod, String id, - @Nullable String userName, + @Nullable String username, long maxTradePeriod, Map<String, String> excludeFromJsonDataMap) { super(paymentMethod, @@ -70,13 +70,13 @@ public final class RevolutAccountPayload extends PaymentAccountPayload { maxTradePeriod, excludeFromJsonDataMap); - this.userName = userName; + this.username = username; } @Override public Message toProtoMessage() { protobuf.RevolutAccountPayload.Builder revolutBuilder = protobuf.RevolutAccountPayload.newBuilder() - .setUserName(userName); + .setUsername(username); return getPaymentAccountPayloadBuilder().setRevolutAccountPayload(revolutBuilder).build(); } @@ -85,7 +85,7 @@ public final class RevolutAccountPayload extends PaymentAccountPayload { protobuf.RevolutAccountPayload revolutAccountPayload = proto.getRevolutAccountPayload(); return new RevolutAccountPayload(proto.getPaymentMethodId(), proto.getId(), - revolutAccountPayload.getUserName(), + revolutAccountPayload.getUsername(), proto.getMaxTradePeriod(), new HashMap<>(proto.getExcludeFromJsonDataMap())); } @@ -104,9 +104,9 @@ public final class RevolutAccountPayload extends PaymentAccountPayload { private Tuple2<String, String> getLabelValueTuple() { String label; String value; - checkArgument(!userName.isEmpty(), "Username must be set"); - label = Res.get("payment.account.userName"); - value = userName; + checkArgument(!username.isEmpty(), "Username must be set"); + label = Res.get("payment.account.username"); + value = username; return new Tuple2<>(label, value); } @@ -123,14 +123,14 @@ public final class RevolutAccountPayload extends PaymentAccountPayload { @Override public byte[] getAgeWitnessInputData() { - return super.getAgeWitnessInputData(userName.getBytes(StandardCharsets.UTF_8)); + return super.getAgeWitnessInputData(username.getBytes(StandardCharsets.UTF_8)); } - public boolean userNameNotSet() { - return userName.isEmpty(); + public boolean usernameNotSet() { + return username.isEmpty(); } - public void setUserName(String userName) { - this.userName = userName; + public void setUserName(String username) { + this.username = username; } } diff --git a/core/src/main/java/haveno/core/payment/payload/RtgsAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/RtgsAccountPayload.java index 5869008766..043a15f22d 100644 --- a/core/src/main/java/haveno/core/payment/payload/RtgsAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/RtgsAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/SameBankAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SameBankAccountPayload.java index d4e3010048..3371237a05 100644 --- a/core/src/main/java/haveno/core/payment/payload/SameBankAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SameBankAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/SatispayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SatispayAccountPayload.java index 4507607a0b..5a96316058 100644 --- a/core/src/main/java/haveno/core/payment/payload/SatispayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SatispayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -91,7 +91,7 @@ public final class SatispayAccountPayload extends CountryBasedPaymentAccountPayl @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + holderName; + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.username") + " " + holderName; } @Override diff --git a/core/src/main/java/haveno/core/payment/payload/SepaAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SepaAccountPayload.java index 2b725e731e..3446a979e8 100644 --- a/core/src/main/java/haveno/core/payment/payload/SepaAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SepaAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/SepaInstantAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SepaInstantAccountPayload.java index 96161af5e5..66a5c1062a 100644 --- a/core/src/main/java/haveno/core/payment/payload/SepaInstantAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SepaInstantAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/SpecificBanksAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SpecificBanksAccountPayload.java index 9c45e65a43..ca9d8a4bc2 100644 --- a/core/src/main/java/haveno/core/payment/payload/SpecificBanksAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SpecificBanksAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/StrikeAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/StrikeAccountPayload.java index 1877d0651d..342f771f79 100644 --- a/core/src/main/java/haveno/core/payment/payload/StrikeAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/StrikeAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -86,7 +86,7 @@ public final class StrikeAccountPayload extends CountryBasedPaymentAccountPayloa @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + holderName; + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.username") + " " + holderName; } @Override diff --git a/core/src/main/java/haveno/core/payment/payload/SwiftAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SwiftAccountPayload.java index cc957b6969..929a4e7888 100644 --- a/core/src/main/java/haveno/core/payment/payload/SwiftAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SwiftAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/SwishAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/SwishAccountPayload.java index 390db4846a..c0a399082c 100644 --- a/core/src/main/java/haveno/core/payment/payload/SwishAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/SwishAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/TikkieAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/TikkieAccountPayload.java index f16385d133..03cf638067 100644 --- a/core/src/main/java/haveno/core/payment/payload/TikkieAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/TikkieAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/TransferwiseAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/TransferwiseAccountPayload.java index 13be85199a..feb7a5e269 100644 --- a/core/src/main/java/haveno/core/payment/payload/TransferwiseAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/TransferwiseAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/TransferwiseUsdAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/TransferwiseUsdAccountPayload.java index 5b61ae1ecb..1daba610db 100644 --- a/core/src/main/java/haveno/core/payment/payload/TransferwiseUsdAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/TransferwiseUsdAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -96,7 +96,7 @@ public final class TransferwiseUsdAccountPayload extends CountryBasedPaymentAcco @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + holderName; + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.username") + " " + holderName; } @Override diff --git a/core/src/main/java/haveno/core/payment/payload/USPostalMoneyOrderAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/USPostalMoneyOrderAccountPayload.java index ca9cd4a738..b411b09a41 100644 --- a/core/src/main/java/haveno/core/payment/payload/USPostalMoneyOrderAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/USPostalMoneyOrderAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/UpholdAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/UpholdAccountPayload.java index c119c1a453..445cac1008 100644 --- a/core/src/main/java/haveno/core/payment/payload/UpholdAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/UpholdAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/UpiAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/UpiAccountPayload.java index 76b6d10510..8f5c8b4f32 100644 --- a/core/src/main/java/haveno/core/payment/payload/UpiAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/UpiAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/VenmoAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/VenmoAccountPayload.java index c67f2eb349..7daee3dc43 100644 --- a/core/src/main/java/haveno/core/payment/payload/VenmoAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/VenmoAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -29,17 +29,13 @@ import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; -// Cannot be deleted as it would break old trade history entries -// Removed due too high chargeback risk -@Deprecated @EqualsAndHashCode(callSuper = true) @ToString @Setter @Getter @Slf4j public final class VenmoAccountPayload extends PaymentAccountPayload { - private String venmoUserName = ""; - private String holderName = ""; + private String emailOrMobileNrOrUsername = ""; public VenmoAccountPayload(String paymentMethod, String id) { super(paymentMethod, id); @@ -52,8 +48,7 @@ public final class VenmoAccountPayload extends PaymentAccountPayload { private VenmoAccountPayload(String paymentMethod, String id, - String venmoUserName, - String holderName, + String emailOrMobileNrOrUsername, long maxTradePeriod, Map<String, String> excludeFromJsonDataMap) { super(paymentMethod, @@ -61,24 +56,21 @@ public final class VenmoAccountPayload extends PaymentAccountPayload { maxTradePeriod, excludeFromJsonDataMap); - this.venmoUserName = venmoUserName; - this.holderName = holderName; + this.emailOrMobileNrOrUsername = emailOrMobileNrOrUsername; } @Override public Message toProtoMessage() { return getPaymentAccountPayloadBuilder() .setVenmoAccountPayload(protobuf.VenmoAccountPayload.newBuilder() - .setVenmoUserName(venmoUserName) - .setHolderName(holderName)) + .setEmailOrMobileNrOrUsername(emailOrMobileNrOrUsername)) .build(); } public static VenmoAccountPayload fromProto(protobuf.PaymentAccountPayload proto) { return new VenmoAccountPayload(proto.getPaymentMethodId(), proto.getId(), - proto.getVenmoAccountPayload().getVenmoUserName(), - proto.getVenmoAccountPayload().getHolderName(), + proto.getVenmoAccountPayload().getEmailOrMobileNrOrUsername(), proto.getMaxTradePeriod(), new HashMap<>(proto.getExcludeFromJsonDataMap())); } @@ -90,8 +82,7 @@ public final class VenmoAccountPayload extends PaymentAccountPayload { @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.owner") + " " + holderName + ", " + - Res.getWithCol("payment.venmo.venmoUserName") + " " + venmoUserName; + return Res.getWithCol("payment.email.mobile.username") + " " + emailOrMobileNrOrUsername; } @Override @@ -101,11 +92,6 @@ public final class VenmoAccountPayload extends PaymentAccountPayload { @Override public byte[] getAgeWitnessInputData() { - return super.getAgeWitnessInputData(venmoUserName.getBytes(StandardCharsets.UTF_8)); - } - - @Override - public String getOwnerId() { - return holderName; + return super.getAgeWitnessInputData(emailOrMobileNrOrUsername.getBytes(StandardCharsets.UTF_8)); } } diff --git a/core/src/main/java/haveno/core/payment/payload/VerseAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/VerseAccountPayload.java index ff39324024..4dc0ad24a8 100644 --- a/core/src/main/java/haveno/core/payment/payload/VerseAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/VerseAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; @@ -71,7 +71,7 @@ public final class VerseAccountPayload extends PaymentAccountPayload { @Override public String getPaymentDetails() { - return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.userName") + " " + holderName; + return Res.get(paymentMethodId) + " - " + Res.getWithCol("payment.account.username") + " " + holderName; } @Override diff --git a/core/src/main/java/haveno/core/payment/payload/WeChatPayAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/WeChatPayAccountPayload.java index 3721298e6a..b13cc907dc 100644 --- a/core/src/main/java/haveno/core/payment/payload/WeChatPayAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/WeChatPayAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/WesternUnionAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/WesternUnionAccountPayload.java index 12db41a47d..6ac1b58615 100644 --- a/core/src/main/java/haveno/core/payment/payload/WesternUnionAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/WesternUnionAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/payload/ZelleAccountPayload.java b/core/src/main/java/haveno/core/payment/payload/ZelleAccountPayload.java index d62e8f9349..86c94abd36 100644 --- a/core/src/main/java/haveno/core/payment/payload/ZelleAccountPayload.java +++ b/core/src/main/java/haveno/core/payment/payload/ZelleAccountPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.payload; diff --git a/core/src/main/java/haveno/core/payment/validation/AccountNrValidator.java b/core/src/main/java/haveno/core/payment/validation/AccountNrValidator.java index ff031ed81e..fc7acfc405 100644 --- a/core/src/main/java/haveno/core/payment/validation/AccountNrValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/AccountNrValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/AdvancedCashValidator.java b/core/src/main/java/haveno/core/payment/validation/AdvancedCashValidator.java index b6504d351c..cce112b189 100644 --- a/core/src/main/java/haveno/core/payment/validation/AdvancedCashValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/AdvancedCashValidator.java @@ -1,11 +1,10 @@ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public class AdvancedCashValidator extends InputValidator { private EmailValidator emailValidator; private RegexValidator regexValidator; diff --git a/core/src/main/java/haveno/core/payment/validation/AliPayValidator.java b/core/src/main/java/haveno/core/payment/validation/AliPayValidator.java index 9956b861b5..fecd324564 100644 --- a/core/src/main/java/haveno/core/payment/validation/AliPayValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/AliPayValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/AustraliaPayidAccountNameValidator.java b/core/src/main/java/haveno/core/payment/validation/AustraliaPayidAccountNameValidator.java index 2a91270bc5..ff4e1300dd 100644 --- a/core/src/main/java/haveno/core/payment/validation/AustraliaPayidAccountNameValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/AustraliaPayidAccountNameValidator.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public final class AustraliaPayidAccountNameValidator extends InputValidator { @Override public ValidationResult validate(String input) { diff --git a/core/src/main/java/haveno/core/payment/validation/AustraliaPayidValidator.java b/core/src/main/java/haveno/core/payment/validation/AustraliaPayidValidator.java index 9c8bf57bc7..bad3c3d7ba 100644 --- a/core/src/main/java/haveno/core/payment/validation/AustraliaPayidValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/AustraliaPayidValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/BICValidator.java b/core/src/main/java/haveno/core/payment/validation/BICValidator.java index f40329d0eb..05c142ede7 100644 --- a/core/src/main/java/haveno/core/payment/validation/BICValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/BICValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/BankIdValidator.java b/core/src/main/java/haveno/core/payment/validation/BankIdValidator.java index ca939f619f..84f8fc2ba7 100644 --- a/core/src/main/java/haveno/core/payment/validation/BankIdValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/BankIdValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/BankValidator.java b/core/src/main/java/haveno/core/payment/validation/BankValidator.java index 4ec60b6c8e..a78aa0dda2 100644 --- a/core/src/main/java/haveno/core/payment/validation/BankValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/BankValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/BranchIdValidator.java b/core/src/main/java/haveno/core/payment/validation/BranchIdValidator.java index c497a63650..9ec00d375f 100644 --- a/core/src/main/java/haveno/core/payment/validation/BranchIdValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/BranchIdValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/CapitualValidator.java b/core/src/main/java/haveno/core/payment/validation/CapitualValidator.java index a156193fce..e18ef0f733 100644 --- a/core/src/main/java/haveno/core/payment/validation/CapitualValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/CapitualValidator.java @@ -1,11 +1,10 @@ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public class CapitualValidator extends InputValidator { private final RegexValidator regexValidator; diff --git a/core/src/main/java/haveno/core/payment/validation/ChaseQuickPayValidator.java b/core/src/main/java/haveno/core/payment/validation/ChaseQuickPayValidator.java index 0bd19a0cc6..27f0e9c0b9 100644 --- a/core/src/main/java/haveno/core/payment/validation/ChaseQuickPayValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/ChaseQuickPayValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/CryptoAddressValidator.java b/core/src/main/java/haveno/core/payment/validation/CryptoAddressValidator.java index f0c419492c..f04fd518bd 100644 --- a/core/src/main/java/haveno/core/payment/validation/CryptoAddressValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/CryptoAddressValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrOrCashtagValidator.java b/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrOrCashtagValidator.java new file mode 100644 index 0000000000..04750ccb0f --- /dev/null +++ b/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrOrCashtagValidator.java @@ -0,0 +1,56 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.payment.validation; + +import haveno.core.util.validation.InputValidator; + +public final class EmailOrMobileNrOrCashtagValidator extends InputValidator { + + private final EmailOrMobileNrValidator emailOrMobileNrValidator; + + /////////////////////////////////////////////////////////////////////////////////////////// + // Public methods + /////////////////////////////////////////////////////////////////////////////////////////// + + public EmailOrMobileNrOrCashtagValidator() { + emailOrMobileNrValidator = new EmailOrMobileNrValidator(); + } + + @Override + public ValidationResult validate(String input) { + ValidationResult result = validateIfNotEmpty(input); + if (!result.isValid) { + return result; + } else { + ValidationResult emailOrMobileResult = emailOrMobileNrValidator.validate(input); + if (emailOrMobileResult.isValid) + return emailOrMobileResult; + else + return validateCashtag(input); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////////////////////////////////////// + + // TODO not impl yet -> see InteracETransferValidator + private ValidationResult validateCashtag(String input) { + return super.validate(input); + } +} diff --git a/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrOrUsernameValidator.java b/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrOrUsernameValidator.java new file mode 100644 index 0000000000..c01dfd302c --- /dev/null +++ b/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrOrUsernameValidator.java @@ -0,0 +1,56 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.payment.validation; + +import haveno.core.util.validation.InputValidator; + +public final class EmailOrMobileNrOrUsernameValidator extends InputValidator { + + private final EmailOrMobileNrValidator emailOrMobileNrValidator; + + /////////////////////////////////////////////////////////////////////////////////////////// + // Public methods + /////////////////////////////////////////////////////////////////////////////////////////// + + public EmailOrMobileNrOrUsernameValidator() { + emailOrMobileNrValidator = new EmailOrMobileNrValidator(); + } + + @Override + public ValidationResult validate(String input) { + ValidationResult result = validateIfNotEmpty(input); + if (!result.isValid) { + return result; + } else { + ValidationResult emailOrMobileResult = emailOrMobileNrValidator.validate(input); + if (emailOrMobileResult.isValid) + return emailOrMobileResult; + else + return validateName(input); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Private methods + /////////////////////////////////////////////////////////////////////////////////////////// + + // TODO: properly implement username validation + private ValidationResult validateName(String input) { + return super.validate(input); + } +} diff --git a/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrValidator.java b/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrValidator.java index 544f805882..a8a2f9b5b3 100644 --- a/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/EmailOrMobileNrValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/EmailValidator.java b/core/src/main/java/haveno/core/payment/validation/EmailValidator.java index d2720de273..731dcb5ae4 100644 --- a/core/src/main/java/haveno/core/payment/validation/EmailValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/EmailValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/F2FValidator.java b/core/src/main/java/haveno/core/payment/validation/F2FValidator.java index 97cfc29ccc..e8dbcf3365 100644 --- a/core/src/main/java/haveno/core/payment/validation/F2FValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/F2FValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/FiatVolumeValidator.java b/core/src/main/java/haveno/core/payment/validation/FiatVolumeValidator.java index 48f81024a2..d88396db15 100644 --- a/core/src/main/java/haveno/core/payment/validation/FiatVolumeValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/FiatVolumeValidator.java @@ -1,26 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.util.validation.MonetaryValidator; -import javax.inject.Inject; - public class FiatVolumeValidator extends MonetaryValidator { @Override public double getMinValue() { diff --git a/core/src/main/java/haveno/core/payment/validation/HalCashValidator.java b/core/src/main/java/haveno/core/payment/validation/HalCashValidator.java index 716b3cac65..5a6cd4f31e 100644 --- a/core/src/main/java/haveno/core/payment/validation/HalCashValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/HalCashValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/IBANValidator.java b/core/src/main/java/haveno/core/payment/validation/IBANValidator.java index 5ed8e7e309..89aee3f3c0 100644 --- a/core/src/main/java/haveno/core/payment/validation/IBANValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/IBANValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/InteracETransferAnswerValidator.java b/core/src/main/java/haveno/core/payment/validation/InteracETransferAnswerValidator.java index 47841dcc9b..4bae615941 100644 --- a/core/src/main/java/haveno/core/payment/validation/InteracETransferAnswerValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/InteracETransferAnswerValidator.java @@ -1,11 +1,10 @@ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public class InteracETransferAnswerValidator extends InputValidator { private LengthValidator lengthValidator; private RegexValidator regexValidator; diff --git a/core/src/main/java/haveno/core/payment/validation/InteracETransferQuestionValidator.java b/core/src/main/java/haveno/core/payment/validation/InteracETransferQuestionValidator.java index 6fd7c865f9..427a61f078 100644 --- a/core/src/main/java/haveno/core/payment/validation/InteracETransferQuestionValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/InteracETransferQuestionValidator.java @@ -1,11 +1,10 @@ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public class InteracETransferQuestionValidator extends InputValidator { private LengthValidator lengthValidator; private RegexValidator regexValidator; @@ -14,7 +13,7 @@ public class InteracETransferQuestionValidator extends InputValidator { public InteracETransferQuestionValidator(LengthValidator lengthValidator, RegexValidator regexValidator) { lengthValidator.setMinLength(1); - lengthValidator.setMaxLength(40); + lengthValidator.setMaxLength(160); this.lengthValidator = lengthValidator; regexValidator.setPattern("[A-Za-z0-9\\-\\_\\'\\,\\.\\? ]+"); diff --git a/core/src/main/java/haveno/core/payment/validation/InteracETransferValidator.java b/core/src/main/java/haveno/core/payment/validation/InteracETransferValidator.java index 973f62af60..f036e0537a 100644 --- a/core/src/main/java/haveno/core/payment/validation/InteracETransferValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/InteracETransferValidator.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.util.validation.InputValidator; import org.apache.commons.lang3.StringUtils; -import javax.inject.Inject; - /* * Interac e-Transfer requires a mail address or Canadian (mobile) phone number * diff --git a/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNameValidator.java b/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNameValidator.java index 1ec805b9f4..7bff62a820 100644 --- a/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNameValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNameValidator.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.payment.JapanBankData; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public final class JapanBankAccountNameValidator extends InputValidator { @Override diff --git a/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNumberValidator.java b/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNumberValidator.java index 364971c833..91ccaa1a65 100644 --- a/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNumberValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/JapanBankAccountNumberValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/JapanBankBranchCodeValidator.java b/core/src/main/java/haveno/core/payment/validation/JapanBankBranchCodeValidator.java index e30b4ef454..3ccd604c41 100644 --- a/core/src/main/java/haveno/core/payment/validation/JapanBankBranchCodeValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/JapanBankBranchCodeValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/JapanBankBranchNameValidator.java b/core/src/main/java/haveno/core/payment/validation/JapanBankBranchNameValidator.java index 79650acb53..6e64658456 100644 --- a/core/src/main/java/haveno/core/payment/validation/JapanBankBranchNameValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/JapanBankBranchNameValidator.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.payment.JapanBankData; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.RegexValidator; -import javax.inject.Inject; - public final class JapanBankBranchNameValidator extends InputValidator { @Override diff --git a/core/src/main/java/haveno/core/payment/validation/JapanBankTransferValidator.java b/core/src/main/java/haveno/core/payment/validation/JapanBankTransferValidator.java index 7839511483..3591ac46b9 100644 --- a/core/src/main/java/haveno/core/payment/validation/JapanBankTransferValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/JapanBankTransferValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/MoneyBeamValidator.java b/core/src/main/java/haveno/core/payment/validation/MoneyBeamValidator.java index c691d15e29..ad9ceae33a 100644 --- a/core/src/main/java/haveno/core/payment/validation/MoneyBeamValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/MoneyBeamValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/PercentageNumberValidator.java b/core/src/main/java/haveno/core/payment/validation/PercentageNumberValidator.java index 3768883181..f874daa018 100644 --- a/core/src/main/java/haveno/core/payment/validation/PercentageNumberValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/PercentageNumberValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/PerfectMoneyValidator.java b/core/src/main/java/haveno/core/payment/validation/PerfectMoneyValidator.java index 201b3bb897..5bbb75b456 100644 --- a/core/src/main/java/haveno/core/payment/validation/PerfectMoneyValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/PerfectMoneyValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/PopmoneyValidator.java b/core/src/main/java/haveno/core/payment/validation/PopmoneyValidator.java index 2af6e40881..9bcb8fca6e 100644 --- a/core/src/main/java/haveno/core/payment/validation/PopmoneyValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/PopmoneyValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/PromptPayValidator.java b/core/src/main/java/haveno/core/payment/validation/PromptPayValidator.java index 30011d9571..f8f740aaea 100644 --- a/core/src/main/java/haveno/core/payment/validation/PromptPayValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/PromptPayValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/RevolutValidator.java b/core/src/main/java/haveno/core/payment/validation/RevolutValidator.java index 7a2c87794e..543fd61d00 100644 --- a/core/src/main/java/haveno/core/payment/validation/RevolutValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/RevolutValidator.java @@ -1,26 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; public final class RevolutValidator extends LengthValidator { public RevolutValidator() { - // Not sure what are requirements for Revolut user names - // Please keep in mind that even we force users to set user name at startup we should handle also the case + // Not sure what are requirements for Revolut usernames + // Please keep in mind that even we force users to set username at startup we should handle also the case // that the old accountID as phone number or email is displayed at the username text field and we do not // want to break validation in those cases. So being too strict on the validators might cause more troubles // as its worth... diff --git a/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java b/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java index 212b8fbd5c..4545a4e210 100644 --- a/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/SecurityDepositValidator.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.payment.PaymentAccount; import haveno.core.util.FormattingUtils; @@ -24,8 +25,6 @@ import haveno.core.util.ParsingUtils; import haveno.core.util.validation.NumberValidator; import haveno.core.xmr.wallet.Restrictions; -import javax.inject.Inject; - public class SecurityDepositValidator extends NumberValidator { private PaymentAccount paymentAccount; @@ -60,7 +59,7 @@ public class SecurityDepositValidator extends NumberValidator { private ValidationResult validateIfNotTooLowPercentageValue(String input) { try { double percentage = ParsingUtils.parsePercentStringToDouble(input); - double minPercentage = Restrictions.getMinBuyerSecurityDepositAsPercent(); + double minPercentage = Restrictions.getMinSecurityDepositAsPercent(); if (percentage < minPercentage) return new ValidationResult(false, Res.get("validation.inputTooSmall", FormattingUtils.formatToPercentWithSymbol(minPercentage))); @@ -74,7 +73,7 @@ public class SecurityDepositValidator extends NumberValidator { private ValidationResult validateIfNotTooHighPercentageValue(String input) { try { double percentage = ParsingUtils.parsePercentStringToDouble(input); - double maxPercentage = Restrictions.getMaxBuyerSecurityDepositAsPercent(); + double maxPercentage = Restrictions.getMaxSecurityDepositAsPercent(); if (percentage > maxPercentage) return new ValidationResult(false, Res.get("validation.inputTooLarge", FormattingUtils.formatToPercentWithSymbol(maxPercentage))); diff --git a/core/src/main/java/haveno/core/payment/validation/SwishValidator.java b/core/src/main/java/haveno/core/payment/validation/SwishValidator.java index 5e50953fbf..22d5984f30 100644 --- a/core/src/main/java/haveno/core/payment/validation/SwishValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/SwishValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/TransferwiseValidator.java b/core/src/main/java/haveno/core/payment/validation/TransferwiseValidator.java index ecf0948730..c6438bb85e 100644 --- a/core/src/main/java/haveno/core/payment/validation/TransferwiseValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/TransferwiseValidator.java @@ -1,26 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.util.validation.InputValidator; -import javax.inject.Inject; - public final class TransferwiseValidator extends InputValidator { private final EmailValidator emailValidator; diff --git a/core/src/main/java/haveno/core/payment/validation/USPostalMoneyOrderValidator.java b/core/src/main/java/haveno/core/payment/validation/USPostalMoneyOrderValidator.java index c75f9d7d9b..6a7d8aab1f 100644 --- a/core/src/main/java/haveno/core/payment/validation/USPostalMoneyOrderValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/USPostalMoneyOrderValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/UpholdValidator.java b/core/src/main/java/haveno/core/payment/validation/UpholdValidator.java index cb37982c93..e7025f0791 100644 --- a/core/src/main/java/haveno/core/payment/validation/UpholdValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/UpholdValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/WeChatPayValidator.java b/core/src/main/java/haveno/core/payment/validation/WeChatPayValidator.java index aacc458d2b..f227200387 100644 --- a/core/src/main/java/haveno/core/payment/validation/WeChatPayValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/WeChatPayValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/main/java/haveno/core/payment/validation/XmrValidator.java b/core/src/main/java/haveno/core/payment/validation/XmrValidator.java index 1fa3c1cbc9..728e91ebdf 100644 --- a/core/src/main/java/haveno/core/payment/validation/XmrValidator.java +++ b/core/src/main/java/haveno/core/payment/validation/XmrValidator.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.trade.HavenoUtils; import haveno.core.util.validation.NumberValidator; -import lombok.Getter; -import lombok.Setter; - -import javax.annotation.Nullable; -import javax.inject.Inject; import java.math.BigDecimal; import java.math.BigInteger; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.Setter; public class XmrValidator extends NumberValidator { @@ -97,7 +96,7 @@ public class XmrValidator extends NumberValidator { try { final BigInteger amount = HavenoUtils.parseXmr(input); if (maxTradeLimit != null && amount.compareTo(maxTradeLimit) > 0) - return new ValidationResult(false, Res.get("validation.btc.exceedsMaxTradeLimit", HavenoUtils.formatXmr(maxTradeLimit, true))); + return new ValidationResult(false, Res.get("validation.xmr.exceedsMaxTradeLimit", HavenoUtils.formatXmr(maxTradeLimit, true))); else return new ValidationResult(true); } catch (Throwable t) { diff --git a/core/src/main/java/haveno/core/presentation/BalancePresentation.java b/core/src/main/java/haveno/core/presentation/BalancePresentation.java index 2ef1a22c7e..9838f6159d 100644 --- a/core/src/main/java/haveno/core/presentation/BalancePresentation.java +++ b/core/src/main/java/haveno/core/presentation/BalancePresentation.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.presentation; +import com.google.inject.Inject; import haveno.common.UserThread; +import haveno.core.api.model.XmrBalanceInfo; import haveno.core.trade.HavenoUtils; import haveno.core.xmr.Balances; import javafx.beans.property.SimpleStringProperty; @@ -25,8 +27,6 @@ import javafx.beans.property.StringProperty; import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; - @Slf4j public class BalancePresentation { @@ -39,14 +39,13 @@ public class BalancePresentation { @Inject public BalancePresentation(Balances balances) { - balances.getAvailableBalance().addListener((observable, oldValue, newValue) -> { - UserThread.execute(() -> availableBalance.set(HavenoUtils.formatXmr(newValue, true))); - }); - balances.getPendingBalance().addListener((observable, oldValue, newValue) -> { - UserThread.execute(() -> pendingBalance.set(HavenoUtils.formatXmr(newValue, true))); - }); - balances.getReservedBalance().addListener((observable, oldValue, newValue) -> { - UserThread.execute(() -> reservedBalance.set(HavenoUtils.formatXmr(newValue, true))); + balances.getUpdateCounter().addListener((observable, oldValue, newValue) -> { + XmrBalanceInfo info = balances.getBalances(); + UserThread.execute(() -> { + availableBalance.set(HavenoUtils.formatXmr(info.getAvailableBalance(), true)); + pendingBalance.set(HavenoUtils.formatXmr(info.getPendingBalance(), true)); + reservedBalance.set(HavenoUtils.formatXmr(info.getReservedBalance(), true)); + }); }); } } diff --git a/core/src/main/java/haveno/core/presentation/CorePresentationModule.java b/core/src/main/java/haveno/core/presentation/CorePresentationModule.java index 8d21e9ea4b..7798da5804 100644 --- a/core/src/main/java/haveno/core/presentation/CorePresentationModule.java +++ b/core/src/main/java/haveno/core/presentation/CorePresentationModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.presentation; diff --git a/core/src/main/java/haveno/core/presentation/SupportTicketsPresentation.java b/core/src/main/java/haveno/core/presentation/SupportTicketsPresentation.java index 652dbf246b..30d0d277f1 100644 --- a/core/src/main/java/haveno/core/presentation/SupportTicketsPresentation.java +++ b/core/src/main/java/haveno/core/presentation/SupportTicketsPresentation.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.presentation; +import com.google.inject.Inject; import haveno.core.support.dispute.arbitration.ArbitrationManager; import haveno.core.support.dispute.mediation.MediationManager; import haveno.core.support.dispute.refund.RefundManager; @@ -26,8 +27,6 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import lombok.Getter; -import javax.inject.Inject; - public class SupportTicketsPresentation { @Getter private final StringProperty numOpenSupportTickets = new SimpleStringProperty(); diff --git a/core/src/main/java/haveno/core/presentation/TradePresentation.java b/core/src/main/java/haveno/core/presentation/TradePresentation.java index a1d745f497..9abd16ca7b 100644 --- a/core/src/main/java/haveno/core/presentation/TradePresentation.java +++ b/core/src/main/java/haveno/core/presentation/TradePresentation.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.presentation; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.core.trade.TradeManager; import javafx.beans.property.BooleanProperty; @@ -25,8 +26,6 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import lombok.Getter; -import javax.inject.Inject; - public class TradePresentation { @Getter private final StringProperty numPendingTrades = new SimpleStringProperty(); diff --git a/core/src/main/java/haveno/core/proto/CoreProtoResolver.java b/core/src/main/java/haveno/core/proto/CoreProtoResolver.java index 2b0dc4b2e0..504d59dc58 100644 --- a/core/src/main/java/haveno/core/proto/CoreProtoResolver.java +++ b/core/src/main/java/haveno/core/proto/CoreProtoResolver.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.proto; @@ -54,6 +54,7 @@ import haveno.core.payment.payload.NequiAccountPayload; import haveno.core.payment.payload.OKPayAccountPayload; import haveno.core.payment.payload.PaxumAccountPayload; import haveno.core.payment.payload.PaymentAccountPayload; +import haveno.core.payment.payload.PayPalAccountPayload; import haveno.core.payment.payload.PayseraAccountPayload; import haveno.core.payment.payload.PaytmAccountPayload; import haveno.core.payment.payload.PerfectMoneyAccountPayload; @@ -236,6 +237,8 @@ public class CoreProtoResolver implements ProtoResolver { return CashAppAccountPayload.fromProto(proto); case VENMO_ACCOUNT_PAYLOAD: return VenmoAccountPayload.fromProto(proto); + case PAYPAL_ACCOUNT_PAYLOAD: + return PayPalAccountPayload.fromProto(proto); default: throw new ProtobufferRuntimeException("Unknown proto message case(PB.PaymentAccountPayload). messageCase=" + messageCase); diff --git a/core/src/main/java/haveno/core/proto/ProtoDevUtil.java b/core/src/main/java/haveno/core/proto/ProtoDevUtil.java index c8299fe80c..4e2517b3fd 100644 --- a/core/src/main/java/haveno/core/proto/ProtoDevUtil.java +++ b/core/src/main/java/haveno/core/proto/ProtoDevUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.proto; diff --git a/core/src/main/java/haveno/core/proto/network/CoreNetworkProtoResolver.java b/core/src/main/java/haveno/core/proto/network/CoreNetworkProtoResolver.java index 3443b150c2..6827295fbf 100644 --- a/core/src/main/java/haveno/core/proto/network/CoreNetworkProtoResolver.java +++ b/core/src/main/java/haveno/core/proto/network/CoreNetworkProtoResolver.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.proto.network; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.proto.ProtobufferException; import haveno.common.proto.ProtobufferRuntimeException; import haveno.common.proto.network.NetworkEnvelope; @@ -53,6 +55,7 @@ import haveno.core.trade.messages.SignContractResponse; import haveno.network.p2p.AckMessage; import haveno.network.p2p.BundleOfEnvelopes; import haveno.network.p2p.CloseConnectionMessage; +import haveno.network.p2p.FileTransferPart; import haveno.network.p2p.PrefixedSealedAndSignedMessage; import haveno.network.p2p.peers.getdata.messages.GetDataResponse; import haveno.network.p2p.peers.getdata.messages.GetUpdatedDataRequest; @@ -69,11 +72,8 @@ import haveno.network.p2p.storage.messages.RemoveMailboxDataMessage; import haveno.network.p2p.storage.payload.MailboxStoragePayload; import haveno.network.p2p.storage.payload.ProtectedMailboxStorageEntry; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.time.Clock; +import lombok.extern.slf4j.Slf4j; // TODO Use ProtobufferException instead of ProtobufferRuntimeException @Slf4j @@ -179,6 +179,9 @@ public class CoreNetworkProtoResolver extends CoreProtoResolver implements Netwo case GET_INVENTORY_RESPONSE: return GetInventoryResponse.fromProto(proto.getGetInventoryResponse(), messageVersion); + case FILE_TRANSFER_PART: + return FileTransferPart.fromProto(proto.getFileTransferPart(), messageVersion); + default: throw new ProtobufferException("Unknown proto message case (PB.NetworkEnvelope). messageCase=" + proto.getMessageCase() + "; proto raw data=" + proto.toString()); diff --git a/core/src/main/java/haveno/core/proto/persistable/CorePersistenceProtoResolver.java b/core/src/main/java/haveno/core/proto/persistable/CorePersistenceProtoResolver.java index 53bd30a2be..441252d9a1 100644 --- a/core/src/main/java/haveno/core/proto/persistable/CorePersistenceProtoResolver.java +++ b/core/src/main/java/haveno/core/proto/persistable/CorePersistenceProtoResolver.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.proto.persistable; +import com.google.inject.Inject; import com.google.inject.Provider; +import com.google.inject.Singleton; import haveno.common.proto.ProtobufferRuntimeException; import haveno.common.proto.network.NetworkProtoResolver; import haveno.common.proto.persistable.NavigationPath; @@ -47,9 +49,6 @@ import haveno.network.p2p.storage.persistence.RemovedPayloadsMap; import haveno.network.p2p.storage.persistence.SequenceNumberMap; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; - // TODO Use ProtobufferException instead of ProtobufferRuntimeException @Slf4j @Singleton diff --git a/core/src/main/java/haveno/core/provider/FeeHttpClient.java b/core/src/main/java/haveno/core/provider/FeeHttpClient.java index 8ca15c3cab..02cc02374e 100644 --- a/core/src/main/java/haveno/core/provider/FeeHttpClient.java +++ b/core/src/main/java/haveno/core/provider/FeeHttpClient.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.network.Socks5ProxyProvider; import haveno.network.http.HttpClientImpl; - import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; @Singleton public class FeeHttpClient extends HttpClientImpl { diff --git a/core/src/main/java/haveno/core/provider/HttpClientProvider.java b/core/src/main/java/haveno/core/provider/HttpClientProvider.java index 19172dc3b4..b6caa932e1 100644 --- a/core/src/main/java/haveno/core/provider/HttpClientProvider.java +++ b/core/src/main/java/haveno/core/provider/HttpClientProvider.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider; diff --git a/core/src/main/java/haveno/core/provider/MempoolHttpClient.java b/core/src/main/java/haveno/core/provider/MempoolHttpClient.java index 70695fdff4..4ef5db8a70 100644 --- a/core/src/main/java/haveno/core/provider/MempoolHttpClient.java +++ b/core/src/main/java/haveno/core/provider/MempoolHttpClient.java @@ -1,30 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.app.Version; import haveno.network.Socks5ProxyProvider; import haveno.network.http.HttpClientImpl; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; import java.io.IOException; +import javax.annotation.Nullable; @Singleton public class MempoolHttpClient extends HttpClientImpl { diff --git a/core/src/main/java/haveno/core/provider/PriceHttpClient.java b/core/src/main/java/haveno/core/provider/PriceHttpClient.java index 2041fe0aa7..589a6429be 100644 --- a/core/src/main/java/haveno/core/provider/PriceHttpClient.java +++ b/core/src/main/java/haveno/core/provider/PriceHttpClient.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.network.Socks5ProxyProvider; import haveno.network.http.HttpClientImpl; - import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; @Singleton public class PriceHttpClient extends HttpClientImpl { diff --git a/core/src/main/java/haveno/core/provider/ProvidersRepository.java b/core/src/main/java/haveno/core/provider/ProvidersRepository.java index 99d7ed767a..8357bb7f08 100644 --- a/core/src/main/java/haveno/core/provider/ProvidersRepository.java +++ b/core/src/main/java/haveno/core/provider/ProvidersRepository.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,23 +35,24 @@ package haveno.core.provider; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Named; - +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; @Slf4j public class ProvidersRepository { + + private static final String DEFAULT_LOCAL_NODE = "http://localhost:8078/"; private static final List<String> DEFAULT_NODES = Arrays.asList( "http://elaxlgigphpicy5q7pi5wkz2ko2vgjbq4576vic7febmx4xcxvk6deqd.onion/", // Haveno - "http://a66ulzwhhudtqy6k2efnhodj2n6wnc5mnzjs3ocqtf47lwtcuo4wxyqd.onion/" // Cake + "http://lrrgpezvdrbpoqvkavzobmj7dr2otxc5x6wgktrw337bk6mxsvfp5yid.onion/" // Cake ); private final Config config; @@ -47,7 +65,7 @@ public class ProvidersRepository { @Getter @Nullable private List<String> bannedNodes; - private int index = 0; + private int index = -1; /////////////////////////////////////////////////////////////////////////////////////////// @@ -63,33 +81,42 @@ public class ProvidersRepository { this.providersFromProgramArgs = providers; this.useLocalhostForP2P = useLocalhostForP2P; - Collections.shuffle(DEFAULT_NODES); + Collections.shuffle(DEFAULT_NODES); // randomize order of default nodes applyBannedNodes(config.bannedPriceRelayNodes); } public void applyBannedNodes(@Nullable List<String> bannedNodes) { this.bannedNodes = bannedNodes; + + // fill provider list fillProviderList(); - selectNextProviderBaseUrl(); + + // select next provider if current provider is null or banned + if (baseUrl.isEmpty() || isBanned(baseUrl)) selectNextProviderBaseUrl(); if (bannedNodes != null && !bannedNodes.isEmpty()) { - log.info("Excluded provider nodes from filter: nodes={}, selected provider baseUrl={}, providerList={}", - bannedNodes, baseUrl, providerList); + log.info("Excluded provider nodes from filter: nodes={}, selected provider baseUrl={}, providerList={}", bannedNodes, baseUrl, providerList); } } // returns true if provider selection loops to beginning - public boolean selectNextProviderBaseUrl() { + public synchronized boolean selectNextProviderBaseUrl() { boolean looped = false; if (!providerList.isEmpty()) { + + // increment index + index++; + + // loop to beginning if (index >= providerList.size()) { index = 0; looped = true; } + // update base url baseUrl = providerList.get(index); - index++; + log.info("Selected price provider: " + baseUrl); if (providerList.size() == 1 && config.baseCurrencyNetwork.isMainnet()) log.warn("We only have one provider"); @@ -108,22 +135,30 @@ public class ProvidersRepository { // If we run in localhost mode we don't have the tor node running, so we need a clearnet host // Use localhost for using a locally running provider providers = List.of( - "http://localhost:8078/", + DEFAULT_LOCAL_NODE, "https://price.haveno.network/", - "http://173.230.142.36:8080/"); + "http://173.230.142.36:8078/"); } else { - providers = DEFAULT_NODES; + providers = new ArrayList<String>(); + //providers.add(DEFAULT_LOCAL_NODE); // try local provider first + providers.addAll(DEFAULT_NODES); } } else { providers = providersFromProgramArgs; } providerList = providers.stream() - .filter(e -> bannedNodes == null || - !bannedNodes.contains(e.replace("http://", "") - .replace("/", "") - .replace(".onion", ""))) + .filter(e -> !isBanned(e)) .map(e -> e.endsWith("/") ? e : e + "/") .map(e -> e.startsWith("http") ? e : "http://" + e) .collect(Collectors.toList()); } + + private boolean isBanned(String provider) { + if (bannedNodes == null) return false; + return bannedNodes.stream() + .anyMatch(e -> provider.replace("http://", "") + .replace("/", "") + .replace(".onion", "") + .equals(e)); + } } diff --git a/core/src/main/java/haveno/core/provider/fee/FeeProvider.java b/core/src/main/java/haveno/core/provider/fee/FeeProvider.java index cedb508bf5..18838cee38 100644 --- a/core/src/main/java/haveno/core/provider/fee/FeeProvider.java +++ b/core/src/main/java/haveno/core/provider/fee/FeeProvider.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.fee; @@ -59,8 +59,7 @@ public class FeeProvider extends HttpClientProvider { map.put(Config.BTC_TX_FEE, btcTxFee); map.put(Config.BTC_MIN_TX_FEE, btcMinTxFee); } catch (Throwable t) { - log.error(t.toString()); - t.printStackTrace(); + log.error("Error getting fees: {}\n", t.getMessage(), t); } return new Tuple2<>(tsMap, map); } diff --git a/core/src/main/java/haveno/core/provider/fee/FeeRequest.java b/core/src/main/java/haveno/core/provider/fee/FeeRequest.java index e4cb558082..a7798a40a4 100644 --- a/core/src/main/java/haveno/core/provider/fee/FeeRequest.java +++ b/core/src/main/java/haveno/core/provider/fee/FeeRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.fee; diff --git a/core/src/main/java/haveno/core/provider/price/MarketPrice.java b/core/src/main/java/haveno/core/provider/price/MarketPrice.java index 5fc7ab06e0..1a328b623c 100644 --- a/core/src/main/java/haveno/core/provider/price/MarketPrice.java +++ b/core/src/main/java/haveno/core/provider/price/MarketPrice.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.price; diff --git a/core/src/main/java/haveno/core/provider/price/PriceFeedService.java b/core/src/main/java/haveno/core/provider/price/PriceFeedService.java index 9dce90670c..c58277792f 100644 --- a/core/src/main/java/haveno/core/provider/price/PriceFeedService.java +++ b/core/src/main/java/haveno/core/provider/price/PriceFeedService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.price; @@ -33,7 +33,6 @@ import haveno.core.monetary.Price; import haveno.core.monetary.TraditionalMoney; import haveno.core.provider.PriceHttpClient; import haveno.core.provider.ProvidersRepository; -import haveno.core.trade.HavenoUtils; import haveno.core.trade.statistics.TradeStatistics3; import haveno.core.user.Preferences; import haveno.network.http.HttpClient; @@ -116,6 +115,7 @@ public class PriceFeedService { /////////////////////////////////////////////////////////////////////////////////////////// public void shutDown() { + log.info("Shutting down {}", getClass().getSimpleName()); if (requestTimer != null) { requestTimer.stop(); requestTimer = null; @@ -137,8 +137,29 @@ public class PriceFeedService { request(false); } - public boolean hasPrices() { - return !cache.isEmpty(); + /** + * Awaits prices to be available, but does not request them. + */ + public void awaitExternalPrices() { + CountDownLatch latch = new CountDownLatch(1); + ChangeListener<? super Number> listener = (observable, oldValue, newValue) -> { + if (hasExternalPrices()) UserThread.execute(() -> latch.countDown()); + }; + UserThread.execute(() -> updateCounter.addListener(listener)); + if (hasExternalPrices()) UserThread.execute(() -> latch.countDown()); + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + UserThread.execute(() -> updateCounter.removeListener(listener)); + } + } + + public boolean hasExternalPrices() { + synchronized (cache) { + return cache.values().stream().anyMatch(MarketPrice::isExternallyProvidedPrice); + } } public void startRequestingPrices() { @@ -223,7 +244,7 @@ public class PriceFeedService { if (baseUrlOfRespondingProvider == null) { final String oldBaseUrl = priceProvider.getBaseUrl(); setNewPriceProvider(); - log.warn("We did not received a response from provider {}. " + + log.warn("We did not receive a response from provider {}. " + "We select the new provider {} and use that for a new request.", oldBaseUrl, priceProvider.getBaseUrl()); } request(true); @@ -258,27 +279,36 @@ public class PriceFeedService { // returns true if provider selection loops back to beginning private boolean setNewPriceProvider() { + httpClient.cancelPendingRequest(); boolean looped = providersRepository.selectNextProviderBaseUrl(); - if (!providersRepository.getBaseUrl().isEmpty()) + if (!providersRepository.getBaseUrl().isEmpty()) { priceProvider = new PriceProvider(httpClient, providersRepository.getBaseUrl()); - else + } else { log.warn("We cannot create a new priceProvider because new base url is empty."); - return looped; + } + return looped; } @Nullable public MarketPrice getMarketPrice(String currencyCode) { - return cache.getOrDefault(currencyCode, null); + synchronized (cache) { + return cache.getOrDefault(CurrencyUtil.getCurrencyCodeBase(currencyCode), null); + } } private void setHavenoMarketPrice(String currencyCode, Price price) { - if (!cache.containsKey(currencyCode) || !cache.get(currencyCode).isExternallyProvidedPrice()) { - cache.put(currencyCode, new MarketPrice(currencyCode, - MathUtils.scaleDownByPowerOf10(price.getValue(), CurrencyUtil.isCryptoCurrency(currencyCode) ? CryptoMoney.SMALLEST_UNIT_EXPONENT : TraditionalMoney.SMALLEST_UNIT_EXPONENT), - 0, - false)); - updateCounter.set(updateCounter.get() + 1); - } + UserThread.execute(() -> { + String currencyCodeBase = CurrencyUtil.getCurrencyCodeBase(currencyCode); + synchronized (cache) { + if (!cache.containsKey(currencyCodeBase) || !cache.get(currencyCodeBase).isExternallyProvidedPrice()) { + cache.put(currencyCodeBase, new MarketPrice(currencyCodeBase, + MathUtils.scaleDownByPowerOf10(price.getValue(), CurrencyUtil.isCryptoCurrency(currencyCode) ? CryptoMoney.SMALLEST_UNIT_EXPONENT : TraditionalMoney.SMALLEST_UNIT_EXPONENT), + 0, + false)); + } + updateCounter.set(updateCounter.get() + 1); + } + }); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -286,12 +316,13 @@ public class PriceFeedService { /////////////////////////////////////////////////////////////////////////////////////////// public void setCurrencyCode(String currencyCode) { - if (this.currencyCode == null || !this.currencyCode.equals(currencyCode)) { - this.currencyCode = currencyCode; - currencyCodeProperty.set(currencyCode); - if (priceConsumer != null) - applyPriceToConsumer(); - } + UserThread.await(() -> { + if (this.currencyCode == null || !this.currencyCode.equals(currencyCode)) { + this.currencyCode = currencyCode; + currencyCodeProperty.set(currencyCode); + if (priceConsumer != null) applyPriceToConsumer(); + } + }); } @@ -348,17 +379,21 @@ public class PriceFeedService { */ public synchronized Map<String, MarketPrice> requestAllPrices() throws ExecutionException, InterruptedException, TimeoutException, CancellationException { CountDownLatch latch = new CountDownLatch(1); - ChangeListener<? super Number> listener = (observable, oldValue, newValue) -> { latch.countDown(); }; - updateCounter.addListener(listener); + ChangeListener<? super Number> listener = (observable, oldValue, newValue) -> latch.countDown(); + UserThread.execute(() -> updateCounter.addListener(listener)); requestAllPricesError = null; requestPrices(); UserThread.runAfter(() -> { - if (latch.getCount() == 0) return; - requestAllPricesError = "Timeout fetching market prices within 20 seconds"; - latch.countDown(); + if (latch.getCount() > 0) requestAllPricesError = "Timeout fetching market prices within 20 seconds"; + UserThread.execute(() -> latch.countDown()); }, 20); - HavenoUtils.awaitLatch(latch); - updateCounter.removeListener(listener); + try { + latch.await(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } finally { + UserThread.execute(() -> updateCounter.removeListener(listener)); + } if (requestAllPricesError != null) throw new RuntimeException(requestAllPricesError); return cache; } @@ -416,7 +451,7 @@ public class PriceFeedService { faultHandler.handleFault(errorMessage, new PriceRequestException(errorMessage)); } - updateCounter.set(updateCounter.get() + 1); + UserThread.execute(() -> updateCounter.set(updateCounter.get() + 1)); return result; } @@ -441,7 +476,9 @@ public class PriceFeedService { Map<String, MarketPrice> priceMap = result; - cache.putAll(priceMap); + synchronized (cache) { + cache.putAll(priceMap); + } resultHandler.run(); }); diff --git a/core/src/main/java/haveno/core/provider/price/PriceProvider.java b/core/src/main/java/haveno/core/provider/price/PriceProvider.java index 32308899eb..931629473a 100644 --- a/core/src/main/java/haveno/core/provider/price/PriceProvider.java +++ b/core/src/main/java/haveno/core/provider/price/PriceProvider.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.price; @@ -21,6 +21,7 @@ import com.google.gson.Gson; import com.google.gson.internal.LinkedTreeMap; import haveno.common.app.Version; import haveno.common.util.MathUtils; +import haveno.core.locale.CurrencyUtil; import haveno.core.provider.HttpClientProvider; import haveno.network.http.HttpClient; import haveno.network.p2p.P2PService; @@ -63,13 +64,13 @@ public class PriceProvider extends HttpClientProvider { String baseCurrencyCode = (String) treeMap.get("baseCurrencyCode"); String counterCurrencyCode = (String) treeMap.get("counterCurrencyCode"); String currencyCode = baseCurrencyCode.equals("XMR") ? counterCurrencyCode : baseCurrencyCode; + currencyCode = CurrencyUtil.getCurrencyCodeBase(currencyCode); double price = (Double) treeMap.get("price"); // json uses double for our timestampSec long value... long timestampSec = MathUtils.doubleToLong((Double) treeMap.get("timestampSec")); marketPriceMap.put(currencyCode, new MarketPrice(currencyCode, price, timestampSec, true)); } catch (Throwable t) { - log.error(t.toString()); - t.printStackTrace(); + log.error("Error getting all prices: {}\n", t.getMessage(), t); } }); diff --git a/core/src/main/java/haveno/core/provider/price/PriceRequest.java b/core/src/main/java/haveno/core/provider/price/PriceRequest.java index ad6070fabb..403ae8edd2 100644 --- a/core/src/main/java/haveno/core/provider/price/PriceRequest.java +++ b/core/src/main/java/haveno/core/provider/price/PriceRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.price; diff --git a/core/src/main/java/haveno/core/provider/price/PriceRequestException.java b/core/src/main/java/haveno/core/provider/price/PriceRequestException.java index e0839dd8c9..7019daa85b 100644 --- a/core/src/main/java/haveno/core/provider/price/PriceRequestException.java +++ b/core/src/main/java/haveno/core/provider/price/PriceRequestException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.price; diff --git a/core/src/main/java/haveno/core/setup/CoreNetworkCapabilities.java b/core/src/main/java/haveno/core/setup/CoreNetworkCapabilities.java index 8ce1c9c330..4eb98a4d70 100644 --- a/core/src/main/java/haveno/core/setup/CoreNetworkCapabilities.java +++ b/core/src/main/java/haveno/core/setup/CoreNetworkCapabilities.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.setup; diff --git a/core/src/main/java/haveno/core/setup/CorePersistedDataHost.java b/core/src/main/java/haveno/core/setup/CorePersistedDataHost.java index de85177ed1..1cda993d69 100644 --- a/core/src/main/java/haveno/core/setup/CorePersistedDataHost.java +++ b/core/src/main/java/haveno/core/setup/CorePersistedDataHost.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.setup; diff --git a/core/src/main/java/haveno/core/setup/CoreSetup.java b/core/src/main/java/haveno/core/setup/CoreSetup.java index 40aeaa4739..d3149c552e 100644 --- a/core/src/main/java/haveno/core/setup/CoreSetup.java +++ b/core/src/main/java/haveno/core/setup/CoreSetup.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.setup; diff --git a/core/src/main/java/haveno/core/support/SupportManager.java b/core/src/main/java/haveno/core/support/SupportManager.java index 783e00c68d..10cbfdafaf 100644 --- a/core/src/main/java/haveno/core/support/SupportManager.java +++ b/core/src/main/java/haveno/core/support/SupportManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support; @@ -21,7 +21,7 @@ import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.crypto.PubKeyRing; import haveno.common.proto.network.NetworkEnvelope; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.api.CoreNotificationService; import haveno.core.locale.Res; import haveno.core.support.dispute.Dispute; @@ -29,8 +29,7 @@ import haveno.core.support.messages.ChatMessage; import haveno.core.support.messages.SupportMessage; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; -import haveno.core.trade.protocol.TradeProtocol; -import haveno.core.trade.protocol.TradeProtocol.MailboxMessageComparator; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessage; import haveno.network.p2p.AckMessageSourceType; import haveno.network.p2p.DecryptedMessageWithPubKey; @@ -39,10 +38,10 @@ import haveno.network.p2p.P2PService; import haveno.network.p2p.SendMailboxMessageListener; import haveno.network.p2p.mailbox.MailboxMessage; import haveno.network.p2p.mailbox.MailboxMessageService; +import haveno.network.p2p.mailbox.MailboxMessageService.DecryptedMessageWithPubKeyComparator; import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; -import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,7 +51,8 @@ import java.util.concurrent.CopyOnWriteArraySet; public abstract class SupportManager { protected final P2PService p2PService; protected final TradeManager tradeManager; - protected final CoreMoneroConnectionsService connectionService; + protected final XmrConnectionService xmrConnectionService; + protected final XmrWalletService xmrWalletService; protected final CoreNotificationService notificationService; protected final Map<String, Timer> delayMsgMap = new HashMap<>(); private final Object lock = new Object(); @@ -67,20 +67,22 @@ public abstract class SupportManager { /////////////////////////////////////////////////////////////////////////////////////////// public SupportManager(P2PService p2PService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, + XmrWalletService xmrWalletService, CoreNotificationService notificationService, TradeManager tradeManager) { this.p2PService = p2PService; - this.connectionService = connectionService; + this.xmrConnectionService = xmrConnectionService; + this.xmrWalletService = xmrWalletService; this.mailboxMessageService = p2PService.getMailboxMessageService(); this.notificationService = notificationService; this.tradeManager = tradeManager; // We get first the message handler called then the onBootstrapped p2PService.addDecryptedDirectMessageListener((decryptedMessageWithPubKey, senderAddress) -> { - if (isReady()) applyDirectMessage(decryptedMessageWithPubKey); - else { - synchronized (lock) { + synchronized (lock) { + if (isReady()) applyDirectMessage(decryptedMessageWithPubKey); + else { // As decryptedDirectMessageWithPubKeys is a CopyOnWriteArraySet we do not need to check if it was already stored decryptedDirectMessageWithPubKeys.add(decryptedMessageWithPubKey); tryApplyMessages(); @@ -88,9 +90,9 @@ public abstract class SupportManager { } }); mailboxMessageService.addDecryptedMailboxListener((decryptedMessageWithPubKey, senderAddress) -> { - if (isReady()) applyMailboxMessage(decryptedMessageWithPubKey); - else { - synchronized (lock) { + synchronized (lock) { + if (isReady()) applyMailboxMessage(decryptedMessageWithPubKey); + else { // As decryptedMailboxMessageWithPubKeys is a CopyOnWriteArraySet we do not need to check if it was already stored decryptedDirectMessageWithPubKeys.add(decryptedMessageWithPubKey); tryApplyMessages(); @@ -184,24 +186,47 @@ public abstract class SupportManager { private void onAckMessage(AckMessage ackMessage) { if (ackMessage.getSourceType() == getAckMessageSourceType()) { if (ackMessage.isSuccess()) { - log.info("Received AckMessage for {} with tradeId {} and uid {}", - ackMessage.getSourceMsgClassName(), ackMessage.getSourceId(), ackMessage.getSourceUid()); + log.info("Received AckMessage for {} with tradeId {} and uid {}", ackMessage.getSourceMsgClassName(), ackMessage.getSourceId(), ackMessage.getSourceUid()); // ack message on chat message received when dispute is opened and closed if (ackMessage.getSourceMsgClassName().equals(ChatMessage.class.getSimpleName())) { Trade trade = tradeManager.getTrade(ackMessage.getSourceId()); for (Dispute dispute : trade.getDisputes()) { - for (ChatMessage chatMessage : dispute.getChatMessages()) { - if (chatMessage.getUid().equals(ackMessage.getSourceUid())) { - if (dispute.isClosed()) trade.syncWalletNormallyForMs(30000); // sync to check for payout - else trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED); + synchronized (dispute.getChatMessages()) { + for (ChatMessage chatMessage : dispute.getChatMessages()) { + if (chatMessage.getUid().equals(ackMessage.getSourceUid())) { + if (trade.getDisputeState() == Trade.DisputeState.DISPUTE_REQUESTED) { + if (dispute.isClosed()) dispute.reOpen(); + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED); + } else if (dispute.isClosed()) { + trade.pollWalletNormallyForMs(60000); // sync to check for payout + } + } + } + } + } + } + } else { + log.warn("Received AckMessage with error state for {} with tradeId={}, sender={}, errorMessage={}", + ackMessage.getSourceMsgClassName(), ackMessage.getSourceId(), ackMessage.getSenderNodeAddress(), ackMessage.getErrorMessage()); + + // nack message on chat message received when dispute closed message is nacked + if (ackMessage.getSourceMsgClassName().equals(ChatMessage.class.getSimpleName())) { + Trade trade = tradeManager.getTrade(ackMessage.getSourceId()); + for (Dispute dispute : trade.getDisputes()) { + synchronized (dispute.getChatMessages()) { + for (ChatMessage chatMessage : dispute.getChatMessages()) { + if (chatMessage.getUid().equals(ackMessage.getSourceUid())) { + if (trade.getDisputeState().isCloseRequested()) { + log.warn("DisputeCloseMessage was nacked. We close the dispute now. tradeId={}, nack sender={}", trade.getId(), ackMessage.getSenderNodeAddress()); + dispute.setIsClosed(); + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_CLOSED); + } + } } } } } - } else { - log.warn("Received AckMessage with error state for {} with tradeId {} and errorMessage={}", - ackMessage.getSourceMsgClassName(), ackMessage.getSourceId(), ackMessage.getErrorMessage()); } getAllChatMessages(ackMessage.getSourceId()).stream() @@ -332,8 +357,9 @@ public abstract class SupportManager { private boolean isReady() { return allServicesInitialized && p2PService.isBootstrapped() && - connectionService.isDownloadComplete() && - connectionService.hasSufficientPeersForBroadcast(); + xmrConnectionService.isDownloadComplete() && + xmrConnectionService.hasSufficientPeersForBroadcast() && + xmrWalletService.isDownloadComplete(); } @@ -390,22 +416,4 @@ public abstract class SupportManager { mailboxMessageService.removeMailboxMsg(ackMessage); } } - - private static class DecryptedMessageWithPubKeyComparator implements Comparator<DecryptedMessageWithPubKey> { - - MailboxMessageComparator mailboxMessageComparator; - public DecryptedMessageWithPubKeyComparator() { - mailboxMessageComparator = new TradeProtocol.MailboxMessageComparator(); - } - - @Override - public int compare(DecryptedMessageWithPubKey m1, DecryptedMessageWithPubKey m2) { - if (m1.getNetworkEnvelope() instanceof MailboxMessage) { - if (m2.getNetworkEnvelope() instanceof MailboxMessage) return mailboxMessageComparator.compare((MailboxMessage) m1.getNetworkEnvelope(), (MailboxMessage) m2.getNetworkEnvelope()); - else return 1; - } else { - return m2.getNetworkEnvelope() instanceof MailboxMessage ? -1 : 0; - } - } - } } diff --git a/core/src/main/java/haveno/core/support/SupportSession.java b/core/src/main/java/haveno/core/support/SupportSession.java index 89f6fdf9e9..b927aaaeb5 100644 --- a/core/src/main/java/haveno/core/support/SupportSession.java +++ b/core/src/main/java/haveno/core/support/SupportSession.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support; diff --git a/core/src/main/java/haveno/core/support/SupportType.java b/core/src/main/java/haveno/core/support/SupportType.java index 7ed7550752..f41f19368e 100644 --- a/core/src/main/java/haveno/core/support/SupportType.java +++ b/core/src/main/java/haveno/core/support/SupportType.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support; diff --git a/core/src/main/java/haveno/core/support/dispute/Attachment.java b/core/src/main/java/haveno/core/support/dispute/Attachment.java index 8160ed17bb..f56e14947b 100644 --- a/core/src/main/java/haveno/core/support/dispute/Attachment.java +++ b/core/src/main/java/haveno/core/support/dispute/Attachment.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; diff --git a/core/src/main/java/haveno/core/support/dispute/Dispute.java b/core/src/main/java/haveno/core/support/dispute/Dispute.java index cabd830ba6..15595b8893 100644 --- a/core/src/main/java/haveno/core/support/dispute/Dispute.java +++ b/core/src/main/java/haveno/core/support/dispute/Dispute.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; @@ -30,8 +30,13 @@ import haveno.core.locale.Res; import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.proto.CoreProtoResolver; import haveno.core.support.SupportType; +import haveno.core.support.dispute.mediation.FileTransferReceiver; +import haveno.core.support.dispute.mediation.FileTransferSender; +import haveno.core.support.dispute.mediation.FileTransferSession; import haveno.core.support.messages.ChatMessage; import haveno.core.trade.Contract; +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.network.NetworkNode; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; @@ -49,6 +54,8 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; + +import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -70,6 +77,10 @@ public final class Dispute implements NetworkPayload, PersistablePayload { REOPENED, CLOSED; + public boolean isOpen() { + return this == NEW || this == OPEN || this == REOPENED; + } + public static Dispute.State fromProto(protobuf.Dispute.State state) { return ProtoUtil.enumFromProto(Dispute.State.class, state.name()); } @@ -151,6 +162,25 @@ public final class Dispute implements NetworkPayload, PersistablePayload { private transient final BooleanProperty isClosedProperty = new SimpleBooleanProperty(); private transient final IntegerProperty badgeCountProperty = new SimpleIntegerProperty(); + private transient FileTransferReceiver fileTransferSession = null; + + public FileTransferReceiver createOrGetFileTransferReceiver(NetworkNode networkNode, + NodeAddress peerNodeAddress, + FileTransferSession.FtpCallback callback) throws IOException { + // the receiver stores its state temporarily here in the dispute + // this method gets called to retrieve the session each time a part of the log files is received + if (fileTransferSession == null) { + fileTransferSession = new FileTransferReceiver(networkNode, peerNodeAddress, this.tradeId, this.traderId, this.getRoleStringForLogFile(), callback); + } + return fileTransferSession; + } + + public FileTransferSender createFileTransferSender(NetworkNode networkNode, + NodeAddress peerNodeAddress, + FileTransferSession.FtpCallback callback) { + return new FileTransferSender(networkNode, peerNodeAddress, this.tradeId, this.traderId, this.getRoleStringForLogFile(), false, callback); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -323,10 +353,12 @@ public final class Dispute implements NetworkPayload, PersistablePayload { /////////////////////////////////////////////////////////////////////////////////////////// public void addAndPersistChatMessage(ChatMessage chatMessage) { - if (!chatMessages.contains(chatMessage)) { - chatMessages.add(chatMessage); - } else { - log.error("disputeDirectMessage already exists"); + synchronized (chatMessages) { + if (!chatMessages.contains(chatMessage)) { + chatMessages.add(chatMessage); + } else { + log.error("disputeDirectMessage already exists"); + } } } @@ -335,13 +367,15 @@ public final class Dispute implements NetworkPayload, PersistablePayload { } public boolean removeAllChatMessages() { - if (chatMessages.size() > 1) { - // removes all chat except the initial guidelines message. - String firstMessageUid = chatMessages.get(0).getUid(); - chatMessages.removeIf((msg) -> !msg.getUid().equals(firstMessageUid)); - return true; + synchronized (chatMessages) { + if (chatMessages.size() > 1) { + // removes all chat except the initial guidelines message. + String firstMessageUid = chatMessages.get(0).getUid(); + chatMessages.removeIf((msg) -> !msg.getUid().equals(firstMessageUid)); + return true; + } + return false; } - return false; } public void maybeClearSensitiveData() { @@ -432,6 +466,10 @@ public final class Dispute implements NetworkPayload, PersistablePayload { return this.disputeState == State.NEW; } + public boolean isOpen() { + return isNew() || this.disputeState == State.OPEN || this.disputeState == State.REOPENED; + } + public boolean isClosed() { return this.disputeState == State.CLOSED; } @@ -478,6 +516,11 @@ public final class Dispute implements NetworkPayload, PersistablePayload { } } + public String getRoleStringForLogFile() { + return (disputeOpenerIsBuyer ? "BUYER" : "SELLER") + "_" + + (disputeOpenerIsMaker ? "MAKER" : "TAKER"); + } + @Nullable public PaymentAccountPayload getBuyerPaymentAccountPayload() { return contract.isBuyerMakerAndSellerTaker() ? makerPaymentAccountPayload : takerPaymentAccountPayload; diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeAlreadyOpenException.java b/core/src/main/java/haveno/core/support/dispute/DisputeAlreadyOpenException.java index d2cf320d42..7273615a62 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeAlreadyOpenException.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeAlreadyOpenException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeList.java b/core/src/main/java/haveno/core/support/dispute/DisputeList.java index 03736026c4..99a80fa472 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeList.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeListService.java b/core/src/main/java/haveno/core/support/dispute/DisputeListService.java index 4f36e2f608..2c90565614 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeListService.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeListService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; @@ -90,12 +90,14 @@ public abstract class DisputeListService<T extends DisputeList<Dispute>> impleme /////////////////////////////////////////////////////////////////////////////////////////// public void cleanupDisputes(@Nullable Consumer<String> closedDisputeHandler) { - disputeList.stream().forEach(dispute -> { - String tradeId = dispute.getTradeId(); - if (dispute.isClosed() && closedDisputeHandler != null) { - closedDisputeHandler.accept(tradeId); - } - }); + synchronized (disputeList.getObservableList()) { + disputeList.stream().forEach(dispute -> { + String tradeId = dispute.getTradeId(); + if (dispute.isClosed() && closedDisputeHandler != null) { + closedDisputeHandler.accept(tradeId); + } + }); + } } @@ -130,7 +132,9 @@ public abstract class DisputeListService<T extends DisputeList<Dispute>> impleme } ObservableList<Dispute> getObservableList() { - return disputeList.getObservableList(); + synchronized (disputeList.getObservableList()) { + return disputeList.getObservableList(); + } } @@ -151,10 +155,12 @@ public abstract class DisputeListService<T extends DisputeList<Dispute>> impleme isAlerting -> { // We get the event before the list gets updated, so we execute on next frame UserThread.execute(() -> { - int numAlerts = (int) disputeList.getList().stream() - .mapToLong(x -> x.getBadgeCountProperty().getValue()) - .sum(); - numOpenDisputes.set(numAlerts); + synchronized (disputeList.getObservableList()) { + int numAlerts = (int) disputeList.getList().stream() + .mapToLong(x -> x.getBadgeCountProperty().getValue()) + .sum(); + numOpenDisputes.set(numAlerts); + } }); }); disputedTradeIds.add(dispute.getTradeId()); diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java index d3c0cb291f..d6b2469744 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeManager.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeManager.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,7 @@ package haveno.core.support.dispute; +import haveno.common.ThreadUtils; import haveno.common.UserThread; import haveno.common.app.Version; import haveno.common.config.Config; @@ -26,7 +44,7 @@ import haveno.common.handlers.FaultHandler; import haveno.common.handlers.ResultHandler; import haveno.common.util.MathUtils; import haveno.common.util.Tuple2; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.api.CoreNotificationService; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -65,6 +83,9 @@ import monero.wallet.model.MoneroTxConfig; import monero.wallet.model.MoneroTxWallet; import javax.annotation.Nullable; + +import org.apache.commons.lang3.exception.ExceptionUtils; + import java.math.BigInteger; import java.security.KeyPair; import java.time.Instant; @@ -104,7 +125,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup public DisputeManager(P2PService p2PService, TradeWalletService tradeWalletService, XmrWalletService xmrWalletService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, CoreNotificationService notificationService, TradeManager tradeManager, ClosedTradableManager closedTradableManager, @@ -113,7 +134,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup DisputeListService<T> disputeListService, Config config, PriceFeedService priceFeedService) { - super(p2PService, connectionService, notificationService, tradeManager); + super(p2PService, xmrConnectionService, xmrWalletService, notificationService, tradeManager); this.tradeWalletService = tradeWalletService; this.xmrWalletService = xmrWalletService; @@ -139,6 +160,11 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup disputeListService.requestPersistence(); } + protected void requestPersistence(Trade trade) { + trade.requestPersistence(); + disputeListService.requestPersistence(); + } + @Override public NodeAddress getPeerNodeAddress(ChatMessage message) { Optional<Dispute> disputeOptional = findDispute(message); @@ -164,10 +190,12 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup @Override public List<ChatMessage> getAllChatMessages(String tradeId) { - return getDisputeList().stream() - .filter(dispute -> dispute.getTradeId().equals(tradeId)) - .flatMap(dispute -> dispute.getChatMessages().stream()) - .collect(Collectors.toList()); + synchronized (getDisputeList().getObservableList()) { + return getDisputeList().stream() + .filter(dispute -> dispute.getTradeId().equals(tradeId)) + .flatMap(dispute -> dispute.getChatMessages().stream()) + .collect(Collectors.toList()); + } } @Override @@ -216,7 +244,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup } public ObservableList<Dispute> getDisputesAsObservableList() { - synchronized(disputeListService.getDisputeList()) { + synchronized(disputeListService.getDisputeList().getObservableList()) { return disputeListService.getObservableList(); } } @@ -226,7 +254,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup } protected T getDisputeList() { - synchronized(disputeListService.getDisputeList()) { + synchronized(disputeListService.getDisputeList().getObservableList()) { return disputeListService.getDisputeList(); } } @@ -246,18 +274,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { tryApplyMessages(); } }); - connectionService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { - if (connectionService.isDownloadComplete()) - tryApplyMessages(); - }); - - connectionService.numPeersProperty().addListener((observable, oldValue, newValue) -> { - if (connectionService.hasSufficientPeersForBroadcast()) + xmrWalletService.downloadPercentageProperty().addListener((observable, oldValue, newValue) -> { + if (xmrWalletService.isSyncedWithinTolerance()) tryApplyMessages(); }); @@ -308,15 +331,21 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup // trader sends message to arbitrator to open dispute public void sendDisputeOpenedMessage(Dispute dispute, - boolean reOpen, - String updatedMultisigHex, ResultHandler resultHandler, FaultHandler faultHandler) { // get trade Trade trade = tradeManager.getTrade(dispute.getTradeId()); if (trade == null) { - log.warn("Dispute trade {} does not exist", dispute.getTradeId()); + String errorMsg = "Dispute trade does not exist, tradeId=" + dispute.getTradeId(); + faultHandler.handleFault(errorMsg, new IllegalStateException(errorMsg)); + return; + } + + // arbitrator cannot open disputes + if (trade.isArbitrator()) { + String errorMsg = "Arbitrators cannot open disputes."; + faultHandler.handleFault(errorMsg, new IllegalStateException(errorMsg)); return; } @@ -330,7 +359,14 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup return; } - synchronized (disputeList) { + // skip if payout is confirmed + if (trade.isPayoutConfirmed()) { + String errorMsg = "Cannot open dispute because payout is already confirmed for " + trade.getClass().getSimpleName() + " " + trade.getId(); + faultHandler.handleFault(errorMsg, new IllegalStateException(errorMsg)); + return; + } + + synchronized (disputeList.getObservableList()) { if (disputeList.contains(dispute)) { String msg = "We got a dispute msg that we have already stored. TradeId = " + dispute.getTradeId() + ", DisputeId = " + dispute.getId(); log.warn(msg); @@ -339,99 +375,109 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup } Optional<Dispute> storedDisputeOptional = findDispute(dispute); - if (!storedDisputeOptional.isPresent() || reOpen) { - String disputeInfo = getDisputeInfo(dispute); - String sysMsg = dispute.isSupportTicket() ? - Res.get("support.youOpenedTicket", disputeInfo, Version.VERSION) : - Res.get("support.youOpenedDispute", disputeInfo, Version.VERSION); + boolean reOpen = storedDisputeOptional.isPresent(); - ChatMessage chatMessage = new ChatMessage( - getSupportType(), - dispute.getTradeId(), - keyRing.getPubKeyRing().hashCode(), - false, - Res.get("support.systemMsg", sysMsg), - p2PService.getAddress()); - chatMessage.setSystemMessage(true); - dispute.addAndPersistChatMessage(chatMessage); - if (!reOpen) { - disputeList.add(dispute); - } - - NodeAddress agentNodeAddress = getAgentNodeAddress(dispute); - DisputeOpenedMessage disputeOpenedMessage = new DisputeOpenedMessage(dispute, - p2PService.getAddress(), - UUID.randomUUID().toString(), - getSupportType(), - updatedMultisigHex, - trade.getProcessModel().getPaymentSentMessage()); - log.info("Send {} to peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid()); - recordPendingMessage(disputeOpenedMessage.getClass().getSimpleName()); - mailboxMessageService.sendEncryptedMailboxMessage(agentNodeAddress, - dispute.getAgentPubKeyRing(), - disputeOpenedMessage, - new SendMailboxMessageListener() { - @Override - public void onArrived() { - log.info("{} arrived at peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid()); - clearPendingMessage(); - - // We use the chatMessage wrapped inside the openNewDisputeMessage for - // the state, as that is displayed to the user and we only persist that msg - chatMessage.setArrived(true); - trade.advanceDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); - requestPersistence(); - resultHandler.handleResult(); - } - - @Override - public void onStoredInMailbox() { - log.info("{} stored in mailbox for peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid()); - clearPendingMessage(); - - // We use the chatMessage wrapped inside the openNewDisputeMessage for - // the state, as that is displayed to the user and we only persist that msg - chatMessage.setStoredInMailbox(true); - trade.advanceDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); - requestPersistence(); - resultHandler.handleResult(); - } - - @Override - public void onFault(String errorMessage) { - log.error("{} failed: Peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + - "chatMessage.uid={}, errorMessage={}", - disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, - disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), - chatMessage.getUid(), errorMessage); - - clearPendingMessage(); - // We use the chatMessage wrapped inside the openNewDisputeMessage for - // the state, as that is displayed to the user and we only persist that msg - chatMessage.setSendMessageError(errorMessage); - requestPersistence(); - faultHandler.handleFault("Sending dispute message failed: " + - errorMessage, new DisputeMessageDeliveryFailedException()); - } - }); + // add or re-open dispute + if (reOpen) { + dispute = storedDisputeOptional.get(); } else { - String msg = "We got a dispute already open for that trade and trading peer.\n" + - "TradeId = " + dispute.getTradeId(); - log.warn(msg); - faultHandler.handleFault(msg, new DisputeAlreadyOpenException()); + disputeList.add(dispute); } + + String disputeInfo = getDisputeInfo(dispute); + String sysMsg = dispute.isSupportTicket() ? + Res.get("support.youOpenedTicket", disputeInfo, Version.VERSION) : + Res.get("support.youOpenedDispute", disputeInfo, Version.VERSION); + + ChatMessage chatMessage = new ChatMessage( + getSupportType(), + dispute.getTradeId(), + keyRing.getPubKeyRing().hashCode(), + false, + Res.get("support.systemMsg", sysMsg), + p2PService.getAddress()); + chatMessage.setSystemMessage(true); + dispute.addAndPersistChatMessage(chatMessage); + + // export latest multisig hex + try { + trade.exportMultisigHex(); + } catch (Exception e) { + log.error("Failed to export multisig hex", e); + } + + // create dispute opened message + NodeAddress agentNodeAddress = getAgentNodeAddress(dispute); + DisputeOpenedMessage disputeOpenedMessage = new DisputeOpenedMessage(dispute, + p2PService.getAddress(), + UUID.randomUUID().toString(), + getSupportType(), + trade.getSelf().getUpdatedMultisigHex(), + trade.getArbitrator().getPaymentSentMessage()); + log.info("Send {} to peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid()); + recordPendingMessage(disputeOpenedMessage.getClass().getSimpleName()); + + // send dispute opened message + trade.setDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); + mailboxMessageService.sendEncryptedMailboxMessage(agentNodeAddress, + dispute.getAgentPubKeyRing(), + disputeOpenedMessage, + new SendMailboxMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived at peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid()); + clearPendingMessage(); + + // We use the chatMessage wrapped inside the openNewDisputeMessage for + // the state, as that is displayed to the user and we only persist that msg + chatMessage.setArrived(true); + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_REQUESTED); + requestPersistence(); + resultHandler.handleResult(); + } + + @Override + public void onStoredInMailbox() { + log.info("{} stored in mailbox for peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid()); + clearPendingMessage(); + + // We use the chatMessage wrapped inside the openNewDisputeMessage for + // the state, as that is displayed to the user and we only persist that msg + chatMessage.setStoredInMailbox(true); + requestPersistence(); + resultHandler.handleResult(); + } + + @Override + public void onFault(String errorMessage) { + log.error("{} failed: Peer {}. tradeId={}, openNewDisputeMessage.uid={}, " + + "chatMessage.uid={}, errorMessage={}", + disputeOpenedMessage.getClass().getSimpleName(), agentNodeAddress, + disputeOpenedMessage.getTradeId(), disputeOpenedMessage.getUid(), + chatMessage.getUid(), errorMessage); + + clearPendingMessage(); + // We use the chatMessage wrapped inside the openNewDisputeMessage for + // the state, as that is displayed to the user and we only persist that msg + chatMessage.setSendMessageError(errorMessage); + trade.setDisputeState(Trade.DisputeState.NO_DISPUTE); + requestPersistence(); + faultHandler.handleFault("Sending dispute message failed: " + + errorMessage, new DisputeMessageDeliveryFailedException()); + } + }); } requestPersistence(); @@ -439,118 +485,151 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup // arbitrator receives dispute opened message from opener, opener's peer receives from arbitrator protected void handleDisputeOpenedMessage(DisputeOpenedMessage message) { - Dispute dispute = message.getDispute(); - log.info("{}.onDisputeOpenedMessage() with trade {}, dispute {}", getClass().getSimpleName(), dispute.getTradeId(), dispute.getId()); + Dispute msgDispute = message.getDispute(); + log.info("Processing {} with trade {}, dispute {}", message.getClass().getSimpleName(), msgDispute.getTradeId(), msgDispute.getId()); // get trade - Trade trade = tradeManager.getTrade(dispute.getTradeId()); + Trade trade = tradeManager.getTrade(msgDispute.getTradeId()); if (trade == null) { - log.warn("Dispute trade {} does not exist", dispute.getTradeId()); + log.warn("Dispute trade {} does not exist", msgDispute.getTradeId()); + return; + } + if (trade.isPayoutPublished()) { + log.warn("Dispute trade {} payout already published", msgDispute.getTradeId()); return; } - synchronized (trade) { - String errorMessage = null; - PubKeyRing senderPubKeyRing = null; - try { + // find existing dispute + Optional<Dispute> storedDisputeOptional = findDispute(msgDispute); - // initialize - T disputeList = getDisputeList(); - if (disputeList == null) { - log.warn("disputes is null"); - return; - } - dispute.setSupportType(message.getSupportType()); - dispute.setState(Dispute.State.NEW); - Contract contract = dispute.getContract(); + // determine if re-opening dispute + boolean reOpen = storedDisputeOptional.isPresent() && storedDisputeOptional.get().isClosed(); - // validate dispute + // use existing dispute or create new + Dispute dispute = reOpen ? storedDisputeOptional.get() : msgDispute; + + // process on trade thread + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + String errorMessage = null; + PubKeyRing senderPubKeyRing = null; try { - DisputeValidation.validateDisputeData(dispute); - DisputeValidation.validateNodeAddresses(dispute, config); - DisputeValidation.validateSenderNodeAddress(dispute, message.getSenderNodeAddress()); - //DisputeValidation.testIfDisputeTriesReplay(dispute, disputeList.getList()); - } catch (DisputeValidation.ValidationException e) { - validationExceptions.add(e); - throw e; - } - // try to validate payment account - // TODO: add field to dispute details: valid, invalid, missing - try { - DisputeValidation.validatePaymentAccountPayload(dispute); - } catch (Exception e) { - log.warn(e.getMessage()); - trade.prependErrorMessage(e.getMessage()); - } - - // get sender - senderPubKeyRing = trade.isArbitrator() ? (dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerPubKeyRing() : contract.getSellerPubKeyRing()) : trade.getArbitrator().getPubKeyRing(); - TradePeer sender = trade.getTradePeer(senderPubKeyRing); - if (sender == null) throw new RuntimeException("Pub key ring is not from arbitrator, buyer, or seller"); - - // message to trader is expected from arbitrator - if (!trade.isArbitrator() && sender != trade.getArbitrator()) { - throw new RuntimeException(message.getClass().getSimpleName() + " to trader is expected only from arbitrator"); - } - - // arbitrator verifies signature of payment sent message if given - if (trade.isArbitrator() && message.getPaymentSentMessage() != null) { - HavenoUtils.verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); - trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex()); - trade.advanceState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); - } - - // update multisig hex - if (message.getUpdatedMultisigHex() != null) sender.setUpdatedMultisigHex(message.getUpdatedMultisigHex()); - trade.importMultisigHex(); - - // update peer node address - // TODO: tests can reuse the same addresses so nullify equal peer - sender.setNodeAddress(message.getSenderNodeAddress()); - - // add chat message with price info - if (trade instanceof ArbitratorTrade) addPriceInfoMessage(dispute, 0); - - // add dispute - synchronized (disputeList) { - if (!disputeList.contains(dispute)) { - Optional<Dispute> storedDisputeOptional = findDispute(dispute); - if (!storedDisputeOptional.isPresent()) { - disputeList.add(dispute); - trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED); - - // send dispute opened message to peer if arbitrator - if (trade.isArbitrator()) sendDisputeOpenedMessageToPeer(dispute, contract, dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing(), trade.getSelf().getUpdatedMultisigHex()); - tradeManager.requestPersistence(); - errorMessage = null; - } else { - // valid case if both have opened a dispute and agent was not online - log.debug("We got a dispute already open for that trade and trading peer. TradeId = {}", - dispute.getTradeId()); - } - - // add chat message with mediation info if applicable - addMediationResultMessage(dispute); - } else { - throw new RuntimeException("We got a dispute msg that we have already stored. TradeId = " + dispute.getTradeId()); + // initialize + T disputeList = getDisputeList(); + if (disputeList == null) { + log.warn("disputes is null"); + return; } + dispute.setSupportType(message.getSupportType()); + dispute.setState(Dispute.State.NEW); + Contract contract = dispute.getContract(); + + // validate dispute + try { + DisputeValidation.validateDisputeData(dispute); + DisputeValidation.validateNodeAddresses(dispute, config); + DisputeValidation.validateSenderNodeAddress(dispute, message.getSenderNodeAddress(), config); + //DisputeValidation.testIfDisputeTriesReplay(dispute, disputeList.getList()); + } catch (DisputeValidation.ValidationException e) { + log.error(ExceptionUtils.getStackTrace(e)); + validationExceptions.add(e); + throw e; + } + + // try to validate payment account + try { + DisputeValidation.validatePaymentAccountPayload(dispute); // TODO: add field to dispute details: valid, invalid, missing + } catch (Exception e) { + log.error(ExceptionUtils.getStackTrace(e)); + trade.prependErrorMessage(e.getMessage()); + throw e; + } + + // get sender + TradePeer sender; + if (reOpen) { // re-open can come from either peer + sender = trade.isArbitrator() ? trade.getTradePeer(message.getSenderNodeAddress()) : trade.getArbitrator(); + senderPubKeyRing = sender.getPubKeyRing(); + } else { + senderPubKeyRing = trade.isArbitrator() ? (dispute.isDisputeOpenerIsBuyer() ? contract.getBuyerPubKeyRing() : contract.getSellerPubKeyRing()) : trade.getArbitrator().getPubKeyRing(); + sender = trade.getTradePeer(senderPubKeyRing); + } + if (sender == null) throw new RuntimeException("Pub key ring is not from arbitrator, buyer, or seller"); + + // update sender node address + sender.setNodeAddress(message.getSenderNodeAddress()); + + // verify message to trader is expected from arbitrator + if (!trade.isArbitrator() && sender != trade.getArbitrator()) { + throw new RuntimeException(message.getClass().getSimpleName() + " to trader is expected only from arbitrator"); + } + + // arbitrator verifies signature of payment sent message if given + if (trade.isArbitrator() && message.getPaymentSentMessage() != null) { + HavenoUtils.verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); + trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex()); + trade.advanceState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); + } + + // update multisig hex + if (message.getUpdatedMultisigHex() != null) sender.setUpdatedMultisigHex(message.getUpdatedMultisigHex()); + + // add chat message with price info + if (trade instanceof ArbitratorTrade) addPriceInfoMessage(dispute, 0); + + // add or re-open dispute + synchronized (disputeList) { + if (!disputeList.contains(msgDispute)) { + if (!storedDisputeOptional.isPresent() || reOpen) { + + // update trade state + if (reOpen) { + trade.setDisputeState(Trade.DisputeState.DISPUTE_OPENED); + } else { + disputeList.add(dispute); + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_OPENED); + } + + // reset buyer and seller unsigned payout tx hex + trade.getBuyer().setUnsignedPayoutTxHex(null); + trade.getSeller().setUnsignedPayoutTxHex(null); + + // send dispute opened message to other peer if arbitrator + if (trade.isArbitrator()) { + TradePeer senderPeer = sender == trade.getMaker() ? trade.getTaker() : trade.getMaker(); + if (senderPeer != trade.getMaker() && senderPeer != trade.getTaker()) throw new RuntimeException("Sender peer is not maker or taker, address=" + senderPeer.getNodeAddress()); + sendDisputeOpenedMessageToPeer(dispute, contract, senderPeer.getPubKeyRing(), trade.getSelf().getUpdatedMultisigHex()); + } + tradeManager.requestPersistence(); + errorMessage = null; + } else { + // valid case if both have opened a dispute and agent was not online + log.debug("We got a dispute already open for that trade and trading peer. TradeId = {}", dispute.getTradeId()); + } + + // add chat message with mediation info if applicable + addMediationResultMessage(dispute); + } else { + throw new RuntimeException("We got a dispute msg that we have already stored. TradeId = " + msgDispute.getTradeId()); + } + } + } catch (Exception e) { + log.error(ExceptionUtils.getStackTrace(e)); + errorMessage = e.getMessage(); + if (trade != null) trade.setErrorMessage(errorMessage); } - } catch (Exception e) { - errorMessage = e.getMessage(); - log.warn(errorMessage); - if (trade != null) trade.setErrorMessage(errorMessage); - } - // use chat message instead of open dispute message for the ack - ObservableList<ChatMessage> messages = message.getDispute().getChatMessages(); - if (!messages.isEmpty()) { - ChatMessage msg = messages.get(0); - sendAckMessage(msg, senderPubKeyRing, errorMessage == null, errorMessage); - } + // use chat message instead of open dispute message for the ack + ObservableList<ChatMessage> messages = message.getDispute().getChatMessages(); + if (!messages.isEmpty()) { + ChatMessage msg = messages.get(messages.size() - 1); // send ack to sender of last chat message + sendAckMessage(msg, senderPubKeyRing, errorMessage == null, errorMessage); + } - requestPersistence(); - } + requestPersistence(); + } + }, trade.getId()); } // arbitrator sends dispute opened message to opener's peer @@ -558,7 +637,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup Contract contractFromOpener, PubKeyRing pubKeyRing, String updatedMultisigHex) { - log.info("{}.sendPeerOpenedDisputeMessage() with trade {}, dispute {}", getClass().getSimpleName(), disputeFromOpener.getTradeId(), disputeFromOpener.getId()); + log.info("{} sendPeerOpenedDisputeMessage() with trade {}, dispute {}", getClass().getSimpleName(), disputeFromOpener.getTradeId(), disputeFromOpener.getId()); // We delay a bit for sending the message to the peer to allow that a openDispute message from the peer is // being used as the valid msg. If dispute agent was offline and both peer requested we want to see the correct // message and not skip the system message of the peer as it would be the case if we have created the system msg @@ -580,6 +659,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup return; } + // create mirrored dispute Dispute dispute = new Dispute(new Date().getTime(), disputeFromOpener.getTradeId(), pubKeyRing.hashCode(), @@ -605,10 +685,9 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup dispute.setDelayedPayoutTxId(disputeFromOpener.getDelayedPayoutTxId()); dispute.setDonationAddressOfDelayedPayoutTx(disputeFromOpener.getDonationAddressOfDelayedPayoutTx()); + // skip if dispute already open Optional<Dispute> storedDisputeOptional = findDispute(dispute); - - // Valid case if both have opened a dispute and agent was not online. - if (storedDisputeOptional.isPresent()) { + if (storedDisputeOptional.isPresent() && !storedDisputeOptional.get().isClosed()) { log.info("We got a dispute already open for that trade and trading peer. TradeId = {}", dispute.getTradeId()); return; } @@ -630,8 +709,15 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup addPriceInfoMessage(dispute, 0); - synchronized (disputeList) { - disputeList.add(dispute); + // add or re-open dispute + boolean reOpen = storedDisputeOptional.isPresent() && storedDisputeOptional.get().isClosed(); + if (reOpen) { + dispute = storedDisputeOptional.get(); + dispute.reOpen(); + } else { + synchronized (disputeList) { + disputeList.add(dispute); + } } // get trade @@ -641,16 +727,16 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup return; } - // We mirrored dispute already! - Contract contract = dispute.getContract(); - PubKeyRing peersPubKeyRing = dispute.isDisputeOpenerIsBuyer() ? contract.getSellerPubKeyRing() : contract.getBuyerPubKeyRing(); - NodeAddress peersNodeAddress = dispute.isDisputeOpenerIsBuyer() ? contract.getSellerNodeAddress() : contract.getBuyerNodeAddress(); + // create dispute opened message with peer dispute + TradePeer peer = trade.getTradePeer(pubKeyRing); + PubKeyRing peersPubKeyRing = peer.getPubKeyRing(); + NodeAddress peersNodeAddress = peer.getNodeAddress(); DisputeOpenedMessage peerOpenedDisputeMessage = new DisputeOpenedMessage(dispute, p2PService.getAddress(), UUID.randomUUID().toString(), getSupportType(), updatedMultisigHex, - trade.getProcessModel().getPaymentSentMessage()); + trade.getArbitrator().getPaymentSentMessage()); log.info("Send {} to peer {}. tradeId={}, peerOpenedDisputeMessage.uid={}, chatMessage.uid={}", peerOpenedDisputeMessage.getClass().getSimpleName(), peersNodeAddress, @@ -722,34 +808,33 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup boolean exists = disputeResult.getChatMessage() != null && disputeResult.getChatMessage().getMessage() != null && !disputeResult.getChatMessage().getMessage().isEmpty(); if (!exists) { ChatMessage chatMessage = new ChatMessage( - getSupportType(), - dispute.getTradeId(), - dispute.getTraderPubKeyRing().hashCode(), - false, - summaryText, - p2PService.getAddress()); + getSupportType(), + dispute.getTradeId(), + dispute.getTraderPubKeyRing().hashCode(), + false, + summaryText, + p2PService.getAddress()); disputeResult.setChatMessage(chatMessage); dispute.addAndPersistChatMessage(chatMessage); } - // create dispute payout tx if not published + // create dispute payout tx TradePeer receiver = trade.getTradePeer(dispute.getTraderPubKeyRing()); - if (!trade.isPayoutPublished() && receiver.getUpdatedMultisigHex() != null) { - trade.getProcessModel().setUnsignedPayoutTx(createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false)); // can be null if we don't have receiver's multisig hex + if (!trade.isPayoutPublished() && receiver.getUpdatedMultisigHex() != null && receiver.getUnsignedPayoutTxHex() == null) { + createDisputePayoutTx(trade, dispute.getContract(), disputeResult, true); } // create dispute closed message - MoneroTxWallet unsignedPayoutTx = receiver.getUpdatedMultisigHex() == null ? null : trade.getProcessModel().getUnsignedPayoutTx(); - String unsignedPayoutTxHex = unsignedPayoutTx == null ? null : unsignedPayoutTx.getTxSet().getMultisigTxHex(); TradePeer receiverPeer = receiver == trade.getBuyer() ? trade.getSeller() : trade.getBuyer(); - boolean deferPublishPayout = !exists && unsignedPayoutTxHex != null && receiverPeer.getUpdatedMultisigHex() != null && trade.getDisputeState().ordinal() >= Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG.ordinal(); + boolean deferPublishPayout = !exists && receiver.getUnsignedPayoutTxHex() != null && receiverPeer.getUpdatedMultisigHex() != null && (trade.getDisputeState() == Trade.DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG || trade.getDisputeState().ordinal() >= Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG.ordinal()); DisputeClosedMessage disputeClosedMessage = new DisputeClosedMessage(disputeResult, p2PService.getAddress(), UUID.randomUUID().toString(), getSupportType(), trade.getSelf().getUpdatedMultisigHex(), - unsignedPayoutTxHex, // include dispute payout tx if arbitrator has their updated multisig info + receiver.getUnsignedPayoutTxHex(), // include dispute payout tx if arbitrator has their updated multisig info deferPublishPayout); // instruct trader to defer publishing payout tx because peer is expected to publish imminently + receiverPeer.setDisputeClosedMessage(disputeClosedMessage); // send dispute closed message log.info("Send {} to trader {}. tradeId={}, {}.uid={}, chatMessage.uid={}", @@ -770,12 +855,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup disputeResult.getChatMessage().getUid()); clearPendingMessage(); + dispute.setIsClosed(); // We use the chatMessage wrapped inside the DisputeClosedMessage for // the state, as that is displayed to the user and we only persist that msg disputeResult.getChatMessage().setArrived(true); trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SAW_ARRIVED_DISPUTE_CLOSED_MSG); - trade.syncWalletNormallyForMs(30000); - requestPersistence(); + trade.pollWalletNormallyForMs(60000); + requestPersistence(trade); resultHandler.handleResult(); } @@ -788,12 +874,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup disputeResult.getChatMessage().getUid()); clearPendingMessage(); + dispute.setIsClosed(); // We use the chatMessage wrapped inside the DisputeClosedMessage for // the state, as that is displayed to the user and we only persist that msg disputeResult.getChatMessage().setStoredInMailbox(true); Trade trade = tradeManager.getTrade(dispute.getTradeId()); trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_STORED_IN_MAILBOX_DISPUTE_CLOSED_MSG); - requestPersistence(); + requestPersistence(trade); resultHandler.handleResult(); } @@ -810,19 +897,13 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup // the state, as that is displayed to the user and we only persist that msg disputeResult.getChatMessage().setSendMessageError(errorMessage); trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SEND_FAILED_DISPUTE_CLOSED_MSG); - requestPersistence(); + requestPersistence(trade); faultHandler.handleFault(errorMessage, new RuntimeException(errorMessage)); } } ); - - // save state - if (unsignedPayoutTx != null) { - trade.setPayoutTx(unsignedPayoutTx); - trade.setPayoutTxHex(unsignedPayoutTx.getTxSet().getMultisigTxHex()); - } trade.advanceDisputeState(Trade.DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG); - requestPersistence(); + requestPersistence(trade); } catch (Exception e) { faultHandler.handleFault(e.getMessage(), e); } @@ -832,59 +913,67 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup // Utils /////////////////////////////////////////////////////////////////////////////////////////// - public MoneroTxWallet createDisputePayoutTx(Trade trade, Contract contract, DisputeResult disputeResult, boolean skipMultisigImport) { + public MoneroTxWallet createDisputePayoutTx(Trade trade, Contract contract, DisputeResult disputeResult, boolean updateState) { // import multisig hex trade.importMultisigHex(); - // sync and save wallet + // sync and poll trade.syncAndPollWallet(); - trade.saveWallet(); // create unsigned dispute payout tx if not already published if (!trade.isPayoutPublished()) { // create unsigned dispute payout tx - log.info("Creating unsigned dispute payout tx for trade {}", trade.getId()); + if (updateState) log.info("Creating unsigned dispute payout tx for trade {}", trade.getId()); try { // trade wallet must be synced if (trade.getWallet().isMultisigImportNeeded()) throw new RuntimeException("Arbitrator's wallet needs updated multisig hex to create payout tx which means a trader must have already broadcast the payout tx for trade " + trade.getId()); - // collect winner and loser payout address and amounts - String winnerPayoutAddress = disputeResult.getWinner() == Winner.BUYER ? - (contract.isBuyerMakerAndSellerTaker() ? contract.getMakerPayoutAddressString() : contract.getTakerPayoutAddressString()) : - (contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString()); - String loserPayoutAddress = winnerPayoutAddress.equals(contract.getMakerPayoutAddressString()) ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString(); - BigInteger winnerPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount(); - BigInteger loserPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount(); - - // check sufficient balance - if (winnerPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Winner payout cannot be negative"); - if (loserPayoutAmount.compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Loser payout cannot be negative"); - if (winnerPayoutAmount.add(loserPayoutAmount).compareTo(trade.getWallet().getUnlockedBalance()) > 0) { - throw new RuntimeException("The payout amounts are more than the wallet's unlocked balance, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs " + winnerPayoutAmount + " + " + loserPayoutAmount + " = " + (winnerPayoutAmount.add(loserPayoutAmount))); + // check amounts + if (disputeResult.getBuyerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Buyer payout cannot be negative"); + if (disputeResult.getSellerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) < 0) throw new RuntimeException("Seller payout cannot be negative"); + if (disputeResult.getBuyerPayoutAmountBeforeCost().add(disputeResult.getSellerPayoutAmountBeforeCost()).compareTo(trade.getWallet().getUnlockedBalance()) > 0) { + throw new RuntimeException("The payout amounts are more than the wallet's unlocked balance, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs " + disputeResult.getBuyerPayoutAmountBeforeCost() + " + " + disputeResult.getSellerPayoutAmountBeforeCost() + " = " + (disputeResult.getBuyerPayoutAmountBeforeCost().add(disputeResult.getSellerPayoutAmountBeforeCost()))); } - // add any loss of precision to winner payout - winnerPayoutAmount = winnerPayoutAmount.add(trade.getWallet().getUnlockedBalance().subtract(winnerPayoutAmount.add(loserPayoutAmount))); + // create dispute payout tx config + MoneroTxConfig txConfig = new MoneroTxConfig().setAccountIndex(0); + String buyerPayoutAddress = contract.isBuyerMakerAndSellerTaker() ? contract.getMakerPayoutAddressString() : contract.getTakerPayoutAddressString(); + String sellerPayoutAddress = contract.isBuyerMakerAndSellerTaker() ? contract.getTakerPayoutAddressString() : contract.getMakerPayoutAddressString(); + txConfig.setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY); + if (disputeResult.getBuyerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(buyerPayoutAddress, disputeResult.getBuyerPayoutAmountBeforeCost()); + if (disputeResult.getSellerPayoutAmountBeforeCost().compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(sellerPayoutAddress, disputeResult.getSellerPayoutAmountBeforeCost()); + + // configure who pays mining fee + BigInteger loserPayoutAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmountBeforeCost() : disputeResult.getBuyerPayoutAmountBeforeCost(); + if (loserPayoutAmount.equals(BigInteger.ZERO)) txConfig.setSubtractFeeFrom(0); // winner pays fee if loser gets 0 + else { + switch (disputeResult.getSubtractFeeFrom()) { + case BUYER_AND_SELLER: + txConfig.setSubtractFeeFrom(0, 1); + break; + case BUYER_ONLY: + txConfig.setSubtractFeeFrom(0); + break; + case SELLER_ONLY: + txConfig.setSubtractFeeFrom(1); + break; + } + } // create dispute payout tx - MoneroTxConfig txConfig = new MoneroTxConfig().setAccountIndex(0); - if (winnerPayoutAmount.compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(winnerPayoutAddress, winnerPayoutAmount); - if (loserPayoutAmount.compareTo(BigInteger.ZERO) > 0) txConfig.addDestination(loserPayoutAddress, loserPayoutAmount); - txConfig.setSubtractFeeFrom(loserPayoutAmount.equals(BigInteger.ZERO) ? 0 : txConfig.getDestinations().size() - 1); // winner only pays fee if loser gets 0 - txConfig.setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY); - MoneroTxWallet payoutTx = null; - try { - payoutTx = trade.getWallet().createTx(txConfig); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Loser payout is too small to cover the mining fee"); - } + MoneroTxWallet payoutTx = trade.createDisputePayoutTx(txConfig); - // save updated multisig hex - trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex()); + // update trade state + if (updateState) { + trade.getProcessModel().setUnsignedPayoutTx(payoutTx); + trade.updatePayout(payoutTx); + if (trade.getBuyer().getUpdatedMultisigHex() != null) trade.getBuyer().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + if (trade.getSeller().getUpdatedMultisigHex() != null) trade.getSeller().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + } + trade.requestPersistence(); return payoutTx; } catch (Exception e) { trade.syncAndPollWallet(); @@ -913,25 +1002,25 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup return new Tuple2<>(peerNodeAddress, receiverPubKeyRing); } - private boolean isAgent(Dispute dispute) { + public boolean isAgent(Dispute dispute) { return keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing()); } - private Optional<Dispute> findDispute(Dispute dispute) { + public Optional<Dispute> findDispute(Dispute dispute) { return findDispute(dispute.getTradeId(), dispute.getTraderId()); } - protected Optional<Dispute> findDispute(DisputeResult disputeResult) { + public Optional<Dispute> findDispute(DisputeResult disputeResult) { ChatMessage chatMessage = disputeResult.getChatMessage(); checkNotNull(chatMessage, "chatMessage must not be null"); return findDispute(disputeResult.getTradeId(), disputeResult.getTraderId()); } - private Optional<Dispute> findDispute(ChatMessage message) { + public Optional<Dispute> findDispute(ChatMessage message) { return findDispute(message.getTradeId(), message.getTraderId()); } - protected Optional<Dispute> findDispute(String tradeId, int traderId) { + public Optional<Dispute> findDispute(String tradeId, int traderId) { T disputeList = getDisputeList(); if (disputeList == null) { log.warn("disputes is null"); @@ -1011,13 +1100,27 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup requestPersistence(); } + protected void addMediationLogsReceivedMessage(Dispute dispute, String logsIdentifier) { + String logsReceivedMessage = Res.get("support.mediatorReceivedLogs", logsIdentifier); + ChatMessage chatMessage = new ChatMessage( + getSupportType(), + dispute.getTradeId(), + keyRing.hashCode(), + false, + logsReceivedMessage, + p2PService.getAddress()); + chatMessage.setSystemMessage(true); + dispute.addAndPersistChatMessage(chatMessage); + requestPersistence(); + } + // If price was going down between take offer time and open dispute time the buyer has an incentive to // not send the payment but to try to make a new trade with the better price. We risks to lose part of the // security deposit (in mediation we will always get back 0.003 BTC to keep some incentive to accept mediated // proposal). But if gain is larger than this loss he has economically an incentive to default in the trade. // We do all those calculations to give a hint to mediators to detect option trades. protected void addPriceInfoMessage(Dispute dispute, int counter) { - if (!priceFeedService.hasPrices()) { + if (!priceFeedService.hasExternalPrices()) { if (counter < 3) { log.info("Price provider has still no data. This is expected at startup. We try again in 10 sec."); UserThread.runAfter(() -> addPriceInfoMessage(dispute, counter + 1), 10); @@ -1039,7 +1142,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup // The amount we would get if we do a new trade with current price BigInteger potentialAmountAtDisputeOpening = priceAtDisputeOpening.getAmountByVolume(contract.getTradeVolume()); - BigInteger buyerSecurityDeposit = BigInteger.valueOf(offerPayload.getBuyerSecurityDeposit()); + BigInteger buyerSecurityDeposit = offerPayload.getMaxBuyerSecurityDeposit(); BigInteger minRefundAtMediatedDispute = Restrictions.getMinRefundAtMediatedDispute(); // minRefundAtMediatedDispute is always larger as buyerSecurityDeposit at mediated payout, we ignore refund agent case here as there it can be 0. BigInteger maxLossSecDeposit = buyerSecurityDeposit.subtract(minRefundAtMediatedDispute); @@ -1048,7 +1151,7 @@ public abstract class DisputeManager<T extends DisputeList<Dispute>> extends Sup String optionTradeDetails; // We don't translate those strings (yet) as it is only displayed to mediators/arbitrators. String headline; - if (potentialGain.compareTo(BigInteger.valueOf(0)) > 0) { + if (potentialGain.compareTo(BigInteger.ZERO) > 0) { headline = "This might be a potential option trade!"; optionTradeDetails = "\nBTC amount calculated with price at dispute opening: " + HavenoUtils.formatXmr(potentialAmountAtDisputeOpening, true) + "\nMax loss of security deposit is: " + HavenoUtils.formatXmr(maxLossSecDeposit, true) + diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeMessageDeliveryFailedException.java b/core/src/main/java/haveno/core/support/dispute/DisputeMessageDeliveryFailedException.java index 0c2ead4286..9d79e59563 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeMessageDeliveryFailedException.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeMessageDeliveryFailedException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeResult.java b/core/src/main/java/haveno/core/support/dispute/DisputeResult.java index 2d73a7c941..f5fc05d338 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeResult.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeResult.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; @@ -61,12 +61,21 @@ public final class DisputeResult implements NetworkPayload { PEER_WAS_LATE } + public enum SubtractFeeFrom { + BUYER_ONLY, + SELLER_ONLY, + BUYER_AND_SELLER + } + private final String tradeId; private final int traderId; @Setter @Nullable private Winner winner; private int reasonOrdinal = Reason.OTHER.ordinal(); + @Setter + @Nullable + private SubtractFeeFrom subtractFeeFrom; private final BooleanProperty tamperProofEvidenceProperty = new SimpleBooleanProperty(); private final BooleanProperty idVerificationProperty = new SimpleBooleanProperty(); private final BooleanProperty screenCastProperty = new SimpleBooleanProperty(); @@ -77,8 +86,8 @@ public final class DisputeResult implements NetworkPayload { @Setter @Nullable private byte[] arbitratorSignature; - private long buyerPayoutAmount; - private long sellerPayoutAmount; + private long buyerPayoutAmountBeforeCost; + private long sellerPayoutAmountBeforeCost; @Setter @Nullable private byte[] arbitratorPubKey; @@ -93,28 +102,30 @@ public final class DisputeResult implements NetworkPayload { int traderId, @Nullable Winner winner, int reasonOrdinal, + @Nullable SubtractFeeFrom subtractFeeFrom, boolean tamperProofEvidence, boolean idVerification, boolean screenCast, String summaryNotes, @Nullable ChatMessage chatMessage, @Nullable byte[] arbitratorSignature, - long buyerPayoutAmount, - long sellerPayoutAmount, + long buyerPayoutAmountBeforeCost, + long sellerPayoutAmountBeforeCost, @Nullable byte[] arbitratorPubKey, long closeDate) { this.tradeId = tradeId; this.traderId = traderId; this.winner = winner; this.reasonOrdinal = reasonOrdinal; + this.subtractFeeFrom = subtractFeeFrom; this.tamperProofEvidenceProperty.set(tamperProofEvidence); this.idVerificationProperty.set(idVerification); this.screenCastProperty.set(screenCast); this.summaryNotesProperty.set(summaryNotes); this.chatMessage = chatMessage; this.arbitratorSignature = arbitratorSignature; - this.buyerPayoutAmount = buyerPayoutAmount; - this.sellerPayoutAmount = sellerPayoutAmount; + this.buyerPayoutAmountBeforeCost = buyerPayoutAmountBeforeCost; + this.sellerPayoutAmountBeforeCost = sellerPayoutAmountBeforeCost; this.arbitratorPubKey = arbitratorPubKey; this.closeDate = closeDate; } @@ -129,14 +140,15 @@ public final class DisputeResult implements NetworkPayload { proto.getTraderId(), ProtoUtil.enumFromProto(DisputeResult.Winner.class, proto.getWinner().name()), proto.getReasonOrdinal(), + ProtoUtil.enumFromProto(DisputeResult.SubtractFeeFrom.class, proto.getSubtractFeeFrom().name()), proto.getTamperProofEvidence(), proto.getIdVerification(), proto.getScreenCast(), proto.getSummaryNotes(), proto.getChatMessage() == null ? null : ChatMessage.fromPayloadProto(proto.getChatMessage()), proto.getArbitratorSignature().toByteArray(), - proto.getBuyerPayoutAmount(), - proto.getSellerPayoutAmount(), + proto.getBuyerPayoutAmountBeforeCost(), + proto.getSellerPayoutAmountBeforeCost(), proto.getArbitratorPubKey().toByteArray(), proto.getCloseDate()); } @@ -151,13 +163,14 @@ public final class DisputeResult implements NetworkPayload { .setIdVerification(idVerificationProperty.get()) .setScreenCast(screenCastProperty.get()) .setSummaryNotes(summaryNotesProperty.get()) - .setBuyerPayoutAmount(buyerPayoutAmount) - .setSellerPayoutAmount(sellerPayoutAmount) + .setBuyerPayoutAmountBeforeCost(buyerPayoutAmountBeforeCost) + .setSellerPayoutAmountBeforeCost(sellerPayoutAmountBeforeCost) .setCloseDate(closeDate); Optional.ofNullable(arbitratorSignature).ifPresent(arbitratorSignature -> builder.setArbitratorSignature(ByteString.copyFrom(arbitratorSignature))); Optional.ofNullable(arbitratorPubKey).ifPresent(arbitratorPubKey -> builder.setArbitratorPubKey(ByteString.copyFrom(arbitratorPubKey))); Optional.ofNullable(winner).ifPresent(result -> builder.setWinner(protobuf.DisputeResult.Winner.valueOf(winner.name()))); + Optional.ofNullable(subtractFeeFrom).ifPresent(result -> builder.setSubtractFeeFrom(protobuf.DisputeResult.SubtractFeeFrom.valueOf(subtractFeeFrom.name()))); Optional.ofNullable(chatMessage).ifPresent(chatMessage -> builder.setChatMessage(chatMessage.toProtoNetworkEnvelope().getChatMessage())); @@ -200,20 +213,22 @@ public final class DisputeResult implements NetworkPayload { return summaryNotesProperty; } - public void setBuyerPayoutAmount(BigInteger buyerPayoutAmount) { - this.buyerPayoutAmount = buyerPayoutAmount.longValueExact(); + public void setBuyerPayoutAmountBeforeCost(BigInteger buyerPayoutAmountBeforeCost) { + if (buyerPayoutAmountBeforeCost.compareTo(BigInteger.ZERO) < 0) throw new IllegalArgumentException("buyerPayoutAmountBeforeCost cannot be negative"); + this.buyerPayoutAmountBeforeCost = buyerPayoutAmountBeforeCost.longValueExact(); } - public BigInteger getBuyerPayoutAmount() { - return BigInteger.valueOf(buyerPayoutAmount); + public BigInteger getBuyerPayoutAmountBeforeCost() { + return BigInteger.valueOf(buyerPayoutAmountBeforeCost); } - public void setSellerPayoutAmount(BigInteger sellerPayoutAmount) { - this.sellerPayoutAmount = sellerPayoutAmount.longValueExact(); + public void setSellerPayoutAmountBeforeCost(BigInteger sellerPayoutAmountBeforeCost) { + if (sellerPayoutAmountBeforeCost.compareTo(BigInteger.ZERO) < 0) throw new IllegalArgumentException("sellerPayoutAmountBeforeCost cannot be negative"); + this.sellerPayoutAmountBeforeCost = sellerPayoutAmountBeforeCost.longValueExact(); } - public BigInteger getSellerPayoutAmount() { - return BigInteger.valueOf(sellerPayoutAmount); + public BigInteger getSellerPayoutAmountBeforeCost() { + return BigInteger.valueOf(sellerPayoutAmountBeforeCost); } public void setCloseDate(Date closeDate) { @@ -231,14 +246,15 @@ public final class DisputeResult implements NetworkPayload { ",\n traderId=" + traderId + ",\n winner=" + winner + ",\n reasonOrdinal=" + reasonOrdinal + + ",\n subtractFeeFrom=" + subtractFeeFrom + ",\n tamperProofEvidenceProperty=" + tamperProofEvidenceProperty + ",\n idVerificationProperty=" + idVerificationProperty + ",\n screenCastProperty=" + screenCastProperty + ",\n summaryNotesProperty=" + summaryNotesProperty + ",\n chatMessage=" + chatMessage + ",\n arbitratorSignature=" + Utilities.bytesAsHexString(arbitratorSignature) + - ",\n buyerPayoutAmount=" + buyerPayoutAmount + - ",\n sellerPayoutAmount=" + sellerPayoutAmount + + ",\n buyerPayoutAmountBeforeCost=" + buyerPayoutAmountBeforeCost + + ",\n sellerPayoutAmountBeforeCost=" + sellerPayoutAmountBeforeCost + ",\n arbitratorPubKey=" + Utilities.bytesAsHexString(arbitratorPubKey) + ",\n closeDate=" + closeDate + "\n}"; diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeSession.java b/core/src/main/java/haveno/core/support/dispute/DisputeSession.java index 3b6613e732..5507fecc9e 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeSession.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeSession.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; @@ -70,7 +70,7 @@ public abstract class DisputeSession extends SupportSession { @Override public boolean chatIsOpen() { - return dispute != null && !dispute.isClosed(); + return dispute != null && dispute.isOpen(); } @Override diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java b/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java index 6e2c7b3bfa..5fbd64dba5 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeSummaryVerification.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; @@ -71,7 +71,7 @@ public class DisputeSummaryVerification { disputeAgent = arbitratorManager.getDisputeAgentByNodeAddress(nodeAddress).orElse(null); checkNotNull(disputeAgent, "Dispute agent is null"); } catch (Throwable e) { - e.printStackTrace(); + log.error("Error verifying signature: {}\n", e.getMessage(), e); throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat")); } @@ -93,7 +93,7 @@ public class DisputeSummaryVerification { throw new IllegalArgumentException(Res.get("support.sigCheck.popup.failed")); } } catch (Throwable e) { - e.printStackTrace(); + log.error("Error verifying signature with agent pub key ring: {}\n", e.getMessage(), e); throw new IllegalArgumentException(Res.get("support.sigCheck.popup.invalidFormat")); } } diff --git a/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java b/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java index fb3cc6a3a8..4591a6fbc2 100644 --- a/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java +++ b/core/src/main/java/haveno/core/support/dispute/DisputeValidation.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute; @@ -77,20 +77,21 @@ public class DisputeValidation { public static void validateSenderNodeAddress(Dispute dispute, - NodeAddress senderNodeAddress) throws NodeAddressException { - if (!senderNodeAddress.equals(dispute.getContract().getBuyerNodeAddress()) - && !senderNodeAddress.equals(dispute.getContract().getSellerNodeAddress()) - && !senderNodeAddress.equals(dispute.getContract().getArbitratorNodeAddress())) { - throw new NodeAddressException(dispute, "senderNodeAddress not matching any of the traders node addresses"); + NodeAddress senderNodeAddress, + Config config) throws NodeAddressException { + if (config.useLocalhostForP2P) return; + if (!senderNodeAddress.getHostName().equals(dispute.getContract().getBuyerNodeAddress().getHostName()) + && !senderNodeAddress.getHostName().equals(dispute.getContract().getSellerNodeAddress().getHostName()) + && !senderNodeAddress.getHostName().equals(dispute.getContract().getArbitratorNodeAddress().getHostName())) { + throw new NodeAddressException(dispute, "senderNodeAddress not matching any of the trade node addresses"); } } public static void validateNodeAddresses(Dispute dispute, Config config) throws NodeAddressException { - if (!config.useLocalhostForP2P) { - validateNodeAddress(dispute, dispute.getContract().getBuyerNodeAddress()); - validateNodeAddress(dispute, dispute.getContract().getSellerNodeAddress()); - } + if (config.useLocalhostForP2P) return; + validateNodeAddress(dispute, dispute.getContract().getBuyerNodeAddress()); + validateNodeAddress(dispute, dispute.getContract().getSellerNodeAddress()); } private static void validateNodeAddress(Dispute dispute, NodeAddress nodeAddress) throws NodeAddressException { diff --git a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgent.java b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgent.java index 5594274b1c..99856622a7 100644 --- a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgent.java +++ b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgent.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.agent; diff --git a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentLookupMap.java b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentLookupMap.java index badef2746d..551dbfc9ef 100644 --- a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentLookupMap.java +++ b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentLookupMap.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.agent; @@ -25,7 +25,7 @@ import javax.annotation.Nullable; @Slf4j public class DisputeAgentLookupMap { - // See also: https://bisq.wiki/Finding_your_mediator + // See also: https://haveno.exchange/wiki/Finding_your_mediator @Nullable public static String getMatrixUserName(String fullAddress) { if (fullAddress.matches("localhost(.*)")) { @@ -45,7 +45,7 @@ public class DisputeAgentLookupMap { case "6c4cim7h7t3bm4bnchbf727qrhdfrfr6lhod25wjtizm2sifpkktvwad.onion:9999": return "pazza83"; default: - log.warn("No user name for dispute agent with address {} found.", fullAddress); + log.warn("No username for dispute agent with address {} found.", fullAddress); return Res.get("shared.na"); } } diff --git a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentManager.java b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentManager.java index 14ae1dd0dc..4b4fc1011e 100644 --- a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentManager.java +++ b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.agent; @@ -151,7 +151,7 @@ public abstract class DisputeAgentManager<T extends DisputeAgent> { else p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { startRepublishDisputeAgent(); } }); diff --git a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentService.java b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentService.java index 842e8029ca..c13302c501 100644 --- a/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentService.java +++ b/core/src/main/java/haveno/core/support/dispute/agent/DisputeAgentService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.agent; diff --git a/core/src/main/java/haveno/core/support/dispute/agent/MultipleHolderNameDetection.java b/core/src/main/java/haveno/core/support/dispute/agent/MultipleHolderNameDetection.java index 1450e5a854..a308bafaef 100644 --- a/core/src/main/java/haveno/core/support/dispute/agent/MultipleHolderNameDetection.java +++ b/core/src/main/java/haveno/core/support/dispute/agent/MultipleHolderNameDetection.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.agent; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeList.java b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeList.java index d40943efe3..bbb28e8a98 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeList.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeListService.java b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeListService.java index 2d9f11756b..4290381f0b 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeListService.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationDisputeListService.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.persistence.PersistenceManager; import haveno.core.support.dispute.DisputeListService; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public final class ArbitrationDisputeListService extends DisputeListService<ArbitrationDisputeList> { diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java index f2ff76ff40..50be387c76 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationManager.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -19,13 +36,14 @@ package haveno.core.support.dispute.arbitration; import com.google.inject.Inject; import com.google.inject.Singleton; -import common.utils.GenUtils; +import haveno.common.ThreadUtils; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.app.Version; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.common.proto.network.NetworkEnvelope; +import haveno.core.api.XmrConnectionService; import haveno.core.api.CoreNotificationService; import haveno.core.locale.Res; import haveno.core.offer.OpenOfferManager; @@ -37,27 +55,37 @@ import haveno.core.support.dispute.DisputeResult; import haveno.core.support.dispute.DisputeResult.Winner; import haveno.core.support.dispute.DisputeSummaryVerification; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; +import haveno.core.support.dispute.mediation.FileTransferReceiver; +import haveno.core.support.dispute.mediation.FileTransferSender; +import haveno.core.support.dispute.mediation.FileTransferSession; import haveno.core.support.dispute.messages.DisputeClosedMessage; import haveno.core.support.dispute.messages.DisputeOpenedMessage; import haveno.core.support.messages.ChatMessage; import haveno.core.support.messages.SupportMessage; +import haveno.core.trade.BuyerTrade; import haveno.core.trade.ClosedTradableManager; import haveno.core.trade.Contract; import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.wallet.TradeWalletService; import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessageSourceType; +import haveno.network.p2p.FileTransferPart; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; +import haveno.network.p2p.network.Connection; +import haveno.network.p2p.network.MessageListener; import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroRpcConnection; import monero.wallet.MoneroWallet; import monero.wallet.model.MoneroDestination; import monero.wallet.model.MoneroMultisigSignResult; import monero.wallet.model.MoneroTxSet; import monero.wallet.model.MoneroTxWallet; +import java.io.IOException; import java.math.BigInteger; import java.util.HashMap; import java.util.HashSet; @@ -66,11 +94,13 @@ import java.util.Map; import java.util.Optional; import java.util.Set; +import org.apache.commons.lang3.exception.ExceptionUtils; + import static com.google.common.base.Preconditions.checkNotNull; @Slf4j @Singleton -public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeList> { +public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeList> implements MessageListener, FileTransferSession.FtpCallback { private final ArbitratorManager arbitratorManager; @@ -84,7 +114,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL public ArbitrationManager(P2PService p2PService, TradeWalletService tradeWalletService, XmrWalletService walletService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, CoreNotificationService notificationService, ArbitratorManager arbitratorManager, TradeManager tradeManager, @@ -94,10 +124,11 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL ArbitrationDisputeListService arbitrationDisputeListService, Config config, PriceFeedService priceFeedService) { - super(p2PService, tradeWalletService, walletService, connectionService, notificationService, tradeManager, closedTradableManager, + super(p2PService, tradeWalletService, walletService, xmrConnectionService, notificationService, tradeManager, closedTradableManager, openOfferManager, keyRing, arbitrationDisputeListService, config, priceFeedService); this.arbitratorManager = arbitratorManager; HavenoUtils.arbitrationManager = this; // TODO: storing static reference, better way? + p2PService.getNetworkNode().addMessageListener(this); // listening for FileTransferPart message } @@ -116,7 +147,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL log.info("Received {} from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), message.getSenderNodeAddress(), message.getTradeId(), message.getUid()); - new Thread(() -> { + ThreadUtils.execute(() -> { if (message instanceof DisputeOpenedMessage) { handleDisputeOpenedMessage((DisputeOpenedMessage) message); } else if (message instanceof ChatMessage) { @@ -126,7 +157,7 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL } else { log.warn("Unsupported message at dispatchMessage. message={}", message); } - }).start(); + }, message.getTradeId()); } } @@ -142,7 +173,28 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL @Override public void cleanupDisputes() { - // no action + + // remove disputes opened by arbitrator, which is not allowed + Set<Dispute> toRemoves = new HashSet<>(); + List<Dispute> disputes = getDisputeList().getList(); + for (Dispute dispute : disputes) { + + // get dispute's trade + final Trade trade = tradeManager.getTrade(dispute.getTradeId()); + if (trade == null) { + log.warn("Dispute trade {} does not exist", dispute.getTradeId()); + return; + } + + // collect dispute if owned by arbitrator + if (dispute.getTraderPubKeyRing().equals(trade.getArbitrator().getPubKeyRing())) { + toRemoves.add(dispute); + } + } + for (Dispute toRemove : toRemoves) { + log.warn("Removing invalid dispute opened by arbitrator, disputeId={}", toRemove.getTradeId(), toRemove.getId()); + getDisputeList().remove(toRemove); + } } @Override @@ -187,151 +239,166 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL } // try to process dispute closed message - ChatMessage chatMessage = null; - Dispute dispute = null; - synchronized (trade) { - try { - DisputeResult disputeResult = disputeClosedMessage.getDisputeResult(); - chatMessage = disputeResult.getChatMessage(); - checkNotNull(chatMessage, "chatMessage must not be null"); - String tradeId = disputeResult.getTradeId(); + ThreadUtils.execute(() -> { + ChatMessage chatMessage = null; + Dispute dispute = null; + synchronized (trade.getLock()) { + try { + DisputeResult disputeResult = disputeClosedMessage.getDisputeResult(); + chatMessage = disputeResult.getChatMessage(); + checkNotNull(chatMessage, "chatMessage must not be null"); + String tradeId = disputeResult.getTradeId(); - log.info("Processing {} for {} {}", disputeClosedMessage.getClass().getSimpleName(), trade.getClass().getSimpleName(), disputeResult.getTradeId()); + log.info("Processing {} for {} {}", disputeClosedMessage.getClass().getSimpleName(), trade.getClass().getSimpleName(), disputeResult.getTradeId()); - // get dispute - Optional<Dispute> disputeOptional = findDispute(disputeResult); - String uid = disputeClosedMessage.getUid(); - if (!disputeOptional.isPresent()) { - log.warn("We got a dispute closed msg but we don't have a matching dispute. " + - "That might happen when we get the DisputeClosedMessage before the dispute was created. " + - "We try again after 2 sec. to apply the DisputeClosedMessage. TradeId = " + tradeId); - if (!delayMsgMap.containsKey(uid)) { - // We delay 2 sec. to be sure the comm. msg gets added first - Timer timer = UserThread.runAfter(() -> handleDisputeClosedMessage(disputeClosedMessage), 2); - delayMsgMap.put(uid, timer); - } else { - log.warn("We got a dispute closed msg after we already repeated to apply the message after a delay. " + - "That should never happen. TradeId = " + tradeId); + // get dispute + Optional<Dispute> disputeOptional = findDispute(disputeResult); + String uid = disputeClosedMessage.getUid(); + if (!disputeOptional.isPresent()) { + log.warn("We got a dispute closed msg but we don't have a matching dispute. " + + "That might happen when we get the DisputeClosedMessage before the dispute was created. " + + "We try again after 2 sec. to apply the DisputeClosedMessage. TradeId = " + tradeId); + if (!delayMsgMap.containsKey(uid)) { + // We delay 2 sec. to be sure the comm. msg gets added first + Timer timer = UserThread.runAfter(() -> handleDisputeClosedMessage(disputeClosedMessage), 2); + delayMsgMap.put(uid, timer); + } else { + log.warn("We got a dispute closed msg after we already repeated to apply the message after a delay. " + + "That should never happen. TradeId = " + tradeId); + } + return; } - return; - } - dispute = disputeOptional.get(); + dispute = disputeOptional.get(); - // verify arbitrator signature - String summaryText = chatMessage.getMessage(); - if (summaryText == null || summaryText.isEmpty()) throw new IllegalArgumentException("Summary text for dispute is missing, tradeId=" + tradeId + (dispute == null ? "" : ", disputeId=" + dispute.getId())); - if (dispute != null) DisputeSummaryVerification.verifySignature(summaryText, dispute.getAgentPubKeyRing()); // use dispute's arbitrator pub key ring - else DisputeSummaryVerification.verifySignature(summaryText, arbitratorManager); // verify using registered arbitrator (will fail is arbitrator is unregistered) + // verify arbitrator signature + String summaryText = chatMessage.getMessage(); + if (summaryText == null || summaryText.isEmpty()) throw new IllegalArgumentException("Summary text for dispute is missing, tradeId=" + tradeId + (dispute == null ? "" : ", disputeId=" + dispute.getId())); + if (dispute != null) DisputeSummaryVerification.verifySignature(summaryText, dispute.getAgentPubKeyRing()); // use dispute's arbitrator pub key ring + else DisputeSummaryVerification.verifySignature(summaryText, arbitratorManager); // verify using registered arbitrator (will fail if arbitrator is unregistered) - // save dispute closed message for reprocessing - trade.getProcessModel().setDisputeClosedMessage(disputeClosedMessage); - requestPersistence(); + // save dispute closed message for reprocessing + trade.getArbitrator().setDisputeClosedMessage(disputeClosedMessage); + requestPersistence(trade); - // verify arbitrator does not receive DisputeClosedMessage - if (keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing())) { - log.error("Arbitrator received disputeResultMessage. That should never happen."); - trade.getProcessModel().setDisputeClosedMessage(null); // don't reprocess - return; - } + // verify arbitrator does not receive DisputeClosedMessage + if (keyRing.getPubKeyRing().equals(dispute.getAgentPubKeyRing())) { + log.error("Arbitrator received disputeResultMessage. That should never happen."); + trade.getArbitrator().setDisputeClosedMessage(null); // don't reprocess + return; + } - // set dispute state - cleanupRetryMap(uid); - if (!dispute.getChatMessages().contains(chatMessage)) { - dispute.addAndPersistChatMessage(chatMessage); - } else { - log.warn("We got a dispute mail msg that we have already stored. TradeId = " + chatMessage.getTradeId()); - } - dispute.setIsClosed(); - if (dispute.disputeResultProperty().get() != null) { - log.info("We already got a dispute result, indicating the message was resent after updating multisig info. TradeId = " + tradeId); - } - dispute.setDisputeResult(disputeResult); + // set dispute state + cleanupRetryMap(uid); + synchronized (dispute.getChatMessages()) { + if (!dispute.getChatMessages().contains(chatMessage)) { + dispute.addAndPersistChatMessage(chatMessage); + } else { + log.warn("We got a dispute mail msg that we have already stored. TradeId = " + chatMessage.getTradeId()); + } + } + dispute.setIsClosed(); + if (dispute.disputeResultProperty().get() != null) { + log.info("We already got a dispute result, indicating the message was resent after updating multisig info. TradeId = " + tradeId); + } + dispute.setDisputeResult(disputeResult); - // sync and save wallet - if (!trade.isPayoutPublished()) { - trade.syncAndPollWallet(); - trade.saveWallet(); - } - - // import multisig hex - if (trade.walletExists()) { + // update multisig hex if (disputeClosedMessage.getUpdatedMultisigHex() != null) trade.getArbitrator().setUpdatedMultisigHex(disputeClosedMessage.getUpdatedMultisigHex()); - trade.importMultisigHex(); - } + if (trade.walletExists()) trade.importMultisigHex(); - // attempt to sign and publish dispute payout tx if given and not already published - if (disputeClosedMessage.getUnsignedPayoutTxHex() != null && !trade.isPayoutPublished()) { + // sync and save wallet + if (!trade.isPayoutPublished()) trade.syncAndPollWallet(); - // wait to sign and publish payout tx if defer flag set - if (disputeClosedMessage.isDeferPublishPayout()) { - log.info("Deferring signing and publishing dispute payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); - GenUtils.waitFor(Trade.DEFER_PUBLISH_MS); - if (!trade.isPayoutUnlocked()) trade.syncAndPollWallet(); - } + // attempt to sign and publish dispute payout tx if given and not already published + if (!trade.isPayoutPublished() && disputeClosedMessage.getUnsignedPayoutTxHex() != null) { - // sign and publish dispute payout tx if peer still has not published - if (!trade.isPayoutPublished()) { - try { - log.info("Signing and publishing dispute payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); - signAndPublishDisputePayoutTx(trade); - } catch (Exception e) { + // wait to sign and publish payout tx if defer flag set + if (disputeClosedMessage.isDeferPublishPayout()) { + log.info("Deferring signing and publishing dispute payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); + for (int i = 0; i < 5; i++) { + if (trade.isPayoutPublished()) break; + HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5); + } + if (!trade.isPayoutPublished()) trade.syncAndPollWallet(); + } - // check if payout published again - trade.syncAndPollWallet(); - if (trade.isPayoutPublished()) { - log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); - } else { - throw new RuntimeException("Failed to sign and publish dispute payout tx from arbitrator: " + e.getMessage() + ". TradeId = " + tradeId); + // sign and publish dispute payout tx if peer still has not published + if (trade.isPayoutPublished()) { + log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); + } else { + try { + log.info("Signing and publishing dispute payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); + signAndPublishDisputePayoutTx(trade); + } catch (Exception e) { + + // check if payout published again + trade.syncAndPollWallet(); + if (trade.isPayoutPublished()) { + log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); + } else { + if (e instanceof IllegalArgumentException || e instanceof IllegalStateException) throw e; + else throw new RuntimeException("Failed to sign and publish dispute payout tx from arbitrator for " + trade.getClass().getSimpleName() + " " + tradeId + ": " + e.getMessage(), e); + } } } } else { - log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); + if (trade.isPayoutPublished()) log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); + else if (disputeClosedMessage.getUnsignedPayoutTxHex() == null) log.info("{} did not receive unsigned dispute payout tx for trade {} because the arbitrator did not have their updated multisig info (can happen if trader went offline after trade started)", trade.getClass().getSimpleName(), trade.getId()); } - } else { - if (trade.isPayoutPublished()) log.info("Dispute payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); - else if (disputeClosedMessage.getUnsignedPayoutTxHex() == null) log.info("{} did not receive unsigned dispute payout tx for trade {} because the arbitrator did not have their updated multisig info (can happen if trader went offline after trade started)", trade.getClass().getSimpleName(), trade.getId()); - } - // We use the chatMessage as we only persist those not the DisputeClosedMessage. - // If we would use the DisputeClosedMessage we could not lookup for the msg when we receive the AckMessage. - sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null); - requestPersistence(); - } catch (Exception e) { - log.warn("Error processing dispute closed message: " + e.getMessage()); - e.printStackTrace(); - requestPersistence(); + // complete disputed trade + if (trade.isPayoutPublished()) { + tradeManager.closeDisputedTrade(trade.getId(), Trade.DisputeState.DISPUTE_CLOSED); + } - // nack bad message and do not reprocess - if (e instanceof IllegalArgumentException) { - trade.getProcessModel().setPaymentReceivedMessage(null); // message is processed - sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), false, e.getMessage()); - requestPersistence(); - throw e; - } + // We use the chatMessage as we only persist those not the DisputeClosedMessage. + // If we would use the DisputeClosedMessage we could not lookup for the msg when we receive the AckMessage. + sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), true, null); + requestPersistence(trade); + } catch (Exception e) { + log.warn("Error processing dispute closed message: {}", e.getMessage()); + log.warn(ExceptionUtils.getStackTrace(e)); + requestPersistence(trade); - // schedule to reprocess message unless deleted - if (trade.getProcessModel().getDisputeClosedMessage() != null) { - if (!reprocessDisputeClosedMessageCounts.containsKey(trade.getId())) reprocessDisputeClosedMessageCounts.put(trade.getId(), 0); - UserThread.runAfter(() -> { - reprocessDisputeClosedMessageCounts.put(trade.getId(), reprocessDisputeClosedMessageCounts.get(trade.getId()) + 1); // increment reprocess count - maybeReprocessDisputeClosedMessage(trade, reprocessOnError); - }, trade.getReprocessDelayInSeconds(reprocessDisputeClosedMessageCounts.get(trade.getId()))); + // nack bad message and do not reprocess + if (HavenoUtils.isIllegal(e)) { + trade.getArbitrator().setDisputeClosedMessage(null); // message is processed + trade.setDisputeState(Trade.DisputeState.DISPUTE_CLOSED); + String warningMsg = "Error processing dispute closed message: " + e.getMessage() + "\n\nOpen another dispute to try again (ctrl+o)."; + trade.prependErrorMessage(warningMsg); + sendAckMessage(chatMessage, dispute.getAgentPubKeyRing(), false, e.getMessage()); + HavenoUtils.havenoSetup.getTopErrorMsg().set(warningMsg); + requestPersistence(trade); + throw e; + } + + // schedule to reprocess message unless deleted + if (trade.getArbitrator().getDisputeClosedMessage() != null && reprocessOnError) { + if (!reprocessDisputeClosedMessageCounts.containsKey(trade.getId())) reprocessDisputeClosedMessageCounts.put(trade.getId(), 0); + UserThread.runAfter(() -> { + reprocessDisputeClosedMessageCounts.put(trade.getId(), reprocessDisputeClosedMessageCounts.get(trade.getId()) + 1); // increment reprocess count + maybeReprocessDisputeClosedMessage(trade, reprocessOnError); + }, trade.getReprocessDelayInSeconds(reprocessDisputeClosedMessageCounts.get(trade.getId()))); + } } } - } + }, trade.getId()); } public void maybeReprocessDisputeClosedMessage(Trade trade, boolean reprocessOnError) { - synchronized (trade) { + if (trade.isShutDownStarted()) return; + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { - // skip if no need to reprocess - if (trade.isArbitrator() || trade.getProcessModel().getDisputeClosedMessage() == null || trade.getProcessModel().getDisputeClosedMessage().getUnsignedPayoutTxHex() == null || trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_CLOSED.ordinal()) { - return; + // skip if no need to reprocess + if (trade.isArbitrator() || trade.getArbitrator().getDisputeClosedMessage() == null || trade.getArbitrator().getDisputeClosedMessage().getUnsignedPayoutTxHex() == null || trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_CLOSED.ordinal()) { + return; + } + + log.warn("Reprocessing dispute closed message for {} {}", trade.getClass().getSimpleName(), trade.getId()); + handleDisputeClosedMessage(trade.getArbitrator().getDisputeClosedMessage(), reprocessOnError); } - - log.warn("Reprocessing dispute closed message for {} {}", trade.getClass().getSimpleName(), trade.getId()); - new Thread(() -> handleDisputeClosedMessage(trade.getProcessModel().getDisputeClosedMessage(), reprocessOnError)).start(); - } + }, trade.getId()); } private MoneroTxSet signAndPublishDisputePayoutTx(Trade trade) { @@ -339,11 +406,11 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL // gather trade info MoneroWallet multisigWallet = trade.getWallet(); Optional<Dispute> disputeOptional = findDispute(trade.getId()); - if (!disputeOptional.isPresent()) throw new RuntimeException("Trader has no dispute when signing dispute payout tx. This should never happen. TradeId = " + trade.getId()); + if (!disputeOptional.isPresent()) throw new IllegalArgumentException("Trader has no dispute when signing dispute payout tx. This should never happen. TradeId = " + trade.getId()); Dispute dispute = disputeOptional.get(); Contract contract = dispute.getContract(); DisputeResult disputeResult = dispute.getDisputeResultProperty().get(); - String unsignedPayoutTxHex = trade.getProcessModel().getDisputeClosedMessage().getUnsignedPayoutTxHex(); + String unsignedPayoutTxHex = trade.getArbitrator().getDisputeClosedMessage().getUnsignedPayoutTxHex(); // Offer offer = checkNotNull(trade.getOffer(), "offer must not be null"); // BigInteger sellerDepositAmount = multisigWallet.getTx(trade instanceof MakerTrade ? trade.getMaker().getDepositTxHash() : trade.getTaker().getDepositTxHash()).getIncomingAmount(); // TODO (woodser): use contract instead of trade to get deposit tx ids when contract has deposit tx ids @@ -352,12 +419,12 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL // parse arbitrator-signed payout tx MoneroTxSet disputeTxSet = multisigWallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(unsignedPayoutTxHex)); - if (disputeTxSet.getTxs() == null || disputeTxSet.getTxs().size() != 1) throw new RuntimeException("Bad arbitrator-signed payout tx"); // TODO (woodser): nack + if (disputeTxSet.getTxs() == null || disputeTxSet.getTxs().size() != 1) throw new IllegalArgumentException("Bad arbitrator-signed payout tx"); // TODO (woodser): nack MoneroTxWallet arbitratorSignedPayoutTx = disputeTxSet.getTxs().get(0); // verify payout tx has 1 or 2 destinations int numDestinations = arbitratorSignedPayoutTx.getOutgoingTransfer() == null || arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations() == null ? 0 : arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations().size(); - if (numDestinations != 1 && numDestinations != 2) throw new RuntimeException("Buyer-signed payout tx does not have 1 or 2 destinations"); + if (numDestinations != 1 && numDestinations != 2) throw new IllegalArgumentException("Buyer-signed payout tx does not have 1 or 2 destinations"); // get buyer and seller destinations (order not preserved) List<MoneroDestination> destinations = arbitratorSignedPayoutTx.getOutgoingTransfer().getDestinations(); @@ -366,72 +433,70 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL MoneroDestination sellerPayoutDestination = buyerFirst ? (numDestinations == 2 ? destinations.get(1) : null) : destinations.get(0); // verify payout addresses - if (buyerPayoutDestination != null && !buyerPayoutDestination.getAddress().equals(contract.getBuyerPayoutAddressString())) throw new RuntimeException("Buyer payout address does not match contract"); - if (sellerPayoutDestination != null && !sellerPayoutDestination.getAddress().equals(contract.getSellerPayoutAddressString())) throw new RuntimeException("Seller payout address does not match contract"); + if (buyerPayoutDestination != null && !buyerPayoutDestination.getAddress().equals(contract.getBuyerPayoutAddressString())) throw new IllegalArgumentException("Buyer payout address does not match contract"); + if (sellerPayoutDestination != null && !sellerPayoutDestination.getAddress().equals(contract.getSellerPayoutAddressString())) throw new IllegalArgumentException("Seller payout address does not match contract"); // verify change address is multisig's primary address - if (!arbitratorSignedPayoutTx.getChangeAmount().equals(BigInteger.ZERO) && !arbitratorSignedPayoutTx.getChangeAddress().equals(multisigWallet.getPrimaryAddress())) throw new RuntimeException("Change address is not multisig wallet's primary address"); + if (!arbitratorSignedPayoutTx.getChangeAmount().equals(BigInteger.ZERO) && !arbitratorSignedPayoutTx.getChangeAddress().equals(multisigWallet.getPrimaryAddress())) throw new IllegalArgumentException("Change address is not multisig wallet's primary address"); // verify sum of outputs = destination amounts + change amount BigInteger destinationSum = (buyerPayoutDestination == null ? BigInteger.ZERO : buyerPayoutDestination.getAmount()).add(sellerPayoutDestination == null ? BigInteger.ZERO : sellerPayoutDestination.getAmount()); - if (!arbitratorSignedPayoutTx.getOutputSum().equals(destinationSum.add(arbitratorSignedPayoutTx.getChangeAmount()))) throw new RuntimeException("Sum of outputs != destination amounts + change amount"); + if (!arbitratorSignedPayoutTx.getOutputSum().equals(destinationSum.add(arbitratorSignedPayoutTx.getChangeAmount()))) throw new IllegalArgumentException("Sum of outputs != destination amounts + change amount"); // get actual payout amounts - BigInteger actualWinnerAmount = disputeResult.getWinner() == Winner.BUYER ? buyerPayoutDestination.getAmount() : sellerPayoutDestination.getAmount(); - BigInteger actualLoserAmount = numDestinations == 1 ? BigInteger.ZERO : disputeResult.getWinner() == Winner.BUYER ? sellerPayoutDestination.getAmount() : buyerPayoutDestination.getAmount(); + BigInteger actualBuyerAmount = buyerPayoutDestination == null ? BigInteger.ZERO : buyerPayoutDestination.getAmount(); + BigInteger actualSellerAmount = sellerPayoutDestination == null ? BigInteger.ZERO : sellerPayoutDestination.getAmount(); // verify payouts sum to unlocked balance within loss of precision due to conversion to centineros - BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount()); // fee + lost dust change - if (trade.getWallet().getUnlockedBalance().subtract(actualWinnerAmount.add(actualLoserAmount).add(txCost)).compareTo(BigInteger.valueOf(0)) > 0) { - throw new RuntimeException("The dispute payout amounts do not sum to the wallet's unlocked balance while verifying the dispute payout tx, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs sum payout amount=" + actualWinnerAmount.add(actualLoserAmount) + ", winner payout=" + actualWinnerAmount + ", loser payout=" + actualLoserAmount); + BigInteger txCost = arbitratorSignedPayoutTx.getFee().add(arbitratorSignedPayoutTx.getChangeAmount()); // cost = fee + lost dust change + if (!arbitratorSignedPayoutTx.getChangeAmount().equals(BigInteger.ZERO)) log.warn("Dust left in multisig wallet for {} {}: {}", getClass().getSimpleName(), trade.getId(), arbitratorSignedPayoutTx.getChangeAmount()); + if (trade.getWallet().getUnlockedBalance().subtract(actualBuyerAmount.add(actualSellerAmount).add(txCost)).compareTo(BigInteger.ZERO) > 0) { + throw new IllegalArgumentException("The dispute payout amounts do not sum to the wallet's unlocked balance while verifying the dispute payout tx, unlocked balance=" + trade.getWallet().getUnlockedBalance() + " vs sum payout amount=" + actualBuyerAmount.add(actualSellerAmount) + ", buyer payout=" + actualBuyerAmount + ", seller payout=" + actualSellerAmount); } - // get expected payout amounts - BigInteger expectedWinnerAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getBuyerPayoutAmount() : disputeResult.getSellerPayoutAmount(); - BigInteger expectedLoserAmount = disputeResult.getWinner() == Winner.BUYER ? disputeResult.getSellerPayoutAmount() : disputeResult.getBuyerPayoutAmount(); + // verify payout amounts + BigInteger[] buyerSellerPayoutTxCost = getBuyerSellerPayoutTxCost(disputeResult, txCost); + BigInteger expectedBuyerAmount = disputeResult.getBuyerPayoutAmountBeforeCost().subtract(buyerSellerPayoutTxCost[0]); + BigInteger expectedSellerAmount = disputeResult.getSellerPayoutAmountBeforeCost().subtract(buyerSellerPayoutTxCost[1]); + if (!expectedBuyerAmount.equals(actualBuyerAmount)) throw new IllegalArgumentException("Unexpected buyer payout: " + expectedBuyerAmount + " vs " + actualBuyerAmount); + if (!expectedSellerAmount.equals(actualSellerAmount)) throw new IllegalArgumentException("Unexpected seller payout: " + expectedSellerAmount + " vs " + actualSellerAmount); - // winner pays cost if loser gets nothing, otherwise loser pays cost - if (expectedLoserAmount.equals(BigInteger.ZERO)) expectedWinnerAmount = expectedWinnerAmount.subtract(txCost); - else expectedLoserAmount = expectedLoserAmount.subtract(txCost); + // check daemon connection + trade.verifyDaemonConnection(); - // verify winner and loser payout amounts - if (!expectedWinnerAmount.equals(actualWinnerAmount)) throw new RuntimeException("Unexpected winner payout: " + expectedWinnerAmount + " vs " + actualWinnerAmount); - if (!expectedLoserAmount.equals(actualLoserAmount)) throw new RuntimeException("Unexpected loser payout: " + expectedLoserAmount + " vs " + actualLoserAmount); - - // check wallet's daemon connection - trade.checkDaemonConnection(); - - // determine if we already signed dispute payout tx - // TODO: better way, such as by saving signed dispute payout tx hex in designated field instead of shared payoutTxHex field? - Set<String> nonSignedDisputePayoutTxHexes = new HashSet<String>(); - if (trade.getProcessModel().getPaymentSentMessage() != null) nonSignedDisputePayoutTxHexes.add(trade.getProcessModel().getPaymentSentMessage().getPayoutTxHex()); - if (trade.getProcessModel().getPaymentReceivedMessage() != null) { - nonSignedDisputePayoutTxHexes.add(trade.getProcessModel().getPaymentReceivedMessage().getUnsignedPayoutTxHex()); - nonSignedDisputePayoutTxHexes.add(trade.getProcessModel().getPaymentReceivedMessage().getSignedPayoutTxHex()); + // adapt from 1.0.6 to 1.0.7 which changes field usage + // TODO: remove after future updates to allow old trades to clear + if (trade.getPayoutTxHex() != null && trade.getBuyer().getPaymentSentMessage() != null && trade.getPayoutTxHex().equals(trade.getBuyer().getPaymentSentMessage().getPayoutTxHex())) { + log.warn("Nullifying payout tx hex after 1.0.7 update {} {}", trade.getClass().getSimpleName(), trade.getShortId()); + if (trade instanceof BuyerTrade) trade.getSelf().setUnsignedPayoutTxHex(trade.getPayoutTxHex()); + trade.setPayoutTxHex(null); } - boolean signed = trade.getPayoutTxHex() != null && !nonSignedDisputePayoutTxHexes.contains(trade.getPayoutTxHex()); // sign arbitrator-signed payout tx - if (!signed) { - MoneroMultisigSignResult result = multisigWallet.signMultisigTxHex(unsignedPayoutTxHex); - if (result.getSignedMultisigTxHex() == null) throw new RuntimeException("Error signing arbitrator-signed payout tx"); - String signedMultisigTxHex = result.getSignedMultisigTxHex(); - disputeTxSet.setMultisigTxHex(signedMultisigTxHex); - trade.setPayoutTxHex(signedMultisigTxHex); - requestPersistence(); + if (trade.getPayoutTxHex() == null) { + try { + MoneroMultisigSignResult result = multisigWallet.signMultisigTxHex(unsignedPayoutTxHex); + if (result.getSignedMultisigTxHex() == null) throw new RuntimeException("Error signing arbitrator-signed payout tx"); + String signedMultisigTxHex = result.getSignedMultisigTxHex(); + disputeTxSet.setMultisigTxHex(signedMultisigTxHex); + trade.setPayoutTxHex(signedMultisigTxHex); + requestPersistence(trade); + } catch (Exception e) { + throw new IllegalStateException(e.getMessage()); + } // verify mining fee is within tolerance by recreating payout tx // TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated? MoneroTxWallet feeEstimateTx = null; try { - feeEstimateTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, true); + feeEstimateTx = createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false); } catch (Exception e) { - log.warn("Could not recreate dispute payout tx to verify fee: " + e.getMessage()); + log.warn("Could not recreate dispute payout tx to verify fee: {}\n", e.getMessage(), e); } if (feeEstimateTx != null) { BigInteger feeEstimate = feeEstimateTx.getFee(); double feeDiff = arbitratorSignedPayoutTx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); - if (feeDiff > XmrWalletService.MINER_FEE_TOLERANCE) throw new IllegalArgumentException("Miner fee is not within " + (XmrWalletService.MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + arbitratorSignedPayoutTx.getFee()); + if (feeDiff > XmrWalletService.MINER_FEE_TOLERANCE) throw new RuntimeException("Miner fee is not within " + (XmrWalletService.MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + arbitratorSignedPayoutTx.getFee()); log.info("Payout tx fee {} is within tolerance, diff %={}", arbitratorSignedPayoutTx.getFee(), feeDiff); } } else { @@ -439,14 +504,105 @@ public final class ArbitrationManager extends DisputeManager<ArbitrationDisputeL } // submit fully signed payout tx to the network - List<String> txHashes = multisigWallet.submitMultisigTxHex(disputeTxSet.getMultisigTxHex()); - disputeTxSet.getTxs().get(0).setHash(txHashes.get(0)); // manually update hash which is known after signed + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + List<String> txHashes = multisigWallet.submitMultisigTxHex(disputeTxSet.getMultisigTxHex()); + disputeTxSet.getTxs().get(0).setHash(txHashes.get(0)); // manually update hash which is known after signed + break; + } catch (Exception e) { + if (trade.isPayoutPublished()) throw new IllegalStateException("Payout tx already published for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + if (HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e); + log.warn("Failed to submit dispute payout tx, tradeId={}, attempt={}/{}, error={}", trade.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + if (trade.getXmrConnectionService().isConnected()) trade.requestSwitchToNextBestConnection(sourceConnection); + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } // update state - trade.setPayoutTx(disputeTxSet.getTxs().get(0)); // TODO (woodser): is trade.payoutTx() mutually exclusive from dispute payout tx? - trade.setPayoutTxId(disputeTxSet.getTxs().get(0).getHash()); + trade.updatePayout(disputeTxSet.getTxs().get(0)); trade.setPayoutState(Trade.PayoutState.PAYOUT_PUBLISHED); dispute.setDisputePayoutTxId(disputeTxSet.getTxs().get(0).getHash()); + requestPersistence(trade); return disputeTxSet; } + + public static BigInteger[] getBuyerSellerPayoutTxCost(DisputeResult disputeResult, BigInteger payoutTxCost) { + boolean isBuyerWinner = disputeResult.getWinner() == Winner.BUYER; + BigInteger loserAmount = isBuyerWinner ? disputeResult.getSellerPayoutAmountBeforeCost() : disputeResult.getBuyerPayoutAmountBeforeCost(); + if (loserAmount.equals(BigInteger.ZERO)) { + BigInteger buyerPayoutTxFee = isBuyerWinner ? payoutTxCost : BigInteger.ZERO; + BigInteger sellerPayoutTxFee = isBuyerWinner ? BigInteger.ZERO : payoutTxCost; + return new BigInteger[] { buyerPayoutTxFee, sellerPayoutTxFee }; + } else { + switch (disputeResult.getSubtractFeeFrom()) { + case BUYER_AND_SELLER: + BigInteger payoutTxFeeSplit = payoutTxCost.divide(BigInteger.valueOf(2)); + return new BigInteger[] { payoutTxFeeSplit, payoutTxFeeSplit }; + case BUYER_ONLY: + return new BigInteger[] { payoutTxCost, BigInteger.ZERO }; + case SELLER_ONLY: + return new BigInteger[] { BigInteger.ZERO, payoutTxCost }; + default: + throw new RuntimeException("Unsupported subtract fee from: " + disputeResult.getSubtractFeeFrom()); + } + } + } + + public FileTransferSender initLogUpload(FileTransferSession.FtpCallback callback, + String tradeId, + int traderId) throws IOException { + Dispute dispute = findDispute(tradeId, traderId) + .orElseThrow(() -> new IOException("could not locate Dispute for tradeId/traderId")); + return dispute.createFileTransferSender(p2PService.getNetworkNode(), + dispute.getContract().getArbitratorNodeAddress(), callback); + } + + private void processFilePartReceived(FileTransferPart ftp) { + if (!ftp.isInitialRequest()) { + return; // existing sessions are processed by FileTransferSession object directly + } + // we create a new session which is related to an open dispute from our list + Optional<Dispute> dispute = findDispute(ftp.getTradeId(), ftp.getTraderId()); + if (dispute.isEmpty()) { + log.error("Received log upload request for unknown TradeId/TraderId {}/{}", ftp.getTradeId(), ftp.getTraderId()); + return; + } + if (dispute.get().isClosed()) { + log.error("Received a file transfer request for closed dispute {}", ftp.getTradeId()); + return; + } + try { + FileTransferReceiver session = dispute.get().createOrGetFileTransferReceiver( + p2PService.getNetworkNode(), ftp.getSenderNodeAddress(), this); + session.processFilePartReceived(ftp); + } catch (IOException e) { + log.error("Unable to process a received file message" + e); + } + } + + @Override + public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { + if (networkEnvelope instanceof FileTransferPart) { // mediator receiving log file data + FileTransferPart ftp = (FileTransferPart) networkEnvelope; + processFilePartReceived(ftp); + } + } + + @Override + public void onFtpProgress(double progressPct) { + log.trace("ftp progress: {}", progressPct); + } + + @Override + public void onFtpComplete(FileTransferSession session) { + Optional<Dispute> dispute = findDispute(session.getFullTradeId(), session.getTraderId()); + dispute.ifPresent(d -> addMediationLogsReceivedMessage(d, session.getZipId())); + } + + @Override + public void onFtpTimeout(String statusMsg, FileTransferSession session) { + session.resetSession(); + } } diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationSession.java b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationSession.java index 0386b95433..01e50a1b25 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationSession.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/ArbitrationSession.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/TraderDataItem.java b/core/src/main/java/haveno/core/support/dispute/arbitration/TraderDataItem.java index efa8f8a4b2..2e729ea815 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/TraderDataItem.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/TraderDataItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/Arbitrator.java b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/Arbitrator.java index 99125ad45d..54ef94c611 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/Arbitrator.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/Arbitrator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration.arbitrator; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java index 3f507e0a49..30fe0be18f 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,18 +34,16 @@ package haveno.core.support.dispute.arbitration.arbitrator; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.filter.FilterManager; import haveno.core.support.dispute.agent.DisputeAgentManager; import haveno.core.user.User; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.ArrayList; import java.util.List; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton @@ -63,7 +78,7 @@ public class ArbitratorManager extends DisputeAgentManager<Arbitrator> { "02a1a458df5acf4ab08fdca748e28f33a955a30854c8c1a831ee733dca7f0d2fcd", "0374dd70f3fa6e47ec5ab97932e1cec6233e98e6ae3129036b17118650c44fd3de"); case XMR_MAINNET: - return new ArrayList<String>(); + return List.of(); default: throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork()); } diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorService.java b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorService.java index 46b35a7ed6..71d017b7c7 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorService.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorService.java @@ -1,29 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration.arbitrator; +import com.google.inject.Inject; import com.google.inject.Singleton; import haveno.core.filter.FilterManager; import haveno.core.support.dispute.agent.DisputeAgentService; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/core/src/main/java/haveno/core/support/dispute/arbitration/messages/ArbitrationMessage.java b/core/src/main/java/haveno/core/support/dispute/arbitration/messages/ArbitrationMessage.java index 6f14f833ea..fa5dd9f253 100644 --- a/core/src/main/java/haveno/core/support/dispute/arbitration/messages/ArbitrationMessage.java +++ b/core/src/main/java/haveno/core/support/dispute/arbitration/messages/ArbitrationMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.arbitration.messages; diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferReceiver.java b/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferReceiver.java new file mode 100644 index 0000000000..6c79469daf --- /dev/null +++ b/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferReceiver.java @@ -0,0 +1,126 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.support.dispute.mediation; + +import haveno.network.p2p.AckMessage; +import haveno.network.p2p.AckMessageSourceType; +import haveno.network.p2p.FileTransferPart; +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.network.NetworkNode; + +import haveno.common.UserThread; +import haveno.common.config.Config; +import haveno.common.util.Utilities; + +import java.nio.file.FileSystems; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +import java.util.concurrent.TimeUnit; + +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +@Slf4j +public class FileTransferReceiver extends FileTransferSession { + protected final String zipFilePath; + + public FileTransferReceiver(NetworkNode networkNode, + NodeAddress peerNodeAddress, + String tradeId, + int traderId, + String traderRole, + @Nullable FileTransferSession.FtpCallback callback) throws IOException { + super(networkNode, peerNodeAddress, tradeId, traderId, traderRole, callback); + zipFilePath = ensureReceivingDirectoryExists().getAbsolutePath() + FileSystems.getDefault().getSeparator() + zipId + ".zip"; + } + + public void processFilePartReceived(FileTransferPart ftp) { + checkpointLastActivity(); + // check that the supplied sequence number is in line with what we are expecting + if (currentBlockSeqNum < 0) { + // we have not yet started receiving a file, validate this ftp packet as the initiation request + initReceiveSession(ftp.uid, ftp.seqNumOrFileLength); + } else if (currentBlockSeqNum == ftp.seqNumOrFileLength) { + // we are in the middle of receiving a file; add the block of data to the file + processReceivedBlock(ftp, networkNode, peerNodeAddress); + } else { + log.error("ftp sequence num mismatch, expected {} received {}", currentBlockSeqNum, ftp.seqNumOrFileLength); + resetSession(); // aborts the file transfer + } + } + + public void initReceiveSession(String uid, long expectedFileBytes) { + networkNode.addMessageListener(this); + this.expectedFileLength = expectedFileBytes; + fileOffsetBytes = 0; + currentBlockSeqNum = 0; + initSessionTimer(); + log.info("Received a start file transfer request, tradeId={}, traderId={}, size={}", fullTradeId, traderId, expectedFileBytes); + log.info("New file will be written to {}", zipFilePath); + UserThread.execute(() -> ackReceivedPart(uid, networkNode, peerNodeAddress)); + } + + private void processReceivedBlock(FileTransferPart ftp, NetworkNode networkNode, NodeAddress peerNodeAddress) { + try { + RandomAccessFile file = new RandomAccessFile(zipFilePath, "rwd"); + file.seek(fileOffsetBytes); + file.write(ftp.messageData.toByteArray(), 0, ftp.messageData.size()); + fileOffsetBytes = fileOffsetBytes + ftp.messageData.size(); + log.info("Sequence number {} for {}, received data {} / {}", + ftp.seqNumOrFileLength, Utilities.getShortId(ftp.tradeId), fileOffsetBytes, expectedFileLength); + currentBlockSeqNum++; + UserThread.runAfter(() -> { + ackReceivedPart(ftp.uid, networkNode, peerNodeAddress); + if (fileOffsetBytes >= expectedFileLength) { + log.info("Success! We have reached the EOF, received {} expected {}", fileOffsetBytes, expectedFileLength); + ftpCallback.ifPresent(c -> c.onFtpComplete(this)); + resetSession(); + } + }, 100, TimeUnit.MILLISECONDS); + } catch (IOException e) { + log.error(e.toString()); + e.printStackTrace(); + } + } + + private void ackReceivedPart(String uid, NetworkNode networkNode, NodeAddress peerNodeAddress) { + AckMessage ackMessage = new AckMessage(peerNodeAddress, + AckMessageSourceType.LOG_TRANSFER, + FileTransferPart.class.getSimpleName(), + uid, + Utilities.getShortId(fullTradeId), + true, // result + null); // errorMessage + log.info("Send AckMessage for {} to peer {}. id={}, uid={}", + ackMessage.getSourceMsgClassName(), peerNodeAddress, ackMessage.getSourceId(), ackMessage.getSourceUid()); + sendMessage(ackMessage, networkNode, peerNodeAddress); + } + + private static File ensureReceivingDirectoryExists() throws IOException { + File directory = new File(Config.appDataDir() + "/clientLogs"); + if (!directory.exists() && !directory.mkdirs()) { + log.error("Could not create directory {}", directory.getAbsolutePath()); + throw new IOException("Could not create directory: " + directory.getAbsolutePath()); + } + return directory; + } +} diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferSender.java b/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferSender.java new file mode 100644 index 0000000000..4efa3ad4b0 --- /dev/null +++ b/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferSender.java @@ -0,0 +1,198 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.support.dispute.mediation; + +import haveno.network.p2p.FileTransferPart; +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.network.NetworkNode; + +import haveno.common.UserThread; +import haveno.common.config.Config; +import haveno.common.util.Utilities; + +import com.google.protobuf.ByteString; + +import java.net.URI; + +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; + +import java.io.IOException; +import java.io.RandomAccessFile; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Stream; + +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +import static haveno.common.file.FileUtil.doesFileContainKeyword; + +@Slf4j +public class FileTransferSender extends FileTransferSession { + protected final String zipFilePath; + private final boolean isTest; + + public FileTransferSender(NetworkNode networkNode, + NodeAddress peerNodeAddress, + String tradeId, + int traderId, + String traderRole, + boolean isTest, + @Nullable FileTransferSession.FtpCallback callback) { + super(networkNode, peerNodeAddress, tradeId, traderId, traderRole, callback); + zipFilePath = Utilities.getUserDataDir() + FileSystems.getDefault().getSeparator() + zipId + ".zip"; + this.isTest = isTest; + updateProgress(); + } + + public void createZipFileToSend() { + createZipFileOfLogs(zipFilePath, zipId, fullTradeId); + } + + public static void createZipFileOfLogs(String zipFilePath, String zipId, String fullTradeId) { + try { + Map<String, String> env = new HashMap<>(); + env.put("create", "true"); + URI uri = URI.create("jar:file:///" + zipFilePath + .replace('\\', '/') + .replaceAll(" ", "%20")); + FileSystem zipfs = FileSystems.newFileSystem(uri, env); + Files.createDirectory(zipfs.getPath(zipId)); // store logfiles in a usefully-named subdir + Stream<Path> paths = Files.walk(Paths.get(Config.appDataDir().toString()), 1); + paths.filter(Files::isRegularFile).forEach(externalTxtFile -> { + try { + // always include haveno.log; and other .log files if they contain the TradeId + if (externalTxtFile.getFileName().toString().equals("haveno.log") || + (fullTradeId == null && externalTxtFile.getFileName().toString().matches(".*.log")) || + (externalTxtFile.getFileName().toString().matches(".*.log") && + doesFileContainKeyword(externalTxtFile.toFile(), fullTradeId))) { + Path pathInZipfile = zipfs.getPath(zipId + "/" + externalTxtFile.getFileName().toString()); + log.info("adding {} to zip file {}", pathInZipfile, zipfs); + Files.copy(externalTxtFile, pathInZipfile, StandardCopyOption.REPLACE_EXISTING); + } + } catch (IOException e) { + log.error(e.toString()); + e.printStackTrace(); + } + }); + zipfs.close(); + } catch (IOException | IllegalArgumentException ex) { + log.error(ex.toString()); + ex.printStackTrace(); + } + } + + public void initSend() throws IOException { + initSessionTimer(); + networkNode.addMessageListener(this); + RandomAccessFile file = new RandomAccessFile(zipFilePath, "r"); + expectedFileLength = file.length(); + file.close(); + // an empty block is sent as request to initiate file transfer, peer must ACK for transfer to continue + dataAwaitingAck = Optional.of(new FileTransferPart(networkNode.getNodeAddress(), fullTradeId, traderId, UUID.randomUUID().toString(), expectedFileLength, ByteString.EMPTY)); + uploadData(); + } + + public void sendNextBlock() throws IOException, IllegalStateException { + if (dataAwaitingAck.isPresent()) { + log.warn("prepNextBlockToSend invoked, but we are still waiting for a previous ACK"); + throw new IllegalStateException("prepNextBlockToSend invoked, but we are still waiting for a previous ACK"); + } + RandomAccessFile file = new RandomAccessFile(zipFilePath, "r"); + file.seek(fileOffsetBytes); + byte[] buff = new byte[FILE_BLOCK_SIZE]; + int nBytesRead = file.read(buff, 0, FILE_BLOCK_SIZE); + file.close(); + if (nBytesRead < 0) { + log.info("Success! We have reached the EOF, {} bytes sent. Removing zip file {}", fileOffsetBytes, zipFilePath); + Files.delete(Paths.get(zipFilePath)); + ftpCallback.ifPresent(c -> c.onFtpComplete(this)); + UserThread.runAfter(this::resetSession, 1); + return; + } + dataAwaitingAck = Optional.of(new FileTransferPart(networkNode.getNodeAddress(), fullTradeId, traderId, UUID.randomUUID().toString(), currentBlockSeqNum, ByteString.copyFrom(buff, 0, nBytesRead))); + uploadData(); + } + + public void retrySend() { + if (transferIsInProgress()) { + log.info("Retry send of current block"); + initSessionTimer(); + uploadData(); + } else { + UserThread.runAfter(() -> ftpCallback.ifPresent((f) -> f.onFtpTimeout("Could not re-send", this)), 1); + } + } + + protected void uploadData() { + if (dataAwaitingAck.isEmpty()) { + return; + } + FileTransferPart ftp = dataAwaitingAck.get(); + log.info("Send FileTransferPart seq {} length {} to peer {}, UID={}", + ftp.seqNumOrFileLength, ftp.messageData.size(), peerNodeAddress, ftp.uid); + sendMessage(ftp, networkNode, peerNodeAddress); + } + + public boolean processAckForFilePart(String ackUid) { + if (dataAwaitingAck.isEmpty()) { + log.warn("We received an ACK we were not expecting. {}", ackUid); + return false; + } + if (!dataAwaitingAck.get().uid.equals(ackUid)) { + log.warn("We received an ACK that has a different UID to what we were expecting. We ignore and wait for the correct ACK"); + log.info("Received {} expecting {}", ackUid, dataAwaitingAck.get().uid); + return false; + } + // fileOffsetBytes gets incremented by the size of the block that was ack'd + fileOffsetBytes += dataAwaitingAck.get().messageData.size(); + currentBlockSeqNum++; + dataAwaitingAck = Optional.empty(); + checkpointLastActivity(); + updateProgress(); + if (isTest) { + return true; + } + UserThread.runAfter(() -> { // to trigger continuing the file transfer + try { + sendNextBlock(); + } catch (IOException e) { + log.error(e.toString()); + e.printStackTrace(); + } + }, 100, TimeUnit.MILLISECONDS); + return true; + } + + public void updateProgress() { + double progressPct = expectedFileLength > 0 ? + ((double) fileOffsetBytes / expectedFileLength) : 0.0; + ftpCallback.ifPresent(c -> c.onFtpProgress(progressPct)); + log.info("ftp progress: {}", String.format("%.0f%%", progressPct * 100)); + } +} diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferSession.java b/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferSession.java new file mode 100644 index 0000000000..96a9e73f96 --- /dev/null +++ b/core/src/main/java/haveno/core/support/dispute/mediation/FileTransferSession.java @@ -0,0 +1,174 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.support.dispute.mediation; + +import haveno.network.p2p.AckMessage; +import haveno.network.p2p.AckMessageSourceType; +import haveno.network.p2p.FileTransferPart; +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.network.Connection; +import haveno.network.p2p.network.MessageListener; +import haveno.network.p2p.network.NetworkNode; + +import haveno.common.UserThread; +import haveno.common.proto.network.NetworkEnvelope; +import haveno.common.util.Utilities; + +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.common.util.concurrent.SettableFuture; + +import java.text.SimpleDateFormat; + +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; + +import static haveno.network.p2p.network.Connection.getPermittedMessageSize; + +@Slf4j +public abstract class FileTransferSession implements MessageListener { + protected static final int FTP_SESSION_TIMEOUT_MILLIS = (int) TimeUnit.SECONDS.toMillis(60); + protected static final int FILE_BLOCK_SIZE = getPermittedMessageSize() - 1024; // allowing space for protobuf + + public interface FtpCallback { + void onFtpProgress(double progressPct); + + void onFtpComplete(FileTransferSession session); + + void onFtpTimeout(String statusMsg, FileTransferSession session); + } + + @Getter + protected final String fullTradeId; + @Getter + protected final int traderId; + @Getter + protected final String zipId; + protected final Optional<FtpCallback> ftpCallback; + protected final NetworkNode networkNode; // for sending network messages + protected final NodeAddress peerNodeAddress; + protected Optional<FileTransferPart> dataAwaitingAck; + protected long fileOffsetBytes; + protected long currentBlockSeqNum; + protected long expectedFileLength; + protected long lastActivityTime; + + public FileTransferSession(NetworkNode networkNode, + NodeAddress peerNodeAddress, + String tradeId, + int traderId, + String traderRole, + @Nullable FileTransferSession.FtpCallback callback) { + this.networkNode = networkNode; + this.peerNodeAddress = peerNodeAddress; + this.fullTradeId = tradeId; + this.traderId = traderId; + this.ftpCallback = Optional.ofNullable(callback); + this.zipId = Utilities.getShortId(fullTradeId) + "_" + traderRole.toUpperCase() + "_" + + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + resetSession(); + } + + public void resetSession() { + lastActivityTime = 0; + currentBlockSeqNum = -1; + fileOffsetBytes = 0; + expectedFileLength = 0; + dataAwaitingAck = Optional.empty(); + networkNode.removeMessageListener(this); + log.info("Ftp session parameters have been reset."); + } + + @Override + public void onMessage(NetworkEnvelope networkEnvelope, Connection connection) { + if (networkEnvelope instanceof FileTransferPart) { + // mediator receiving log file data + FileTransferPart ftp = (FileTransferPart) networkEnvelope; + if (this instanceof FileTransferReceiver) { + ((FileTransferReceiver) this).processFilePartReceived(ftp); + } + } else if (networkEnvelope instanceof AckMessage) { + AckMessage ackMessage = (AckMessage) networkEnvelope; + if (ackMessage.getSourceType() == AckMessageSourceType.LOG_TRANSFER) { + if (ackMessage.isSuccess()) { + log.info("Received AckMessage for {} with id {} and uid {}", + ackMessage.getSourceMsgClassName(), ackMessage.getSourceId(), ackMessage.getSourceUid()); + if (this instanceof FileTransferSender) { + ((FileTransferSender) this).processAckForFilePart(ackMessage.getSourceUid()); + } + } else { + log.warn("Received AckMessage with error state for {} with id {} and errorMessage={}", + ackMessage.getSourceMsgClassName(), ackMessage.getSourceId(), ackMessage.getErrorMessage()); + } + } + } + } + + protected void checkpointLastActivity() { + lastActivityTime = System.currentTimeMillis(); + } + + protected void initSessionTimer() { + UserThread.runAfter(() -> { + if (!transferIsInProgress()) // transfer may have finished before this timer executes + return; + if (System.currentTimeMillis() - lastActivityTime < FTP_SESSION_TIMEOUT_MILLIS) { + log.info("Last activity was {}, we have not yet timed out.", new Date(lastActivityTime)); + initSessionTimer(); + } else { + log.warn("File transfer session timed out. expected: {} received: {}", expectedFileLength, fileOffsetBytes); + ftpCallback.ifPresent((e) -> e.onFtpTimeout("Timed out during send", this)); + } + }, FTP_SESSION_TIMEOUT_MILLIS / 4, TimeUnit.MILLISECONDS); // check more frequently than the timeout + } + + protected boolean transferIsInProgress() { + return fileOffsetBytes != expectedFileLength; + } + + protected void sendMessage(NetworkEnvelope message, NetworkNode networkNode, NodeAddress nodeAddress) { + SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, message); + if (future != null) { // is null when testing with Mockito + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(Connection connection) { + } + + @Override + public void onFailure(@NotNull Throwable throwable) { + String errorSend = "Sending " + message.getClass().getSimpleName() + + " to " + nodeAddress.getFullAddress() + + " failed. That is expected if the peer is offline.\n\t" + + ".\n\tException=" + throwable.getMessage(); + log.warn(errorSend); + ftpCallback.ifPresent((f) -> f.onFtpTimeout("Peer offline", FileTransferSession.this)); + resetSession(); + } + }, MoreExecutors.directExecutor()); + } + } +} diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeList.java b/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeList.java index f05fa82563..6387984b20 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeList.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation; diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeListService.java b/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeListService.java index 37021b9974..b15a3b15fe 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeListService.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/MediationDisputeListService.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.persistence.PersistenceManager; import haveno.core.support.dispute.DisputeListService; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public final class MediationDisputeListService extends DisputeListService<MediationDisputeList> { diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java b/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java index 8f7fb75c59..b7fa902b83 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/MediationManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation; @@ -26,7 +26,7 @@ import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.api.CoreNotificationService; import haveno.core.locale.Res; import haveno.core.offer.OpenOffer; @@ -71,7 +71,7 @@ public final class MediationManager extends DisputeManager<MediationDisputeList> public MediationManager(P2PService p2PService, TradeWalletService tradeWalletService, XmrWalletService walletService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, CoreNotificationService notificationService, TradeManager tradeManager, ClosedTradableManager closedTradableManager, @@ -80,7 +80,7 @@ public final class MediationManager extends DisputeManager<MediationDisputeList> MediationDisputeListService mediationDisputeListService, Config config, PriceFeedService priceFeedService) { - super(p2PService, tradeWalletService, walletService, connectionService, notificationService, tradeManager, closedTradableManager, + super(p2PService, tradeWalletService, walletService, xmrConnectionService, notificationService, tradeManager, closedTradableManager, openOfferManager, keyRing, mediationDisputeListService, config, priceFeedService); } @@ -188,8 +188,8 @@ public final class MediationManager extends DisputeManager<MediationDisputeList> Trade trade = tradeOptional.get(); if (trade.getDisputeState() == Trade.DisputeState.MEDIATION_REQUESTED || trade.getDisputeState() == Trade.DisputeState.MEDIATION_STARTED_BY_PEER) { - trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmount().longValueExact()); - trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmount().longValueExact()); + trade.getProcessModel().setBuyerPayoutAmountFromMediation(disputeResult.getBuyerPayoutAmountBeforeCost().longValueExact()); + trade.getProcessModel().setSellerPayoutAmountFromMediation(disputeResult.getSellerPayoutAmountBeforeCost().longValueExact()); trade.setDisputeState(Trade.DisputeState.MEDIATION_CLOSED); @@ -222,8 +222,8 @@ public final class MediationManager extends DisputeManager<MediationDisputeList> Optional<Dispute> optionalDispute = findDispute(tradeId); checkArgument(optionalDispute.isPresent(), "dispute must be present"); DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get(); - BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount(); - BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount(); + BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmountBeforeCost(); + BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmountBeforeCost(); ProcessModel processModel = trade.getProcessModel(); processModel.setBuyerPayoutAmountFromMediation(buyerPayoutAmount.longValueExact()); processModel.setSellerPayoutAmountFromMediation(sellerPayoutAmount.longValueExact()); diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/MediationResultState.java b/core/src/main/java/haveno/core/support/dispute/mediation/MediationResultState.java index 123cd9168c..706e03d3d6 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/MediationResultState.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/MediationResultState.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation; diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/MediationSession.java b/core/src/main/java/haveno/core/support/dispute/mediation/MediationSession.java index 794c3ab4c8..fdcd8ab1b2 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/MediationSession.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/MediationSession.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation; diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/mediator/Mediator.java b/core/src/main/java/haveno/core/support/dispute/mediation/mediator/Mediator.java index e0f4b94b07..f3efa6a9d6 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/mediator/Mediator.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/mediator/Mediator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation.mediator; diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorManager.java b/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorManager.java index 095d80f58f..62ad2c01b0 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorManager.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorManager.java @@ -1,30 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation.mediator; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.core.filter.FilterManager; import haveno.core.support.dispute.agent.DisputeAgentManager; import haveno.core.user.User; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.List; @Singleton diff --git a/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorService.java b/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorService.java index e70ec66bf7..b3f3d793da 100644 --- a/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorService.java +++ b/core/src/main/java/haveno/core/support/dispute/mediation/mediator/MediatorService.java @@ -1,35 +1,34 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.mediation.mediator; +import com.google.inject.Inject; import com.google.inject.Singleton; import haveno.core.filter.FilterManager; import haveno.core.support.dispute.agent.DisputeAgentService; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Slf4j diff --git a/core/src/main/java/haveno/core/support/dispute/messages/DisputeClosedMessage.java b/core/src/main/java/haveno/core/support/dispute/messages/DisputeClosedMessage.java index 03d757b008..88a1b6a9df 100644 --- a/core/src/main/java/haveno/core/support/dispute/messages/DisputeClosedMessage.java +++ b/core/src/main/java/haveno/core/support/dispute/messages/DisputeClosedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.messages; diff --git a/core/src/main/java/haveno/core/support/dispute/messages/DisputeMessage.java b/core/src/main/java/haveno/core/support/dispute/messages/DisputeMessage.java index f8113fd3fc..433f9f4145 100644 --- a/core/src/main/java/haveno/core/support/dispute/messages/DisputeMessage.java +++ b/core/src/main/java/haveno/core/support/dispute/messages/DisputeMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.messages; diff --git a/core/src/main/java/haveno/core/support/dispute/messages/DisputeOpenedMessage.java b/core/src/main/java/haveno/core/support/dispute/messages/DisputeOpenedMessage.java index ce77288ec1..fb6fb2fc19 100644 --- a/core/src/main/java/haveno/core/support/dispute/messages/DisputeOpenedMessage.java +++ b/core/src/main/java/haveno/core/support/dispute/messages/DisputeOpenedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.messages; diff --git a/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeList.java b/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeList.java index c020a60cf0..2ad31a0107 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeList.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund; diff --git a/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeListService.java b/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeListService.java index 1eca8d6924..c4578f49dc 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeListService.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/RefundDisputeListService.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.persistence.PersistenceManager; import haveno.core.support.dispute.DisputeListService; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public final class RefundDisputeListService extends DisputeListService<RefundDisputeList> { diff --git a/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java b/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java index 15b50af1ba..fa3503f625 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/RefundManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund; @@ -24,7 +24,7 @@ import haveno.common.UserThread; import haveno.common.app.Version; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.api.CoreNotificationService; import haveno.core.locale.Res; import haveno.core.offer.OpenOffer; @@ -66,7 +66,7 @@ public final class RefundManager extends DisputeManager<RefundDisputeList> { public RefundManager(P2PService p2PService, TradeWalletService tradeWalletService, XmrWalletService walletService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, CoreNotificationService notificationService, TradeManager tradeManager, ClosedTradableManager closedTradableManager, @@ -76,7 +76,7 @@ public final class RefundManager extends DisputeManager<RefundDisputeList> { RefundDisputeListService refundDisputeListService, Config config, PriceFeedService priceFeedService) { - super(p2PService, tradeWalletService, walletService, connectionService, notificationService, tradeManager, closedTradableManager, + super(p2PService, tradeWalletService, walletService, xmrConnectionService, notificationService, tradeManager, closedTradableManager, openOfferManager, keyRing, refundDisputeListService, config, priceFeedService); } diff --git a/core/src/main/java/haveno/core/support/dispute/refund/RefundResultState.java b/core/src/main/java/haveno/core/support/dispute/refund/RefundResultState.java index 15e54bf91f..cf5f5b350c 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/RefundResultState.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/RefundResultState.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund; diff --git a/core/src/main/java/haveno/core/support/dispute/refund/RefundSession.java b/core/src/main/java/haveno/core/support/dispute/refund/RefundSession.java index 567293f37e..309eb7bd20 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/RefundSession.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/RefundSession.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund; diff --git a/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgent.java b/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgent.java index 4ba38736cc..ff8ae44235 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgent.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgent.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund.refundagent; diff --git a/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentManager.java b/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentManager.java index 9281234c11..3e31c38ac7 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentManager.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentManager.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund.refundagent; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.core.filter.FilterManager; import haveno.core.support.dispute.agent.DisputeAgentManager; import haveno.core.user.User; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.List; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton diff --git a/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentService.java b/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentService.java index 6324445bd7..1aa4eed879 100644 --- a/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentService.java +++ b/core/src/main/java/haveno/core/support/dispute/refund/refundagent/RefundAgentService.java @@ -1,29 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.dispute.refund.refundagent; +import com.google.inject.Inject; import com.google.inject.Singleton; import haveno.core.filter.FilterManager; import haveno.core.support.dispute.agent.DisputeAgentService; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Map; diff --git a/core/src/main/java/haveno/core/support/messages/ChatMessage.java b/core/src/main/java/haveno/core/support/messages/ChatMessage.java index eedf4bd190..a9663ee353 100644 --- a/core/src/main/java/haveno/core/support/messages/ChatMessage.java +++ b/core/src/main/java/haveno/core/support/messages/ChatMessage.java @@ -1,41 +1,41 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.messages; -import haveno.common.app.Version; -import haveno.common.util.Utilities; +import haveno.core.locale.Res; import haveno.core.support.SupportType; import haveno.core.support.dispute.Attachment; import haveno.core.support.dispute.Dispute; import haveno.core.support.dispute.DisputeResult; + import haveno.network.p2p.NodeAddress; + +import haveno.common.UserThread; +import haveno.common.app.Version; +import haveno.common.util.Utilities; + import javafx.beans.property.BooleanProperty; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import javax.annotation.Nullable; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -44,13 +44,22 @@ import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import java.lang.ref.WeakReference; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + /* Message for direct communication between two nodes. Originally built for trader to * arbitrator communication as no other direct communication was allowed. Arbitrator is * considered as the server and trader as the client in arbitration chats * * For trader to trader communication the maker is considered to be the server * and the taker is considered as the client. - * */ + */ @EqualsAndHashCode(callSuper = true) // listener is transient and therefore excluded anyway @Getter @Slf4j @@ -84,14 +93,14 @@ public final class ChatMessage extends SupportMessage { private final StringProperty sendMessageErrorProperty; private final StringProperty ackErrorProperty; - transient private Listener listener; + transient private WeakReference<Listener> listener; public ChatMessage(SupportType supportType, - String tradeId, - int traderId, - boolean senderIsTrader, - String message, - NodeAddress senderNodeAddress) { + String tradeId, + int traderId, + boolean senderIsTrader, + String message, + NodeAddress senderNodeAddress) { this(supportType, tradeId, traderId, @@ -111,12 +120,12 @@ public final class ChatMessage extends SupportMessage { } public ChatMessage(SupportType supportType, - String tradeId, - int traderId, - boolean senderIsTrader, - String message, - NodeAddress senderNodeAddress, - ArrayList<Attachment> attachments) { + String tradeId, + int traderId, + boolean senderIsTrader, + String message, + NodeAddress senderNodeAddress, + ArrayList<Attachment> attachments) { this(supportType, tradeId, traderId, @@ -136,12 +145,12 @@ public final class ChatMessage extends SupportMessage { } public ChatMessage(SupportType supportType, - String tradeId, - int traderId, - boolean senderIsTrader, - String message, - NodeAddress senderNodeAddress, - long date) { + String tradeId, + int traderId, + boolean senderIsTrader, + String message, + NodeAddress senderNodeAddress, + long date) { this(supportType, tradeId, traderId, @@ -198,7 +207,9 @@ public final class ChatMessage extends SupportMessage { notifyChangeListener(); } - public protobuf.ChatMessage.Builder toProtoChatMessageBuilder() { + // We cannot rename protobuf definition because it would break backward compatibility + @Override + public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.ChatMessage.Builder builder = protobuf.ChatMessage.newBuilder() .setType(SupportType.toProtoMessage(supportType)) .setTradeId(tradeId) @@ -216,14 +227,6 @@ public final class ChatMessage extends SupportMessage { .setWasDisplayed(wasDisplayed); Optional.ofNullable(sendMessageErrorProperty.get()).ifPresent(builder::setSendMessageError); Optional.ofNullable(ackErrorProperty.get()).ifPresent(builder::setAckError); - - return builder; - } - - // We cannot rename protobuf definition because it would break backward compatibility - @Override - public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { - protobuf.ChatMessage.Builder builder = toProtoChatMessageBuilder(); return getNetworkEnvelopeBuilder() .setChatMessage(builder) .build(); @@ -296,6 +299,16 @@ public final class ChatMessage extends SupportMessage { notifyChangeListener(); } + // each chat message notifies the user if an ACK is not received in time + public void startAckTimer() { + UserThread.runAfter(() -> { + if (!this.getAcknowledgedProperty().get() && !this.getStoredInMailboxProperty().get()) { + this.setArrived(false); + this.setAckError(Res.get("support.errorTimeout")); + } + }, 60, TimeUnit.SECONDS); + } + public ReadOnlyBooleanProperty acknowledgedProperty() { return acknowledgedProperty; } @@ -327,12 +340,8 @@ public final class ChatMessage extends SupportMessage { return Utilities.getShortId(tradeId); } - public void addChangeListener(Listener listener) { - this.listener = listener; - } - - public void removeChangeListener() { - this.listener = null; + public void addWeakMessageStateListener(Listener listener) { + this.listener = new WeakReference<>(listener); } public boolean isResultMessage(Dispute dispute) { @@ -352,7 +361,10 @@ public final class ChatMessage extends SupportMessage { private void notifyChangeListener() { if (listener != null) { - listener.onMessageStateChanged(); + Listener listener = this.listener.get(); + if (listener != null) { + listener.onMessageStateChanged(); + } } } @@ -375,4 +387,4 @@ public final class ChatMessage extends SupportMessage { ",\n ackErrorProperty=" + ackErrorProperty + "\n} " + super.toString(); } -} +} \ No newline at end of file diff --git a/core/src/main/java/haveno/core/support/messages/SupportMessage.java b/core/src/main/java/haveno/core/support/messages/SupportMessage.java index f7e7151948..a1fa3febea 100644 --- a/core/src/main/java/haveno/core/support/messages/SupportMessage.java +++ b/core/src/main/java/haveno/core/support/messages/SupportMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.messages; diff --git a/core/src/main/java/haveno/core/support/traderchat/TradeChatSession.java b/core/src/main/java/haveno/core/support/traderchat/TradeChatSession.java index 17fb238ded..3d657be32d 100644 --- a/core/src/main/java/haveno/core/support/traderchat/TradeChatSession.java +++ b/core/src/main/java/haveno/core/support/traderchat/TradeChatSession.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.traderchat; @@ -62,7 +62,7 @@ public class TradeChatSession extends SupportSession { @Override public boolean chatIsOpen() { - return trade != null && trade.getState() != Trade.State.TRADE_COMPLETED; + return trade != null && !trade.isCompleted(); } @Override diff --git a/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java b/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java index eea25bc6d4..f462becdf0 100644 --- a/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java +++ b/core/src/main/java/haveno/core/support/traderchat/TraderChatManager.java @@ -1,26 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.support.traderchat; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.PubKeyRing; import haveno.common.crypto.PubKeyRingProvider; -import haveno.core.api.CoreMoneroConnectionsService; import haveno.core.api.CoreNotificationService; +import haveno.core.api.XmrConnectionService; import haveno.core.locale.Res; import haveno.core.support.SupportManager; import haveno.core.support.SupportType; @@ -28,18 +30,16 @@ import haveno.core.support.messages.ChatMessage; import haveno.core.support.messages.SupportMessage; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessageSourceType; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; +import java.util.List; +import java.util.Optional; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.List; -import java.util.Optional; - @Slf4j @Singleton public class TraderChatManager extends SupportManager { @@ -52,11 +52,12 @@ public class TraderChatManager extends SupportManager { @Inject public TraderChatManager(P2PService p2PService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, + XmrWalletService xmrWalletService, CoreNotificationService notificationService, TradeManager tradeManager, PubKeyRingProvider pubKeyRingProvider) { - super(p2PService, connectionService, notificationService, tradeManager); + super(p2PService, xmrConnectionService, xmrWalletService, notificationService, tradeManager); this.pubKeyRingProvider = pubKeyRingProvider; } diff --git a/core/src/main/java/haveno/core/trade/ArbitratorTrade.java b/core/src/main/java/haveno/core/trade/ArbitratorTrade.java index 03b0d20215..ea179a655a 100644 --- a/core/src/main/java/haveno/core/trade/ArbitratorTrade.java +++ b/core/src/main/java/haveno/core/trade/ArbitratorTrade.java @@ -1,3 +1,20 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.trade; import haveno.common.proto.ProtoUtil; @@ -11,6 +28,8 @@ import lombok.extern.slf4j.Slf4j; import java.math.BigInteger; import java.util.UUID; +import javax.annotation.Nullable; + /** * Trade in the context of an arbitrator. */ @@ -19,19 +38,19 @@ public class ArbitratorTrade extends Trade { public ArbitratorTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, NodeAddress makerNodeAddress, NodeAddress takerNodeAddress, - NodeAddress arbitratorNodeAddress) { - super(offer, tradeAmount, takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, arbitratorNodeAddress); + NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { + super(offer, tradeAmount, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, arbitratorNodeAddress, challenge); } @Override - public BigInteger getPayoutAmount() { + public BigInteger getPayoutAmountBeforeCost() { throw new RuntimeException("Arbitrator does not have a payout amount"); } @@ -59,14 +78,14 @@ public class ArbitratorTrade extends Trade { return fromProto(new ArbitratorTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, uid, proto.getProcessModel().getMaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getMaker().getNodeAddress()) : null, proto.getProcessModel().getTaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getTaker().getNodeAddress()) : null, - proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null), + proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null, + ProtoUtil.stringOrNullFromProto(proto.getChallenge())), proto, coreProtoResolver); } diff --git a/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java b/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java index 5b4b0a62e5..ca38f1ca06 100644 --- a/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java +++ b/core/src/main/java/haveno/core/trade/BuyerAsMakerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -28,6 +28,8 @@ import lombok.extern.slf4j.Slf4j; import java.math.BigInteger; import java.util.UUID; +import javax.annotation.Nullable; + @Slf4j public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade { @@ -37,24 +39,24 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade { public BuyerAsMakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takeOfferFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, NodeAddress makerNodeAddress, NodeAddress takerNodeAddress, - NodeAddress arbitratorNodeAddress) { + NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { super(offer, tradeAmount, - takeOfferFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -81,14 +83,14 @@ public final class BuyerAsMakerTrade extends BuyerTrade implements MakerTrade { BuyerAsMakerTrade trade = new BuyerAsMakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, uid, proto.getProcessModel().getMaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getMaker().getNodeAddress()) : null, proto.getProcessModel().getTaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getTaker().getNodeAddress()) : null, - proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null); + proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null, + ProtoUtil.stringOrNullFromProto(proto.getChallenge())); trade.setPrice(proto.getPrice()); diff --git a/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java b/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java index 0582ed5081..2b9501919c 100644 --- a/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java +++ b/core/src/main/java/haveno/core/trade/BuyerAsTakerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -38,24 +38,24 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade { public BuyerAsTakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } @@ -83,14 +83,14 @@ public final class BuyerAsTakerTrade extends BuyerTrade implements TakerTrade { return fromProto(new BuyerAsTakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, uid, proto.getProcessModel().getMaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getMaker().getNodeAddress()) : null, proto.getProcessModel().getTaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getTaker().getNodeAddress()) : null, - proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null), + proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null, + ProtoUtil.stringOrNullFromProto(proto.getChallenge())), proto, coreProtoResolver); } diff --git a/core/src/main/java/haveno/core/trade/BuyerTrade.java b/core/src/main/java/haveno/core/trade/BuyerTrade.java index 315bf9eb25..9de8f1e03f 100644 --- a/core/src/main/java/haveno/core/trade/BuyerTrade.java +++ b/core/src/main/java/haveno/core/trade/BuyerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -32,30 +32,30 @@ import static com.google.common.base.Preconditions.checkNotNull; public abstract class BuyerTrade extends Trade { BuyerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, @Nullable NodeAddress takerNodeAddress, @Nullable NodeAddress makerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, takerNodeAddress, makerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } @Override - public BigInteger getPayoutAmount() { + public BigInteger getPayoutAmountBeforeCost() { checkNotNull(getAmount(), "Invalid state: getTradeAmount() = null"); - return checkNotNull(getOffer()).getBuyerSecurityDeposit().add(getAmount()); + return getAmount().add(getBuyerSecurityDepositBeforeMiningFee()); } @Override diff --git a/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java b/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java index 5fdb2dbd73..ee10d599ee 100644 --- a/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java +++ b/core/src/main/java/haveno/core/trade/CleanupMailboxMessages.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; +import com.google.inject.Inject; import haveno.common.crypto.PubKeyRing; import haveno.common.proto.network.NetworkEnvelope; import haveno.core.trade.messages.TradeMessage; @@ -27,10 +28,8 @@ import haveno.network.p2p.DecryptedMessageWithPubKey; import haveno.network.p2p.P2PService; import haveno.network.p2p.mailbox.MailboxMessage; import haveno.network.p2p.mailbox.MailboxMessageService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.List; +import lombok.extern.slf4j.Slf4j; //TODO with the redesign of mailbox messages that is not required anymore. We leave it for now as we want to minimize // changes for the 1.5.0 release but we should clean up afterwards... @@ -64,7 +63,7 @@ public class CleanupMailboxMessages { } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { cleanupMailboxMessages(trades); } }); @@ -107,7 +106,7 @@ public class CleanupMailboxMessages { } private boolean isMyMessage(TradeMessage message, Trade trade) { - return message.getTradeId().equals(trade.getId()); + return message.getOfferId().equals(trade.getId()); } private boolean isMyMessage(AckMessage ackMessage, Trade trade) { diff --git a/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java b/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java index eab604b6f6..3b4f244e3f 100644 --- a/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java +++ b/core/src/main/java/haveno/core/trade/CleanupMailboxMessagesService.java @@ -1,23 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; -import haveno.common.crypto.PubKeyRing; +import com.google.inject.Inject; import haveno.common.proto.network.NetworkEnvelope; import haveno.core.trade.messages.TradeMessage; import haveno.network.p2p.AckMessage; @@ -27,10 +27,8 @@ import haveno.network.p2p.DecryptedMessageWithPubKey; import haveno.network.p2p.P2PService; import haveno.network.p2p.mailbox.MailboxMessage; import haveno.network.p2p.mailbox.MailboxMessageService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.List; +import lombok.extern.slf4j.Slf4j; //TODO with the redesign of mailbox messages that is not required anymore. We leave it for now as we want to minimize // changes for the 1.5.0 release but we should clean up afterwards... @@ -64,7 +62,7 @@ public class CleanupMailboxMessagesService { } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { cleanupMailboxMessages(trades); } }); @@ -107,7 +105,7 @@ public class CleanupMailboxMessagesService { } private boolean isMyMessage(TradeMessage message, Trade trade) { - return message.getTradeId().equals(trade.getId()); + return message.getOfferId().equals(trade.getId()); } private boolean isMyMessage(AckMessage ackMessage, Trade trade) { @@ -116,15 +114,6 @@ public class CleanupMailboxMessagesService { } private boolean isPubKeyValid(DecryptedMessageWithPubKey decryptedMessageWithPubKey, Trade trade) { - // We can only validate the peers pubKey if we have it already. If we are the taker we get it from the offer - // Otherwise it depends on the state of the trade protocol if we have received the peers pubKeyRing already. - PubKeyRing peersPubKeyRing = trade.getTradePeer().getPubKeyRing(); - boolean isValid = true; - if (peersPubKeyRing != null && - !decryptedMessageWithPubKey.getSignaturePubKey().equals(peersPubKeyRing.getSignaturePubKey())) { - isValid = false; - log.warn("SignaturePubKey in decryptedMessageWithPubKey does not match the SignaturePubKey we have set for our trading peer."); - } - return isValid; + return trade.getProtocol().isPubKeyValid(decryptedMessageWithPubKey); } } diff --git a/core/src/main/java/haveno/core/trade/ClosedTradableFormatter.java b/core/src/main/java/haveno/core/trade/ClosedTradableFormatter.java index 5f8ca1211e..db42547d45 100644 --- a/core/src/main/java/haveno/core/trade/ClosedTradableFormatter.java +++ b/core/src/main/java/haveno/core/trade/ClosedTradableFormatter.java @@ -1,39 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.monetary.CryptoMoney; import haveno.core.monetary.TraditionalMoney; import haveno.core.monetary.Volume; import haveno.core.offer.OpenOffer; -import haveno.core.util.FormattingUtils; -import lombok.extern.slf4j.Slf4j; -import org.bitcoinj.core.Monetary; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.math.BigInteger; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static haveno.core.trade.ClosedTradableUtil.castToTrade; import static haveno.core.trade.ClosedTradableUtil.getTotalTxFee; import static haveno.core.trade.ClosedTradableUtil.getTotalVolumeByCurrency; @@ -42,10 +33,17 @@ import static haveno.core.trade.ClosedTradableUtil.isOpenOffer; import static haveno.core.trade.Trade.DisputeState.DISPUTE_CLOSED; import static haveno.core.trade.Trade.DisputeState.MEDIATION_CLOSED; import static haveno.core.trade.Trade.DisputeState.REFUND_REQUEST_CLOSED; +import haveno.core.util.FormattingUtils; import static haveno.core.util.FormattingUtils.formatPercentagePrice; import static haveno.core.util.FormattingUtils.formatToPercentWithSymbol; import static haveno.core.util.VolumeUtil.formatVolume; import static haveno.core.util.VolumeUtil.formatVolumeWithCode; +import java.math.BigInteger; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.bitcoinj.core.Monetary; @Slf4j @Singleton @@ -85,11 +83,19 @@ public class ClosedTradableFormatter { } public String getBuyerSecurityDepositAsString(Tradable tradable) { - return HavenoUtils.formatXmr(tradable.getOffer().getBuyerSecurityDeposit()); + if (tradable instanceof Trade) { + Trade trade = castToTrade(tradable); + return HavenoUtils.formatXmr(trade.getBuyerSecurityDepositBeforeMiningFee()); + } + return HavenoUtils.formatXmr(tradable.getOffer().getMaxBuyerSecurityDeposit()); } public String getSellerSecurityDepositAsString(Tradable tradable) { - return HavenoUtils.formatXmr(tradable.getOffer().getSellerSecurityDeposit()); + if (tradable instanceof Trade) { + Trade trade = castToTrade(tradable); + return HavenoUtils.formatXmr(trade.getSellerSecurityDepositBeforeMiningFee()); + } + return HavenoUtils.formatXmr(tradable.getOffer().getMaxSellerSecurityDeposit()); } public String getTradeFeeAsString(Tradable tradable, boolean appendCode) { diff --git a/core/src/main/java/haveno/core/trade/ClosedTradableManager.java b/core/src/main/java/haveno/core/trade/ClosedTradableManager.java index a86b82aa2d..0a48fc5188 100644 --- a/core/src/main/java/haveno/core/trade/ClosedTradableManager.java +++ b/core/src/main/java/haveno/core/trade/ClosedTradableManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -216,8 +216,8 @@ public class ClosedTradableManager implements PersistedDataHost { public BigInteger getXmrTradeFee(Tradable tradable) { return isMaker(tradable) ? - tradable.getOptionalMakerFee().orElse(BigInteger.valueOf(0)) : - tradable.getOptionalTakerFee().orElse(BigInteger.valueOf(0)); + tradable.getOptionalMakerFee().orElse(BigInteger.ZERO) : + tradable.getOptionalTakerFee().orElse(BigInteger.ZERO); } public boolean isMaker(Tradable tradable) { @@ -227,4 +227,12 @@ public class ClosedTradableManager implements PersistedDataHost { private void requestPersistence() { persistenceManager.requestPersistence(); } + + public void removeTrade(Trade trade) { + synchronized (closedTradables) { + if (closedTradables.remove(trade)) { + requestPersistence(); + } + } + } } diff --git a/core/src/main/java/haveno/core/trade/ClosedTradableUtil.java b/core/src/main/java/haveno/core/trade/ClosedTradableUtil.java index 8a093d8031..82c9a29239 100644 --- a/core/src/main/java/haveno/core/trade/ClosedTradableUtil.java +++ b/core/src/main/java/haveno/core/trade/ClosedTradableUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -41,6 +41,14 @@ public class ClosedTradableUtil { public static Map<String, Long> getTotalVolumeByCurrency(List<Tradable> tradableList) { Map<String, Long> map = new HashMap<>(); tradableList.stream() + .filter(tradable -> { + if (tradable instanceof Trade) { + Trade trade = castToTrade(tradable); + return trade.isCompleted(); // TODO: does not consider if trade was reverted by arbitrator + } else { + return false; + } + }) .flatMap(tradable -> tradable.getOptionalVolume().stream()) .forEach(volume -> { String currencyCode = volume.getCurrencyCode(); diff --git a/core/src/main/java/haveno/core/trade/Contract.java b/core/src/main/java/haveno/core/trade/Contract.java index 71a360f910..9a88eaff56 100644 --- a/core/src/main/java/haveno/core/trade/Contract.java +++ b/core/src/main/java/haveno/core/trade/Contract.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -19,6 +36,7 @@ package haveno.core.trade; import com.google.protobuf.ByteString; import haveno.common.crypto.PubKeyRing; +import haveno.common.proto.ProtoUtil; import haveno.common.proto.network.NetworkPayload; import haveno.common.util.JsonExclude; import haveno.common.util.Utilities; @@ -36,6 +54,7 @@ import org.apache.commons.lang3.StringUtils; import javax.annotation.Nullable; import java.math.BigInteger; +import java.util.Optional; import static com.google.common.base.Preconditions.checkArgument; @@ -62,6 +81,7 @@ public final class Contract implements NetworkPayload { private final String makerPayoutAddressString; private final String takerPayoutAddressString; private final String makerDepositTxHash; + @Nullable private final String takerDepositTxHash; public Contract(OfferPayload offerPayload, @@ -82,7 +102,7 @@ public final class Contract implements NetworkPayload { String makerPayoutAddressString, String takerPayoutAddressString, String makerDepositTxHash, - String takerDepositTxHash) { + @Nullable String takerDepositTxHash) { this.offerPayload = offerPayload; this.tradeAmount = tradeAmount; this.tradePrice = tradePrice; @@ -117,6 +137,31 @@ public final class Contract implements NetworkPayload { // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// + @Override + public protobuf.Contract toProtoMessage() { + protobuf.Contract.Builder builder = protobuf.Contract.newBuilder() + .setOfferPayload(offerPayload.toProtoMessage().getOfferPayload()) + .setTradeAmount(tradeAmount) + .setTradePrice(tradePrice) + .setBuyerNodeAddress(buyerNodeAddress.toProtoMessage()) + .setSellerNodeAddress(sellerNodeAddress.toProtoMessage()) + .setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()) + .setIsBuyerMakerAndSellerTaker(isBuyerMakerAndSellerTaker) + .setMakerAccountId(makerAccountId) + .setTakerAccountId(takerAccountId) + .setMakerPaymentMethodId(makerPaymentMethodId) + .setTakerPaymentMethodId(takerPaymentMethodId) + .setMakerPaymentAccountPayloadHash(ByteString.copyFrom(makerPaymentAccountPayloadHash)) + .setTakerPaymentAccountPayloadHash(ByteString.copyFrom(takerPaymentAccountPayloadHash)) + .setMakerPubKeyRing(makerPubKeyRing.toProtoMessage()) + .setTakerPubKeyRing(takerPubKeyRing.toProtoMessage()) + .setMakerPayoutAddressString(makerPayoutAddressString) + .setTakerPayoutAddressString(takerPayoutAddressString) + .setMakerDepositTxHash(makerDepositTxHash); + Optional.ofNullable(takerDepositTxHash).ifPresent(builder::setTakerDepositTxHash); + return builder.build(); + } + public static Contract fromProto(protobuf.Contract proto, CoreProtoResolver coreProtoResolver) { return new Contract(OfferPayload.fromProto(proto.getOfferPayload()), proto.getTradeAmount(), @@ -136,32 +181,7 @@ public final class Contract implements NetworkPayload { proto.getMakerPayoutAddressString(), proto.getTakerPayoutAddressString(), proto.getMakerDepositTxHash(), - proto.getTakerDepositTxHash()); - } - - @Override - public protobuf.Contract toProtoMessage() { - return protobuf.Contract.newBuilder() - .setOfferPayload(offerPayload.toProtoMessage().getOfferPayload()) - .setTradeAmount(tradeAmount) - .setTradePrice(tradePrice) - .setBuyerNodeAddress(buyerNodeAddress.toProtoMessage()) - .setSellerNodeAddress(sellerNodeAddress.toProtoMessage()) - .setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage()) - .setIsBuyerMakerAndSellerTaker(isBuyerMakerAndSellerTaker) - .setMakerAccountId(makerAccountId) - .setTakerAccountId(takerAccountId) - .setMakerPaymentMethodId(makerPaymentMethodId) - .setTakerPaymentMethodId(takerPaymentMethodId) - .setMakerPaymentAccountPayloadHash(ByteString.copyFrom(makerPaymentAccountPayloadHash)) - .setTakerPaymentAccountPayloadHash(ByteString.copyFrom(takerPaymentAccountPayloadHash)) - .setMakerPubKeyRing(makerPubKeyRing.toProtoMessage()) - .setTakerPubKeyRing(takerPubKeyRing.toProtoMessage()) - .setMakerPayoutAddressString(makerPayoutAddressString) - .setTakerPayoutAddressString(takerPayoutAddressString) - .setMakerDepositTxHash(makerDepositTxHash) - .setTakerDepositTxHash(takerDepositTxHash) - .build(); + ProtoUtil.stringOrNullFromProto(proto.getTakerDepositTxHash())); } @@ -246,7 +266,13 @@ public final class Contract implements NetworkPayload { // edits a contract json string public static String sanitizeContractAsJson(String contractAsJson) { - return contractAsJson; // TODO: anything to sanitize? + return contractAsJson + .replaceAll( + "\"takerPaymentAccountPayload\": \\{[^}]*}", + "\"takerPaymentAccountPayload\": null") + .replaceAll( + "\"makerPaymentAccountPayload\": \\{[^}]*}", + "\"makerPaymentAccountPayload\": null"); } public void printDiff(@Nullable String peersContractAsJson) { diff --git a/core/src/main/java/haveno/core/trade/HavenoUtils.java b/core/src/main/java/haveno/core/trade/HavenoUtils.java index c41a96d55f..fcd5c556e1 100644 --- a/core/src/main/java/haveno/core/trade/HavenoUtils.java +++ b/core/src/main/java/haveno/core/trade/HavenoUtils.java @@ -19,41 +19,62 @@ package haveno.core.trade; import com.google.common.base.CaseFormat; import com.google.common.base.Charsets; + +import common.utils.GenUtils; import haveno.common.config.Config; import haveno.common.crypto.CryptoException; import haveno.common.crypto.Hash; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; import haveno.common.crypto.Sig; +import haveno.common.file.FileUtil; +import haveno.common.util.Base64; import haveno.common.util.Utilities; +import haveno.core.api.CoreNotificationService; +import haveno.core.api.XmrConnectionService; import haveno.core.app.HavenoSetup; import haveno.core.offer.OfferPayload; +import haveno.core.offer.OpenOfferManager; import haveno.core.support.dispute.arbitration.ArbitrationManager; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; -import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.messages.PaymentReceivedMessage; import haveno.core.trade.messages.PaymentSentMessage; +import haveno.core.user.Preferences; import haveno.core.util.JsonUtil; +import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.NodeAddress; + +import java.io.File; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.InetAddress; import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.security.PrivateKey; +import java.security.SecureRandom; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Collection; +import java.util.Calendar; +import java.util.Date; import java.util.List; import java.util.Locale; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nullable; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.SourceDataLine; + import lombok.extern.slf4j.Slf4j; import monero.common.MoneroRpcConnection; +import monero.daemon.model.MoneroOutput; +import monero.wallet.model.MoneroDestination; +import monero.wallet.model.MoneroTxWallet; + import org.bitcoinj.core.Coin; /** @@ -62,8 +83,37 @@ import org.bitcoinj.core.Coin; @Slf4j public class HavenoUtils { - // Use the US locale as a base for all DecimalFormats (commas should be omitted from number strings). - private static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = DecimalFormatSymbols.getInstance(Locale.US); + // configure release date + private static final String RELEASE_DATE = "25-05-2024 00:00:00"; // optionally set to release date of the network in format dd-mm-yyyy to impose temporary limits, etc. e.g. "25-05-2024 00:00:00" + public static final int RELEASE_LIMIT_DAYS = 60; // number of days to limit sell offers to max buy limit for new accounts + public static final int WARN_ON_OFFER_EXCEEDS_UNSIGNED_BUY_LIMIT_DAYS = 182; // number of days to warn if sell offer exceeds unsigned buy limit + public static final int ARBITRATOR_ACK_TIMEOUT_SECONDS = 60; + + // configure fees + public static final boolean ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS = true; + public static final double PENALTY_FEE_PCT = 0.02; // 2% + public static final double MAKER_FEE_PCT = 0.0015; // 0.15% + public static final double TAKER_FEE_PCT = 0.0075; // 0.75% + public static final double MAKER_FEE_FOR_TAKER_WITHOUT_DEPOSIT_PCT = MAKER_FEE_PCT + TAKER_FEE_PCT; // customize maker's fee when no deposit or fee from taker + + // other configuration + public static final long LOG_POLL_ERROR_PERIOD_MS = 1000 * 60 * 4; // log poll errors up to once every 4 minutes + public static final long LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS = 1000 * 30; // log warnings when daemon not synced once every 30s + public static final int PRIVATE_OFFER_PASSPHRASE_NUM_WORDS = 8; // number of words in a private offer passphrase + + // synchronize requests to the daemon + private static boolean SYNC_DAEMON_REQUESTS = false; // sync long requests to daemon (e.g. refresh, update pool) // TODO: performance suffers by syncing daemon requests, but otherwise we sometimes get sporadic errors? + private static boolean SYNC_WALLET_REQUESTS = false; // additionally sync wallet functions to daemon (e.g. create txs) + private static Object DAEMON_LOCK = new Object(); + public static Object getDaemonLock() { + return SYNC_DAEMON_REQUESTS ? DAEMON_LOCK : new Object(); + } + public static Object getWalletFunctionLock() { + return SYNC_WALLET_REQUESTS ? getDaemonLock() : new Object(); + } + + // non-configurable + public static final DecimalFormatSymbols DECIMAL_FORMAT_SYMBOLS = DecimalFormatSymbols.getInstance(Locale.US); // use the US locale as a base for all DecimalFormats (commas should be omitted from number strings) public static int XMR_SMALLEST_UNIT_EXPONENT = 12; public static final String LOOPBACK_HOST = "127.0.0.1"; // local loopback address to host Monero node public static final String LOCALHOST = "localhost"; @@ -71,12 +121,49 @@ public class HavenoUtils { private static final BigInteger XMR_AU_MULTIPLIER = new BigInteger("1000000000000"); public static final DecimalFormat XMR_FORMATTER = new DecimalFormat("##############0.000000000000", DECIMAL_FORMAT_SYMBOLS); public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss"); - private static final int POOL_SIZE = 10; - private static final ExecutorService POOL = Executors.newFixedThreadPool(POOL_SIZE); - // TODO: better way to share references? - public static ArbitrationManager arbitrationManager; + // shared references TODO: better way to share references? public static HavenoSetup havenoSetup; + public static ArbitrationManager arbitrationManager; + public static XmrWalletService xmrWalletService; + public static XmrConnectionService xmrConnectionService; + public static OpenOfferManager openOfferManager; + public static CoreNotificationService notificationService; + public static Preferences preferences; + + public static boolean isSeedNode() { + return havenoSetup == null; + } + + public static boolean isDaemon() { + if (isSeedNode()) return true; + return havenoSetup.getCoreContext().isApiUser(); + } + + @SuppressWarnings("unused") + public static Date getReleaseDate() { + if (RELEASE_DATE == null) return null; + try { + return DATE_FORMAT.parse(RELEASE_DATE); + } catch (Exception e) { + log.error("Failed to parse release date: " + RELEASE_DATE, e); + throw new IllegalArgumentException(e); + } + } + + public static boolean isReleasedWithinDays(int days) { + Date releaseDate = getReleaseDate(); + if (releaseDate == null) return false; + Calendar calendar = Calendar.getInstance(); + calendar.setTime(releaseDate); + calendar.add(Calendar.DATE, days); + Date releaseDatePlusDays = calendar.getTime(); + return new Date().before(releaseDatePlusDays); + } + + public static void waitFor(long waitMs) { + GenUtils.waitFor(waitMs); + } // ----------------------- CONVERSION UTILS ------------------------------- @@ -97,7 +184,7 @@ public class HavenoUtils { } public static long atomicUnitsToCentineros(long atomicUnits) { - return atomicUnits / CENTINEROS_AU_MULTIPLIER; + return atomicUnitsToCentineros(BigInteger.valueOf(atomicUnits)); } public static long atomicUnitsToCentineros(BigInteger atomicUnits) { @@ -121,7 +208,7 @@ public class HavenoUtils { } public static BigInteger xmrToAtomicUnits(double xmr) { - return BigDecimal.valueOf(xmr).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger(); + return new BigDecimal(xmr).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger(); } public static long xmrToCentineros(double xmr) { @@ -133,7 +220,11 @@ public class HavenoUtils { } public static double divide(BigInteger auDividend, BigInteger auDivisor) { - return (double) atomicUnitsToCentineros(auDividend) / (double) atomicUnitsToCentineros(auDivisor); + return atomicUnitsToXmr(auDividend) / atomicUnitsToXmr(auDivisor); + } + + public static BigInteger multiply(BigInteger amount1, double amount2) { + return amount1 == null ? null : new BigDecimal(amount1).multiply(BigDecimal.valueOf(amount2)).toBigInteger(); } // ------------------------- FORMAT UTILS --------------------------------- @@ -175,6 +266,10 @@ public class HavenoUtils { return applyDecimals(formatted, Math.max(2, decimalPlaces)) + (appendCode ? " XMR" : ""); } + public static String formatPercent(double percent) { + return (percent * 100) + "%"; + } + private static String applyDecimals(String decimalStr, int decimalPlaces) { if (decimalStr.contains(".")) return decimalStr + getNumZeros(decimalPlaces - (decimalStr.length() - decimalStr.indexOf(".") - 1)); else return decimalStr + "." + getNumZeros(decimalPlaces); @@ -187,60 +282,51 @@ public class HavenoUtils { } public static BigInteger parseXmr(String input) { - if (input == null || input.length() == 0) return BigInteger.valueOf(0); + if (input == null || input.length() == 0) return BigInteger.ZERO; try { - return xmrToAtomicUnits(new BigDecimal(input).doubleValue()); + return new BigDecimal(input).multiply(new BigDecimal(XMR_AU_MULTIPLIER)).toBigInteger(); } catch (Exception e) { - return BigInteger.valueOf(0); + return BigInteger.ZERO; } } - // ------------------------------ FEE UTILS ------------------------------- - - @Nullable - public static BigInteger getMakerFee(@Nullable BigInteger amount) { - if (amount != null) { - BigInteger feePerXmr = getFeePerXmr(HavenoUtils.getMakerFeePerXmr(), amount); - return feePerXmr.max(HavenoUtils.getMinMakerFee()); - } else { - return null; - } - } - - @Nullable - public static BigInteger getTakerFee(@Nullable BigInteger amount) { - if (amount != null) { - BigInteger feePerXmr = HavenoUtils.getFeePerXmr(HavenoUtils.getTakerFeePerXmr(), amount); - return feePerXmr.max(HavenoUtils.getMinTakerFee()); - } else { - return null; - } - } - - private static BigInteger getMakerFeePerXmr() { - return HavenoUtils.xmrToAtomicUnits(0.001); - } - - public static BigInteger getMinMakerFee() { - return HavenoUtils.xmrToAtomicUnits(0.00005); - } - - private static BigInteger getTakerFeePerXmr() { - return HavenoUtils.xmrToAtomicUnits(0.003); - } - - public static BigInteger getMinTakerFee() { - return HavenoUtils.xmrToAtomicUnits(0.00005); - } - - public static BigInteger getFeePerXmr(BigInteger feePerXmr, BigInteger amount) { - BigDecimal feePerXmrAsDecimal = feePerXmr == null ? BigDecimal.valueOf(0) : new BigDecimal(feePerXmr); - BigDecimal amountMultiplier = BigDecimal.valueOf(divide(amount == null ? BigInteger.valueOf(0) : amount, HavenoUtils.xmrToAtomicUnits(1.0))); - return feePerXmrAsDecimal.multiply(amountMultiplier).toBigInteger(); - } - // ------------------------ SIGNING AND VERIFYING ------------------------- + public static String generateChallenge() { + try { + + // load bip39 words + String fileName = "bip39_english.txt"; + File bip39File = new File(havenoSetup.getConfig().appDataDir, fileName); + if (!bip39File.exists()) FileUtil.resourceToFile(fileName, bip39File); + List<String> bip39Words = Files.readAllLines(bip39File.toPath(), StandardCharsets.UTF_8); + + // select words randomly + List<String> passphraseWords = new ArrayList<String>(); + SecureRandom secureRandom = new SecureRandom(); + for (int i = 0; i < PRIVATE_OFFER_PASSPHRASE_NUM_WORDS; i++) { + passphraseWords.add(bip39Words.get(secureRandom.nextInt(bip39Words.size()))); + } + return String.join(" ", passphraseWords); + } catch (Exception e) { + throw new IllegalStateException("Failed to generate challenge", e); + } + } + + public static String getChallengeHash(String challenge) { + if (challenge == null) return null; + + // tokenize passphrase + String[] words = challenge.toLowerCase().split(" "); + + // collect first 4 letters of each word, which are unique in bip39 + List<String> prefixes = new ArrayList<String>(); + for (String word : words) prefixes.add(word.substring(0, Math.min(word.length(), 4))); + + // hash the result + return Base64.encode(Hash.getSha256Hash(String.join(" ", prefixes).getBytes())); + } + public static byte[] sign(KeyRing keyRing, String message) { return sign(keyRing.getSignatureKeyPair().getPrivate(), message); } @@ -309,46 +395,6 @@ public class HavenoUtils { return isSignatureValid(arbitrator.getPubKeyRing(), offer.getSignatureHash(), offer.getArbitratorSignature()); } - /** - * Check if the maker signature for a trade request is valid. - * - * @param request is the trade request to check - * @return true if the maker's signature is valid for the trade request - */ - public static boolean isMakerSignatureValid(InitTradeRequest request, byte[] signature, PubKeyRing makerPubKeyRing) { - - // re-create trade request with signed fields - InitTradeRequest signedRequest = new InitTradeRequest( - request.getTradeId(), - request.getSenderNodeAddress(), - request.getPubKeyRing(), - request.getTradeAmount(), - request.getTradePrice(), - request.getTradeFee(), - request.getAccountId(), - request.getPaymentAccountId(), - request.getPaymentMethodId(), - request.getUid(), - request.getMessageVersion(), - request.getAccountAgeWitnessSignatureOfOfferId(), - request.getCurrentDate(), - request.getMakerNodeAddress(), - request.getTakerNodeAddress(), - null, - null, - null, - null, - request.getPayoutAddress(), - null - ); - - // get trade request as string - String tradeRequestAsJson = JsonUtil.objectToJson(signedRequest); - - // verify maker signature - return isSignatureValid(makerPubKeyRing, tradeRequestAsJson, signature); - } - /** * Verify the buyer signature for a PaymentSentMessage. * @@ -374,7 +420,7 @@ public class HavenoUtils { } // verify trade id - if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); + if (!trade.getId().equals(message.getOfferId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getOfferId()); } /** @@ -402,20 +448,15 @@ public class HavenoUtils { } // verify trade id - if (!trade.getId().equals(message.getTradeId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getTradeId()); + if (!trade.getId().equals(message.getOfferId())) throw new IllegalArgumentException("The " + message.getClass().getSimpleName() + " has the wrong trade id, expected " + trade.getId() + " but was " + message.getOfferId()); // verify buyer signature of payment sent message - verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); + if (message.getPaymentSentMessage() != null) verifyPaymentSentMessage(trade, message.getPaymentSentMessage()); } // ----------------------------- OTHER UTILS ------------------------------ - /** - * Get address to collect trade fees. - * - * @return the address which collects trade fees - */ - public static String getTradeFeeAddress() { + public static String getGlobalTradeFeeAddress() { switch (Config.baseCurrencyNetwork()) { case XMR_LOCAL: return "Bd37nTGHjL3RvPxc9dypzpWiXQrPzxxG4RsWAasD9CV2iZ1xfFZ7mzTKNDxWBfsqQSUimctAsGtTZ8c8bZJy35BYL9jYj88"; @@ -428,15 +469,48 @@ public class HavenoUtils { } } + public static String getBurnAddress() { + switch (Config.baseCurrencyNetwork()) { + case XMR_LOCAL: + return "Bd37nTGHjL3RvPxc9dypzpWiXQrPzxxG4RsWAasD9CV2iZ1xfFZ7mzTKNDxWBfsqQSUimctAsGtTZ8c8bZJy35BYL9jYj88"; + case XMR_STAGENET: + return "577XbZ8yGfrWJM3aAoCpHVgDCm5higshGVJBb4ZNpTYARp8rLcCdcA1J8QgRfFWTzmJ8QgRfFWTzmJ8QgRfFWTzmCbXF9hd"; + case XMR_MAINNET: + return "46uVWiE1d4kWJM3aAoCpHVgDCm5higshGVJBb4ZNpTYARp8rLcCdcA1J8QgRfFWTzmJ8QgRfFWTzmJ8QgRfFWTzmCag5CXT"; + default: + throw new RuntimeException("Unhandled base currency network: " + Config.baseCurrencyNetwork()); + } + } + /** * Check if the given URI is on local host. */ - public static boolean isLocalHost(String uri) { + public static boolean isLocalHost(String uriString) { try { - String host = new URI(uri).getHost(); + String host = new URI(uriString).getHost(); return LOOPBACK_HOST.equals(host) || LOCALHOST.equals(host); } catch (Exception e) { - throw new RuntimeException(e); + return false; + } + } + + /** + * Check if the given URI is local or a private IP address. + */ + public static boolean isPrivateIp(String uriString) { + if (isLocalHost(uriString)) return true; + try { + + // get the host + URI uri = new URI(uriString); + String host = uri.getHost(); + + // check if private IP address + if (host == null) return false; + InetAddress inetAddress = InetAddress.getByName(host); + return inetAddress.isAnyLocalAddress() || inetAddress.isLoopbackAddress() || inetAddress.isSiteLocalAddress(); + } catch (Exception e) { + return false; } } @@ -461,54 +535,6 @@ public class HavenoUtils { } } - /** - * Submit tasks to a global thread pool. - */ - public static Future<?> submitTask(Runnable task) { - return POOL.submit(task); - } - - public static List<Future<?>> submitTasks(List<Runnable> tasks) { - List<Future<?>> futures = new ArrayList<>(); - for (Runnable task : tasks) futures.add(submitTask(task)); - return futures; - } - - // TODO: replace with GenUtils.executeTasks() once monero-java updated - - public static void executeTasks(Collection<Runnable> tasks) { - executeTasks(tasks, tasks.size()); - } - - public static void executeTasks(Collection<Runnable> tasks, int maxConcurrency) { - executeTasks(tasks, maxConcurrency, null); - } - - public static void executeTasks(Collection<Runnable> tasks, int maxConcurrency, Long timeoutSeconds) { - if (tasks.isEmpty()) return; - ExecutorService pool = Executors.newFixedThreadPool(maxConcurrency); - List<Future<?>> futures = new ArrayList<>(); - for (Runnable task : tasks) futures.add(pool.submit(task)); - pool.shutdown(); - - // interrupt after timeout - if (timeoutSeconds != null) { - try { - if (!pool.awaitTermination(timeoutSeconds, TimeUnit.SECONDS)) pool.shutdownNow(); - } catch (InterruptedException e) { - pool.shutdownNow(); - throw new RuntimeException(e); - } - } - - // throw exception from any tasks - try { - for (Future<?> future : futures) future.get(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - public static String toCamelCase(String underscore) { return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, underscore); } @@ -518,4 +544,109 @@ public class HavenoUtils { if (c1 == null) return false; return c1.equals(c2); // equality considers uri, username, and password } + + // TODO: move to monero-java MoneroTxWallet + public static MoneroDestination getDestination(String address, MoneroTxWallet tx) { + for (MoneroDestination destination : tx.getOutgoingTransfer().getDestinations()) { + if (address.equals(destination.getAddress())) return destination; + } + return null; + } + + public static List<String> getInputKeyImages(MoneroTxWallet tx) { + List<String> inputKeyImages = new ArrayList<String>(); + for (MoneroOutput input : tx.getInputs()) inputKeyImages.add(input.getKeyImage().getHex()); + return inputKeyImages; + } + + public static int getDefaultMoneroPort() { + if (Config.baseCurrencyNetwork().isMainnet()) return 18081; + else if (Config.baseCurrencyNetwork().isTestnet()) return 28081; + else if (Config.baseCurrencyNetwork().isStagenet()) return 38081; + else throw new RuntimeException("Base network is not local testnet, stagenet, or mainnet"); + } + + public static void setTopError(String msg) { + havenoSetup.getTopErrorMsg().set(msg); + } + + public static boolean isConnectionRefused(Throwable e) { + return e != null && e.getMessage().contains("Connection refused"); + } + + public static boolean isReadTimeout(Throwable e) { + return e != null && e.getMessage().contains("Read timed out"); + } + + public static boolean isUnresponsive(Throwable e) { + return isConnectionRefused(e) || isReadTimeout(e); + } + + public static boolean isNotEnoughSigners(Throwable e) { + return e != null && e.getMessage().contains("Not enough signers"); + } + + public static boolean isTransactionRejected(Throwable e) { + return e != null && e.getMessage().contains("was rejected"); + } + + public static boolean isIllegal(Throwable e) { + return e instanceof IllegalArgumentException || e instanceof IllegalStateException; + } + + public static void playChimeSound() { + playAudioFile("chime.wav"); + } + + public static void playCashRegisterSound() { + playAudioFile("cash_register.wav"); + } + + private static void playAudioFile(String fileName) { + if (isDaemon()) return; // ignore if running as daemon + if (!preferences.getUseSoundForNotificationsProperty().get()) return; // ignore if sounds disabled + new Thread(() -> { + try { + + // get audio file + File wavFile = new File(havenoSetup.getConfig().appDataDir, fileName); + if (!wavFile.exists()) FileUtil.resourceToFile(fileName, wavFile); + AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(wavFile); + + // get original format + AudioFormat baseFormat = audioInputStream.getFormat(); + + // set target format: PCM_SIGNED, 16-bit, 44100 Hz + AudioFormat targetFormat = new AudioFormat( + AudioFormat.Encoding.PCM_SIGNED, + 44100.0f, + 16, // 16-bit instead of 32-bit float + baseFormat.getChannels(), + baseFormat.getChannels() * 2, // Frame size: 2 bytes per channel (16-bit) + 44100.0f, + false // Little-endian + ); + + // convert audio to target format + AudioInputStream convertedStream = AudioSystem.getAudioInputStream(targetFormat, audioInputStream); + + // play audio + DataLine.Info info = new DataLine.Info(SourceDataLine.class, targetFormat); + SourceDataLine sourceLine = (SourceDataLine) AudioSystem.getLine(info); + sourceLine.open(targetFormat); + sourceLine.start(); + byte[] buffer = new byte[1024]; + int bytesRead = 0; + while ((bytesRead = convertedStream.read(buffer, 0, buffer.length)) != -1) { + sourceLine.write(buffer, 0, bytesRead); + } + sourceLine.drain(); + sourceLine.close(); + convertedStream.close(); + audioInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } } diff --git a/core/src/main/java/haveno/core/trade/MakerTrade.java b/core/src/main/java/haveno/core/trade/MakerTrade.java index dabf614031..5362e33347 100644 --- a/core/src/main/java/haveno/core/trade/MakerTrade.java +++ b/core/src/main/java/haveno/core/trade/MakerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; diff --git a/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java b/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java index cd7ac5cdcc..07f4a16157 100644 --- a/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java +++ b/core/src/main/java/haveno/core/trade/SellerAsMakerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -38,24 +38,24 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade public SellerAsMakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } @@ -83,14 +83,14 @@ public final class SellerAsMakerTrade extends SellerTrade implements MakerTrade SellerAsMakerTrade trade = new SellerAsMakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, uid, proto.getProcessModel().getMaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getMaker().getNodeAddress()) : null, proto.getProcessModel().getTaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getTaker().getNodeAddress()) : null, - proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null); + proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null, + ProtoUtil.stringOrNullFromProto(proto.getChallenge())); trade.setPrice(proto.getPrice()); diff --git a/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java b/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java index a3d0bfeb13..4b5e594a1e 100644 --- a/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java +++ b/core/src/main/java/haveno/core/trade/SellerAsTakerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -38,24 +38,24 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade public SellerAsTakerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } @@ -83,14 +83,14 @@ public final class SellerAsTakerTrade extends SellerTrade implements TakerTrade return fromProto(new SellerAsTakerTrade( Offer.fromProto(proto.getOffer()), BigInteger.valueOf(proto.getAmount()), - BigInteger.valueOf(proto.getTakerFee()), proto.getPrice(), xmrWalletService, processModel, uid, proto.getProcessModel().getMaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getMaker().getNodeAddress()) : null, proto.getProcessModel().getTaker().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getTaker().getNodeAddress()) : null, - proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null), + proto.getProcessModel().getArbitrator().hasNodeAddress() ? NodeAddress.fromProto(proto.getProcessModel().getArbitrator().getNodeAddress()) : null, + ProtoUtil.stringOrNullFromProto(proto.getChallenge())), proto, coreProtoResolver); } diff --git a/core/src/main/java/haveno/core/trade/SellerTrade.java b/core/src/main/java/haveno/core/trade/SellerTrade.java index 7b009a0d52..fae3cce7a1 100644 --- a/core/src/main/java/haveno/core/trade/SellerTrade.java +++ b/core/src/main/java/haveno/core/trade/SellerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -26,35 +26,33 @@ import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; import java.math.BigInteger; -import static com.google.common.base.Preconditions.checkNotNull; - @Slf4j public abstract class SellerTrade extends Trade { SellerTrade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { super(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } @Override - public BigInteger getPayoutAmount() { - return checkNotNull(getOffer()).getSellerSecurityDeposit(); + public BigInteger getPayoutAmountBeforeCost() { + return getSellerSecurityDepositBeforeMiningFee(); } @Override diff --git a/core/src/main/java/haveno/core/trade/TakerTrade.java b/core/src/main/java/haveno/core/trade/TakerTrade.java index 8ef0aa3012..6659d4bc11 100644 --- a/core/src/main/java/haveno/core/trade/TakerTrade.java +++ b/core/src/main/java/haveno/core/trade/TakerTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; diff --git a/core/src/main/java/haveno/core/trade/Tradable.java b/core/src/main/java/haveno/core/trade/Tradable.java index 596f4c6c93..1033987cc7 100644 --- a/core/src/main/java/haveno/core/trade/Tradable.java +++ b/core/src/main/java/haveno/core/trade/Tradable.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; @@ -57,7 +57,7 @@ public interface Tradable extends PersistablePayload { } default BigInteger getTotalTxFee() { - return asTradeModel().map(Trade::getTotalTxFee).get(); + return asTradeModel().map(Trade::getTotalTxFee).orElse(BigInteger.ZERO); } default Optional<BigInteger> getOptionalTakerFee() { @@ -65,7 +65,7 @@ public interface Tradable extends PersistablePayload { } default Optional<BigInteger> getOptionalMakerFee() { - return asTradeModel().map(Trade::getOffer).map(Offer::getMakerFee).or(() -> Optional.ofNullable(getOffer().getMakerFee())); + return asTradeModel().map(Trade::getMakerFee); } default Optional<NodeAddress> getOptionalTradePeerNodeAddress() { diff --git a/core/src/main/java/haveno/core/trade/TradableList.java b/core/src/main/java/haveno/core/trade/TradableList.java index c940cbec40..ed36c388e6 100644 --- a/core/src/main/java/haveno/core/trade/TradableList.java +++ b/core/src/main/java/haveno/core/trade/TradableList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; diff --git a/core/src/main/java/haveno/core/trade/Trade.java b/core/src/main/java/haveno/core/trade/Trade.java index 4bc6e9b62c..95b067b28a 100644 --- a/core/src/main/java/haveno/core/trade/Trade.java +++ b/core/src/main/java/haveno/core/trade/Trade.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -20,22 +37,25 @@ package haveno.core.trade; import com.google.common.base.Preconditions; import com.google.protobuf.ByteString; import com.google.protobuf.Message; - +import haveno.common.ThreadUtils; import haveno.common.UserThread; import haveno.common.crypto.Encryption; import haveno.common.crypto.PubKeyRing; import haveno.common.proto.ProtoUtil; import haveno.common.taskrunner.Model; import haveno.common.util.Utilities; -import haveno.core.api.CoreMoneroConnectionsService; import haveno.core.monetary.Price; import haveno.core.monetary.Volume; +import haveno.core.network.MessageState; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; +import haveno.core.offer.OpenOffer; import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.proto.CoreProtoResolver; import haveno.core.proto.network.CoreNetworkProtoResolver; import haveno.core.support.dispute.Dispute; +import haveno.core.support.dispute.DisputeResult; +import haveno.core.support.dispute.arbitration.ArbitrationManager; import haveno.core.support.dispute.mediation.MediationResultState; import haveno.core.support.dispute.refund.RefundResultState; import haveno.core.support.messages.ChatMessage; @@ -45,18 +65,23 @@ import haveno.core.trade.protocol.ProcessModelServiceProvider; import haveno.core.trade.protocol.TradeListener; import haveno.core.trade.protocol.TradePeer; import haveno.core.trade.protocol.TradeProtocol; +import haveno.core.trade.statistics.TradeStatistics3; import haveno.core.util.VolumeUtil; import haveno.core.xmr.model.XmrAddressEntry; +import haveno.core.xmr.wallet.XmrWalletBase; import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.AckMessage; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; +import haveno.network.p2p.network.TorNetworkNode; import javafx.beans.property.DoubleProperty; +import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyStringProperty; import javafx.beans.property.SimpleDoubleProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -69,11 +94,13 @@ import monero.common.MoneroError; import monero.common.MoneroRpcConnection; import monero.common.TaskLooper; import monero.daemon.MoneroDaemon; +import monero.daemon.model.MoneroKeyImage; import monero.daemon.model.MoneroTx; import monero.wallet.MoneroWallet; import monero.wallet.MoneroWalletRpc; import monero.wallet.model.MoneroDestination; import monero.wallet.model.MoneroMultisigSignResult; +import monero.wallet.model.MoneroOutputQuery; import monero.wallet.model.MoneroOutputWallet; import monero.wallet.model.MoneroTxConfig; import monero.wallet.model.MoneroTxQuery; @@ -106,12 +133,22 @@ import static com.google.common.base.Preconditions.checkNotNull; * stored in the task model. */ @Slf4j -public abstract class Trade implements Tradable, Model { +public abstract class Trade extends XmrWalletBase implements Tradable, Model { + @Getter + public final Object lock = new Object(); private static final String MONERO_TRADE_WALLET_PREFIX = "xmr_trade_"; - private MoneroWallet wallet; // trade wallet - private Object walletLock = new Object(); - boolean wasWalletSynced = false; + private static final long SHUTDOWN_TIMEOUT_MS = 60000; + private static final long SYNC_EVERY_NUM_BLOCKS = 360; // ~1/2 day + private static final long DELETE_AFTER_NUM_BLOCKS = 2; // if deposit requested but not published + private static final long EXTENDED_RPC_TIMEOUT = 600000; // 10 minutes + private static final long DELETE_AFTER_MS = TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS; + protected final Object pollLock = new Object(); + protected static final Object importMultisigLock = new Object(); + private boolean pollInProgress; + private boolean restartInProgress; + private Subscription protocolErrorStateSubscription; + private Subscription protocolErrorHeightSubscription; /////////////////////////////////////////////////////////////////////////////////////////// // Enums @@ -145,7 +182,7 @@ public abstract class Trade implements Tradable, Model { DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN(Phase.DEPOSITS_UNLOCKED), // payment sent - BUYER_CONFIRMED_IN_UI_PAYMENT_SENT(Phase.PAYMENT_SENT), + BUYER_CONFIRMED_PAYMENT_SENT(Phase.PAYMENT_SENT), BUYER_SENT_PAYMENT_SENT_MSG(Phase.PAYMENT_SENT), BUYER_SEND_FAILED_PAYMENT_SENT_MSG(Phase.PAYMENT_SENT), BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG(Phase.PAYMENT_SENT), @@ -153,14 +190,11 @@ public abstract class Trade implements Tradable, Model { SELLER_RECEIVED_PAYMENT_SENT_MSG(Phase.PAYMENT_SENT), // payment received - SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT(Phase.PAYMENT_RECEIVED), + SELLER_CONFIRMED_PAYMENT_RECEIPT(Phase.PAYMENT_RECEIVED), SELLER_SENT_PAYMENT_RECEIVED_MSG(Phase.PAYMENT_RECEIVED), SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG(Phase.PAYMENT_RECEIVED), SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG(Phase.PAYMENT_RECEIVED), - SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG(Phase.PAYMENT_RECEIVED), - - // trade completed - TRADE_COMPLETED(Phase.COMPLETED); + SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG(Phase.PAYMENT_RECEIVED); @NotNull public Phase getPhase() { @@ -199,8 +233,7 @@ public abstract class Trade implements Tradable, Model { DEPOSITS_CONFIRMED, DEPOSITS_UNLOCKED, PAYMENT_SENT, - PAYMENT_RECEIVED, - COMPLETED; + PAYMENT_RECEIVED; public static Trade.Phase fromProto(protobuf.Trade.Phase phase) { return ProtoUtil.enumFromProto(Trade.Phase.class, phase.name()); @@ -285,7 +318,11 @@ public abstract class Trade implements Tradable, Model { } public boolean isOpen() { - return this == DisputeState.DISPUTE_OPENED; + return isRequested() && !isClosed(); + } + + public boolean isCloseRequested() { + return this.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal(); } public boolean isClosed() { @@ -318,8 +355,6 @@ public abstract class Trade implements Tradable, Model { private final ProcessModel processModel; @Getter private final Offer offer; - private final long takerFee; - private final long totalTxFee; // Added in 1.5.1 @Getter @@ -329,7 +364,7 @@ public abstract class Trade implements Tradable, Model { private long takeOfferDate; // Initialization - private static final int TOTAL_INIT_STEPS = 15; // total estimated steps + private static final int TOTAL_INIT_STEPS = 24; // total estimated steps private int initStep = 0; @Getter private double initProgress = 0; @@ -375,20 +410,22 @@ public abstract class Trade implements Tradable, Model { // Immutable @Getter transient final private XmrWalletService xmrWalletService; - transient final private DoubleProperty initProgressProperty = new SimpleDoubleProperty(0.0); transient final private ObjectProperty<State> stateProperty = new SimpleObjectProperty<>(state); transient final private ObjectProperty<Phase> phaseProperty = new SimpleObjectProperty<>(state.phase); transient final private ObjectProperty<PayoutState> payoutStateProperty = new SimpleObjectProperty<>(payoutState); transient final private ObjectProperty<DisputeState> disputeStateProperty = new SimpleObjectProperty<>(disputeState); transient final private ObjectProperty<TradePeriodState> tradePeriodStateProperty = new SimpleObjectProperty<>(periodState); + @Getter + transient public final IntegerProperty depositTxsUpdateCounter = new SimpleIntegerProperty(0); transient final private StringProperty errorMessageProperty = new SimpleStringProperty(); transient private Subscription tradeStateSubscription; transient private Subscription tradePhaseSubscription; transient private Subscription payoutStateSubscription; - transient private TaskLooper txPollLooper; - transient private Long walletRefreshPeriod; - transient private Long syncNormalStartTime; + transient private Subscription disputeStateSubscription; + transient private TaskLooper pollLooper; + transient private Long pollPeriodMs; + transient private Long pollNormalStartTimeMs; public static final long DEFER_PUBLISH_MS = 25000; // 25 seconds private static final long IDLE_SYNC_PERIOD_MS = 1680000; // 28 minutes (monero's default connection timeout is 30 minutes on a local connection, so beyond this the wallets will disconnect) @@ -397,10 +434,7 @@ public abstract class Trade implements Tradable, Model { // Mutable @Getter transient private boolean isInitialized; - @Getter - transient private boolean isShutDownStarted; - @Getter - transient private boolean isShutDown; + transient private boolean isFullyInitialized; // Added in v1.2.0 transient private ObjectProperty<BigInteger> tradeAmountProperty; @@ -443,12 +477,17 @@ public abstract class Trade implements Tradable, Model { @Nullable @Getter @Setter - private String payoutTxHex; + private String payoutTxHex; // signed payout tx hex @Getter @Setter private String payoutTxKey; + private long payoutTxFee; private Long payoutHeight; private IdlePayoutSyncer idlePayoutSyncer; + @Getter + private boolean isCompleted; + @Getter + private final String challenge; /////////////////////////////////////////////////////////////////////////////////////////// // Constructors @@ -457,24 +496,25 @@ public abstract class Trade implements Tradable, Model { // maker protected Trade(Offer offer, BigInteger tradeAmount, - BigInteger takerFee, long tradePrice, XmrWalletService xmrWalletService, ProcessModel processModel, String uid, @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { + super(); this.offer = offer; this.amount = tradeAmount.longValueExact(); - this.takerFee = takerFee.longValueExact(); - this.totalTxFee = 0l; // TODO: sum tx fees this.price = tradePrice; this.xmrWalletService = xmrWalletService; + this.xmrConnectionService = xmrWalletService.getXmrConnectionService(); this.processModel = processModel; this.uid = uid; this.takeOfferDate = new Date().getTime(); this.tradeListeners = new ArrayList<TradeListener>(); + this.challenge = challenge; getMaker().setNodeAddress(makerNodeAddress); getTaker().setNodeAddress(takerNodeAddress); @@ -490,7 +530,6 @@ public abstract class Trade implements Tradable, Model { protected Trade(Offer offer, BigInteger tradeAmount, BigInteger txFee, - BigInteger takerFee, long tradePrice, @Nullable NodeAddress mediatorNodeAddress, // TODO (woodser): remove mediator, refund agent from trade @Nullable NodeAddress refundAgentNodeAddress, @@ -499,18 +538,19 @@ public abstract class Trade implements Tradable, Model { String uid, @Nullable NodeAddress makerNodeAddress, @Nullable NodeAddress takerNodeAddress, - @Nullable NodeAddress arbitratorNodeAddress) { + @Nullable NodeAddress arbitratorNodeAddress, + @Nullable String challenge) { this(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); } // TODO: remove these constructors @@ -519,25 +559,25 @@ public abstract class Trade implements Tradable, Model { protected Trade(Offer offer, BigInteger tradeAmount, Coin txFee, - BigInteger takerFee, long tradePrice, NodeAddress makerNodeAddress, NodeAddress takerNodeAddress, NodeAddress arbitratorNodeAddress, XmrWalletService xmrWalletService, ProcessModel processModel, - String uid) { + String uid, + @Nullable String challenge) { this(offer, tradeAmount, - takerFee, tradePrice, xmrWalletService, processModel, uid, makerNodeAddress, takerNodeAddress, - arbitratorNodeAddress); + arbitratorNodeAddress, + challenge); setAmount(tradeAmount); } @@ -575,47 +615,51 @@ public abstract class Trade implements Tradable, Model { /////////////////////////////////////////////////////////////////////////////////////////// public void initialize(ProcessModelServiceProvider serviceProvider) { - synchronized (this) { - if (isInitialized) throw new IllegalStateException(getClass().getSimpleName() + " " + getId() + " is already initialized"); + if (isInitialized) throw new IllegalStateException(getClass().getSimpleName() + " " + getId() + " is already initialized"); - // set arbitrator pub key ring once known - serviceProvider.getArbitratorManager().getDisputeAgentByNodeAddress(getArbitratorNodeAddress()).ifPresent(arbitrator -> { - getArbitrator().setPubKeyRing(arbitrator.getPubKeyRing()); - }); + // done if payout unlocked and marked complete + if (isPayoutUnlocked() && isCompleted()) { + clearAndShutDown(); + return; + } - // listen to daemon connection - xmrWalletService.getConnectionsService().addConnectionListener(newConnection -> onConnectionChanged(newConnection)); + // set arbitrator pub key ring once known + serviceProvider.getArbitratorManager().getDisputeAgentByNodeAddress(getArbitratorNodeAddress()).ifPresent(arbitrator -> { + getArbitrator().setPubKeyRing(arbitrator.getPubKeyRing()); + }); - // check if done - if (isPayoutUnlocked()) { - if (walletExists()) deleteWallet(); - return; - } + // handle connection change on dedicated thread + xmrConnectionService.addConnectionListener(connection -> { + ThreadUtils.execute(() -> onConnectionChanged(connection), getId()); + }); - // reset buyer's payment sent state if no ack receive - if (this instanceof BuyerTrade && getState().ordinal() >= Trade.State.BUYER_CONFIRMED_IN_UI_PAYMENT_SENT.ordinal() && getState().ordinal() < Trade.State.BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG.ordinal()) { - log.warn("Resetting state of {} {} from {} to {} because no ack was received", getClass().getSimpleName(), getId(), getState(), Trade.State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN); - setState(Trade.State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN); - } + // reset buyer's payment sent state if no ack receive + if (this instanceof BuyerTrade && getState().ordinal() >= Trade.State.BUYER_CONFIRMED_PAYMENT_SENT.ordinal() && getState().ordinal() < Trade.State.BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG.ordinal()) { + log.warn("Resetting state of {} {} from {} to {} because no ack was received", getClass().getSimpleName(), getId(), getState(), Trade.State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN); + setState(Trade.State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN); + } - // reset seller's payment received state if no ack receive - if (this instanceof SellerTrade && getState().ordinal() >= Trade.State.SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT.ordinal() && getState().ordinal() < Trade.State.SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG.ordinal()) { - log.warn("Resetting state of {} {} from {} to {} because no ack was received", getClass().getSimpleName(), getId(), getState(), Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); - setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); - } + // reset seller's payment received state if no ack receive + if (this instanceof SellerTrade && getState().ordinal() >= Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT.ordinal() && getState().ordinal() < Trade.State.SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG.ordinal()) { + log.warn("Resetting state of {} {} from {} to {} because no ack was received", getClass().getSimpleName(), getId(), getState(), Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); + setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); + } - // handle trade state events - tradeStateSubscription = EasyBind.subscribe(stateProperty, newValue -> { - if (newValue == Trade.State.MULTISIG_COMPLETED) { - updateWalletRefreshPeriod(); - startPolling(); - } - }); + // handle trade state events + tradeStateSubscription = EasyBind.subscribe(stateProperty, newValue -> { + if (!isInitialized || isShutDownStarted) return; + // no processing + }); - // handle trade phase events - tradePhaseSubscription = EasyBind.subscribe(phaseProperty, newValue -> { - if (isDepositsPublished() && !isPayoutUnlocked()) updateWalletRefreshPeriod(); - if (isCompleted()) { + // handle trade phase events + tradePhaseSubscription = EasyBind.subscribe(phaseProperty, newValue -> { + if (!isInitialized || isShutDownStarted) return; + ThreadUtils.submitToPool(() -> { + if (newValue == Trade.Phase.DEPOSIT_REQUESTED) startPolling(); + if (newValue == Trade.Phase.DEPOSITS_PUBLISHED) onDepositsPublished(); + if (newValue == Trade.Phase.PAYMENT_SENT) onPaymentSent(); + if (isDepositsPublished() && !isPayoutUnlocked()) updatePollPeriod(); + if (isPaymentReceived()) { UserThread.execute(() -> { if (tradePhaseSubscription != null) { tradePhaseSubscription.unsubscribe(); @@ -624,74 +668,112 @@ public abstract class Trade implements Tradable, Model { }); } }); + }); - // handle payout events - payoutStateSubscription = EasyBind.subscribe(payoutStateProperty, newValue -> { - if (isPayoutPublished()) updateWalletRefreshPeriod(); + // handle payout events + payoutStateSubscription = EasyBind.subscribe(payoutStateProperty, newValue -> { + if (!isInitialized || isShutDownStarted) return; + ThreadUtils.submitToPool(() -> { + if (isPayoutPublished()) updatePollPeriod(); - // cleanup when payout published + // handle when payout published if (newValue == Trade.PayoutState.PAYOUT_PUBLISHED) { log.info("Payout published for {} {}", getClass().getSimpleName(), getId()); - // complete disputed trade - if (getDisputeState().isArbitrated() && !getDisputeState().isClosed()) processModel.getTradeManager().closeDisputedTrade(getId(), Trade.DisputeState.DISPUTE_CLOSED); + // sync main wallet to update pending balance + ThreadUtils.submitToPool(() -> { + HavenoUtils.waitFor(1000); + if (isPayoutConfirmed()) return; + if (isShutDownStarted) return; + if (xmrConnectionService.isConnected()) syncAndPollWallet(); + }); - // complete arbitrator trade + // complete disputed trade + if (getDisputeState().isArbitrated() && !getDisputeState().isClosed()) { + processModel.getTradeManager().closeDisputedTrade(getId(), Trade.DisputeState.DISPUTE_CLOSED); + if (!isArbitrator()) for (Dispute dispute : getDisputes()) dispute.setIsClosed(); // auto close trader tickets + } + + // auto complete arbitrator trade if (isArbitrator() && !isCompleted()) processModel.getTradeManager().onTradeCompleted(this); + // maybe publish trade statistic + maybePublishTradeStatistics(); + // reset address entries processModel.getXmrWalletService().resetAddressEntriesForTrade(getId()); } - // cleanup when payout unlocks + // handle when payout unlocks if (newValue == Trade.PayoutState.PAYOUT_UNLOCKED) { if (!isInitialized) return; log.info("Payout unlocked for {} {}, deleting multisig wallet", getClass().getSimpleName(), getId()); - deleteWallet(); - if (idlePayoutSyncer != null) { - xmrWalletService.removeWalletListener(idlePayoutSyncer); - idlePayoutSyncer = null; - } - UserThread.execute(() -> { - if (payoutStateSubscription != null) { - payoutStateSubscription.unsubscribe(); - payoutStateSubscription = null; - } - }); + if (isCompleted()) clearAndShutDown(); + else deleteWallet(); } }); + }); - // arbitrator syncs idle wallet when payout unlock expected - if (this instanceof ArbitratorTrade) { - idlePayoutSyncer = new IdlePayoutSyncer(); - xmrWalletService.addWalletListener(idlePayoutSyncer); - } - - // trade is initialized - isInitialized = true; - - // done if payout unlocked or deposit not requested - if (!isDepositRequested() || isPayoutUnlocked()) return; - - // done if wallet does not exist - if (!walletExists()) { - MoneroTx payoutTx = getPayoutTx(); - if (payoutTx != null && payoutTx.getNumConfirmations() >= 10) { - log.warn("Payout state for {} {} is {} but payout is unlocked, updating state", getClass().getSimpleName(), getId(), getPayoutState()); - setPayoutStateUnlocked(); - return; - } else { - throw new IllegalStateException("Missing trade wallet for " + getClass().getSimpleName() + " " + getId()); + // handle dispute events + disputeStateSubscription = EasyBind.subscribe(disputeStateProperty, newValue -> { + if (!isInitialized || isShutDownStarted) return; + ThreadUtils.submitToPool(() -> { + if (isDisputeClosed()) { + maybePublishTradeStatistics(); } - } + }); + }); - // initialize syncing and polling - initSyncing(); + // arbitrator syncs idle wallet when payout unlock expected + if (this instanceof ArbitratorTrade) { + idlePayoutSyncer = new IdlePayoutSyncer(); + xmrWalletService.addWalletListener(idlePayoutSyncer); } + + // TODO: buyer's payment sent message state property can become unsynced (after improper shut down?) + if (isBuyer()) { + MessageState expectedState = getPaymentSentMessageState(); + if (expectedState != null && expectedState != processModel.getPaymentSentMessageStateProperty().get()) { + log.warn("Updating unexpected payment sent message state for {} {}, expected={}, actual={}", getClass().getSimpleName(), getId(), expectedState, processModel.getPaymentSentMessageStateProperty().get()); + processModel.getPaymentSentMessageStateProperty().set(expectedState); + } + } + + // trade is initialized + isInitialized = true; + + // done if deposit not requested or payout unlocked + if (!isDepositRequested() || isPayoutUnlocked()) { + isFullyInitialized = true; + return; + } + + // open wallet or done if wallet does not exist + if (walletExists()) getWallet(); + else { + MoneroTx payoutTx = getPayoutTx(); + if (payoutTx != null && payoutTx.getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK) { + log.warn("Payout state for {} {} is {} but payout is unlocked, updating state", getClass().getSimpleName(), getId(), getPayoutState()); + setPayoutStateUnlocked(); + isFullyInitialized = true; + return; + } else { + log.warn("Missing trade wallet for {} {}, state={}, marked completed={}", getClass().getSimpleName(), getShortId(), getState(), isCompleted()); + return; + } + } + + // start polling if deposit requested + if (isDepositRequested()) tryInitPolling(); + isFullyInitialized = true; + } + + public void awaitInitialized() { + while (!isFullyInitialized) HavenoUtils.waitFor(100); // TODO: use proper notification and refactor isInitialized, fullyInitialized, and arbitrator idling } public void requestPersistence() { - processModel.getTradeManager().requestPersistence(); + if (processModel.getTradeManager() != null) processModel.getTradeManager().requestPersistence(); } public TradeProtocol getProtocol() { @@ -710,13 +792,18 @@ public abstract class Trade implements Tradable, Model { return getArbitrator() == null ? null : getArbitrator().getNodeAddress(); } + public void setCompleted(boolean completed) { + this.isCompleted = completed; + if (isPayoutUnlocked()) clearAndShutDown(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // WALLET MANAGEMENT /////////////////////////////////////////////////////////////////////////////////////////// public boolean walletExists() { synchronized (walletLock) { - return xmrWalletService.walletExists(MONERO_TRADE_WALLET_PREFIX + getId()); + return xmrWalletService.walletExists(getWalletName()); } } @@ -740,52 +827,77 @@ public abstract class Trade implements Tradable, Model { } } + public long getHeight() { + return walletHeight.get(); + } + private String getWalletName() { - return MONERO_TRADE_WALLET_PREFIX + getId(); + return MONERO_TRADE_WALLET_PREFIX + getShortId() + "_" + getShortUid(); } - public void checkDaemonConnection() { - CoreMoneroConnectionsService connectionService = xmrWalletService.getConnectionsService(); - connectionService.checkConnection(); - connectionService.verifyConnection(); - if (!getWallet().isConnectedToDaemon()) throw new RuntimeException("Trade wallet is not connected to a Monero node"); + public void verifyDaemonConnection() { + if (!Boolean.TRUE.equals(xmrConnectionService.isConnected())) throw new RuntimeException("Connection service is not connected to a Monero node"); } - public boolean isWalletConnected() { - try { - checkDaemonConnection(); - return true; - } catch (Exception e) { - return false; + public boolean isWalletConnectedToDaemon() { + synchronized (walletLock) { + try { + if (wallet == null) return false; + return wallet.isConnectedToDaemon(); + } catch (Exception e) { + return false; + } } } + public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) { + if (xmrConnectionService.requestSwitchToNextBestConnection(sourceConnection)) { + onConnectionChanged(xmrConnectionService.getConnection()); // change connection on same thread + return true; + } + return false; + } + public boolean isIdling() { - return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists(); // arbitrator idles trade after deposits confirm + return this instanceof ArbitratorTrade && isDepositsConfirmed() && walletExists() && pollNormalStartTimeMs == null; // arbitrator idles trade after deposits confirm unless overriden + } + + public boolean isSyncedWithinTolerance() { + synchronized (walletLock) { + if (wallet == null) return false; + if (!xmrConnectionService.isSyncedWithinTolerance()) return false; + Long targetHeight = xmrConnectionService.getTargetHeight(); + if (targetHeight == null) return false; + if (targetHeight - walletHeight.get() <= 3) return true; // synced if within 3 blocks of target height + return false; + } } public void syncAndPollWallet() { syncWallet(true); } - public void syncWalletNormallyForMs(long syncNormalDuration) { - syncNormalStartTime = System.currentTimeMillis(); - setWalletRefreshPeriod(xmrWalletService.getConnectionsService().getRefreshPeriodMs()); - UserThread.runAfter(() -> { - if (!isShutDown && System.currentTimeMillis() >= syncNormalStartTime + syncNormalDuration) updateWalletRefreshPeriod(); - }, syncNormalDuration); + public void pollWalletNormallyForMs(long pollNormalDuration) { + pollNormalStartTimeMs = System.currentTimeMillis(); + + // override wallet poll period + setPollPeriod(xmrConnectionService.getRefreshPeriodMs()); + + // reset wallet poll period after duration + new Thread(() -> { + HavenoUtils.waitFor(pollNormalDuration); + Long pollNormalStartTimeMsCopy = pollNormalStartTimeMs; // copy to avoid race condition + if (pollNormalStartTimeMsCopy == null) return; + if (!isShutDown && System.currentTimeMillis() >= pollNormalStartTimeMsCopy + pollNormalDuration) { + pollNormalStartTimeMs = null; + updatePollPeriod(); + } + }).start(); } - public void importMultisigHex() { - List<String> multisigHexes = new ArrayList<String>(); - if (getBuyer().getUpdatedMultisigHex() != null) multisigHexes.add(getBuyer().getUpdatedMultisigHex()); - if (getSeller().getUpdatedMultisigHex() != null) multisigHexes.add(getSeller().getUpdatedMultisigHex()); - if (getArbitrator().getUpdatedMultisigHex() != null) multisigHexes.add(getArbitrator().getUpdatedMultisigHex()); - if (!multisigHexes.isEmpty()) { - log.info("Importing multisig hex for {} {}", getClass().getSimpleName(), getId()); - getWallet().importMultisigHex(multisigHexes.toArray(new String[0])); - log.info("Done importing multisig hex for {} {}", getClass().getSimpleName(), getId()); - } + // TODO: checking error strings isn't robust, but the library doesn't provide a way to check if multisig hex is invalid. throw IllegalArgumentException from library on invalid multisig hex? + private boolean isInvalidImportError(String errMsg) { + return errMsg.contains("Failed to parse hex") || errMsg.contains("Multisig info is for a different account"); } public void changeWalletPassword(String oldPassword, String newPassword) { @@ -795,10 +907,36 @@ public abstract class Trade implements Tradable, Model { } } + public void requestSaveWallet() { + + // save wallet off main thread + ThreadUtils.execute(() -> { + synchronized (walletLock) { + if (walletExists()) saveWallet(); + } + }, getId()); + } + public void saveWallet() { synchronized (walletLock) { - if (wallet == null) throw new RuntimeException("Trade wallet is not open for trade " + getId()); - xmrWalletService.saveWallet(wallet, true); + if (!walletExists()) { + log.warn("Cannot save wallet for {} {} because it does not exist", getClass().getSimpleName(), getShortId()); + return; + } + if (wallet == null) throw new RuntimeException("Trade wallet is not open for trade " + getShortId()); + xmrWalletService.saveWallet(wallet); + maybeBackupWallet(); + } + } + + private void maybeBackupWallet() { + boolean createBackup = !isArbitrator() && !(Utilities.isWindows() && isWalletOpen()); // create backup unless arbitrator or windows and wallet is open (cannot copy file while open on windows) + if (createBackup) xmrWalletService.backupWallet(getWalletName()); + } + + private boolean isWalletOpen() { + synchronized (walletLock) { + return wallet != null; } } @@ -807,15 +945,20 @@ public abstract class Trade implements Tradable, Model { if (wallet == null) throw new RuntimeException("Trade wallet to close is not open for trade " + getId()); stopPolling(); xmrWalletService.closeWallet(wallet, true); + maybeBackupWallet(); wallet = null; + pollPeriodMs = null; } } - private void stopWallet() { - synchronized (walletLock) { - if (wallet == null) throw new RuntimeException("Trade wallet to close is not open for trade " + getId()); + private void forceCloseWallet() { + if (wallet != null) { + try { + xmrWalletService.forceCloseWallet(wallet, wallet.getPath()); + } catch (Exception e) { + log.warn("Error force closing wallet for {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage()); + } stopPolling(); - xmrWalletService.stopWallet(wallet, wallet.getPath(), true); wallet = null; } } @@ -825,27 +968,48 @@ public abstract class Trade implements Tradable, Model { if (walletExists()) { try { - // check if funds deposited but payout not unlocked - if (isDepositsPublished() && !isPayoutUnlocked()) { - throw new RuntimeException("Refusing to delete wallet for " + getClass().getSimpleName() + " " + getId() + " because the deposit txs have been published but payout tx has not unlocked"); + // check wallet state if deposit requested + if (isDepositRequested()) { + + // ensure wallet is initialized + boolean syncedWallet = false; + if (wallet == null) { + log.warn("Wallet is not initialized for {} {}, opening", getClass().getSimpleName(), getId()); + getWallet(); + syncWallet(true); + syncedWallet = true; + } + + // sync wallet if deposit requested and payout not unlocked + if (!isPayoutUnlocked() && !syncedWallet) { + log.warn("Syncing wallet on deletion for trade {} {}, syncing", getClass().getSimpleName(), getId()); + syncWallet(true); + } + + // check if deposits published and payout not unlocked + if (isDepositsPublished() && !isPayoutUnlocked()) { + throw new IllegalStateException("Refusing to delete wallet for " + getClass().getSimpleName() + " " + getId() + " because the deposit txs have been published but payout tx has not unlocked"); + } + + // check for balance + if (wallet.getBalance().compareTo(BigInteger.ZERO) > 0) { + log.warn("Rescanning spent outputs for {} {}", getClass().getSimpleName(), getId()); + wallet.rescanSpent(); + if (wallet.getBalance().compareTo(BigInteger.ZERO) > 0) { + throw new IllegalStateException("Refusing to delete wallet for " + getClass().getSimpleName() + " " + getId() + " because it has a balance of " + wallet.getBalance()); + } + } } - // force stop the wallet - if (wallet != null) stopWallet(); + // force close wallet without warning + forceCloseWallet(); // delete wallet - log.info("Deleting wallet for {} {}", getClass().getSimpleName(), getId()); + log.info("Deleting wallet and backups for {} {}", getClass().getSimpleName(), getId()); xmrWalletService.deleteWallet(getWalletName()); - - // delete trade wallet backups unless deposits requested and payouts not unlocked - if (isDepositRequested() && !isDepositFailed() && !isPayoutUnlocked()) { - log.warn("Refusing to delete backup wallet for " + getClass().getSimpleName() + " " + getId() + " in the small chance it becomes funded"); - return; - } xmrWalletService.deleteWalletBackups(getWalletName()); } catch (Exception e) { - log.warn(e.getMessage()); - e.printStackTrace(); + log.warn("Error deleting wallet for {} {}: {}\n", getClass().getSimpleName(), getId(), e.getMessage(), e); setErrorMessage(e.getMessage()); processModel.getTradeManager().getNotificationService().sendErrorNotification("Error", e.getMessage()); } @@ -891,33 +1055,199 @@ public abstract class Trade implements Tradable, Model { return contract; } + public MoneroTxWallet createTx(MoneroTxConfig txConfig) { + synchronized (walletLock) { + synchronized (HavenoUtils.getWalletFunctionLock()) { + MoneroTxWallet tx = wallet.createTx(txConfig); + exportMultisigHex(); + saveWallet(); + return tx; + } + } + } + + public void exportMultisigHex() { + synchronized (walletLock) { + getSelf().setUpdatedMultisigHex(wallet.exportMultisigHex()); + requestPersistence(); + } + } + + public void importMultisigHexIfNeeded() { + synchronized (walletLock) { + if (wallet.isMultisigImportNeeded()) { + importMultisigHex(); + } + } + } + + public void importMultisigHex() { + synchronized (walletLock) { + synchronized (HavenoUtils.getDaemonLock()) { // lock on daemon because import calls full refresh + synchronized (importMultisigLock) { + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + doImportMultisigHex(); + break; + } catch (IllegalArgumentException | IllegalStateException e) { + throw e; + } catch (Exception e) { + handleWalletError(e, sourceConnection); + doPollWallet(); + if (isPayoutPublished()) break; + log.warn("Failed to import multisig hex, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } + } + } + } + } + + private void doImportMultisigHex() { + + // ensure wallet sees deposits confirmed + if (!isDepositsConfirmed()) syncAndPollWallet(); + + // collect multisig hex from peers + List<String> multisigHexes = new ArrayList<String>(); + for (TradePeer peer : getOtherPeers()) if (peer.getUpdatedMultisigHex() != null) multisigHexes.add(peer.getUpdatedMultisigHex()); + + // import multisig hex + log.info("Importing multisig hexes for {} {}, count={}", getClass().getSimpleName(), getShortId(), multisigHexes.size()); + long startTime = System.currentTimeMillis(); + if (!multisigHexes.isEmpty()) { + try { + wallet.importMultisigHex(multisigHexes.toArray(new String[0])); + + // check if import is still needed // TODO: we once received a multisig hex which was too short, causing import to still be needed + if (wallet.isMultisigImportNeeded()) { + String errorMessage = "Multisig import still needed for " + getClass().getSimpleName() + " " + getShortId() + " after already importing, multisigHexes=" + multisigHexes; + log.warn(errorMessage); + + // ignore multisig hex which is significantly shorter than others + int maxLength = 0; + boolean removed = false; + for (String hex : multisigHexes) maxLength = Math.max(maxLength, hex.length()); + for (String hex : new ArrayList<>(multisigHexes)) { + if (hex.length() < maxLength / 2) { + String ignoringMessage = "Ignoring multisig hex from " + getMultisigHexRole(hex) + " for " + getClass().getSimpleName() + " " + getShortId() + " because it is too short, multisigHex=" + hex; + setErrorMessage(ignoringMessage); + log.warn(ignoringMessage); + multisigHexes.remove(hex); + removed = true; + } + } + + // re-import valid multisig hexes + if (removed) wallet.importMultisigHex(multisigHexes.toArray(new String[0])); + if (wallet.isMultisigImportNeeded()) throw new IllegalStateException(errorMessage); + } + } catch (MoneroError e) { + + // import multisig hex individually if one is invalid + if (isInvalidImportError(e.getMessage())) { + log.warn("Peer has invalid multisig hex for {} {}, importing individually", getClass().getSimpleName(), getShortId()); + boolean imported = false; + Exception lastError = null; + for (TradePeer peer : getOtherPeers()) { + if (peer.getUpdatedMultisigHex() == null) continue; + try { + wallet.importMultisigHex(peer.getUpdatedMultisigHex()); + imported = true; + } catch (MoneroError e2) { + lastError = e2; + if (isInvalidImportError(e2.getMessage())) { + log.warn("{} has invalid multisig hex for {} {}, error={}, multisigHex={}", getPeerRole(peer), getClass().getSimpleName(), getShortId(), e2.getMessage(), peer.getUpdatedMultisigHex()); + } else { + throw e2; + } + } + } + if (!imported) throw new IllegalArgumentException("Could not import any multisig hexes for " + getClass().getSimpleName() + " " + getShortId(), lastError); + } else { + throw e; + } + } + saveWallet(); + } + log.info("Done importing multisig hexes for {} {} in {} ms, count={}", getClass().getSimpleName(), getShortId(), System.currentTimeMillis() - startTime, multisigHexes.size()); + } + + private void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) { + if (HavenoUtils.isUnresponsive(e)) forceCloseWallet(); // wallet can be stuck a while + if (!HavenoUtils.isIllegal(e) && xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection); + getWallet(); // re-open wallet + } + + private String getMultisigHexRole(String multisigHex) { + if (multisigHex.equals(getArbitrator().getUpdatedMultisigHex())) return "arbitrator"; + if (multisigHex.equals(getBuyer().getUpdatedMultisigHex())) return "buyer"; + if (multisigHex.equals(getSeller().getUpdatedMultisigHex())) return "seller"; + throw new IllegalArgumentException("Multisig hex does not belong to any peer"); + } + /** * Create the payout tx. * - * @return MoneroTxWallet the payout tx when the trade is successfully completed + * @return the payout tx when the trade is successfully completed */ public MoneroTxWallet createPayoutTx() { // check connection to monero daemon - checkDaemonConnection(); + verifyDaemonConnection(); - // check multisig import - if (getWallet().isMultisigImportNeeded()) throw new RuntimeException("Cannot create payout tx because multisig import is needed"); + // create payout tx + synchronized (walletLock) { + synchronized (HavenoUtils.getWalletFunctionLock()) { + + // import multisig hex if needed + importMultisigHexIfNeeded(); + + // create payout tx + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + return doCreatePayoutTx(); + } catch (IllegalArgumentException | IllegalStateException e) { + throw e; + } catch (Exception e) { + handleWalletError(e, sourceConnection); + doPollWallet(); + if (isPayoutPublished()) break; + log.warn("Failed to create payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } + throw new RuntimeException("Failed to create payout tx for " + getClass().getSimpleName() + " " + getId()); + } + } + } + + private MoneroTxWallet doCreatePayoutTx() { + + // check if multisig import needed + if (wallet.isMultisigImportNeeded()) throw new IllegalStateException("Cannot create payout tx because multisig import is needed for " + getClass().getSimpleName() + " " + getShortId()); + + // recover if missing wallet data + recoverIfMissingWalletData(); // gather info - MoneroWallet multisigWallet = getWallet(); - String sellerPayoutAddress = this.getSeller().getPayoutAddressString(); - String buyerPayoutAddress = this.getBuyer().getPayoutAddressString(); + String sellerPayoutAddress = getSeller().getPayoutAddressString(); + String buyerPayoutAddress = getBuyer().getPayoutAddressString(); Preconditions.checkNotNull(sellerPayoutAddress, "Seller payout address must not be null"); Preconditions.checkNotNull(buyerPayoutAddress, "Buyer payout address must not be null"); - BigInteger sellerDepositAmount = multisigWallet.getTx(this.getSeller().getDepositTxHash()).getIncomingAmount(); - BigInteger buyerDepositAmount = multisigWallet.getTx(this.getBuyer().getDepositTxHash()).getIncomingAmount(); + BigInteger sellerDepositAmount = getSeller().getDepositTx().getIncomingAmount(); + BigInteger buyerDepositAmount = hasBuyerAsTakerWithoutDeposit() ? BigInteger.ZERO : getBuyer().getDepositTx().getIncomingAmount(); BigInteger tradeAmount = getAmount(); BigInteger buyerPayoutAmount = buyerDepositAmount.add(tradeAmount); BigInteger sellerPayoutAmount = sellerDepositAmount.subtract(tradeAmount); // create payout tx - MoneroTxWallet payoutTx = multisigWallet.createTx(new MoneroTxConfig() + MoneroTxWallet payoutTx = createTx(new MoneroTxConfig() .setAccountIndex(0) .addDestination(buyerPayoutAddress, buyerPayoutAmount) .addDestination(sellerPayoutAddress, sellerPayoutAmount) @@ -925,32 +1255,91 @@ public abstract class Trade implements Tradable, Model { .setRelay(false) .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); - // save updated multisig hex - getSelf().setUpdatedMultisigHex(multisigWallet.exportMultisigHex()); + // update state + BigInteger payoutTxFeeSplit = payoutTx.getFee().divide(BigInteger.valueOf(2)); + getBuyer().setPayoutTxFee(payoutTxFeeSplit); + getBuyer().setPayoutAmount(HavenoUtils.getDestination(buyerPayoutAddress, payoutTx).getAmount()); + getSeller().setPayoutTxFee(payoutTxFeeSplit); + getSeller().setPayoutAmount(HavenoUtils.getDestination(sellerPayoutAddress, payoutTx).getAmount()); return payoutTx; } + public MoneroTxWallet createDisputePayoutTx(MoneroTxConfig txConfig) { + synchronized (walletLock) { + synchronized (HavenoUtils.getWalletFunctionLock()) { + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + if (wallet.isMultisigImportNeeded()) throw new IllegalStateException("Cannot create dispute payout tx because multisig import is needed for " + getClass().getSimpleName() + " " + getShortId()); + return createTx(txConfig); + } catch (IllegalArgumentException | IllegalStateException e) { + throw e; + } catch (Exception e) { + if (e.getMessage().contains("not possible")) throw new IllegalArgumentException("Loser payout is too small to cover the mining fee"); + handleWalletError(e, sourceConnection); + doPollWallet(); + if (isPayoutPublished()) break; + log.warn("Failed to create dispute payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } + throw new RuntimeException("Failed to create payout tx for " + getClass().getSimpleName() + " " + getId()); + } + } + } + /** - * Verify a payout tx. + * Process a payout tx. * * @param payoutTxHex is the payout tx hex to verify * @param sign signs the payout tx if true * @param publish publishes the signed payout tx if true */ - public void verifyPayoutTx(String payoutTxHex, boolean sign, boolean publish) { - log.info("Verifying payout tx"); + public void processPayoutTx(String payoutTxHex, boolean sign, boolean publish) { + synchronized (walletLock) { + synchronized (HavenoUtils.getWalletFunctionLock()) { + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + doProcessPayoutTx(payoutTxHex, sign, publish); + break; + } catch (IllegalArgumentException | IllegalStateException e) { + throw e; + } catch (Exception e) { + handleWalletError(e, sourceConnection); + doPollWallet(); + if (isPayoutPublished()) break; + log.warn("Failed to process payout tx, tradeId={}, attempt={}/{}, error={}", getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage(), e); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } finally { + requestSaveWallet(); + requestPersistence(); + } + } + } + } + } + + private void doProcessPayoutTx(String payoutTxHex, boolean sign, boolean publish) { + log.info("Processing payout tx for {} {}", getClass().getSimpleName(), getId()); + + // recover if missing wallet data + recoverIfMissingWalletData(); // gather relevant info MoneroWallet wallet = getWallet(); Contract contract = getContract(); - BigInteger sellerDepositAmount = wallet.getTx(getSeller().getDepositTxHash()).getIncomingAmount(); // TODO (woodser): redundancy of processModel.getPreparedDepositTxId() vs this.getDepositTxId() necessary or avoidable? - BigInteger buyerDepositAmount = wallet.getTx(getBuyer().getDepositTxHash()).getIncomingAmount(); + BigInteger sellerDepositAmount = getSeller().getDepositTx().getIncomingAmount(); + BigInteger buyerDepositAmount = hasBuyerAsTakerWithoutDeposit() ? BigInteger.ZERO : getBuyer().getDepositTx().getIncomingAmount(); BigInteger tradeAmount = getAmount(); // describe payout tx MoneroTxSet describedTxSet = wallet.describeTxSet(new MoneroTxSet().setMultisigTxHex(payoutTxHex)); if (describedTxSet.getTxs() == null || describedTxSet.getTxs().size() != 1) throw new IllegalArgumentException("Bad payout tx"); // TODO (woodser): test nack MoneroTxWallet payoutTx = describedTxSet.getTxs().get(0); + if (payoutTxId == null) updatePayout(payoutTx); // update payout tx if not signed // verify payout tx has exactly 2 destinations if (payoutTx.getOutgoingTransfer() == null || payoutTx.getOutgoingTransfer().getDestinations() == null || payoutTx.getOutgoingTransfer().getDestinations().size() != 2) throw new IllegalArgumentException("Payout tx does not have exactly two destinations"); @@ -965,6 +1354,7 @@ public abstract class Trade implements Tradable, Model { if (!sellerPayoutDestination.getAddress().equals(contract.getSellerPayoutAddressString())) throw new IllegalArgumentException("Seller payout address does not match contract"); // verify change address is multisig's primary address + if (!payoutTx.getChangeAmount().equals(BigInteger.ZERO)) log.warn("Dust left in multisig wallet for {} {}: {}", getClass().getSimpleName(), getId(), payoutTx.getChangeAmount()); if (!payoutTx.getChangeAmount().equals(BigInteger.ZERO) && !payoutTx.getChangeAddress().equals(wallet.getPrimaryAddress())) throw new IllegalArgumentException("Change address is not multisig wallet's primary address"); // verify sum of outputs = destination amounts + change amount @@ -972,46 +1362,62 @@ public abstract class Trade implements Tradable, Model { // verify buyer destination amount is deposit amount + this amount - 1/2 tx costs BigInteger txCost = payoutTx.getFee().add(payoutTx.getChangeAmount()); - BigInteger expectedBuyerPayout = buyerDepositAmount.add(tradeAmount).subtract(txCost.divide(BigInteger.valueOf(2))); + BigInteger txCostSplit = txCost.divide(BigInteger.valueOf(2)); + BigInteger expectedBuyerPayout = buyerDepositAmount.add(tradeAmount).subtract(txCostSplit); if (!buyerPayoutDestination.getAmount().equals(expectedBuyerPayout)) throw new IllegalArgumentException("Buyer destination amount is not deposit amount + trade amount - 1/2 tx costs, " + buyerPayoutDestination.getAmount() + " vs " + expectedBuyerPayout); // verify seller destination amount is deposit amount - this amount - 1/2 tx costs - BigInteger expectedSellerPayout = sellerDepositAmount.subtract(tradeAmount).subtract(txCost.divide(BigInteger.valueOf(2))); + BigInteger expectedSellerPayout = sellerDepositAmount.subtract(tradeAmount).subtract(txCostSplit); if (!sellerPayoutDestination.getAmount().equals(expectedSellerPayout)) throw new IllegalArgumentException("Seller destination amount is not deposit amount - trade amount - 1/2 tx costs, " + sellerPayoutDestination.getAmount() + " vs " + expectedSellerPayout); - // check wallet connection - if (sign || publish) checkDaemonConnection(); + // check connection + boolean doSign = sign && getPayoutTxHex() == null; + if (doSign || publish) verifyDaemonConnection(); // handle tx signing - if (sign) { + if (doSign) { // sign tx - MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex); - if (result.getSignedMultisigTxHex() == null) throw new RuntimeException("Error signing payout tx"); - payoutTxHex = result.getSignedMultisigTxHex(); + try { + MoneroMultisigSignResult result = wallet.signMultisigTxHex(payoutTxHex); + if (result.getSignedMultisigTxHex() == null) throw new IllegalArgumentException("Error signing payout tx, signed multisig hex is null"); + setPayoutTxHex(result.getSignedMultisigTxHex()); + } catch (Exception e) { + throw new IllegalStateException(e); + } // describe result - describedTxSet = wallet.describeMultisigTxSet(payoutTxHex); + describedTxSet = wallet.describeMultisigTxSet(getPayoutTxHex()); payoutTx = describedTxSet.getTxs().get(0); + updatePayout(payoutTx); // verify fee is within tolerance by recreating payout tx // TODO (monero-project): creating tx will require exchanging updated multisig hex if message needs reprocessed. provide weight with describe_transfer so fee can be estimated? - MoneroTxWallet feeEstimateTx = createPayoutTx();; + log.info("Creating fee estimate tx for {} {}", getClass().getSimpleName(), getId()); + saveWallet(); // save wallet before creating fee estimate tx + MoneroTxWallet feeEstimateTx = createPayoutTx(); BigInteger feeEstimate = feeEstimateTx.getFee(); double feeDiff = payoutTx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); // TODO: use BigDecimal? if (feeDiff > XmrWalletService.MINER_FEE_TOLERANCE) throw new IllegalArgumentException("Miner fee is not within " + (XmrWalletService.MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + payoutTx.getFee()); log.info("Payout tx fee {} is within tolerance, diff %={}", payoutTx.getFee(), feeDiff); } - // update trade state - setPayoutTx(payoutTx); - setPayoutTxHex(payoutTxHex); + // save trade state + saveWallet(); + requestPersistence(); // submit payout tx - if (publish) { - //if (true) throw new RuntimeException("Let's pretend there's an error last second submitting tx to daemon, so we need to resubmit payout hex"); - wallet.submitMultisigTxHex(payoutTxHex); - pollWallet(); + boolean doPublish = publish && !isPayoutPublished(); + if (doPublish) { + try { + wallet.submitMultisigTxHex(getPayoutTxHex()); + setPayoutStatePublished(); + } catch (Exception e) { + if (!isPayoutPublished()) { + if (HavenoUtils.isTransactionRejected(e) || HavenoUtils.isNotEnoughSigners(e)) throw new IllegalArgumentException(e); + throw new RuntimeException("Failed to submit payout tx for " + getClass().getSimpleName() + " " + getId() + ", error=" + e.getMessage(), e); + } + } } } @@ -1036,6 +1442,7 @@ public abstract class Trade implements Tradable, Model { // set payment account payload getTradePeer().setPaymentAccountPayload(paymentAccountPayload); + processModel.getPaymentAccountDecryptedProperty().set(true); } catch (Exception e) { throw new RuntimeException(e); } @@ -1043,59 +1450,32 @@ public abstract class Trade implements Tradable, Model { @Nullable public MoneroTx getTakerDepositTx() { - return getDepositTx(getTaker()); + return getTaker().getDepositTx(); } @Nullable public MoneroTx getMakerDepositTx() { - return getDepositTx(getMaker()); - } - - private MoneroTx getDepositTx(TradePeer trader) { - String depositId = trader.getDepositTxHash(); - if (depositId == null) return null; - try { - if (trader.getDepositTx() == null || !trader.getDepositTx().isConfirmed()) { - MoneroTx depositTx = getDepositTxFromWalletOrDaemon(depositId); - if (depositTx != null) trader.setDepositTx(depositTx); - } - return trader.getDepositTx(); - } catch (MoneroError e) { - log.error("Error getting {} deposit tx {}: {}", getPeerRole(trader), depositId, e.getMessage()); // TODO: peer.getRole() - return null; - } - } - - private MoneroTx getDepositTxFromWalletOrDaemon(String txId) { - MoneroTx tx = null; - - // first check wallet - if (getWallet() != null) { - List<MoneroTxWallet> filteredTxs = getWallet().getTxs(new MoneroTxQuery() - .setHash(txId) - .setIsConfirmed(isDepositsConfirmed() ? true : null)); // avoid checking pool if confirmed - if (filteredTxs.size() == 1) tx = filteredTxs.get(0); - } - - // then check daemon - if (tx == null) tx = getXmrWalletService().getTxWithCache(txId); - return tx; + return getMaker().getDepositTx(); } public void addAndPersistChatMessage(ChatMessage chatMessage) { - if (!chatMessages.contains(chatMessage)) { - chatMessages.add(chatMessage); - } else { - log.error("Trade ChatMessage already exists"); + synchronized (chatMessages) { + if (!chatMessages.contains(chatMessage)) { + chatMessages.add(chatMessage); + } else { + log.error("Trade ChatMessage already exists"); + } } } public boolean removeAllChatMessages() { - if (chatMessages.size() > 0) { - chatMessages.clear(); - return true; + synchronized (chatMessages) { + if (chatMessages.size() > 0) { + chatMessages.clear(); + return true; + } + return false; } - return false; } public boolean mediationResultAppliedPenaltyToSeller() { @@ -1103,10 +1483,37 @@ public abstract class Trade implements Tradable, Model { // by mediators and we keep the confirm disabled to avoid that the seller can complete the trade // without the penalty. long payoutAmountFromMediation = processModel.getSellerPayoutAmountFromMediation(); - long normalPayoutAmount = getSellerSecurityDeposit().longValueExact(); + long normalPayoutAmount = getSeller().getSecurityDeposit().longValueExact(); return payoutAmountFromMediation < normalPayoutAmount; } + public void clearAndShutDown() { + ThreadUtils.execute(() -> { + clearProcessData(); + onShutDownStarted(); + ThreadUtils.submitToPool(() -> shutDown()); // run off trade thread + }, getId()); + } + + private void clearProcessData() { + + // delete trade wallet + synchronized (walletLock) { + if (!walletExists()) return; // done if already cleared + deleteWallet(); + } + + // TODO: clear other process data + setPayoutTxHex(null); + for (TradePeer peer : getAllPeers()) { + peer.setUnsignedPayoutTxHex(null); + peer.setUpdatedMultisigHex(null); + peer.setDisputeClosedMessage(null); + peer.setPaymentSentMessage(null); + peer.setPaymentReceivedMessage(null); + } + } + public void maybeClearSensitiveData() { String change = ""; if (removeAllChatMessages()) { @@ -1118,35 +1525,199 @@ public abstract class Trade implements Tradable, Model { } public void onShutDownStarted() { + if (wallet != null) log.info("Preparing to shut down {} {}", getClass().getSimpleName(), getId()); isShutDownStarted = true; - if (wallet != null) log.info("{} {} preparing for shut down", getClass().getSimpleName(), getId()); - - // repeatedly acquire trade lock to allow other threads to finish - for (int i = 0; i < 20; i++) { - synchronized (this) { - synchronized (walletLock) { - if (isShutDown) break; - } - } - } + stopPolling(); } public void shutDown() { - if (!isPayoutUnlocked()) log.info("{} {} shutting down", getClass().getSimpleName(), getId()); - synchronized (this) { - isInitialized = false; - isShutDown = true; - synchronized (walletLock) { - if (wallet != null) { - xmrWalletService.saveWallet(wallet, false); // skip backup - stopWallet(); + if (isShutDown) return; // ignore if already shut down + isShutDownStarted = true; + if (!isPayoutUnlocked()) log.info("Shutting down {} {}", getClass().getSimpleName(), getId()); + + // create task to shut down trade + Runnable shutDownTask = () -> { + + // repeatedly acquire lock to clear tasks + for (int i = 0; i < 20; i++) { + synchronized (getLock()) { + HavenoUtils.waitFor(10); } } + + // shut down trade threads + synchronized (getLock()) { + isInitialized = false; + isShutDown = true; + List<Runnable> shutDownThreads = new ArrayList<>(); + shutDownThreads.add(() -> ThreadUtils.shutDown(getId())); + ThreadUtils.awaitTasks(shutDownThreads); + } + + // save and close + if (wallet != null) { + try { + closeWallet(); + } catch (Exception e) { + // warning will be logged for main wallet, so skip logging here + //log.warn("Error closing monero-wallet-rpc subprocess for {} {}: {}. Was Haveno stopped manually with ctrl+c?", getClass().getSimpleName(), getId(), e.getMessage()); + } + } + }; + + // shut down trade with timeout + try { + ThreadUtils.awaitTask(shutDownTask, SHUTDOWN_TIMEOUT_MS); + } catch (Exception e) { + log.warn("Error shutting down {} {}: {}\n", getClass().getSimpleName(), getId(), e.getMessage(), e); + + // force close wallet + forceCloseWallet(); + } + + // de-initialize + if (idlePayoutSyncer != null) { + xmrWalletService.removeWalletListener(idlePayoutSyncer); + idlePayoutSyncer = null; + } + UserThread.execute(() -> { if (tradeStateSubscription != null) tradeStateSubscription.unsubscribe(); if (tradePhaseSubscription != null) tradePhaseSubscription.unsubscribe(); if (payoutStateSubscription != null) payoutStateSubscription.unsubscribe(); - idlePayoutSyncer = null; // main wallet removes listener itself + if (disputeStateSubscription != null) disputeStateSubscription.unsubscribe(); + }); + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // Trade error cleanup + /////////////////////////////////////////////////////////////////////////////////////////// + + public void onProtocolError() { + + // check if deposit published + if (isDepositsPublished()) { + restoreDepositsPublishedTrade(); + return; } + + // unreserve taker's key images + if (this instanceof TakerTrade) { + ThreadUtils.submitToPool(() -> { + xmrWalletService.thawOutputs(getSelf().getReserveTxKeyImages()); + }); + } + + // unreserve maker's open offer + Optional<OpenOffer> openOffer = processModel.getOpenOfferManager().getOpenOfferById(this.getId()); + if (this instanceof MakerTrade && openOffer.isPresent()) { + processModel.getOpenOfferManager().unreserveOpenOffer(openOffer.get()); + } + + // remove if deposit not requested or is failed + if (!isDepositRequested() || isDepositFailed()) { + removeTradeOnError(); + return; + } + + // done if wallet already deleted + if (!walletExists()) return; + + // move to failed trades + processModel.getTradeManager().onMoveInvalidTradeToFailedTrades(this); + + // set error height + if (processModel.getTradeProtocolErrorHeight() == 0) { + log.warn("Scheduling to remove trade if unfunded for {} {} from height {}", getClass().getSimpleName(), getId(), xmrConnectionService.getLastInfo().getHeight()); + processModel.setTradeProtocolErrorHeight(xmrConnectionService.getLastInfo().getHeight()); + } + + // listen for deposits published to restore trade + protocolErrorStateSubscription = EasyBind.subscribe(stateProperty(), state -> { + if (isDepositsPublished()) { + restoreDepositsPublishedTrade(); + if (protocolErrorStateSubscription != null) { // unsubscribe + protocolErrorStateSubscription.unsubscribe(); + protocolErrorStateSubscription = null; + } + } + }); + + // listen for block confirmations to remove trade + long startTime = System.currentTimeMillis(); + protocolErrorHeightSubscription = EasyBind.subscribe(walletHeight, lastWalletHeight -> { + if (isShutDown || isDepositsPublished()) return; + if (lastWalletHeight.longValue() < processModel.getTradeProtocolErrorHeight() + DELETE_AFTER_NUM_BLOCKS) return; + if (System.currentTimeMillis() - startTime < DELETE_AFTER_MS) return; + + // remove trade off thread + ThreadUtils.submitToPool(() -> { + + // get trade's deposit txs from daemon + MoneroTx makerDepositTx = getMaker().getDepositTxHash() == null ? null : xmrWalletService.getDaemon().getTx(getMaker().getDepositTxHash()); + MoneroTx takerDepositTx = getTaker().getDepositTxHash() == null ? null : xmrWalletService.getDaemon().getTx(getTaker().getDepositTxHash()); + + // remove trade and wallet if neither deposit tx published + if (makerDepositTx == null && takerDepositTx == null) { + log.warn("Deleting {} {} after protocol error", getClass().getSimpleName(), getId()); + if (this instanceof ArbitratorTrade && (getMaker().getReserveTxHash() != null || getTaker().getReserveTxHash() != null)) { + processModel.getTradeManager().onMoveInvalidTradeToFailedTrades(this); // arbitrator retains trades with reserved funds for analysis and penalty + deleteWallet(); + onShutDownStarted(); + ThreadUtils.submitToPool(() -> shutDown()); // run off thread + } else { + removeTradeOnError(); + } + } else if (!isPayoutPublished()) { + + // set error if wallet may be partially funded + String errorMessage = "Refusing to delete " + getClass().getSimpleName() + " " + getId() + " after protocol error because its wallet might be funded"; + prependErrorMessage(errorMessage); + log.warn(errorMessage); + } + + // unsubscribe + if (protocolErrorHeightSubscription != null) { + protocolErrorHeightSubscription.unsubscribe(); + protocolErrorHeightSubscription = null; + } + }); + }); + } + + private void restoreDepositsPublishedTrade() { + + // close open offer + if (this instanceof MakerTrade && processModel.getOpenOfferManager().getOpenOfferById(getId()).isPresent()) { + log.info("Closing open offer because {} {} was restored after protocol error", getClass().getSimpleName(), getShortId()); + processModel.getOpenOfferManager().closeOpenOffer(checkNotNull(getOffer())); + } + + // re-freeze outputs + xmrWalletService.freezeOutputs(getSelf().getReserveTxKeyImages()); + + // restore trade from failed trades + processModel.getTradeManager().onMoveFailedTradeToPendingTrades(this); + } + + private void removeTradeOnError() { + log.warn("removeTradeOnError() trade={}, tradeId={}, state={}", getClass().getSimpleName(), getShortId(), getState()); + + // force close and re-open wallet in case stuck + forceCloseWallet(); + if (isDepositRequested()) getWallet(); + + // shut down trade thread + try { + ThreadUtils.shutDown(getId(), 1000l); + } catch (Exception e) { + log.warn("Error shutting down trade thread for {} {}: {}", getClass().getSimpleName(), getId(), e.getMessage()); + } + + // clear and shut down trade + clearAndShutDown(); + + // unregister trade + processModel.getTradeManager().unregisterTrade(this); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1162,7 +1733,7 @@ public abstract class Trade implements Tradable, Model { // Abstract /////////////////////////////////////////////////////////////////////////////////////////// - public abstract BigInteger getPayoutAmount(); + public abstract BigInteger getPayoutAmountBeforeCost(); public abstract boolean confirmPermitted(); @@ -1178,10 +1749,16 @@ public abstract class Trade implements Tradable, Model { } public void addInitProgressStep() { + startProtocolTimeout(); initProgress = Math.min(1.0, (double) ++initStep / TOTAL_INIT_STEPS); + //if (this instanceof TakerTrade) log.warn("Init step count: " + initStep); // log init step count for taker trades in order to update total steps UserThread.execute(() -> initProgressProperty.set(initProgress)); } + public void startProtocolTimeout() { + getProtocol().startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS); + } + public void setState(State state) { if (isInitialized) { // We don't want to log at startup the setState calls from all persisted trades @@ -1194,7 +1771,8 @@ public abstract class Trade implements Tradable, Model { } this.state = state; - UserThread.execute(() -> { + requestPersistence(); + UserThread.await(() -> { stateProperty.set(state); phaseProperty.set(state.getPhase()); }); @@ -1225,9 +1803,8 @@ public abstract class Trade implements Tradable, Model { } this.payoutState = payoutState; - UserThread.execute(() -> { - payoutStateProperty.set(payoutState); - }); + requestPersistence(); + UserThread.await(() -> payoutStateProperty.set(payoutState)); } public void setDisputeState(DisputeState disputeState) { @@ -1276,12 +1853,57 @@ public abstract class Trade implements Tradable, Model { getVolumeProperty().set(getVolume()); } - public void setPayoutTx(MoneroTxWallet payoutTx) { + public void updatePayout(MoneroTxWallet payoutTx) { + + // set payout tx fields this.payoutTx = payoutTx; - payoutTxId = payoutTx.getHash(); - if ("".equals(payoutTxId)) payoutTxId = null; // tx hash is empty until signed payoutTxKey = payoutTx.getKey(); + payoutTxFee = payoutTx.getFee().longValueExact(); + payoutTxId = payoutTx.getHash(); + if ("".equals(payoutTxId)) payoutTxId = null; // tx id is empty until signed + + // set payout tx id in dispute(s) for (Dispute dispute : getDisputes()) dispute.setDisputePayoutTxId(payoutTxId); + + // set final payout amounts + if (isPaymentReceived()) { + BigInteger splitTxFee = payoutTx.getFee().divide(BigInteger.valueOf(2)); + getBuyer().setPayoutTxFee(splitTxFee); + getSeller().setPayoutTxFee(splitTxFee); + getBuyer().setPayoutAmount(getBuyer().getSecurityDeposit().subtract(getBuyer().getPayoutTxFee()).add(getAmount())); + getSeller().setPayoutAmount(getSeller().getSecurityDeposit().subtract(getSeller().getPayoutTxFee())); + } else if (getDisputeState().isClosed()) { + DisputeResult disputeResult = getDisputeResult(); + if (disputeResult == null) log.warn("Dispute result is not set for {} {}", getClass().getSimpleName(), getId()); + else { + BigInteger[] buyerSellerPayoutTxFees = ArbitrationManager.getBuyerSellerPayoutTxCost(disputeResult, payoutTx.getFee()); + getBuyer().setPayoutTxFee(buyerSellerPayoutTxFees[0]); + getSeller().setPayoutTxFee(buyerSellerPayoutTxFees[1]); + getBuyer().setPayoutAmount(disputeResult.getBuyerPayoutAmountBeforeCost().subtract(getBuyer().getPayoutTxFee())); + getSeller().setPayoutAmount(disputeResult.getSellerPayoutAmountBeforeCost().subtract(getSeller().getPayoutTxFee())); + } + } + } + + public DisputeResult getDisputeResult() { + if (getDisputes().isEmpty()) return null; + return getDisputes().get(getDisputes().size() - 1).getDisputeResultProperty().get(); + } + + @Nullable + public MoneroTx getPayoutTx() { + if (payoutTx == null) { + payoutTx = payoutTxId == null ? null : (this instanceof ArbitratorTrade) ? xmrWalletService.getDaemonTxWithCache(payoutTxId) : xmrWalletService.getTx(payoutTxId); + } + return payoutTx; + } + + public void setPayoutTxFee(BigInteger payoutTxFee) { + this.payoutTxFee = payoutTxFee.longValueExact(); + } + + public BigInteger getPayoutTxFee() { + return BigInteger.valueOf(payoutTxFee); } public void setErrorMessage(String errorMessage) { @@ -1333,12 +1955,17 @@ public abstract class Trade implements Tradable, Model { throw new RuntimeException("Trade is not maker, taker, or arbitrator"); } - private List<TradePeer> getPeers() { + private List<TradePeer> getOtherPeers() { + List<TradePeer> peers = getAllPeers(); + if (!peers.remove(getSelf())) throw new IllegalStateException("Failed to remove self from list of peers"); + return peers; + } + + private List<TradePeer> getAllPeers() { List<TradePeer> peers = new ArrayList<TradePeer>(); peers.add(getMaker()); peers.add(getTaker()); peers.add(getArbitrator()); - if (!peers.remove(getSelf())) throw new IllegalStateException("Failed to remove self from list of peers"); return peers; } @@ -1392,6 +2019,24 @@ public abstract class Trade implements Tradable, Model { throw new IllegalArgumentException("Trade is not buyer, seller, or arbitrator"); } + public MessageState getPaymentSentMessageState() { + if (isPaymentReceived()) return MessageState.ACKNOWLEDGED; + if (processModel.getPaymentSentMessageStateProperty().get() == MessageState.ACKNOWLEDGED) return MessageState.ACKNOWLEDGED; + switch (state) { + case BUYER_SENT_PAYMENT_SENT_MSG: + case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG: + return MessageState.SENT; + case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG: + return MessageState.STORED_IN_MAILBOX; + case SELLER_RECEIVED_PAYMENT_SENT_MSG: + return MessageState.ARRIVED; + case BUYER_SEND_FAILED_PAYMENT_SENT_MSG: + return MessageState.FAILED; + default: + return null; + } + } + public String getPeerRole(TradePeer peer) { if (peer == getBuyer()) return "Buyer"; if (peer == getSeller()) return "Seller"; @@ -1454,9 +2099,9 @@ public abstract class Trade implements Tradable, Model { final long tradeTime = getTakeOfferDate().getTime(); MoneroDaemon daemonRpc = xmrWalletService.getDaemon(); if (daemonRpc == null) throw new RuntimeException("Cannot set start time for trade " + getId() + " because it has no connection to monerod"); - if (getMakerDepositTx() == null || getTakerDepositTx() == null) throw new RuntimeException("Cannot set start time for trade " + getId() + " because its unlocked deposit tx is null. Is client connected to a daemon?"); + if (getMakerDepositTx() == null || (getTakerDepositTx() == null && !hasBuyerAsTakerWithoutDeposit())) throw new RuntimeException("Cannot set start time for trade " + getId() + " because its unlocked deposit tx is null. Is client connected to a daemon?"); - long maxHeight = Math.max(getMakerDepositTx().getHeight(), getTakerDepositTx().getHeight()); + long maxHeight = Math.max(getMakerDepositTx().getHeight(), hasBuyerAsTakerWithoutDeposit() ? 0l : getTakerDepositTx().getHeight()); long blockTime = daemonRpc.getBlockByHeight(maxHeight).getTimestamp(); // If block date is in future (Date in blocks can be off by +/- 2 hours) we use our current date. @@ -1487,7 +2132,8 @@ public abstract class Trade implements Tradable, Model { } public boolean isDepositsPublished() { - return getState().getPhase().ordinal() >= Phase.DEPOSITS_PUBLISHED.ordinal() && getMaker().getDepositTxHash() != null && getTaker().getDepositTxHash() != null; + if (isDepositFailed()) return false; + return getState().getPhase().ordinal() >= Phase.DEPOSITS_PUBLISHED.ordinal() && getMaker().getDepositTxHash() != null && (getTaker().getDepositTxHash() != null || hasBuyerAsTakerWithoutDeposit()); } public boolean isFundsLockedIn() { @@ -1503,7 +2149,7 @@ public abstract class Trade implements Tradable, Model { if (this instanceof BuyerTrade) { return getArbitrator().isDepositsConfirmedMessageAcked(); } else { - for (TradePeer peer : getPeers()) if (!peer.isDepositsConfirmedMessageAcked()) return false; + for (TradePeer peer : getOtherPeers()) if (!peer.isDepositsConfirmedMessageAcked()) return false; return true; } } @@ -1516,12 +2162,22 @@ public abstract class Trade implements Tradable, Model { return getState().getPhase().ordinal() >= Phase.PAYMENT_SENT.ordinal(); } - public boolean isPaymentReceived() { - return getState().getPhase().ordinal() >= Phase.PAYMENT_RECEIVED.ordinal(); + public boolean hasPaymentReceivedMessage() { + return (isSeller() ? getBuyer() : getSeller()).getPaymentReceivedMessage() != null; // seller stores message to buyer and arbitrator, peers store message from seller } - public boolean isCompleted() { - return getState().getPhase().ordinal() >= Phase.COMPLETED.ordinal(); + public boolean hasDisputeClosedMessage() { + + // arbitrator stores message to buyer and seller, peers store message from arbitrator + return isArbitrator() ? getBuyer().getDisputeClosedMessage() != null || getSeller().getDisputeClosedMessage() != null : getArbitrator().getDisputeClosedMessage() != null; + } + + public boolean isDisputeClosed() { + return getDisputeState().isClosed(); + } + + public boolean isPaymentReceived() { + return getState().getPhase().ordinal() >= Phase.PAYMENT_RECEIVED.ordinal(); } public boolean isPayoutPublished() { @@ -1595,6 +2251,26 @@ public abstract class Trade implements Tradable, Model { return offer.getShortId(); } + public String getShortUid() { + return Utilities.getShortId(getUid()); + } + + public BigInteger getFrozenAmount() { + BigInteger sum = BigInteger.ZERO; + if (getSelf().getReserveTxKeyImages() != null) { + for (String keyImage : getSelf().getReserveTxKeyImages()) { + List<MoneroOutputWallet> outputs = xmrWalletService.getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage))); + if (!outputs.isEmpty()) sum = sum.add(outputs.get(0).getAmount()); + } + } + return sum; + } + + public BigInteger getReservedAmount() { + if (isArbitrator() || !isDepositsPublished() || isPayoutPublished()) return BigInteger.ZERO; + return isBuyer() ? getBuyer().getSecurityDeposit() : getAmount().add(getSeller().getSecurityDeposit()); + } + public Price getPrice() { return Price.valueOf(offer.getCurrencyCode(), price); } @@ -1605,34 +2281,36 @@ public abstract class Trade implements Tradable, Model { } public BigInteger getMakerFee() { - return offer.getMakerFee(); + return offer.getMakerFee(getAmount()); } public BigInteger getTakerFee() { - return BigInteger.valueOf(takerFee); + return hasBuyerAsTakerWithoutDeposit() ? BigInteger.ZERO : offer.getTakerFee(getAmount()); + } + + public BigInteger getSecurityDepositBeforeMiningFee() { + return isBuyer() ? getBuyerSecurityDepositBeforeMiningFee() : getSellerSecurityDepositBeforeMiningFee(); + } + + public BigInteger getBuyerSecurityDepositBeforeMiningFee() { + return offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(getAmount()); + } + + public BigInteger getSellerSecurityDepositBeforeMiningFee() { + return offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(getAmount()); + } + + public boolean isBuyerAsTakerWithoutDeposit() { + return isBuyer() && isTaker() && BigInteger.ZERO.equals(getBuyerSecurityDepositBeforeMiningFee()); + } + + public boolean hasBuyerAsTakerWithoutDeposit() { + return getBuyer() == getTaker() && BigInteger.ZERO.equals(getBuyerSecurityDepositBeforeMiningFee()); } @Override public BigInteger getTotalTxFee() { - return BigInteger.valueOf(totalTxFee); - } - - public BigInteger getBuyerSecurityDeposit() { - if (getBuyer().getDepositTxHash() == null) return null; - return getBuyer().getSecurityDeposit(); - } - - public BigInteger getSellerSecurityDeposit() { - if (getSeller().getDepositTxHash() == null) return null; - return getSeller().getSecurityDeposit(); - } - - @Nullable - public MoneroTx getPayoutTx() { - if (payoutTx == null) { - payoutTx = payoutTxId == null ? null : (this instanceof ArbitratorTrade) ? xmrWalletService.getTxWithCache(payoutTxId) : xmrWalletService.getWallet().getTx(payoutTxId); - } - return payoutTx; + return getSelf().getDepositTxFee().add(getSelf().getPayoutTxFee()); // sum my tx fees } public boolean hasErrorMessage() { @@ -1645,7 +2323,7 @@ public abstract class Trade implements Tradable, Model { } public boolean isTxChainInvalid() { - return processModel.getMaker().getDepositTxHash() == null || processModel.getTaker().getDepositTxHash() == null; + return processModel.getMaker().getDepositTxHash() == null || (processModel.getTaker().getDepositTxHash() == null && !hasBuyerAsTakerWithoutDeposit()); } /** @@ -1655,12 +2333,37 @@ public abstract class Trade implements Tradable, Model { */ public long getReprocessDelayInSeconds(int reprocessCount) { int retryCycles = 3; // reprocess on next refresh periods for first few attempts (app might auto switch to a good connection) - if (reprocessCount < retryCycles) return xmrWalletService.getConnectionsService().getRefreshPeriodMs() / 1000; + if (reprocessCount < retryCycles) return xmrConnectionService.getRefreshPeriodMs() / 1000; long delay = 60; for (int i = retryCycles; i < reprocessCount; i++) delay *= 2; return Math.min(MAX_REPROCESS_DELAY_SECONDS, delay); } + public void maybePublishTradeStatistics() { + if (shouldPublishTradeStatistics()) doPublishTradeStatistics(); + } + + public boolean shouldPublishTradeStatistics() { + if (!isSeller()) return false; + return tradeAmountTransferred(); + } + + public boolean tradeAmountTransferred() { + return isPaymentReceived() || (getDisputeResult() != null && getDisputeResult().getWinner() == DisputeResult.Winner.SELLER); + } + + private void doPublishTradeStatistics() { + String referralId = processModel.getReferralIdService().getOptionalReferralId().orElse(null); + boolean isTorNetworkNode = getProcessModel().getP2PService().getNetworkNode() instanceof TorNetworkNode; + TradeStatistics3 tradeStatistics = TradeStatistics3.from(this, referralId, isTorNetworkNode, true); + if (tradeStatistics.isValid()) { + log.info("Publishing trade statistics for {} {}", getClass().getSimpleName(), getId()); + processModel.getP2PService().addPersistableNetworkPayload(tradeStatistics, true); + } else { + log.warn("Trade statistics are invalid for {} {}. We do not publish: {}", getClass().getSimpleName(), getId(), tradeStatistics); + } + } + /////////////////////////////////////////////////////////////////////////////////////////// // Private @@ -1684,10 +2387,16 @@ public abstract class Trade implements Tradable, Model { private void onConnectionChanged(MoneroRpcConnection connection) { synchronized (walletLock) { + // use current connection + connection = xmrConnectionService.getConnection(); + // check if ignored if (isShutDownStarted) return; if (getWallet() == null) return; - if (HavenoUtils.connectionConfigsEqual(connection, wallet.getDaemonConnection())) return; + if (HavenoUtils.connectionConfigsEqual(connection, wallet.getDaemonConnection())) { + updatePollPeriod(); + return; + } // set daemon connection (must restart monero-wallet-rpc if proxy uri changed) String oldProxyUri = wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getProxyUri(); @@ -1702,31 +2411,32 @@ public abstract class Trade implements Tradable, Model { } // sync and reprocess messages on new thread - if (isInitialized && connection != null && !Boolean.FALSE.equals(connection.isConnected())) { - HavenoUtils.submitTask(() -> { - initSyncing(); - }); + if (isInitialized && connection != null && !Boolean.FALSE.equals(xmrConnectionService.isConnected())) { + ThreadUtils.execute(() -> tryInitPolling(), getId()); } } } - - private void initSyncing() { + private void tryInitPolling() { if (isShutDownStarted) return; + + // set known deposit txs + List<MoneroTxWallet> depositTxs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true).setInTxPool(false)); + setDepositTxs(depositTxs); + + // start polling if (!isIdling()) { - initSyncingAux(); + tryInitPollingAux(); } else { - long startSyncingInMs = ThreadLocalRandom.current().nextLong(0, getWalletRefreshPeriod()); // random time to start syncing - UserThread.runAfter(() -> { - if (!isShutDownStarted) { - initSyncingAux(); - } - }, startSyncingInMs / 1000l); + long startSyncingInMs = ThreadLocalRandom.current().nextLong(0, getPollPeriod()); // random time to start polling + UserThread.runAfter(() -> ThreadUtils.execute(() -> { + if (!isShutDownStarted) tryInitPollingAux(); + }, getId()), startSyncingInMs / 1000l); } } - private void initSyncingAux() { - if (!wasWalletSynced) trySyncWallet(false); - updateWalletRefreshPeriod(); + private void tryInitPollingAux() { + if (!wasWalletSynced) trySyncWallet(true); + updatePollPeriod(); // reprocess pending payout messages this.getProtocol().maybeReprocessPaymentReceivedMessage(false); @@ -1746,36 +2456,44 @@ public abstract class Trade implements Tradable, Model { } private void syncWallet(boolean pollWallet) { - if (getWallet() == null) throw new RuntimeException("Cannot sync trade wallet because it doesn't exist for " + getClass().getSimpleName() + ", " + getId()); - if (getWallet().getDaemonConnection() == null) throw new RuntimeException("Cannot sync trade wallet because it's not connected to a Monero daemon for " + getClass().getSimpleName() + ", " + getId()); - log.info("Syncing wallet for {} {}", getClass().getSimpleName(), getId()); - xmrWalletService.syncWallet(getWallet()); - log.info("Done syncing wallet for {} {}", getClass().getSimpleName(), getId()); - - // apply tor after wallet synced depending on configuration - if (!wasWalletSynced) { - wasWalletSynced = true; - if (xmrWalletService.isProxyApplied(wasWalletSynced)) { - onConnectionChanged(xmrWalletService.getConnectionsService().getConnection()); + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + synchronized (walletLock) { + if (getWallet() == null) throw new RuntimeException("Cannot sync trade wallet because it doesn't exist for " + getClass().getSimpleName() + ", " + getId()); + if (getWallet().getDaemonConnection() == null) throw new RuntimeException("Cannot sync trade wallet because it's not connected to a Monero daemon for " + getClass().getSimpleName() + ", " + getId()); + if (isWalletBehind()) { + log.info("Syncing wallet for {} {}", getClass().getSimpleName(), getShortId()); + long startTime = System.currentTimeMillis(); + syncWalletIfBehind(); + log.info("Done syncing wallet for {} {} in {} ms", getClass().getSimpleName(), getShortId(), System.currentTimeMillis() - startTime); + } } + + // apply tor after wallet synced depending on configuration + if (!wasWalletSynced) { + wasWalletSynced = true; + if (xmrWalletService.isProxyApplied(wasWalletSynced)) { + onConnectionChanged(xmrConnectionService.getConnection()); + } + } + + if (pollWallet) doPollWallet(); + } catch (Exception e) { + ThreadUtils.execute(() -> requestSwitchToNextBestConnection(sourceConnection), getId()); + throw e; } - - if (pollWallet) pollWallet(); } - public void updateWalletRefreshPeriod() { - setWalletRefreshPeriod(getWalletRefreshPeriod()); + public void updatePollPeriod() { + if (isShutDownStarted) return; + setPollPeriod(getPollPeriod()); } - private void setWalletRefreshPeriod(long walletRefreshPeriod) { - synchronized (walletLock) { + private void setPollPeriod(long pollPeriodMs) { + synchronized (pollLock) { if (this.isShutDownStarted) return; - if (this.walletRefreshPeriod != null && this.walletRefreshPeriod == walletRefreshPeriod) return; - this.walletRefreshPeriod = walletRefreshPeriod; - if (getWallet() != null) { - log.info("Setting wallet refresh rate for {} {} to {}", getClass().getSimpleName(), getId(), walletRefreshPeriod); - getWallet().startSyncing(getWalletRefreshPeriod()); // TODO (monero-project): wallet rpc waits until last sync period finishes before starting new sync period - } + if (this.pollPeriodMs != null && this.pollPeriodMs == pollPeriodMs) return; + this.pollPeriodMs = pollPeriodMs; if (isPolling()) { stopPolling(); startPolling(); @@ -1783,100 +2501,164 @@ public abstract class Trade implements Tradable, Model { } } + private long getPollPeriod() { + if (isIdling()) return IDLE_SYNC_PERIOD_MS; + return xmrConnectionService.getRefreshPeriodMs(); + } + private void startPolling() { - synchronized (walletLock) { - if (isPolling()) return; + synchronized (pollLock) { + if (isShutDownStarted || isPolling()) return; + updatePollPeriod(); log.info("Starting to poll wallet for {} {}", getClass().getSimpleName(), getId()); - txPollLooper = new TaskLooper(() -> pollWallet()); - txPollLooper.start(walletRefreshPeriod); + pollLooper = new TaskLooper(() -> pollWallet()); + pollLooper.start(pollPeriodMs); } } private void stopPolling() { - synchronized (walletLock) { + synchronized (pollLock) { if (isPolling()) { - txPollLooper.stop(); - txPollLooper = null; + pollLooper.stop(); + pollLooper = null; } } } private boolean isPolling() { - synchronized (walletLock) { - return txPollLooper != null; + synchronized (pollLock) { + return pollLooper != null; } } private void pollWallet() { - try { + synchronized (pollLock) { + if (pollInProgress) return; + } + doPollWallet(); + } - // skip if either deposit tx id is unknown - if (processModel.getMaker().getDepositTxHash() == null || processModel.getTaker().getDepositTxHash() == null) return; + private void doPollWallet() { + + // skip if shut down started + if (isShutDownStarted) return; + + // set poll in progress + boolean pollInProgressSet = false; + synchronized (pollLock) { + if (!pollInProgress) pollInProgressSet = true; + pollInProgress = true; + } + + // poll wallet + try { // skip if payout unlocked if (isPayoutUnlocked()) return; - // rescan spent outputs to detect payout tx after deposits unlocked - if (isDepositsUnlocked() && !isPayoutPublished()) getWallet().rescanSpent(); + // skip if deposit txs unknown or not requested + if (!isDepositRequested() || processModel.getMaker().getDepositTxHash() == null || (processModel.getTaker().getDepositTxHash() == null && !hasBuyerAsTakerWithoutDeposit())) return; - // get txs from trade wallet - boolean payoutExpected = isPaymentReceived() || processModel.getPaymentReceivedMessage() != null || disputeState.ordinal() > DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal() || processModel.getDisputeClosedMessage() != null; - boolean checkPool = !isDepositsConfirmed() || (!isPayoutConfirmed() && payoutExpected); - MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true); - if (!checkPool) query.setInTxPool(false); // avoid pool check if possible - List<MoneroTxWallet> txs = wallet.getTxs(query); + // skip if daemon not synced + if (xmrConnectionService.getTargetHeight() == null || !xmrConnectionService.isSyncedWithinTolerance()) return; - // warn on double spend // TODO: other handling? - for (MoneroTxWallet tx : txs) { - if (Boolean.TRUE.equals(tx.isDoubleSpendSeen())) log.warn("Double spend seen for tx {} for {} {}", tx.getHash(), getClass().getSimpleName(), getId()); - } + // sync if wallet too far behind daemon + if (walletHeight.get() < xmrConnectionService.getTargetHeight() - SYNC_EVERY_NUM_BLOCKS) syncWallet(false); - // check deposit txs + // update deposit txs if (!isDepositsUnlocked()) { - - // update trader txs - MoneroTxWallet makerDepositTx = null; - MoneroTxWallet takerDepositTx = null; - for (MoneroTxWallet tx : txs) { - if (tx.getHash().equals(processModel.getMaker().getDepositTxHash())) makerDepositTx = tx; - if (tx.getHash().equals(processModel.getTaker().getDepositTxHash())) takerDepositTx = tx; + + // sync wallet if behind + syncWalletIfBehind(); + + // get txs from trade wallet + MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true); + Boolean updatePool = !isDepositsConfirmed() && (getMaker().getDepositTx() == null || (getTaker().getDepositTx() == null && hasBuyerAsTakerWithoutDeposit())); + if (!updatePool) query.setInTxPool(false); // avoid updating from pool if possible + List<MoneroTxWallet> txs; + if (!updatePool) txs = wallet.getTxs(query); + else { + synchronized (walletLock) { + synchronized (HavenoUtils.getDaemonLock()) { + txs = wallet.getTxs(query); + } + } } - if (makerDepositTx != null) getMaker().setDepositTx(makerDepositTx); - if (takerDepositTx != null) getTaker().setDepositTx(takerDepositTx); + setDepositTxs(txs); + if (getMaker().getDepositTx() == null || (getTaker().getDepositTx() == null && !hasBuyerAsTakerWithoutDeposit())) return; // skip if either deposit tx not seen + setStateDepositsSeen(); - // skip if deposit txs not seen - if (makerDepositTx == null || takerDepositTx == null) return; - - // set security deposits + // set actual security deposits if (getBuyer().getSecurityDeposit().longValueExact() == 0) { - BigInteger buyerSecurityDeposit = ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount(); + BigInteger buyerSecurityDeposit = hasBuyerAsTakerWithoutDeposit() ? BigInteger.ZERO : ((MoneroTxWallet) getBuyer().getDepositTx()).getIncomingAmount(); BigInteger sellerSecurityDeposit = ((MoneroTxWallet) getSeller().getDepositTx()).getIncomingAmount().subtract(getAmount()); getBuyer().setSecurityDeposit(buyerSecurityDeposit); getSeller().setSecurityDeposit(sellerSecurityDeposit); } - // update state - setStateDepositsPublished(); - if (makerDepositTx.isConfirmed() && takerDepositTx.isConfirmed()) setStateDepositsConfirmed(); - if (!makerDepositTx.isLocked() && !takerDepositTx.isLocked()) setStateDepositsUnlocked(); + // check for deposit txs confirmation + if (getMaker().getDepositTx().isConfirmed() && (hasBuyerAsTakerWithoutDeposit() || getTaker().getDepositTx().isConfirmed())) setStateDepositsConfirmed(); + + // check for deposit txs unlocked + if (getMaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK && (hasBuyerAsTakerWithoutDeposit() || getTaker().getDepositTx().getNumConfirmations() >= XmrWalletService.NUM_BLOCKS_UNLOCK)) { + setStateDepositsUnlocked(); + } } - // check payout tx + // check for payout tx if (isDepositsUnlocked()) { - // check if any outputs spent (observed on payout published) - for (MoneroTxWallet tx : txs) { - for (MoneroOutputWallet output : tx.getOutputsWallet()) { - if (Boolean.TRUE.equals(output.isSpent())) { - setPayoutStatePublished(); + // determine if payout tx expected + boolean isPayoutExpected = isPaymentReceived() || hasPaymentReceivedMessage() || hasDisputeClosedMessage() || disputeState.ordinal() >= DisputeState.ARBITRATOR_SENT_DISPUTE_CLOSED_MSG.ordinal(); + + // sync wallet if payout expected or payout is published + if (isPayoutExpected || isPayoutPublished()) syncWalletIfBehind(); + + // rescan spent outputs to detect unconfirmed payout tx + if (isPayoutExpected && wallet.getBalance().compareTo(BigInteger.ZERO) > 0) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + wallet.rescanSpent(); + } catch (Exception e) { + log.warn("Failed to rescan spent outputs for {} {}, errorMessage={}", getClass().getSimpleName(), getShortId(), e.getMessage()); + ThreadUtils.execute(() -> requestSwitchToNextBestConnection(sourceConnection), getId()); // do not block polling thread + } + } + + // get txs from trade wallet + MoneroTxQuery query = new MoneroTxQuery().setIncludeOutputs(true); + boolean updatePool = isPayoutExpected && !isPayoutConfirmed(); + if (!updatePool) query.setInTxPool(false); // avoid updating from pool if possible + List<MoneroTxWallet> txs = null; + if (!updatePool) txs = wallet.getTxs(query); + else { + synchronized (walletLock) { + synchronized (HavenoUtils.getDaemonLock()) { + txs = wallet.getTxs(query); } } } + setDepositTxs(txs); + + // check if any outputs spent (observed on payout published) + boolean hasSpentOutput = false; + boolean hasFailedTx = false; + for (MoneroTxWallet tx : txs) { + if (tx.isFailed()) hasFailedTx = true; + for (MoneroOutputWallet output : tx.getOutputsWallet()) { + if (Boolean.TRUE.equals(output.isSpent())) hasSpentOutput = true; + } + } + if (hasSpentOutput) setPayoutStatePublished(); + else if (hasFailedTx && isPayoutPublished()) { + log.warn("{} {} is in payout published state but has failed tx and no spent outputs, resetting payout state to unpublished", getClass().getSimpleName(), getShortId()); + setPayoutState(PayoutState.PAYOUT_UNPUBLISHED); + } // check for outgoing txs (appears after wallet submits payout tx or on payout confirmed) for (MoneroTxWallet tx : txs) { - if (tx.isOutgoing()) { - setPayoutTx(tx); + if (tx.isOutgoing() && !tx.isFailed()) { + updatePayout(tx); setPayoutStatePublished(); if (tx.isConfirmed()) setPayoutStateConfirmed(); if (!tx.isLocked()) setPayoutStateUnlocked(); @@ -1884,18 +2666,136 @@ public abstract class Trade implements Tradable, Model { } } } catch (Exception e) { - if (!isShutDownStarted && getWallet() != null && isWalletConnected()) { - log.warn("Error polling trade wallet for {} {}: {}. Monerod={}", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getConnectionsService().getConnection()); + if (HavenoUtils.isUnresponsive(e)) forceRestartTradeWallet(); + else { + boolean isWalletConnected = isWalletConnectedToDaemon(); + if (wallet != null && !isShutDownStarted && isWalletConnected) { + log.warn("Error polling trade wallet for {} {}, errorMessage={}. Monerod={}", getClass().getSimpleName(), getShortId(), e.getMessage(), wallet.getDaemonConnection()); + //e.printStackTrace(); + } + } + } finally { + if (pollInProgressSet) { + synchronized (pollLock) { + pollInProgress = false; + } + } + requestSaveWallet(); + } + } + + private void syncWalletIfBehind() { + synchronized (walletLock) { + if (isWalletBehind()) { + + // TODO: local tests have timing failures unless sync called directly + if (xmrConnectionService.getTargetHeight() - walletHeight.get() < XmrWalletBase.DIRECT_SYNC_WITHIN_BLOCKS) { + xmrWalletService.syncWallet(wallet); + } else { + syncWithProgress(); + } + walletHeight.set(wallet.getHeight()); } } } - private long getWalletRefreshPeriod() { - if (isIdling()) return IDLE_SYNC_PERIOD_MS; - return xmrWalletService.getConnectionsService().getRefreshPeriodMs(); + private boolean isWalletBehind() { + return walletHeight.get() < xmrConnectionService.getTargetHeight(); } - private void setStateDepositsPublished() { + private void setDepositTxs(List<MoneroTxWallet> txs) { + for (MoneroTxWallet tx : txs) { + if (tx.getHash().equals(getMaker().getDepositTxHash())) getMaker().setDepositTx(tx); + if (tx.getHash().equals(getTaker().getDepositTxHash())) getTaker().setDepositTx(tx); + } + depositTxsUpdateCounter.set(depositTxsUpdateCounter.get() + 1); + } + + // TODO: wallet is sometimes missing balance or deposits, due to specific daemon connections, not saving? + private void recoverIfMissingWalletData() { + synchronized (walletLock) { + if (isWalletMissingData()) { + log.warn("Wallet is missing data for {} {}, attempting to recover", getClass().getSimpleName(), getShortId()); + + // force restart wallet + forceRestartTradeWallet(); + + // skip if payout published in the meantime + if (isPayoutPublished()) return; + + // rescan blockchain with global daemon lock + synchronized (HavenoUtils.getDaemonLock()) { + Long timeout = null; + try { + + // extend rpc timeout for rescan + if (wallet instanceof MoneroWalletRpc) { + timeout = ((MoneroWalletRpc) wallet).getRpcConnection().getTimeout(); + ((MoneroWalletRpc) wallet).getRpcConnection().setTimeout(EXTENDED_RPC_TIMEOUT); + } + + // rescan blockchain + log.warn("Rescanning blockchain for {} {}", getClass().getSimpleName(), getShortId()); + wallet.rescanBlockchain(); + } catch (Exception e) { + log.warn("Error rescanning blockchain for {} {}, errorMessage={}", getClass().getSimpleName(), getShortId(), e.getMessage()); + if (HavenoUtils.isUnresponsive(e)) forceRestartTradeWallet(); // wallet can be stuck a while + throw e; + } finally { + + // restore rpc timeout + if (wallet instanceof MoneroWalletRpc) { + ((MoneroWalletRpc) wallet).getRpcConnection().setTimeout(timeout); + } + } + } + + // import multisig hex + log.warn("Importing multisig hex to recover wallet data for {} {}", getClass().getSimpleName(), getShortId()); + importMultisigHex(); + + // poll wallet + doPollWallet(); + + // check again if missing data + if (isWalletMissingData()) throw new IllegalStateException("Wallet is still missing data after attempting recovery for " + getClass().getSimpleName() + " " + getShortId()); + } + } + } + + private boolean isWalletMissingData() { + synchronized (walletLock) { + if (!isDepositsUnlocked() || isPayoutPublished()) return false; + if (getMakerDepositTx() == null) { + log.warn("Missing maker deposit tx for {} {}", getClass().getSimpleName(), getId()); + return true; + } + if (getTakerDepositTx() == null && !hasBuyerAsTakerWithoutDeposit()) { + log.warn("Missing taker deposit tx for {} {}", getClass().getSimpleName(), getId()); + return true; + } + if (wallet.getBalance().equals(BigInteger.ZERO)) { + doPollWallet(); // poll once more to be sure + if (isPayoutPublished()) return false; // payout can become published while checking balance + log.warn("Wallet balance is zero for {} {}", getClass().getSimpleName(), getId()); + return true; + } + return false; + } + } + + private void forceRestartTradeWallet() { + if (isShutDownStarted || restartInProgress) return; + log.warn("Force restarting trade wallet for {} {}", getClass().getSimpleName(), getId()); + restartInProgress = true; + forceCloseWallet(); + if (!isShutDownStarted) wallet = getWallet(); + restartInProgress = false; + pollWallet(); + if (!isShutDownStarted) ThreadUtils.execute(() -> tryInitPolling(), getId()); + } + + private void setStateDepositsSeen() { if (!isDepositsPublished()) setState(State.DEPOSIT_TXS_SEEN_IN_NETWORK); } @@ -1922,6 +2822,10 @@ public abstract class Trade implements Tradable, Model { if (!isPayoutUnlocked()) setPayoutState(PayoutState.PAYOUT_UNLOCKED); } + private Trade getTrade() { + return this; + } + /** * Listen to block notifications from the main wallet in order to sync * idling trade wallets awaiting the payout to confirm or unlock. @@ -1932,13 +2836,11 @@ public abstract class Trade implements Tradable, Model { @Override public void onNewBlock(long height) { - HavenoUtils.submitTask(() -> { // allow rapid notifications + ThreadUtils.execute(() -> { // allow rapid notifications // skip rapid succession blocks - synchronized (this) { - if (processing) return; - processing = true; - } + if (processing) return; + processing = true; // skip if not idling and not waiting for payout to unlock if (!isIdling() || !isPayoutPublished() || isPayoutUnlocked()) { @@ -1949,9 +2851,10 @@ public abstract class Trade implements Tradable, Model { try { // get payout height if unknown - if (payoutHeight == null && getPayoutTxId() != null) { + if (payoutHeight == null && getPayoutTxId() != null && isPayoutPublished()) { MoneroTx tx = xmrWalletService.getDaemon().getTx(getPayoutTxId()); - if (tx.isConfirmed()) payoutHeight = tx.getHeight(); + if (tx == null) log.warn("Payout tx not found for {} {}, txId={}", getTrade().getClass().getSimpleName(), getId(), getPayoutTxId()); + else if (tx.isConfirmed()) payoutHeight = tx.getHeight(); } // sync wallet if confirm or unlock expected @@ -1963,10 +2866,35 @@ public abstract class Trade implements Tradable, Model { processing = false; } catch (Exception e) { processing = false; - e.printStackTrace(); - if (isInitialized && !isShutDownStarted && !isWalletConnected()) throw e; + if (!isInitialized || isShutDownStarted) return; + if (isWalletConnectedToDaemon()) { + log.warn("Error polling idle trade for {} {}: {}. Monerod={}\n", getClass().getSimpleName(), getId(), e.getMessage(), getXmrWalletService().getXmrConnectionService().getConnection(), e); + }; } - }); + }, getId()); + } + } + + private void onDepositsPublished() { + + // skip if arbitrator + if (this instanceof ArbitratorTrade) return; + + // close open offer or reset address entries + if (this instanceof MakerTrade) { + processModel.getOpenOfferManager().closeOpenOffer(getOffer()); + HavenoUtils.notificationService.sendTradeNotification(this, Phase.DEPOSITS_PUBLISHED, "Offer Taken", "Your offer " + offer.getId() + " has been accepted"); // TODO (woodser): use language translation + } else { + getXmrWalletService().resetAddressEntriesForOpenOffer(getId()); + } + + // freeze outputs until spent + ThreadUtils.submitToPool(() -> xmrWalletService.freezeOutputs(getSelf().getReserveTxKeyImages())); + } + + private void onPaymentSent() { + if (this instanceof SellerTrade) { + HavenoUtils.notificationService.sendTradeNotification(this, Phase.PAYMENT_SENT, "Payment Sent", "The buyer has sent the payment"); // TODO (woodser): use language translation } } @@ -1978,8 +2906,6 @@ public abstract class Trade implements Tradable, Model { public Message toProtoMessage() { protobuf.Trade.Builder builder = protobuf.Trade.newBuilder() .setOffer(offer.toProtoMessage()) - .setTakerFee(takerFee) - .setTotalTxFee(totalTxFee) .setTakeOfferDate(takeOfferDate) .setProcessModel(processModel.toProtoMessage()) .setAmount(amount) @@ -1988,12 +2914,13 @@ public abstract class Trade implements Tradable, Model { .setPayoutState(Trade.PayoutState.toProtoMessage(payoutState)) .setDisputeState(Trade.DisputeState.toProtoMessage(disputeState)) .setPeriodState(Trade.TradePeriodState.toProtoMessage(periodState)) - .addAllChatMessage(chatMessages.stream() + .addAllChatMessage(getChatMessages().stream() .map(msg -> msg.toProtoNetworkEnvelope().getChatMessage()) .collect(Collectors.toList())) .setLockTime(lockTime) .setStartTime(startTime) - .setUid(uid); + .setUid(uid) + .setIsCompleted(isCompleted); Optional.ofNullable(payoutTxId).ifPresent(builder::setPayoutTxId); Optional.ofNullable(contract).ifPresent(e -> builder.setContract(contract.toProtoMessage())); @@ -2006,6 +2933,7 @@ public abstract class Trade implements Tradable, Model { Optional.ofNullable(payoutTxHex).ifPresent(e -> builder.setPayoutTxHex(payoutTxHex)); Optional.ofNullable(payoutTxKey).ifPresent(e -> builder.setPayoutTxKey(payoutTxKey)); Optional.ofNullable(counterCurrencyExtraData).ifPresent(e -> builder.setCounterCurrencyExtraData(counterCurrencyExtraData)); + Optional.ofNullable(challenge).ifPresent(e -> builder.setChallenge(challenge)); return builder.build(); } @@ -2028,6 +2956,7 @@ public abstract class Trade implements Tradable, Model { trade.setLockTime(proto.getLockTime()); trade.setStartTime(proto.getStartTime()); trade.setCounterCurrencyExtraData(ProtoUtil.stringOrNullFromProto(proto.getCounterCurrencyExtraData())); + trade.setCompleted(proto.getIsCompleted()); trade.chatMessages.addAll(proto.getChatMessageList().stream() .map(ChatMessage::fromPayloadProto) @@ -2040,8 +2969,7 @@ public abstract class Trade implements Tradable, Model { public String toString() { return "Trade{" + "\n offer=" + offer + - ",\n takerFee=" + takerFee + - ",\n totalTxFee=" + totalTxFee + + ",\n totalTxFee=" + getTotalTxFee() + ",\n takeOfferDate=" + takeOfferDate + ",\n processModel=" + processModel + ",\n payoutTxId='" + payoutTxId + '\'' + @@ -2058,8 +2986,6 @@ public abstract class Trade implements Tradable, Model { ",\n counterCurrencyTxId='" + counterCurrencyTxId + '\'' + ",\n counterCurrencyExtraData='" + counterCurrencyExtraData + '\'' + ",\n chatMessages=" + chatMessages + - ",\n totalTxFee=" + totalTxFee + - ",\n takerFee=" + takerFee + ",\n xmrWalletService=" + xmrWalletService + ",\n stateProperty=" + stateProperty + ",\n statePhaseProperty=" + phaseProperty + @@ -2076,6 +3002,8 @@ public abstract class Trade implements Tradable, Model { ",\n startTime=" + startTime + ",\n refundResultState=" + refundResultState + ",\n refundResultStateProperty=" + refundResultStateProperty + + ",\n isCompleted=" + isCompleted + + ",\n challenge='" + challenge + '\'' + "\n}"; } } diff --git a/core/src/main/java/haveno/core/trade/TradeDataValidation.java b/core/src/main/java/haveno/core/trade/TradeDataValidation.java index c0dc6c39d2..7ab2109e73 100644 --- a/core/src/main/java/haveno/core/trade/TradeDataValidation.java +++ b/core/src/main/java/haveno/core/trade/TradeDataValidation.java @@ -1,23 +1,22 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; -import haveno.core.offer.Offer; import haveno.core.support.dispute.Dispute; import haveno.core.xmr.wallet.BtcWalletService; import lombok.Getter; @@ -36,6 +35,8 @@ import java.util.function.Consumer; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +// TODO: remove for XMR? + @Slf4j public class TradeDataValidation { @@ -127,9 +128,8 @@ public class TradeDataValidation { // Check amount TransactionOutput output = delayedPayoutTx.getOutput(0); - Offer offer = checkNotNull(trade.getOffer()); - BigInteger msOutputAmount = offer.getBuyerSecurityDeposit() - .add(offer.getSellerSecurityDeposit()) + BigInteger msOutputAmount = trade.getBuyerSecurityDepositBeforeMiningFee() + .add(trade.getSellerSecurityDepositBeforeMiningFee()) .add(checkNotNull(trade.getAmount())); if (!output.getValue().equals(msOutputAmount)) { diff --git a/core/src/main/java/haveno/core/trade/TradeManager.java b/core/src/main/java/haveno/core/trade/TradeManager.java index 62aeaf7bb1..a3cca84912 100644 --- a/core/src/main/java/haveno/core/trade/TradeManager.java +++ b/core/src/main/java/haveno/core/trade/TradeManager.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,11 +34,15 @@ package haveno.core.trade; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; - -import common.utils.GenUtils; +import com.google.inject.Inject; import haveno.common.ClockWatcher; +import haveno.common.ThreadUtils; +import haveno.common.UserThread; import haveno.common.crypto.KeyRing; +import haveno.common.crypto.PubKeyRing; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.FaultHandler; import haveno.common.handlers.ResultHandler; @@ -44,16 +65,21 @@ import haveno.core.provider.price.PriceFeedService; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import haveno.core.support.dispute.mediation.mediator.MediatorManager; +import haveno.core.support.dispute.messages.DisputeClosedMessage; +import haveno.core.support.dispute.messages.DisputeOpenedMessage; import haveno.core.trade.Trade.DisputeState; -import haveno.core.trade.Trade.Phase; import haveno.core.trade.failed.FailedTradesManager; import haveno.core.trade.handlers.TradeResultHandler; import haveno.core.trade.messages.DepositRequest; import haveno.core.trade.messages.DepositResponse; +import haveno.core.trade.messages.DepositsConfirmedMessage; import haveno.core.trade.messages.InitMultisigRequest; import haveno.core.trade.messages.InitTradeRequest; +import haveno.core.trade.messages.PaymentReceivedMessage; +import haveno.core.trade.messages.PaymentSentMessage; import haveno.core.trade.messages.SignContractRequest; import haveno.core.trade.messages.SignContractResponse; +import haveno.core.trade.messages.TradeMessage; import haveno.core.trade.protocol.ArbitratorProtocol; import haveno.core.trade.protocol.MakerProtocol; import haveno.core.trade.protocol.ProcessModel; @@ -68,33 +94,21 @@ import haveno.core.user.User; import haveno.core.util.Validator; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.XmrWalletService; +import haveno.network.p2p.AckMessage; +import haveno.network.p2p.AckMessageSourceType; import haveno.network.p2p.BootstrapListener; import haveno.network.p2p.DecryptedDirectMessageListener; import haveno.network.p2p.DecryptedMessageWithPubKey; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.P2PService; +import haveno.network.p2p.SendMailboxMessageListener; +import haveno.network.p2p.mailbox.MailboxMessage; +import haveno.network.p2p.mailbox.MailboxMessageService; import haveno.network.p2p.network.TorNetworkNode; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.LongProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleLongProperty; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import lombok.Getter; -import lombok.Setter; -import monero.daemon.model.MoneroTx; -import monero.wallet.model.MoneroOutputQuery; -import org.bitcoinj.core.Coin; -import org.bouncycastle.crypto.params.KeyParameter; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import javax.inject.Inject; import java.math.BigInteger; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -104,11 +118,23 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.LongProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleLongProperty; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.Setter; +import monero.daemon.model.MoneroTx; +import org.bitcoinj.core.Coin; +import org.bouncycastle.crypto.params.KeyParameter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class TradeManager implements PersistedDataHost, DecryptedDirectMessageListener { @@ -144,13 +170,39 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi private final TradableList<Trade> tradableList = new TradableList<>(); @Getter private final BooleanProperty persistedTradesInitialized = new SimpleBooleanProperty(); - @Setter - @Nullable - private ErrorMessageHandler takeOfferRequestErrorMessageHandler; @Getter private final LongProperty numPendingTrades = new SimpleLongProperty(); private final ReferralIdService referralIdService; + @Setter + @Nullable + private Consumer<String> lockedUpFundsHandler; // TODO: this is unused + + // set comparator for processing mailbox messages + static { + MailboxMessageService.setMailboxMessageComparator(new MailboxMessageComparator()); + } + + /** + * Sort mailbox messages for processing. + */ + public static class MailboxMessageComparator implements Comparator<MailboxMessage> { + private static List<Class<? extends MailboxMessage>> messageOrder = Arrays.asList( + AckMessage.class, + DepositsConfirmedMessage.class, + PaymentSentMessage.class, + PaymentReceivedMessage.class, + DisputeOpenedMessage.class, + DisputeClosedMessage.class); + + @Override + public int compare(MailboxMessage m1, MailboxMessage m2) { + int idx1 = messageOrder.indexOf(m1.getClass()); + int idx2 = messageOrder.indexOf(m2.getClass()); + return idx1 - idx2; + } + } + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -204,7 +256,9 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi failedTradesManager.setUnFailTradeCallback(this::unFailTrade); - xmrWalletService.setTradeManager(this); + // TODO: better way to set references + xmrWalletService.setTradeManager(this); // TODO: set reference in HavenoUtils for consistency + HavenoUtils.notificationService = notificationService; } @@ -230,23 +284,27 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi /////////////////////////////////////////////////////////////////////////////////////////// @Override - public void onDirectMessage(DecryptedMessageWithPubKey message, NodeAddress peer) { + public void onDirectMessage(DecryptedMessageWithPubKey message, NodeAddress sender) { NetworkEnvelope networkEnvelope = message.getNetworkEnvelope(); - new Thread(() -> { + if (!(networkEnvelope instanceof TradeMessage)) return; + TradeMessage tradeMessage = (TradeMessage) networkEnvelope; + String tradeId = tradeMessage.getOfferId(); + log.info("TradeManager received {} for tradeId={}, sender={}, uid={}", networkEnvelope.getClass().getSimpleName(), tradeId, sender, tradeMessage.getUid()); + ThreadUtils.execute(() -> { if (networkEnvelope instanceof InitTradeRequest) { - handleInitTradeRequest((InitTradeRequest) networkEnvelope, peer); + handleInitTradeRequest((InitTradeRequest) networkEnvelope, sender); } else if (networkEnvelope instanceof InitMultisigRequest) { - handleInitMultisigRequest((InitMultisigRequest) networkEnvelope, peer); + handleInitMultisigRequest((InitMultisigRequest) networkEnvelope, sender); } else if (networkEnvelope instanceof SignContractRequest) { - handleSignContractRequest((SignContractRequest) networkEnvelope, peer); + handleSignContractRequest((SignContractRequest) networkEnvelope, sender); } else if (networkEnvelope instanceof SignContractResponse) { - handleSignContractResponse((SignContractResponse) networkEnvelope, peer); + handleSignContractResponse((SignContractResponse) networkEnvelope, sender); } else if (networkEnvelope instanceof DepositRequest) { - handleDepositRequest((DepositRequest) networkEnvelope, peer); + handleDepositRequest((DepositRequest) networkEnvelope, sender); } else if (networkEnvelope instanceof DepositResponse) { - handleDepositResponse((DepositResponse) networkEnvelope, peer); + handleDepositResponse((DepositResponse) networkEnvelope, sender); } - }).start(); + }, tradeId); } @@ -260,7 +318,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { initPersistedTrades(); } }); @@ -308,15 +366,14 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi trade.onShutDownStarted(); } catch (Exception e) { if (e.getMessage() != null && e.getMessage().contains("Connection reset")) return; // expected if shut down with ctrl+c - log.warn("Error notifying {} {} that shut down started {}", getClass().getSimpleName(), trade.getId()); - e.printStackTrace(); + log.warn("Error notifying {} {} that shut down started: {}\n", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e); } }); try { - HavenoUtils.executeTasks(tasks); + ThreadUtils.awaitTasks(tasks); } catch (Exception e) { log.warn("Error notifying trades that shut down started: {}", e.getMessage()); - e.printStackTrace(); + throw e; } } @@ -338,44 +395,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi trade.shutDown(); } catch (Exception e) { if (e.getMessage() != null && (e.getMessage().contains("Connection reset") || e.getMessage().contains("Connection refused"))) return; // expected if shut down with ctrl+c - log.warn("Error closing {} {}", trade.getClass().getSimpleName(), trade.getId()); - e.printStackTrace(); + log.warn("Error closing {} {}: {}", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e); } }); try { - HavenoUtils.executeTasks(tasks); + ThreadUtils.awaitTasks(tasks); } catch (Exception e) { - log.warn("Error shutting down trades: {}", e.getMessage()); - e.printStackTrace(); - } - } - - private void thawUnreservedOutputs() { - if (xmrWalletService.getWallet() == null) return; - - // collect reserved outputs - Set<String> reservedKeyImages = new HashSet<String>(); - for (Trade trade : getObservableList()) { - if (trade.getSelf().getReserveTxKeyImages() == null) continue; - reservedKeyImages.addAll(trade.getSelf().getReserveTxKeyImages()); - } - for (OpenOffer openOffer : openOfferManager.getObservableList()) { - if (openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() == null) continue; - reservedKeyImages.addAll(openOffer.getOffer().getOfferPayload().getReserveTxKeyImages()); - } - - // thaw unreserved outputs - Set<String> unreservedFrozenKeyImages = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery() - .setIsFrozen(true) - .setIsSpent(false)) - .stream() - .map(output -> output.getKeyImage().getHex()) - .collect(Collectors.toSet()); - unreservedFrozenKeyImages.removeAll(reservedKeyImages); - if (!unreservedFrozenKeyImages.isEmpty()) { - log.warn("Thawing outputs which are not reserved for offer or trade: " + unreservedFrozenKeyImages); - xmrWalletService.thawOutputs(unreservedFrozenKeyImages); - xmrWalletService.saveMainWallet(); + log.warn("Error shutting down trades: {}\n", e.getMessage(), e); } } @@ -412,11 +438,11 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi Set<Runnable> tasks = new HashSet<Runnable>(); Set<String> uids = new HashSet<String>(); Set<Trade> tradesToSkip = new HashSet<Trade>(); - Set<Trade> tradesToMaybeRemoveOnError = new HashSet<Trade>(); + Set<Trade> uninitializedTrades = new HashSet<Trade>(); for (Trade trade : trades) { tasks.add(() -> { try { - + // check for duplicate uid if (!uids.add(trade.getUid())) { log.warn("Found trade with duplicate uid, skipping. That should never happen. {} {}, uid={}", trade.getClass().getSimpleName(), trade.getId(), trade.getUid()); @@ -424,23 +450,29 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi return; } + // skip if marked as failed + if (failedTradesManager.getObservableList().contains(trade)) { + log.warn("Skipping initialization of failed trade {} {}", trade.getClass().getSimpleName(), trade.getId()); + tradesToSkip.add(trade); + return; + } + // initialize trade initPersistedTrade(trade); // remove trade if protocol didn't initialize if (getOpenTradeByUid(trade.getUid()).isPresent() && !trade.isDepositsPublished()) { - tradesToMaybeRemoveOnError.add(trade); + uninitializedTrades.add(trade); } } catch (Exception e) { if (!isShutDownStarted) { - e.printStackTrace(); - log.warn("Error initializing {} {}: {}", trade.getClass().getSimpleName(), trade.getId(), e.getMessage()); + log.warn("Error initializing {} {}: {}\n", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e); trade.setInitError(e); } } }); }; - HavenoUtils.executeTasks(tasks, threadPoolSize); + ThreadUtils.awaitTasks(tasks, threadPoolSize); log.info("Done initializing persisted trades"); if (isShutDownStarted) return; @@ -449,30 +481,34 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // sync idle trades once in background after active trades for (Trade trade : trades) { - if (trade.isIdling()) HavenoUtils.submitTask(() -> trade.syncAndPollWallet()); + if (trade.isIdling()) ThreadUtils.submitToPool(() -> trade.syncAndPollWallet()); } - - // process after all wallets initialized - if (HavenoUtils.havenoSetup != null) { // null for seednode - // maybe remove trades on error - for (Trade trade : tradesToMaybeRemoveOnError) { - maybeRemoveTradeOnError(trade); + // process after all wallets initialized + if (!HavenoUtils.isSeedNode()) { + + // handle uninitialized trades + for (Trade trade : uninitializedTrades) { + trade.onProtocolError(); } - // thaw unreserved outputs - thawUnreservedOutputs(); + // freeze or thaw outputs + xmrWalletService.fixReservedOutputs(); // reset any available funded address entries + if (isShutDownStarted) return; xmrWalletService.getAddressEntriesForAvailableBalanceStream() .filter(addressEntry -> addressEntry.getOfferId() != null) .forEach(addressEntry -> { log.warn("Swapping pending {} entries at startup. offerId={}", addressEntry.getContext(), addressEntry.getOfferId()); xmrWalletService.swapAddressEntryToAvailable(addressEntry.getOfferId(), addressEntry.getContext()); }); + + checkForLockedUpFunds(); } // notify that persisted trades initialized + if (isShutDownStarted) return; persistedTradesInitialized.set(true); getObservableList().addListener((ListChangeListener<Trade>) change -> onTradesChanged()); onTradesChanged(); @@ -487,7 +523,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi }).start(); // allow execution to start - GenUtils.waitFor(100); + HavenoUtils.waitFor(100); } private void initPersistedTrade(Trade trade) { @@ -507,286 +543,305 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void handleInitTradeRequest(InitTradeRequest request, NodeAddress sender) { - log.info("Received InitTradeRequest from {} with tradeId {} and uid {}", sender, request.getTradeId(), request.getUid()); + log.info("TradeManager handling InitTradeRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); - try { - Validator.nonEmptyStringOf(request.getTradeId()); - } catch (Throwable t) { - log.warn("Invalid InitTradeRequest message " + request.toString()); - return; - } + try { + Validator.nonEmptyStringOf(request.getOfferId()); + } catch (Throwable t) { + log.warn("Invalid InitTradeRequest message " + request.toString()); + return; + } - // handle request as arbitrator - boolean isArbitrator = request.getArbitratorNodeAddress().equals(p2PService.getNetworkNode().getNodeAddress()); - if (isArbitrator) { + // handle request as maker + if (request.getMakerNodeAddress().equals(p2PService.getNetworkNode().getNodeAddress())) { - // verify this node is registered arbitrator - Arbitrator thisArbitrator = user.getRegisteredArbitrator(); - NodeAddress thisAddress = p2PService.getNetworkNode().getNodeAddress(); - if (thisArbitrator == null || !thisArbitrator.getNodeAddress().equals(thisAddress)) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because we are not an arbitrator", sender, request.getTradeId()); - return; - } + // get open offer + Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(request.getOfferId()); + if (!openOfferOptional.isPresent()) return; + OpenOffer openOffer = openOfferOptional.get(); + if (openOffer.getState() != OpenOffer.State.AVAILABLE) return; + Offer offer = openOffer.getOffer(); - // get offer associated with trade - Offer offer = null; - for (Offer anOffer : offerBookService.getOffers()) { - if (anOffer.getId().equals(request.getTradeId())) { - offer = anOffer; - } - } - if (offer == null) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because offer is not on the books", sender, request.getTradeId()); - return; - } + // validate challenge + if (openOffer.getChallenge() != null && !HavenoUtils.getChallengeHash(openOffer.getChallenge()).equals(HavenoUtils.getChallengeHash(request.getChallenge()))) { + log.warn("Ignoring InitTradeRequest to maker because challenge is incorrect, tradeId={}, sender={}", request.getOfferId(), sender); + return; + } + + // ensure trade does not already exist + Optional<Trade> tradeOptional = getOpenTrade(request.getOfferId()); + if (tradeOptional.isPresent()) { + log.warn("Ignoring InitTradeRequest to maker because trade already exists with id " + request.getOfferId() + ". This should never happen."); + return; + } + + // reserve open offer + openOfferManager.reserveOpenOffer(openOffer); + + // initialize trade + Trade trade; + if (offer.isBuyOffer()) + trade = new BuyerAsMakerTrade(offer, + BigInteger.valueOf(request.getTradeAmount()), + offer.getOfferPayload().getPrice(), + xmrWalletService, + getNewProcessModel(offer), + UUID.randomUUID().toString(), + request.getMakerNodeAddress(), + request.getTakerNodeAddress(), + request.getArbitratorNodeAddress(), + openOffer.getChallenge()); + else + trade = new SellerAsMakerTrade(offer, + BigInteger.valueOf(request.getTradeAmount()), + offer.getOfferPayload().getPrice(), + xmrWalletService, + getNewProcessModel(offer), + UUID.randomUUID().toString(), + request.getMakerNodeAddress(), + request.getTakerNodeAddress(), + request.getArbitratorNodeAddress(), + openOffer.getChallenge()); + trade.getMaker().setPaymentAccountId(trade.getOffer().getOfferPayload().getMakerPaymentAccountId()); + trade.getTaker().setPaymentAccountId(request.getTakerPaymentAccountId()); + trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing()); + trade.getTaker().setPubKeyRing(request.getTakerPubKeyRing()); + trade.getSelf().setPaymentAccountId(offer.getOfferPayload().getMakerPaymentAccountId()); + trade.getSelf().setReserveTxHash(openOffer.getReserveTxHash()); // TODO (woodser): initialize in initTradeAndProtocol? + trade.getSelf().setReserveTxHex(openOffer.getReserveTxHex()); + trade.getSelf().setReserveTxKey(openOffer.getReserveTxKey()); + trade.getSelf().setReserveTxKeyImages(offer.getOfferPayload().getReserveTxKeyImages()); + initTradeAndProtocol(trade, createTradeProtocol(trade)); + addTrade(trade); + + // process with protocol + ((MakerProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender, errorMessage -> { + log.warn("Maker error during trade initialization: " + errorMessage); + trade.onProtocolError(); + }); + } - // verify arbitrator is payload signer unless they are offline - // TODO (woodser): handle if payload signer differs from current arbitrator (verify signer is offline) + // handle request as arbitrator + else if (request.getArbitratorNodeAddress().equals(p2PService.getNetworkNode().getNodeAddress())) { - // verify maker is offer owner - // TODO (woodser): maker address might change if they disconnect and reconnect, should allow maker address to differ if pubKeyRing is same ? - if (!offer.getOwnerNodeAddress().equals(request.getMakerNodeAddress())) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because maker is not offer owner", sender, request.getTradeId()); - return; - } - - Trade trade; - Optional<Trade> tradeOptional = getOpenTrade(offer.getId()); - if (tradeOptional.isPresent()) { - trade = tradeOptional.get(); - - // verify request is from maker - if (!sender.equals(request.getMakerNodeAddress())) { - log.warn("Trade is already taken"); // TODO (woodser): need to respond with bad ack - return; - } - } else { - - // verify request is from taker - if (!sender.equals(request.getTakerNodeAddress())) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because request must be from taker when trade is not initialized", sender, request.getTradeId()); + // verify this node is registered arbitrator + Arbitrator thisArbitrator = user.getRegisteredArbitrator(); + NodeAddress thisAddress = p2PService.getNetworkNode().getNodeAddress(); + if (thisArbitrator == null || !thisArbitrator.getNodeAddress().equals(thisAddress)) { + log.warn("Ignoring InitTradeRequest because we are not an arbitrator, tradeId={}, sender={}", request.getOfferId(), sender); return; } - // get expected taker fee - BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(request.getTradeAmount())); - - // create arbitrator trade - trade = new ArbitratorTrade(offer, - BigInteger.valueOf(request.getTradeAmount()), - takerFee, - offer.getOfferPayload().getPrice(), - xmrWalletService, - getNewProcessModel(offer), - UUID.randomUUID().toString(), - request.getMakerNodeAddress(), - request.getTakerNodeAddress(), - request.getArbitratorNodeAddress()); - - // set reserve tx hash if available - Optional<SignedOffer> signedOfferOptional = openOfferManager.getSignedOfferById(request.getTradeId()); - if (signedOfferOptional.isPresent()) { - SignedOffer signedOffer = signedOfferOptional.get(); - trade.getMaker().setReserveTxHash(signedOffer.getReserveTxHash()); + // get offer associated with trade + Offer offer = null; + for (Offer anOffer : offerBookService.getOffers()) { + if (anOffer.getId().equals(request.getOfferId())) { + offer = anOffer; + } + } + if (offer == null) { + log.warn("Ignoring InitTradeRequest to arbitrator because offer is not on the books, tradeId={}, sender={}", request.getOfferId(), sender); + return; } - // initialize trade protocol - initTradeAndProtocol(trade, createTradeProtocol(trade)); - synchronized (tradableList) { - tradableList.add(trade); + // verify arbitrator is payload signer unless they are offline + // TODO (woodser): handle if payload signer differs from current arbitrator (verify signer is offline) + + // verify maker is offer owner + // TODO (woodser): maker address might change if they disconnect and reconnect, should allow maker address to differ if pubKeyRing is same? + if (!offer.getOwnerNodeAddress().equals(request.getMakerNodeAddress())) { + log.warn("Ignoring InitTradeRequest to arbitrator because maker is not offer owner, tradeId={}, sender={}", request.getOfferId(), sender); + return; } - } - ((ArbitratorProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender, errorMessage -> { - log.warn("Arbitrator error during trade initialization for trade {}: {}", trade.getId(), errorMessage); - maybeRemoveTradeOnError(trade); - if (takeOfferRequestErrorMessageHandler != null) takeOfferRequestErrorMessageHandler.handleErrorMessage(errorMessage); - }); + // validate challenge hash + if (offer.getChallengeHash() != null && !offer.getChallengeHash().equals(HavenoUtils.getChallengeHash(request.getChallenge()))) { + log.warn("Ignoring InitTradeRequest to arbitrator because challenge hash is incorrect, tradeId={}, sender={}", request.getOfferId(), sender); + return; + } - requestPersistence(); - } + // handle trade + Trade trade; + Optional<Trade> tradeOptional = getOpenTrade(offer.getId()); + if (tradeOptional.isPresent()) { + trade = tradeOptional.get(); - // handle request as maker - else { + // verify request is from taker + if (!sender.equals(request.getTakerNodeAddress())) { + if (sender.equals(request.getMakerNodeAddress())) { + log.warn("Received InitTradeRequest from maker to arbitrator for trade that is already initializing, tradeId={}, sender={}", request.getOfferId(), sender); + sendAckMessage(sender, trade.getMaker().getPubKeyRing(), request, false, "Trade is already initializing for " + getClass().getSimpleName() + " " + trade.getId()); + } else { + log.warn("Ignoring InitTradeRequest from non-taker, tradeId={}, sender={}", request.getOfferId(), sender); + } + return; + } + } else { - Optional<OpenOffer> openOfferOptional = openOfferManager.getOpenOfferById(request.getTradeId()); - if (!openOfferOptional.isPresent()) { - return; - } + // verify request is from maker + if (!sender.equals(request.getMakerNodeAddress())) { + log.warn("Ignoring InitTradeRequest to arbitrator because request must be from maker when trade is not initialized, tradeId={}, sender={}", request.getOfferId(), sender); + return; + } - OpenOffer openOffer = openOfferOptional.get(); - if (openOffer.getState() != OpenOffer.State.AVAILABLE) { - return; - } + // create arbitrator trade + trade = new ArbitratorTrade(offer, + BigInteger.valueOf(request.getTradeAmount()), + offer.getOfferPayload().getPrice(), + xmrWalletService, + getNewProcessModel(offer), + UUID.randomUUID().toString(), + request.getMakerNodeAddress(), + request.getTakerNodeAddress(), + request.getArbitratorNodeAddress(), + request.getChallenge()); - Offer offer = openOffer.getOffer(); + // set reserve tx hash if available + Optional<SignedOffer> signedOfferOptional = openOfferManager.getSignedOfferById(request.getOfferId()); + if (signedOfferOptional.isPresent()) { + SignedOffer signedOffer = signedOfferOptional.get(); + trade.getMaker().setReserveTxHash(signedOffer.getReserveTxHash()); + } - // verify request is from arbitrator - Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(sender); - if (arbitrator == null) { - log.warn("Ignoring InitTradeRequest from {} with tradeId {} because request is not from accepted arbitrator", sender, request.getTradeId()); - return; - } + // initialize trade protocol + initTradeAndProtocol(trade, createTradeProtocol(trade)); + addTrade(trade); + } - Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId()); - if (tradeOptional.isPresent()) { - log.warn("Maker trade already exists with id " + request.getTradeId() + ". This should never happen."); - return; - } + // process with protocol + ((ArbitratorProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender, errorMessage -> { + log.warn("Arbitrator error during trade initialization for trade {}: {}", trade.getId(), errorMessage); + trade.onProtocolError(); + }); - // reserve open offer - openOfferManager.reserveOpenOffer(openOffer); + requestPersistence(); + } - // get expected taker fee - BigInteger takerFee = HavenoUtils.getTakerFee(BigInteger.valueOf(request.getTradeAmount())); + // handle request as taker + else if (request.getTakerNodeAddress().equals(p2PService.getNetworkNode().getNodeAddress())) { - Trade trade; - if (offer.isBuyOffer()) - trade = new BuyerAsMakerTrade(offer, - BigInteger.valueOf(request.getTradeAmount()), - takerFee, - offer.getOfferPayload().getPrice(), - xmrWalletService, - getNewProcessModel(offer), - UUID.randomUUID().toString(), - request.getMakerNodeAddress(), - request.getTakerNodeAddress(), - request.getArbitratorNodeAddress()); - else - trade = new SellerAsMakerTrade(offer, - BigInteger.valueOf(request.getTradeAmount()), - takerFee, - offer.getOfferPayload().getPrice(), - xmrWalletService, - getNewProcessModel(offer), - UUID.randomUUID().toString(), - request.getMakerNodeAddress(), - request.getTakerNodeAddress(), - request.getArbitratorNodeAddress()); + // verify request is from arbitrator + Arbitrator arbitrator = user.getAcceptedArbitratorByAddress(sender); + if (arbitrator == null) { + log.warn("Ignoring InitTradeRequest to taker because request is not from accepted arbitrator, tradeId={}, sender={}", request.getOfferId(), sender); + return; + } - trade.getArbitrator().setPubKeyRing(arbitrator.getPubKeyRing()); - trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing()); - initTradeAndProtocol(trade, createTradeProtocol(trade)); - trade.getSelf().setPaymentAccountId(offer.getOfferPayload().getMakerPaymentAccountId()); - trade.getSelf().setReserveTxHash(openOffer.getReserveTxHash()); // TODO (woodser): initialize in initTradeAndProtocol? - trade.getSelf().setReserveTxHex(openOffer.getReserveTxHex()); - trade.getSelf().setReserveTxKey(openOffer.getReserveTxKey()); - trade.getSelf().setReserveTxKeyImages(offer.getOfferPayload().getReserveTxKeyImages()); - synchronized (tradableList) { - tradableList.add(trade); - } + // get trade + Optional<Trade> tradeOptional = getOpenTrade(request.getOfferId()); + if (!tradeOptional.isPresent()) { + log.warn("Ignoring InitTradeRequest to taker because trade is not initialized, tradeId={}, sender={}", request.getOfferId(), sender); + return; + } + Trade trade = tradeOptional.get(); - // notify on phase changes - // TODO (woodser): save subscription, bind on startup - EasyBind.subscribe(trade.statePhaseProperty(), phase -> { - if (phase == Phase.DEPOSITS_PUBLISHED) { - notificationService.sendTradeNotification(trade, "Offer Taken", "Your offer " + offer.getId() + " has been accepted"); // TODO (woodser): use language translation - } - }); - - ((MakerProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender, errorMessage -> { - log.warn("Maker error during trade initialization: " + errorMessage); - maybeRemoveTradeOnError(trade); - if (takeOfferRequestErrorMessageHandler != null) takeOfferRequestErrorMessageHandler.handleErrorMessage(errorMessage); - }); - - requestPersistence(); - } + // process with protocol + ((TakerProtocol) getTradeProtocol(trade)).handleInitTradeRequest(request, sender); + } + + // invalid sender + else { + log.warn("Ignoring InitTradeRequest because sender is not maker, arbitrator, or taker, tradeId={}, sender={}", request.getOfferId(), sender); + return; + } } - private void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + private void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) { + log.info("TradeManager handling InitMultisigRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid InitMultisigRequest " + request.toString()); return; } - Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId()); + Optional<Trade> tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId() + " at node " + P2PService.getMyNodeAddress()); + log.warn("No trade with id " + request.getOfferId() + " at node " + P2PService.getMyNodeAddress()); return; } Trade trade = tradeOptional.get(); - getTradeProtocol(trade).handleInitMultisigRequest(request, peer); + getTradeProtocol(trade).handleInitMultisigRequest(request, sender); } - private void handleSignContractRequest(SignContractRequest request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + private void handleSignContractRequest(SignContractRequest request, NodeAddress sender) { + log.info("TradeManager handling SignContractRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid SignContractRequest message " + request.toString()); return; } - Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId()); + Optional<Trade> tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId()); + log.warn("No trade with id " + request.getOfferId()); return; } Trade trade = tradeOptional.get(); - getTradeProtocol(trade).handleSignContractRequest(request, peer); + getTradeProtocol(trade).handleSignContractRequest(request, sender); } - private void handleSignContractResponse(SignContractResponse request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + private void handleSignContractResponse(SignContractResponse request, NodeAddress sender) { + log.info("TradeManager handling SignContractResponse for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid SignContractResponse message " + request.toString()); return; } - Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId()); + Optional<Trade> tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId()); + log.warn("No trade with id " + request.getOfferId()); return; } Trade trade = tradeOptional.get(); - ((TraderProtocol) getTradeProtocol(trade)).handleSignContractResponse(request, peer); + ((TraderProtocol) getTradeProtocol(trade)).handleSignContractResponse(request, sender); } - private void handleDepositRequest(DepositRequest request, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", request.getClass().getSimpleName(), request.getTradeId(), peer, request.getUid()); + private void handleDepositRequest(DepositRequest request, NodeAddress sender) { + log.info("TradeManager handling DepositRequest for tradeId={}, sender={}, uid={}", request.getOfferId(), sender, request.getUid()); try { - Validator.nonEmptyStringOf(request.getTradeId()); + Validator.nonEmptyStringOf(request.getOfferId()); } catch (Throwable t) { log.warn("Invalid DepositRequest message " + request.toString()); return; } - Optional<Trade> tradeOptional = getOpenTrade(request.getTradeId()); + Optional<Trade> tradeOptional = getOpenTrade(request.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + request.getTradeId()); + log.warn("No trade with id " + request.getOfferId()); return; } Trade trade = tradeOptional.get(); - ((ArbitratorProtocol) getTradeProtocol(trade)).handleDepositRequest(request, peer); + ((ArbitratorProtocol) getTradeProtocol(trade)).handleDepositRequest(request, sender); } - private void handleDepositResponse(DepositResponse response, NodeAddress peer) { - log.info("Received {} for trade {} from {} with uid {}", response.getClass().getSimpleName(), response.getTradeId(), peer, response.getUid()); + private void handleDepositResponse(DepositResponse response, NodeAddress sender) { + log.info("TradeManager handling DepositResponse for tradeId={}, sender={}, uid={}", response.getOfferId(), sender, response.getUid()); try { - Validator.nonEmptyStringOf(response.getTradeId()); + Validator.nonEmptyStringOf(response.getOfferId()); } catch (Throwable t) { log.warn("Invalid DepositResponse message " + response.toString()); return; } - Optional<Trade> tradeOptional = getOpenTrade(response.getTradeId()); + Optional<Trade> tradeOptional = getOpenTrade(response.getOfferId()); if (!tradeOptional.isPresent()) { - log.warn("No trade with id " + response.getTradeId()); - return; + tradeOptional = getFailedTrade(response.getOfferId()); + if (!tradeOptional.isPresent()) { + log.warn("No trade with id " + response.getOfferId()); + return; + } } Trade trade = tradeOptional.get(); - ((TraderProtocol) getTradeProtocol(trade)).handleDepositResponse(response, peer); + ((TraderProtocol) getTradeProtocol(trade)).handleDepositResponse(response, sender); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -804,7 +859,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // First we check if offer is still available then we create the trade with the protocol public void onTakeOffer(BigInteger amount, - BigInteger takerFee, BigInteger fundsNeededForTrade, Offer offer, String paymentAccountId, @@ -815,76 +869,64 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi checkArgument(!wasOfferAlreadyUsedInTrade(offer.getId())); - OfferAvailabilityModel model = getOfferAvailabilityModel(offer, isTakerApiUser, paymentAccountId, amount); - offer.checkOfferAvailability(model, - () -> { - if (offer.getState() == Offer.State.AVAILABLE) { - Trade trade; - if (offer.isBuyOffer()) { - trade = new SellerAsTakerTrade(offer, - amount, - takerFee, - model.getTradeRequest().getTradePrice(), - xmrWalletService, - getNewProcessModel(offer), - UUID.randomUUID().toString(), - model.getPeerNodeAddress(), - P2PService.getMyNodeAddress(), - offer.getOfferPayload().getArbitratorSigner()); - } else { - trade = new BuyerAsTakerTrade(offer, - amount, - takerFee, - model.getTradeRequest().getTradePrice(), - xmrWalletService, - getNewProcessModel(offer), - UUID.randomUUID().toString(), - model.getPeerNodeAddress(), - P2PService.getMyNodeAddress(), - offer.getOfferPayload().getArbitratorSigner()); - } + // validate inputs + if (amount.compareTo(offer.getAmount()) > 0) throw new RuntimeException("Trade amount exceeds offer amount"); + if (amount.compareTo(offer.getMinAmount()) < 0) throw new RuntimeException("Trade amount is less than minimum offer amount"); - trade.getProcessModel().setTradeMessage(model.getTradeRequest()); - trade.getProcessModel().setMakerSignature(model.getMakerSignature()); - trade.getProcessModel().setUseSavingsWallet(useSavingsWallet); - trade.getProcessModel().setFundsNeededForTrade(fundsNeededForTrade.longValueExact()); - trade.getMaker().setPubKeyRing(trade.getOffer().getPubKeyRing()); - trade.getSelf().setPubKeyRing(model.getPubKeyRing()); - trade.getSelf().setPaymentAccountId(paymentAccountId); - trade.addInitProgressStep(); + // ensure trade is not already open + Optional<Trade> tradeOptional = getOpenTrade(offer.getId()); + if (tradeOptional.isPresent()) throw new RuntimeException("Cannot create trade protocol because trade with ID " + offer.getId() + " is already open"); - // ensure trade is not already open - Optional<Trade> tradeOptional = getOpenTrade(offer.getId()); - if (tradeOptional.isPresent()) throw new RuntimeException("Cannot create trade protocol because trade with ID " + trade.getId() + " is already open"); + // create trade + Trade trade; + if (offer.isBuyOffer()) { + trade = new SellerAsTakerTrade(offer, + amount, + offer.getPrice().getValue(), + xmrWalletService, + getNewProcessModel(offer), + UUID.randomUUID().toString(), + offer.getMakerNodeAddress(), + P2PService.getMyNodeAddress(), + null, + offer.getChallenge()); + } else { + trade = new BuyerAsTakerTrade(offer, + amount, + offer.getPrice().getValue(), + xmrWalletService, + getNewProcessModel(offer), + UUID.randomUUID().toString(), + offer.getMakerNodeAddress(), + P2PService.getMyNodeAddress(), + null, + offer.getChallenge()); + } + trade.getProcessModel().setUseSavingsWallet(useSavingsWallet); + trade.getProcessModel().setFundsNeededForTrade(fundsNeededForTrade.longValueExact()); + trade.getMaker().setPaymentAccountId(offer.getOfferPayload().getMakerPaymentAccountId()); + trade.getMaker().setPubKeyRing(offer.getPubKeyRing()); + trade.getSelf().setPubKeyRing(keyRing.getPubKeyRing()); + trade.getSelf().setPaymentAccountId(paymentAccountId); + trade.getSelf().setPaymentMethodId(user.getPaymentAccount(paymentAccountId).getPaymentAccountPayload().getPaymentMethodId()); - // initialize trade protocol - TradeProtocol tradeProtocol = createTradeProtocol(trade); - synchronized (tradableList) { - tradableList.add(trade); - } + // initialize trade protocol + TradeProtocol tradeProtocol = createTradeProtocol(trade); + addTrade(trade); - initTradeAndProtocol(trade, tradeProtocol); + initTradeAndProtocol(trade, tradeProtocol); + trade.addInitProgressStep(); - // take offer and persist trade on success - ((TakerProtocol) tradeProtocol).onTakeOffer(result -> { - tradeResultHandler.handleResult(trade); - requestPersistence(); - }, errorMessage -> { - log.warn("Taker error during trade initialization: " + errorMessage); - maybeRemoveTradeOnError(trade); - errorMessageHandler.handleErrorMessage(errorMessage); - if (takeOfferRequestErrorMessageHandler != null) takeOfferRequestErrorMessageHandler.handleErrorMessage(errorMessage); - }); - requestPersistence(); - } else { - log.warn("Cannot take offer {} because it's not available, state={}", offer.getId(), offer.getState()); - } - }, - errorMessage -> { - log.warn("Taker error during check offer availability: " + errorMessage); - errorMessageHandler.handleErrorMessage(errorMessage); - if (takeOfferRequestErrorMessageHandler != null) takeOfferRequestErrorMessageHandler.handleErrorMessage(errorMessage); - }); + // process with protocol + ((TakerProtocol) tradeProtocol).onTakeOffer(result -> { + tradeResultHandler.handleResult(trade); + requestPersistence(); + }, errorMessage -> { + log.warn("Taker error during trade initialization: " + errorMessage); + xmrWalletService.resetAddressEntriesForOpenOffer(trade.getId()); // TODO: move to maybe remove on error + trade.onProtocolError(); + errorMessageHandler.handleErrorMessage(errorMessage); + }); requestPersistence(); } @@ -931,14 +973,34 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi public void onTradeCompleted(Trade trade) { if (trade.isCompleted()) throw new RuntimeException("Trade " + trade.getId() + " was already completed"); closedTradableManager.add(trade); - trade.setState(Trade.State.TRADE_COMPLETED); - removeTrade(trade); + trade.setCompleted(true); + removeTrade(trade, true); // TODO The address entry should have been removed already. Check and if its the case remove that. xmrWalletService.resetAddressEntriesForTrade(trade.getId()); requestPersistence(); } + public void unregisterTrade(Trade trade) { + log.warn("Unregistering {} {}", trade.getClass().getSimpleName(), trade.getId()); + removeTrade(trade, true); + removeFailedTrade(trade); + requestPersistence(); + } + + public void removeTrade(Trade trade, boolean removeDirectMessageListener) { + log.info("TradeManager.removeTrade() " + trade.getId()); + + // remove trade + synchronized (tradableList) { + if (!tradableList.remove(trade)) return; + } + + // unregister message listener and persist + if (removeDirectMessageListener) p2PService.removeDecryptedDirectMessageListener(getTradeProtocol(trade)); + requestPersistence(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Dispute @@ -949,7 +1011,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi if (tradeOptional.isPresent()) { Trade trade = tradeOptional.get(); trade.setDisputeState(disputeState); - onTradeCompleted(trade); xmrWalletService.resetAddressEntriesForTrade(trade.getId()); requestPersistence(); } @@ -974,6 +1035,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } private void updateTradePeriodState() { + if (isShutDownStarted) return; for (Trade trade : new ArrayList<Trade>(tradableList.getList())) { if (!trade.isPayoutPublished()) { Date maxTradePeriodDate = trade.getMaxTradePeriodDate(); @@ -998,15 +1060,34 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi /////////////////////////////////////////////////////////////////////////////////////////// // If trade is in already in critical state (if taker role: taker fee; both roles: after deposit published) - // we move the trade to failedTradesManager + // we move the trade to FailedTradesManager public void onMoveInvalidTradeToFailedTrades(Trade trade) { - removeTrade(trade); failedTradesManager.add(trade); + removeTrade(trade, false); } - public void addFailedTradeToPendingTrades(Trade trade) { + public void onMoveFailedTradeToPendingTrades(Trade trade) { + addTradeToPendingTrades(trade); + failedTradesManager.removeTrade(trade); + } + + public void onMoveClosedTradeToPendingTrades(Trade trade) { + trade.setCompleted(false); + addTradeToPendingTrades(trade); + closedTradableManager.removeTrade(trade); + } + + private void removeFailedTrade(Trade trade) { + failedTradesManager.removeTrade(trade); + } + + private void addTradeToPendingTrades(Trade trade) { if (!trade.isInitialized()) { - initPersistedTrade(trade); + try { + initPersistedTrade(trade); + } catch (Exception e) { + log.warn("Error initializing {} {} on move to pending trades", trade.getClass().getSimpleName(), trade.getShortId(), e); + } } addTrade(trade); } @@ -1017,6 +1098,14 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } } + private void checkForLockedUpFunds() { + try { + getSetOfFailedOrClosedTradeIdsFromLockedInFunds(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + public Set<String> getSetOfFailedOrClosedTradeIdsFromLockedInFunds() throws TradeTxException { AtomicReference<TradeTxException> tradeTxException = new AtomicReference<>(); synchronized (tradableList) { @@ -1055,7 +1144,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi log.warn("We found a closed trade with locked up funds. " + "That should never happen. trade ID={} ID={}, state={}, payoutState={}, disputeState={}", trade.getClass().getSimpleName(), trade.getId(), trade.getState(), trade.getPayoutState(), trade.getDisputeState()); } - } else { + } else if (!trade.hasBuyerAsTakerWithoutDeposit()) { log.warn("Closed trade with locked up funds missing taker deposit tx. {} ID={}, state={}, payoutState={}, disputeState={}", trade.getClass().getSimpleName(), trade.getId(), trade.getState(), trade.getPayoutState(), trade.getDisputeState()); tradeTxException.set(new TradeTxException(Res.get("error.closedTradeWithNoDepositTx", trade.getShortId()))); } @@ -1080,11 +1169,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi initPersistedTrade(trade); - synchronized (tradableList) { - if (!tradableList.contains(trade)) { - tradableList.add(trade); + UserThread.execute(() -> { + synchronized (tradableList) { + if (!tradableList.contains(trade)) { + tradableList.add(trade); + } } - } + }); return true; } @@ -1107,6 +1198,48 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi // Getters, Utils /////////////////////////////////////////////////////////////////////////////////////////// + public void sendAckMessage(NodeAddress peer, PubKeyRing peersPubKeyRing, TradeMessage message, boolean result, @Nullable String errorMessage) { + + // create ack message + String tradeId = message.getOfferId(); + String sourceUid = message.getUid(); + AckMessage ackMessage = new AckMessage(P2PService.getMyNodeAddress(), + AckMessageSourceType.TRADE_MESSAGE, + message.getClass().getSimpleName(), + sourceUid, + tradeId, + result, + errorMessage); + + // send ack message + log.info("Send AckMessage for {} to peer {}. tradeId={}, sourceUid={}", + ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid); + p2PService.getMailboxMessageService().sendEncryptedMailboxMessage( + peer, + peersPubKeyRing, + ackMessage, + new SendMailboxMessageListener() { + @Override + public void onArrived() { + log.info("AckMessage for {} arrived at peer {}. tradeId={}, sourceUid={}", + ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid); + } + + @Override + public void onStoredInMailbox() { + log.info("AckMessage for {} stored in mailbox for peer {}. tradeId={}, sourceUid={}", + ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid); + } + + @Override + public void onFault(String errorMessage) { + log.error("AckMessage for {} failed. Peer {}. tradeId={}, sourceUid={}, errorMessage={}", + ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid, errorMessage); + } + } + ); + } + public ObservableList<Trade> getObservableList() { synchronized (tradableList) { return tradableList.getObservableList(); @@ -1146,6 +1279,12 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } } + public boolean hasOpenTrade(Trade trade) { + synchronized (tradableList) { + return tradableList.contains(trade); + } + } + public Optional<Trade> getOpenTradeByUid(String tradeUid) { synchronized (tradableList) { return tradableList.stream().filter(e -> e.getUid().equals(tradeUid)).findFirst(); @@ -1153,11 +1292,13 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } public List<Trade> getAllTrades() { - List<Trade> trades = new ArrayList<Trade>(); - trades.addAll(tradableList.getList()); - trades.addAll(closedTradableManager.getClosedTrades()); - trades.addAll(failedTradesManager.getObservableList()); - return trades; + synchronized (tradableList) { + List<Trade> trades = new ArrayList<Trade>(); + trades.addAll(tradableList.getList()); + trades.addAll(closedTradableManager.getClosedTrades()); + trades.addAll(failedTradesManager.getObservableList()); + return trades; + } } public List<Trade> getOpenTrades() { @@ -1176,7 +1317,7 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi public Optional<Trade> getClosedTrade(String tradeId) { return closedTradableManager.getClosedTrades().stream().filter(e -> e.getId().equals(tradeId)).findFirst(); } - + public Optional<Trade> getFailedTrade(String tradeId) { return failedTradesManager.getTradeById(tradeId); } @@ -1189,138 +1330,6 @@ public class TradeManager implements PersistedDataHost, DecryptedDirectMessageLi } } - private void removeTrade(Trade trade) { - log.info("TradeManager.removeTrade() " + trade.getId()); - synchronized (tradableList) { - if (!tradableList.contains(trade)) return; - - // remove trade - tradableList.remove(trade); - - // unregister and persist - p2PService.removeDecryptedDirectMessageListener(getTradeProtocol(trade)); - requestPersistence(); - } - } - - private void maybeRemoveTradeOnError(Trade trade) { - synchronized (tradableList) { - if (trade.isDepositRequested() && !trade.isDepositFailed()) { - listenForCleanup(trade); - } else { - removeTradeOnError(trade); - } - } - } - - private void removeTradeOnError(Trade trade) { - log.warn("TradeManager.removeTradeOnError() " + trade.getId()); - synchronized (tradableList) { - - // unreserve taker key images - if (trade instanceof TakerTrade && trade.getSelf().getReserveTxKeyImages() != null) { - xmrWalletService.thawOutputs(trade.getSelf().getReserveTxKeyImages()); - xmrWalletService.saveMainWallet(); - trade.getSelf().setReserveTxKeyImages(null); - } - - // unreserve open offer - Optional<OpenOffer> openOffer = openOfferManager.getOpenOfferById(trade.getId()); - if (trade instanceof MakerTrade && openOffer.isPresent()) { - openOfferManager.unreserveOpenOffer(openOffer.get()); - } - - // remove trade from list - removeTrade(trade); - - // delete trade wallet - if (trade.walletExists()) trade.deleteWallet(); - } - } - - private void listenForCleanup(Trade trade) { - if (getOpenTrade(trade.getId()).isPresent() && trade.isDepositRequested()) { - if (trade.isDepositsPublished()) { - cleanupPublishedTrade(trade); - } else { - log.warn("Scheduling to delete open trade if unfunded for {} {}", trade.getClass().getSimpleName(), trade.getId()); - new TradeCleanupListener(trade); // TODO: better way than creating listener? - } - } - } - - private void cleanupPublishedTrade(Trade trade) { - if (trade instanceof MakerTrade && openOfferManager.getOpenOfferById(trade.getId()).isPresent()) { - log.warn("Closing open offer as cleanup step"); - openOfferManager.closeOpenOffer(checkNotNull(trade.getOffer())); - } - } - - private class TradeCleanupListener { - - private static final long REMOVE_AFTER_MS = 60000; - private static final int REMOVE_AFTER_NUM_CONFIRMATIONS = 1; - private Long startHeight; - private Subscription stateSubscription; - private Subscription heightSubscription; - - public TradeCleanupListener(Trade trade) { - - // listen for deposits published to close open offer - stateSubscription = EasyBind.subscribe(trade.stateProperty(), state -> { - if (trade.isDepositsPublished()) { - cleanupPublishedTrade(trade); - if (stateSubscription != null) { - stateSubscription.unsubscribe(); - stateSubscription = null; - } - } - }); - - // listen for block confirmation to remove trade - long startTime = System.currentTimeMillis(); - heightSubscription = EasyBind.subscribe(xmrWalletService.getConnectionsService().chainHeightProperty(), lastBlockHeight -> { - if (isShutDown) return; - if (startHeight == null) startHeight = lastBlockHeight.longValue(); - if (lastBlockHeight.longValue() >= startHeight + REMOVE_AFTER_NUM_CONFIRMATIONS) { - new Thread(() -> { - - // wait minimum time - GenUtils.waitFor(Math.max(0, REMOVE_AFTER_MS - (System.currentTimeMillis() - startTime))); - - // get trade's deposit txs from daemon - MoneroTx makerDepositTx = trade.getMaker().getDepositTxHash() == null ? null : xmrWalletService.getDaemon().getTx(trade.getMaker().getDepositTxHash()); - MoneroTx takerDepositTx = trade.getTaker().getDepositTxHash() == null ? null : xmrWalletService.getDaemon().getTx(trade.getTaker().getDepositTxHash()); - - // remove trade and wallet if neither deposit tx published - if (makerDepositTx == null && takerDepositTx == null) { - log.warn("Deleting {} {} after protocol error", trade.getClass().getSimpleName(), trade.getId()); - if (trade instanceof ArbitratorTrade && (trade.getMaker().getReserveTxHash() != null || trade.getTaker().getReserveTxHash() != null)) { - onMoveInvalidTradeToFailedTrades(trade); // arbitrator retains trades with reserved funds for analysis and penalty - } else { - removeTradeOnError(trade); - failedTradesManager.removeTrade(trade); - } - } else if (!trade.isPayoutPublished()) { - - // set error that wallet may be partially funded - String errorMessage = "Refusing to delete " + trade.getClass().getSimpleName() + " " + trade.getId() + " after protocol timeout because its wallet might be funded"; - trade.prependErrorMessage(errorMessage); - log.warn(errorMessage); - } - - // unsubscribe - if (heightSubscription != null) { - heightSubscription.unsubscribe(); - heightSubscription = null; - } - - }).start(); - } - }); - } - } - // TODO Remove once tradableList is refactored to a final field // (part of the persistence refactor PR) private void onTradesChanged() { diff --git a/core/src/main/java/haveno/core/trade/TradeModule.java b/core/src/main/java/haveno/core/trade/TradeModule.java index 9581749364..7fc993811b 100644 --- a/core/src/main/java/haveno/core/trade/TradeModule.java +++ b/core/src/main/java/haveno/core/trade/TradeModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; diff --git a/core/src/main/java/haveno/core/trade/TradeTxException.java b/core/src/main/java/haveno/core/trade/TradeTxException.java index 78f8a74e48..164cea1873 100644 --- a/core/src/main/java/haveno/core/trade/TradeTxException.java +++ b/core/src/main/java/haveno/core/trade/TradeTxException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; diff --git a/core/src/main/java/haveno/core/trade/TradeUtil.java b/core/src/main/java/haveno/core/trade/TradeUtil.java index ba57166bba..bfebca486b 100644 --- a/core/src/main/java/haveno/core/trade/TradeUtil.java +++ b/core/src/main/java/haveno/core/trade/TradeUtil.java @@ -1,40 +1,38 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.common.util.Tuple2; -import haveno.core.locale.Res; -import haveno.core.offer.Offer; -import haveno.core.xmr.wallet.BtcWalletService; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Date; -import java.util.Objects; - -import static com.google.common.base.Preconditions.checkNotNull; import static haveno.core.locale.CurrencyUtil.getCurrencyPair; import static haveno.core.locale.CurrencyUtil.isTraditionalCurrency; +import haveno.core.locale.Res; +import haveno.core.offer.Offer; import static haveno.core.util.FormattingUtils.formatDurationAsWords; +import haveno.core.xmr.wallet.BtcWalletService; import static java.lang.String.format; +import java.util.Date; +import java.util.Objects; +import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; /** * This class contains trade utility methods. @@ -174,7 +172,7 @@ public class TradeUtil { * @param trade Trade * @return String describing a trader's role for a given trade */ - public String getRole(Trade trade) { + public static String getRole(Trade trade) { Offer offer = trade.getOffer(); if (offer == null) throw new IllegalStateException(format("could not get role because no offer was found for trade '%s'", @@ -193,7 +191,7 @@ public class TradeUtil { * @param currencyCode String * @return String describing a trader's role */ - public String getRole(boolean isBuyerMakerAndSellerTaker, boolean isMaker, String currencyCode) { + private static String getRole(boolean isBuyerMakerAndSellerTaker, boolean isMaker, String currencyCode) { if (isTraditionalCurrency(currencyCode)) { String baseCurrencyCode = Res.getBaseCurrencyCode(); if (isBuyerMakerAndSellerTaker) diff --git a/core/src/main/java/haveno/core/trade/failed/FailedTradesManager.java b/core/src/main/java/haveno/core/trade/failed/FailedTradesManager.java index c525e9512f..a99c28242e 100644 --- a/core/src/main/java/haveno/core/trade/failed/FailedTradesManager.java +++ b/core/src/main/java/haveno/core/trade/failed/FailedTradesManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.failed; diff --git a/core/src/main/java/haveno/core/trade/handlers/TradeResultHandler.java b/core/src/main/java/haveno/core/trade/handlers/TradeResultHandler.java index 7dd80e1881..293739b07a 100644 --- a/core/src/main/java/haveno/core/trade/handlers/TradeResultHandler.java +++ b/core/src/main/java/haveno/core/trade/handlers/TradeResultHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.handlers; diff --git a/core/src/main/java/haveno/core/trade/handlers/TransactionResultHandler.java b/core/src/main/java/haveno/core/trade/handlers/TransactionResultHandler.java index 33c31dc816..198fbdc4bd 100644 --- a/core/src/main/java/haveno/core/trade/handlers/TransactionResultHandler.java +++ b/core/src/main/java/haveno/core/trade/handlers/TransactionResultHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.handlers; diff --git a/core/src/main/java/haveno/core/trade/messages/DepositRequest.java b/core/src/main/java/haveno/core/trade/messages/DepositRequest.java index 9af9af55b4..b0ac60af85 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -33,7 +33,9 @@ import java.util.Optional; public final class DepositRequest extends TradeMessage implements DirectMessage { private final long currentDate; private final byte[] contractSignature; + @Nullable private final String depositTxHex; + @Nullable private final String depositTxKey; @Nullable private final byte[] paymentAccountKey; @@ -43,8 +45,8 @@ public final class DepositRequest extends TradeMessage implements DirectMessage String messageVersion, long currentDate, byte[] contractSignature, - String depositTxHex, - String depositTxKey, + @Nullable String depositTxHex, + @Nullable String depositTxKey, @Nullable byte[] paymentAccountKey) { super(messageVersion, tradeId, uid); this.currentDate = currentDate; @@ -62,14 +64,13 @@ public final class DepositRequest extends TradeMessage implements DirectMessage @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.DepositRequest.Builder builder = protobuf.DepositRequest.newBuilder() - .setTradeId(tradeId) - .setUid(uid) - .setDepositTxHex(depositTxHex) - .setDepositTxKey(depositTxKey); + .setTradeId(offerId) + .setUid(uid); builder.setCurrentDate(currentDate); Optional.ofNullable(paymentAccountKey).ifPresent(e -> builder.setPaymentAccountKey(ByteString.copyFrom(e))); + Optional.ofNullable(depositTxHex).ifPresent(builder::setDepositTxHex); + Optional.ofNullable(depositTxKey).ifPresent(builder::setDepositTxKey); Optional.ofNullable(contractSignature).ifPresent(e -> builder.setContractSignature(ByteString.copyFrom(e))); - return getNetworkEnvelopeBuilder().setDepositRequest(builder).build(); } @@ -81,8 +82,8 @@ public final class DepositRequest extends TradeMessage implements DirectMessage messageVersion, proto.getCurrentDate(), ProtoUtil.byteArrayOrNullFromProto(proto.getContractSignature()), - proto.getDepositTxHex(), - proto.getDepositTxKey(), + ProtoUtil.stringOrNullFromProto(proto.getDepositTxHex()), + ProtoUtil.stringOrNullFromProto(proto.getDepositTxKey()), ProtoUtil.byteArrayOrNullFromProto(proto.getPaymentAccountKey())); } diff --git a/core/src/main/java/haveno/core/trade/messages/DepositResponse.java b/core/src/main/java/haveno/core/trade/messages/DepositResponse.java index eac1b36c80..c9024a93f3 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositResponse.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -30,15 +30,21 @@ import java.util.Optional; public final class DepositResponse extends TradeMessage implements DirectMessage { private final long currentDate; private final String errorMessage; + private final long buyerSecurityDeposit; + private final long sellerSecurityDeposit; public DepositResponse(String tradeId, String uid, String messageVersion, long currentDate, - String errorMessage) { + String errorMessage, + long buyerSecurityDeposit, + long sellerSecurityDeposit) { super(messageVersion, tradeId, uid); this.currentDate = currentDate; this.errorMessage = errorMessage; + this.buyerSecurityDeposit = buyerSecurityDeposit; + this.sellerSecurityDeposit = sellerSecurityDeposit; } @@ -49,9 +55,11 @@ public final class DepositResponse extends TradeMessage implements DirectMessage @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.DepositResponse.Builder builder = protobuf.DepositResponse.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid); builder.setCurrentDate(currentDate); + builder.setBuyerSecurityDeposit(buyerSecurityDeposit); + builder.setSellerSecurityDeposit(sellerSecurityDeposit); Optional.ofNullable(errorMessage).ifPresent(e -> builder.setErrorMessage(errorMessage)); return getNetworkEnvelopeBuilder().setDepositResponse(builder).build(); @@ -64,7 +72,9 @@ public final class DepositResponse extends TradeMessage implements DirectMessage proto.getUid(), messageVersion, proto.getCurrentDate(), - ProtoUtil.stringOrNullFromProto(proto.getErrorMessage())); + ProtoUtil.stringOrNullFromProto(proto.getErrorMessage()), + proto.getBuyerSecurityDeposit(), + proto.getSellerSecurityDeposit()); } @Override @@ -72,6 +82,8 @@ public final class DepositResponse extends TradeMessage implements DirectMessage return "DepositResponse {" + ",\n currentDate=" + currentDate + ",\n errorMessage=" + errorMessage + + ",\n buyerSecurityDeposit=" + buyerSecurityDeposit + + ",\n sellerSecurityDeposit=" + sellerSecurityDeposit + "\n} " + super.toString(); } } diff --git a/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java b/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java index 28c9b455c6..2d66df218a 100644 --- a/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/DepositsConfirmedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -61,7 +61,7 @@ public final class DepositsConfirmedMessage extends TradeMailboxMessage { @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.DepositsConfirmedMessage.Builder builder = protobuf.DepositsConfirmedMessage.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setPubKeyRing(pubKeyRing.toProtoMessage()) .setUid(uid); diff --git a/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java b/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java index 99cb291a5b..b949a14493 100644 --- a/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/InitMultisigRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -36,6 +36,8 @@ public final class InitMultisigRequest extends TradeMessage implements DirectMes private final String madeMultisigHex; @Nullable private final String exchangedMultisigHex; + @Nullable + private final String tradeFeeAddress; public InitMultisigRequest(String tradeId, String uid, @@ -43,12 +45,14 @@ public final class InitMultisigRequest extends TradeMessage implements DirectMes long currentDate, String preparedMultisigHex, String madeMultisigHex, - String exchangedMultisigHex) { + String exchangedMultisigHex, + String tradeFeeAddress) { super(messageVersion, tradeId, uid); this.currentDate = currentDate; this.preparedMultisigHex = preparedMultisigHex; this.madeMultisigHex = madeMultisigHex; this.exchangedMultisigHex = exchangedMultisigHex; + this.tradeFeeAddress = tradeFeeAddress; } @@ -59,12 +63,13 @@ public final class InitMultisigRequest extends TradeMessage implements DirectMes @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.InitMultisigRequest.Builder builder = protobuf.InitMultisigRequest.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid); Optional.ofNullable(preparedMultisigHex).ifPresent(e -> builder.setPreparedMultisigHex(preparedMultisigHex)); Optional.ofNullable(madeMultisigHex).ifPresent(e -> builder.setMadeMultisigHex(madeMultisigHex)); Optional.ofNullable(exchangedMultisigHex).ifPresent(e -> builder.setExchangedMultisigHex(exchangedMultisigHex)); + Optional.ofNullable(tradeFeeAddress).ifPresent(e -> builder.setTradeFeeAddress(tradeFeeAddress)); builder.setCurrentDate(currentDate); @@ -80,16 +85,18 @@ public final class InitMultisigRequest extends TradeMessage implements DirectMes proto.getCurrentDate(), ProtoUtil.stringOrNullFromProto(proto.getPreparedMultisigHex()), ProtoUtil.stringOrNullFromProto(proto.getMadeMultisigHex()), - ProtoUtil.stringOrNullFromProto(proto.getExchangedMultisigHex())); + ProtoUtil.stringOrNullFromProto(proto.getExchangedMultisigHex()), + ProtoUtil.stringOrNullFromProto(proto.getTradeFeeAddress())); } @Override public String toString() { return "InitMultisigRequest {" + ",\n currentDate=" + currentDate + - ",\n preparedMultisigHex='" + preparedMultisigHex + - ",\n madeMultisigHex='" + madeMultisigHex + - ",\n exchangedMultisigHex='" + exchangedMultisigHex + + ",\n preparedMultisigHex=" + preparedMultisigHex + + ",\n madeMultisigHex=" + madeMultisigHex + + ",\n exchangedMultisigHex=" + exchangedMultisigHex + + ",\n tradeFeeAddress=" + tradeFeeAddress + "\n} " + super.toString(); } } diff --git a/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java b/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java index 810e9c2874..817162addd 100644 --- a/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/InitTradeRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -33,21 +33,19 @@ import java.util.Optional; @EqualsAndHashCode(callSuper = true) @Value public final class InitTradeRequest extends TradeMessage implements DirectMessage { - private final NodeAddress senderNodeAddress; + TradeProtocolVersion tradeProtocolVersion; private final long tradeAmount; private final long tradePrice; - private final long tradeFee; - private final String accountId; - private final String paymentAccountId; private final String paymentMethodId; - private final PubKeyRing pubKeyRing; - - // added in v 0.6. can be null if we trade with an older peer + @Nullable + private final String makerAccountId; + private final String takerAccountId; + private final String makerPaymentAccountId; + private final String takerPaymentAccountId; + private final PubKeyRing takerPubKeyRing; @Nullable private final byte[] accountAgeWitnessSignatureOfOfferId; private final long currentDate; - - // XMR integration private final NodeAddress makerNodeAddress; private final NodeAddress takerNodeAddress; @Nullable @@ -61,37 +59,39 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag @Nullable private final String payoutAddress; @Nullable - private final byte[] makerSignature; + private final String challenge; - public InitTradeRequest(String tradeId, - NodeAddress senderNodeAddress, - PubKeyRing pubKeyRing, - long tradeAmount, - long tradePrice, - long tradeFee, - String accountId, - String paymentAccountId, - String paymentMethodId, - String uid, - String messageVersion, - @Nullable byte[] accountAgeWitnessSignatureOfOfferId, - long currentDate, - NodeAddress makerNodeAddress, - NodeAddress takerNodeAddress, - NodeAddress arbitratorNodeAddress, - @Nullable String reserveTxHash, - @Nullable String reserveTxHex, - @Nullable String reserveTxKey, - @Nullable String payoutAddress, - @Nullable byte[] makerSignature) { - super(messageVersion, tradeId, uid); - this.senderNodeAddress = senderNodeAddress; - this.pubKeyRing = pubKeyRing; + public InitTradeRequest(TradeProtocolVersion tradeProtocolVersion, + String offerId, + long tradeAmount, + long tradePrice, + String paymentMethodId, + @Nullable String makerAccountId, + String takerAccountId, + String makerPaymentAccountId, + String takerPaymentAccountId, + PubKeyRing takerPubKeyRing, + String uid, + String messageVersion, + @Nullable byte[] accountAgeWitnessSignatureOfOfferId, + long currentDate, + NodeAddress makerNodeAddress, + NodeAddress takerNodeAddress, + NodeAddress arbitratorNodeAddress, + @Nullable String reserveTxHash, + @Nullable String reserveTxHex, + @Nullable String reserveTxKey, + @Nullable String payoutAddress, + @Nullable String challenge) { + super(messageVersion, offerId, uid); + this.tradeProtocolVersion = tradeProtocolVersion; this.tradeAmount = tradeAmount; this.tradePrice = tradePrice; - this.tradeFee = tradeFee; - this.accountId = accountId; - this.paymentAccountId = paymentAccountId; + this.makerAccountId = makerAccountId; + this.takerAccountId = takerAccountId; + this.makerPaymentAccountId = makerPaymentAccountId; + this.takerPaymentAccountId = takerPaymentAccountId; + this.takerPubKeyRing = takerPubKeyRing; this.paymentMethodId = paymentMethodId; this.accountAgeWitnessSignatureOfOfferId = accountAgeWitnessSignatureOfOfferId; this.currentDate = currentDate; @@ -102,7 +102,7 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag this.reserveTxHex = reserveTxHex; this.reserveTxKey = reserveTxKey; this.payoutAddress = payoutAddress; - this.makerSignature = makerSignature; + this.challenge = challenge; } @@ -110,29 +110,31 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag // PROTO BUFFER /////////////////////////////////////////////////////////////////////////////////////////// - @Override + + @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.InitTradeRequest.Builder builder = protobuf.InitTradeRequest.newBuilder() - .setTradeId(tradeId) - .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) + .setTradeProtocolVersion(TradeProtocolVersion.toProtoMessage(tradeProtocolVersion)) + .setOfferId(offerId) .setTakerNodeAddress(takerNodeAddress.toProtoMessage()) .setMakerNodeAddress(makerNodeAddress.toProtoMessage()) .setTradeAmount(tradeAmount) .setTradePrice(tradePrice) - .setTradeFee(tradeFee) - .setPubKeyRing(pubKeyRing.toProtoMessage()) - .setPaymentAccountId(paymentAccountId) + .setTakerPubKeyRing(takerPubKeyRing.toProtoMessage()) + .setMakerPaymentAccountId(makerPaymentAccountId) + .setTakerPaymentAccountId(takerPaymentAccountId) .setPaymentMethodId(paymentMethodId) - .setAccountId(accountId) + .setTakerAccountId(takerAccountId) .setUid(uid); + Optional.ofNullable(makerAccountId).ifPresent(e -> builder.setMakerAccountId(makerAccountId)); Optional.ofNullable(arbitratorNodeAddress).ifPresent(e -> builder.setArbitratorNodeAddress(arbitratorNodeAddress.toProtoMessage())); Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash)); Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex)); Optional.ofNullable(reserveTxKey).ifPresent(e -> builder.setReserveTxKey(reserveTxKey)); Optional.ofNullable(payoutAddress).ifPresent(e -> builder.setPayoutAddress(payoutAddress)); + Optional.ofNullable(challenge).ifPresent(e -> builder.setChallenge(challenge)); Optional.ofNullable(accountAgeWitnessSignatureOfOfferId).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfOfferId(ByteString.copyFrom(e))); - Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(ByteString.copyFrom(e))); builder.setCurrentDate(currentDate); return getNetworkEnvelopeBuilder().setInitTradeRequest(builder).build(); @@ -141,15 +143,16 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag public static InitTradeRequest fromProto(protobuf.InitTradeRequest proto, CoreProtoResolver coreProtoResolver, String messageVersion) { - return new InitTradeRequest(proto.getTradeId(), - NodeAddress.fromProto(proto.getSenderNodeAddress()), - PubKeyRing.fromProto(proto.getPubKeyRing()), + return new InitTradeRequest(TradeProtocolVersion.fromProto(proto.getTradeProtocolVersion()), + proto.getOfferId(), proto.getTradeAmount(), proto.getTradePrice(), - proto.getTradeFee(), - proto.getAccountId(), - proto.getPaymentAccountId(), proto.getPaymentMethodId(), + ProtoUtil.stringOrNullFromProto(proto.getMakerAccountId()), + proto.getTakerAccountId(), + proto.getMakerPaymentAccountId(), + proto.getTakerPaymentAccountId(), + PubKeyRing.fromProto(proto.getTakerPubKeyRing()), proto.getUid(), messageVersion, ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfOfferId()), @@ -161,28 +164,32 @@ public final class InitTradeRequest extends TradeMessage implements DirectMessag ProtoUtil.stringOrNullFromProto(proto.getReserveTxHex()), ProtoUtil.stringOrNullFromProto(proto.getReserveTxKey()), ProtoUtil.stringOrNullFromProto(proto.getPayoutAddress()), - ProtoUtil.byteArrayOrNullFromProto(proto.getMakerSignature())); + ProtoUtil.stringOrNullFromProto(proto.getChallenge())); } @Override public String toString() { return "InitTradeRequest{" + - "\n senderNodeAddress=" + senderNodeAddress + + "\n tradeProtocolVersion=" + tradeProtocolVersion + + ",\n offerId=" + offerId + ",\n tradeAmount=" + tradeAmount + ",\n tradePrice=" + tradePrice + - ",\n tradeFee=" + tradeFee + - ",\n pubKeyRing=" + pubKeyRing + - ",\n accountId='" + accountId + '\'' + - ",\n paymentAccountId=" + paymentAccountId + ",\n paymentMethodId=" + paymentMethodId + - ",\n arbitratorNodeAddress=" + arbitratorNodeAddress + + ",\n makerAccountId=" + makerAccountId + + ",\n takerAccountId=" + takerAccountId + + ",\n makerPaymentAccountId=" + makerPaymentAccountId + + ",\n takerPaymentAccountId=" + takerPaymentAccountId + + ",\n takerPubKeyRing=" + takerPubKeyRing + ",\n accountAgeWitnessSignatureOfOfferId=" + Utilities.bytesAsHexString(accountAgeWitnessSignatureOfOfferId) + ",\n currentDate=" + currentDate + + ",\n makerNodeAddress=" + makerNodeAddress + + ",\n takerNodeAddress=" + takerNodeAddress + + ",\n arbitratorNodeAddress=" + arbitratorNodeAddress + ",\n reserveTxHash=" + reserveTxHash + ",\n reserveTxHex=" + reserveTxHex + ",\n reserveTxKey=" + reserveTxKey + ",\n payoutAddress=" + payoutAddress + - ",\n makerSignature=" + (makerSignature == null ? null : Utilities.byteArrayToInteger(makerSignature)) + + ",\n challenge=" + challenge + "\n} " + super.toString(); } } diff --git a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java index dc4c87286c..3f8d48cbec 100644 --- a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxPublishedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -61,7 +61,7 @@ public final class MediatedPayoutTxPublishedMessage extends TradeMailboxMessage public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { return getNetworkEnvelopeBuilder() .setMediatedPayoutTxPublishedMessage(protobuf.MediatedPayoutTxPublishedMessage.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setPayoutTx(ByteString.copyFrom(payoutTx)) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid)) diff --git a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java index b2039583c8..edc85671cd 100644 --- a/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/MediatedPayoutTxSignatureMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -63,7 +63,7 @@ public class MediatedPayoutTxSignatureMessage extends TradeMailboxMessage { return getNetworkEnvelopeBuilder() .setMediatedPayoutTxSignatureMessage(protobuf.MediatedPayoutTxSignatureMessage.newBuilder() .setTxSignature(ByteString.copyFrom(txSignature)) - .setTradeId(tradeId) + .setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid)) .build(); @@ -79,8 +79,8 @@ public class MediatedPayoutTxSignatureMessage extends TradeMailboxMessage { } @Override - public String getTradeId() { - return tradeId; + public String getOfferId() { + return offerId; } @@ -88,7 +88,7 @@ public class MediatedPayoutTxSignatureMessage extends TradeMailboxMessage { public String toString() { return "MediatedPayoutSignatureMessage{" + "\n txSignature=" + Utilities.bytesAsHexString(txSignature) + - ",\n tradeId='" + tradeId + '\'' + + ",\n tradeId='" + offerId + '\'' + ",\n senderNodeAddress=" + senderNodeAddress + "\n} " + super.toString(); } diff --git a/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java index 6a06e582f1..a7f23190d6 100644 --- a/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/PaymentReceivedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -46,6 +46,7 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage { private final AccountAgeWitness buyerAccountAgeWitness; @Nullable private final SignedWitness buyerSignedWitness; + @Nullable private final PaymentSentMessage paymentSentMessage; @Setter @Nullable @@ -60,7 +61,7 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage { boolean deferPublishPayout, AccountAgeWitness buyerAccountAgeWitness, @Nullable SignedWitness buyerSignedWitness, - PaymentSentMessage paymentSentMessage) { + @Nullable PaymentSentMessage paymentSentMessage) { this(tradeId, senderNodeAddress, uid, @@ -104,7 +105,7 @@ public final class PaymentReceivedMessage extends TradeMailboxMessage { @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.PaymentReceivedMessage.Builder builder = protobuf.PaymentReceivedMessage.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid) .setDeferPublishPayout(deferPublishPayout); diff --git a/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java b/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java index a9c8f10a99..6b6f400add 100644 --- a/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/PaymentSentMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -101,7 +101,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage { @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { final protobuf.PaymentSentMessage.Builder builder = protobuf.PaymentSentMessage.newBuilder(); - builder.setTradeId(tradeId) + builder.setTradeId(offerId) .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) .setUid(uid); @@ -141,7 +141,7 @@ public final class PaymentSentMessage extends TradeMailboxMessage { @Override public String toString() { return "PaymentSentMessage{" + - ",\n tradeId=" + tradeId + + ",\n tradeId=" + offerId + ",\n uid='" + uid + '\'' + ",\n senderNodeAddress=" + senderNodeAddress + ",\n counterCurrencyTxId=" + counterCurrencyTxId + diff --git a/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java b/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java index 3ed13d1215..ab82e13dec 100644 --- a/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/messages/SignContractRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -35,7 +35,9 @@ public final class SignContractRequest extends TradeMessage implements DirectMes private final String accountId; private final byte[] paymentAccountPayloadHash; private final String payoutAddress; + @Nullable private final String depositTxHash; + @Nullable private final byte[] accountAgeWitnessSignatureOfDepositHash; public SignContractRequest(String tradeId, @@ -45,7 +47,7 @@ public final class SignContractRequest extends TradeMessage implements DirectMes String accountId, byte[] paymentAccountPayloadHash, String payoutAddress, - String depositTxHash, + @Nullable String depositTxHash, @Nullable byte[] accountAgeWitnessSignatureOfDepositHash) { super(messageVersion, tradeId, uid); this.currentDate = currentDate; @@ -64,14 +66,13 @@ public final class SignContractRequest extends TradeMessage implements DirectMes @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.SignContractRequest.Builder builder = protobuf.SignContractRequest.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid) .setAccountId(accountId) .setPaymentAccountPayloadHash(ByteString.copyFrom(paymentAccountPayloadHash)) - .setPayoutAddress(payoutAddress) - .setDepositTxHash(depositTxHash); - + .setPayoutAddress(payoutAddress); Optional.ofNullable(accountAgeWitnessSignatureOfDepositHash).ifPresent(e -> builder.setAccountAgeWitnessSignatureOfDepositHash(ByteString.copyFrom(e))); + Optional.ofNullable(depositTxHash).ifPresent(builder::setDepositTxHash); builder.setCurrentDate(currentDate); return getNetworkEnvelopeBuilder().setSignContractRequest(builder).build(); @@ -87,7 +88,7 @@ public final class SignContractRequest extends TradeMessage implements DirectMes proto.getAccountId(), proto.getPaymentAccountPayloadHash().toByteArray(), proto.getPayoutAddress(), - proto.getDepositTxHash(), + ProtoUtil.stringOrNullFromProto(proto.getDepositTxHash()), ProtoUtil.byteArrayOrNullFromProto(proto.getAccountAgeWitnessSignatureOfDepositHash())); } diff --git a/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java b/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java index fae3835840..ec85dacd48 100644 --- a/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java +++ b/core/src/main/java/haveno/core/trade/messages/SignContractResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -58,7 +58,7 @@ public final class SignContractResponse extends TradeMessage implements DirectMe @Override public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { protobuf.SignContractResponse.Builder builder = protobuf.SignContractResponse.newBuilder() - .setTradeId(tradeId) + .setTradeId(offerId) .setUid(uid); Optional.ofNullable(contractAsJson).ifPresent(e -> builder.setContractAsJson(contractAsJson)); diff --git a/core/src/main/java/haveno/core/trade/messages/TradeMailboxMessage.java b/core/src/main/java/haveno/core/trade/messages/TradeMailboxMessage.java index 88e0d99866..f45881d6d2 100644 --- a/core/src/main/java/haveno/core/trade/messages/TradeMailboxMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/TradeMailboxMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; diff --git a/core/src/main/java/haveno/core/trade/messages/TradeMessage.java b/core/src/main/java/haveno/core/trade/messages/TradeMessage.java index c105729892..9642f00130 100644 --- a/core/src/main/java/haveno/core/trade/messages/TradeMessage.java +++ b/core/src/main/java/haveno/core/trade/messages/TradeMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.messages; @@ -27,12 +27,12 @@ import lombok.ToString; @Getter @ToString public abstract class TradeMessage extends NetworkEnvelope implements UidMessage { - protected final String tradeId; + protected final String offerId; protected final String uid; - protected TradeMessage(String messageVersion, String tradeId, String uid) { + protected TradeMessage(String messageVersion, String offerId, String uid) { super(messageVersion); - this.tradeId = tradeId; + this.offerId = offerId; this.uid = uid; } } diff --git a/core/src/main/java/haveno/core/trade/messages/TradeProtocolVersion.java b/core/src/main/java/haveno/core/trade/messages/TradeProtocolVersion.java new file mode 100644 index 0000000000..1dd50d5b75 --- /dev/null +++ b/core/src/main/java/haveno/core/trade/messages/TradeProtocolVersion.java @@ -0,0 +1,33 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.trade.messages; + +import haveno.common.proto.ProtoUtil; + +public enum TradeProtocolVersion { + MULTISIG_2_3; + + public static TradeProtocolVersion fromProto( + protobuf.TradeProtocolVersion tradeProtocolVersion) { + return ProtoUtil.enumFromProto(TradeProtocolVersion.class, tradeProtocolVersion.name()); + } + + public static protobuf.TradeProtocolVersion toProtoMessage(TradeProtocolVersion tradeProtocolVersion) { + return protobuf.TradeProtocolVersion.valueOf(tradeProtocolVersion.name()); + } +} \ No newline at end of file diff --git a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java index 9958cc2b77..98b3f1ab0d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/ArbitratorProtocol.java @@ -1,5 +1,6 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.trade.ArbitratorTrade; import haveno.core.trade.Trade; @@ -43,8 +44,8 @@ public class ArbitratorProtocol extends DisputeProtocol { public void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer, ErrorMessageHandler errorMessageHandler) { System.out.println("ArbitratorProtocol.handleInitTradeRequest()"); - new Thread(() -> { - synchronized (trade) { + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; processModel.setTradeMessage(message); // TODO (woodser): confirm these are null without being set @@ -58,17 +59,17 @@ public class ArbitratorProtocol extends DisputeProtocol { ArbitratorSendInitTradeOrMultisigRequests.class) .using(new TradeTaskRunner(trade, () -> { - startTimeout(TRADE_TIMEOUT); + startTimeout(); handleTaskRunnerSuccess(peer, message); }, errorMessage -> { handleTaskRunnerFault(peer, message, errorMessage); })) - .withTimeout(TRADE_TIMEOUT)) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) .executeTasks(true); awaitTradeLatch(); } - }).start(); + }, trade.getId()); } @Override @@ -78,12 +79,12 @@ public class ArbitratorProtocol extends DisputeProtocol { public void handleDepositRequest(DepositRequest request, NodeAddress sender) { System.out.println("ArbitratorProtocol.handleDepositRequest() " + trade.getId()); - new Thread(() -> { - synchronized (trade) { + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { latchTrade(); Validator.checkTradeId(processModel.getOfferId(), request); processModel.setTradeMessage(request); - expect(phase(Trade.Phase.INIT) + expect(anyPhase(Trade.Phase.INIT, Trade.Phase.DEPOSIT_REQUESTED) .with(request) .from(sender)) .setup(tasks( @@ -98,17 +99,16 @@ public class ArbitratorProtocol extends DisputeProtocol { }, errorMessage -> { handleTaskRunnerFault(sender, request, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) + }))) .executeTasks(true); awaitTradeLatch(); } - }).start(); + }, trade.getId()); } @Override public void handleDepositResponse(DepositResponse response, NodeAddress sender) { - log.warn("Arbitrator ignoring DepositResponse for trade " + response.getTradeId()); + log.warn("Arbitrator ignoring DepositResponse for trade " + response.getOfferId()); } @SuppressWarnings("unchecked") @@ -116,4 +116,13 @@ public class ArbitratorProtocol extends DisputeProtocol { public Class<? extends TradeTask>[] getDepositsConfirmedTasks() { return new Class[] { SendDepositsConfirmedMessageToBuyer.class, SendDepositsConfirmedMessageToSeller.class }; } + + @Override + public void handleError(String errorMessage) { + // set trade state to send deposit responses with nack + if (trade instanceof ArbitratorTrade && trade.getState() == Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST) { + trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED); + } + super.handleError(errorMessage); + } } diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java index f6a6e3514c..160e1bee6c 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerAsMakerProtocol.java @@ -15,14 +15,32 @@ e * This file is part of Haveno. * along with Haveno. If not, see <http://www.gnu.org/licenses/>. */ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.trade.BuyerAsMakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.protocol.tasks.ApplyFilter; -import haveno.core.trade.protocol.tasks.MakerSendInitTradeRequest; +import haveno.core.trade.protocol.tasks.MakerSendInitTradeRequestToArbitrator; import haveno.core.trade.protocol.tasks.ProcessInitTradeRequest; import haveno.network.p2p.NodeAddress; import lombok.extern.slf4j.Slf4j; @@ -43,8 +61,8 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol NodeAddress peer, ErrorMessageHandler errorMessageHandler) { System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); - new Thread(() -> { - synchronized (trade) { + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; expect(phase(Trade.Phase.INIT) @@ -53,19 +71,19 @@ public class BuyerAsMakerProtocol extends BuyerProtocol implements MakerProtocol .setup(tasks( ApplyFilter.class, ProcessInitTradeRequest.class, - MakerSendInitTradeRequest.class) + MakerSendInitTradeRequestToArbitrator.class) .using(new TradeTaskRunner(trade, () -> { - startTimeout(TRADE_TIMEOUT); + startTimeout(); handleTaskRunnerSuccess(peer, message); }, errorMessage -> { handleTaskRunnerFault(peer, message, errorMessage); })) - .withTimeout(TRADE_TIMEOUT)) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) .executeTasks(true); awaitTradeLatch(); } - }).start(); + }, trade.getId()); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java index 4d96d6ceb9..7a5a899e87 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerAsTakerProtocol.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,13 +35,18 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.trade.BuyerAsTakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.handlers.TradeResultHandler; +import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.protocol.tasks.ApplyFilter; +import haveno.core.trade.protocol.tasks.ProcessInitTradeRequest; import haveno.core.trade.protocol.tasks.TakerReserveTradeFunds; import haveno.core.trade.protocol.tasks.TakerSendInitTradeRequestToArbitrator; +import haveno.core.trade.protocol.tasks.TakerSendInitTradeRequestToMaker; +import haveno.network.p2p.NodeAddress; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -46,37 +68,60 @@ public class BuyerAsTakerProtocol extends BuyerProtocol implements TakerProtocol @Override public void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getCanonicalName() + ".onTakeOffer()"); - new Thread(() -> { - synchronized (trade) { - latchTrade(); - this.tradeResultHandler = tradeResultHandler; - this.errorMessageHandler = errorMessageHandler; - expect(phase(Trade.Phase.INIT) - .with(TakerEvent.TAKE_OFFER) - .from(trade.getTradePeer().getNodeAddress())) - .setup(tasks( - ApplyFilter.class, - TakerReserveTradeFunds.class, - TakerSendInitTradeRequestToArbitrator.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - unlatchTrade(); - }, - errorMessage -> { - handleError(errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(true); - awaitTradeLatch(); - } - }).start(); + System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + latchTrade(); + this.tradeResultHandler = tradeResultHandler; + this.errorMessageHandler = errorMessageHandler; + expect(phase(Trade.Phase.INIT) + .with(TakerEvent.TAKE_OFFER) + .from(trade.getTradePeer().getNodeAddress())) + .setup(tasks( + ApplyFilter.class, + TakerReserveTradeFunds.class, + TakerSendInitTradeRequestToMaker.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(); + unlatchTrade(); + }, + errorMessage -> { + handleError(errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); } @Override - protected void handleError(String errorMessage) { - trade.getXmrWalletService().resetAddressEntriesForOpenOffer(trade.getId()); - super.handleError(errorMessage); + public void handleInitTradeRequest(InitTradeRequest message, + NodeAddress peer) { + System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + latchTrade(); + expect(phase(Trade.Phase.INIT) + .with(message) + .from(peer)) + .setup(tasks( + ApplyFilter.class, + ProcessInitTradeRequest.class, + TakerSendInitTradeRequestToArbitrator.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(); + handleTaskRunnerSuccess(peer, message); + }, + errorMessage -> { + handleTaskRunnerFault(peer, message, errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java index 6481212281..06e1eead7c 100644 --- a/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/BuyerProtocol.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,7 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.trade.BuyerTrade; @@ -28,6 +46,7 @@ import haveno.core.trade.protocol.tasks.BuyerPreparePaymentSentMessage; import haveno.core.trade.protocol.tasks.BuyerSendPaymentSentMessageToArbitrator; import haveno.core.trade.protocol.tasks.BuyerSendPaymentSentMessageToSeller; import haveno.core.trade.protocol.tasks.SendDepositsConfirmedMessageToArbitrator; +import haveno.core.trade.protocol.tasks.SendDepositsConfirmedMessageToSeller; import haveno.core.trade.protocol.tasks.TradeTask; import haveno.network.p2p.NodeAddress; import lombok.extern.slf4j.Slf4j; @@ -54,26 +73,30 @@ public class BuyerProtocol extends DisputeProtocol { super.onInitialized(); // re-send payment sent message if not acked - synchronized (trade) { - if (trade.getState().ordinal() >= Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal() && trade.getState().ordinal() < Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal()) { - latchTrade(); - given(anyPhase(Trade.Phase.PAYMENT_SENT) - .with(BuyerEvent.STARTUP)) - .setup(tasks( - BuyerSendPaymentSentMessageToSeller.class, - BuyerSendPaymentSentMessageToArbitrator.class) - .using(new TradeTaskRunner(trade, - () -> { - unlatchTrade(); - }, - (errorMessage) -> { - log.warn("Error sending PaymentSentMessage on startup: " + errorMessage); - unlatchTrade(); - }))) - .executeTasks(); - awaitTradeLatch(); + ThreadUtils.execute(() -> { + if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; + synchronized (trade.getLock()) { + if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; + if (trade.getState().ordinal() >= Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal() && trade.getState().ordinal() < Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal()) { + latchTrade(); + given(anyPhase(Trade.Phase.PAYMENT_SENT) + .with(BuyerEvent.STARTUP)) + .setup(tasks( + BuyerSendPaymentSentMessageToSeller.class, + BuyerSendPaymentSentMessageToArbitrator.class) + .using(new TradeTaskRunner(trade, + () -> { + unlatchTrade(); + }, + (errorMessage) -> { + log.warn("Error sending PaymentSentMessage on startup: " + errorMessage); + unlatchTrade(); + }))) + .executeTasks(); + awaitTradeLatch(); + } } - } + }, trade.getId()); } @Override @@ -97,8 +120,8 @@ public class BuyerProtocol extends DisputeProtocol { public void onPaymentSent(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { System.out.println("BuyerProtocol.onPaymentSent()"); - new Thread(() -> { - synchronized (trade) { + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; BuyerEvent event = BuyerEvent.PAYMENT_SENT; @@ -112,14 +135,17 @@ public class BuyerProtocol extends DisputeProtocol { BuyerSendPaymentSentMessageToArbitrator.class) .using(new TradeTaskRunner(trade, () -> { + stopTimeout(); this.errorMessageHandler = null; resultHandler.handleResult(); handleTaskRunnerSuccess(event); }, (errorMessage) -> { + log.warn("Error confirming payment sent, reverting state to {}, error={}", Trade.State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN, errorMessage); + trade.setState(Trade.State.DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN); handleTaskRunnerFault(event, errorMessage); }))) - .run(() -> trade.setState(Trade.State.BUYER_CONFIRMED_IN_UI_PAYMENT_SENT)) + .run(() -> trade.advanceState(Trade.State.BUYER_CONFIRMED_PAYMENT_SENT)) .executeTasks(true); } catch (Exception e) { errorMessageHandler.handleErrorMessage("Error confirming payment sent: " + e.getMessage()); @@ -127,12 +153,12 @@ public class BuyerProtocol extends DisputeProtocol { } awaitTradeLatch(); } - }).start(); + }, trade.getId()); } @SuppressWarnings("unchecked") @Override public Class<? extends TradeTask>[] getDepositsConfirmedTasks() { - return new Class[] { SendDepositsConfirmedMessageToArbitrator.class }; + return new Class[] { SendDepositsConfirmedMessageToSeller.class, SendDepositsConfirmedMessageToArbitrator.class }; } } diff --git a/core/src/main/java/haveno/core/trade/protocol/DisputeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/DisputeProtocol.java index 73cfe0093f..75715559be 100644 --- a/core/src/main/java/haveno/core/trade/protocol/DisputeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/DisputeProtocol.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol; diff --git a/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java b/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java index f51fac1703..d237006197 100644 --- a/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/FluentProtocol.java @@ -1,20 +1,21 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ + package haveno.core.trade.protocol; import haveno.common.taskrunner.Task; @@ -236,7 +237,7 @@ public class FluentProtocol { boolean isTradeIdValid = message == null || isTradeIdValid(trade.getId(), message); if (!isTradeIdValid) { String info = MessageFormat.format("TradeId does not match tradeId in message, TradeId={0}, tradeId in message={1}", - trade.getId(), message.getTradeId()); + trade.getId(), message.getOfferId()); result = Result.INVALID_TRADE_ID.info(info); return result; } diff --git a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java index aae3b75bba..54aaa65d37 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java +++ b/core/src/main/java/haveno/core/trade/protocol/ProcessModel.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,7 +35,6 @@ package haveno.core.trade.protocol; import com.google.protobuf.ByteString; -import haveno.common.app.Version; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; import haveno.common.proto.ProtoUtil; @@ -34,12 +50,9 @@ import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.proto.CoreProtoResolver; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import haveno.core.support.dispute.mediation.mediator.MediatorManager; -import haveno.core.support.dispute.messages.DisputeClosedMessage; import haveno.core.support.dispute.refund.refundagent.RefundAgentManager; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; -import haveno.core.trade.messages.PaymentReceivedMessage; -import haveno.core.trade.messages.PaymentSentMessage; import haveno.core.trade.messages.TradeMessage; import haveno.core.trade.statistics.ReferralIdService; import haveno.core.trade.statistics.TradeStatisticsManager; @@ -101,7 +114,7 @@ public class ProcessModel implements Model, PersistablePayload { private byte[] payoutTxSignature; @Nullable @Setter - private byte[] preparedDepositTx; + private byte[] preparedDepositTx; // TODO: remove this unused field @Setter private boolean useSavingsWallet; @Setter @@ -111,7 +124,7 @@ public class ProcessModel implements Model, PersistablePayload { // After successful verified we copy that over to the trade.tradePeerAddress @Nullable @Setter - private NodeAddress tempTradePeerNodeAddress; // TODO (woodser): remove entirely? + private NodeAddress tempTradePeerNodeAddress; // Added in v.1.1.6 @Nullable @@ -123,8 +136,6 @@ public class ProcessModel implements Model, PersistablePayload { private long sellerPayoutAmountFromMediation; // Added for XMR integration - @Getter - transient private MoneroTxWallet takeOfferFeeTx; // TODO (woodser): remove @Setter transient private TradeMessage tradeMessage; @Getter @@ -136,32 +147,26 @@ public class ProcessModel implements Model, PersistablePayload { transient private MoneroTxWallet reserveTx; @Getter @Setter - transient private MoneroTxWallet depositTxXmr; - @Getter - @Setter transient private MoneroTxWallet unsignedPayoutTx; @Nullable @Getter @Setter + private String tradeFeeAddress; + @Getter + @Setter private String multisigAddress; - @Nullable - @Setter @Getter - private PaymentSentMessage paymentSentMessage; - @Nullable @Setter - @Getter - private PaymentReceivedMessage paymentReceivedMessage; - @Nullable - @Setter - @Getter - private DisputeClosedMessage disputeClosedMessage; + private long tradeProtocolErrorHeight; // We want to indicate the user the state of the message delivery of the // PaymentSentMessage. As well we do an automatic re-send in case it was not ACKed yet. // To enable that even after restart we persist the state. @Setter private ObjectProperty<MessageState> paymentSentMessageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED); + @Setter + private ObjectProperty<MessageState> paymentSentMessageStatePropertyArbitrator = new SimpleObjectProperty<>(MessageState.UNDEFINED); + private ObjectProperty<Boolean> paymentAccountDecryptedProperty = new SimpleObjectProperty<>(false); public ProcessModel(String offerId, String accountId, PubKeyRing pubKeyRing) { this(offerId, accountId, pubKeyRing, new TradePeer(), new TradePeer(), new TradePeer()); @@ -199,8 +204,10 @@ public class ProcessModel implements Model, PersistablePayload { .setUseSavingsWallet(useSavingsWallet) .setFundsNeededForTrade(fundsNeededForTrade) .setPaymentSentMessageState(paymentSentMessageStateProperty.get().name()) + .setPaymentSentMessageStateArbitrator(paymentSentMessageStatePropertyArbitrator.get().name()) .setBuyerPayoutAmountFromMediation(buyerPayoutAmountFromMediation) - .setSellerPayoutAmountFromMediation(sellerPayoutAmountFromMediation); + .setSellerPayoutAmountFromMediation(sellerPayoutAmountFromMediation) + .setTradeProtocolErrorHeight(tradeProtocolErrorHeight); Optional.ofNullable(maker).ifPresent(e -> builder.setMaker((protobuf.TradePeer) maker.toProtoMessage())); Optional.ofNullable(taker).ifPresent(e -> builder.setTaker((protobuf.TradePeer) taker.toProtoMessage())); Optional.ofNullable(arbitrator).ifPresent(e -> builder.setArbitrator((protobuf.TradePeer) arbitrator.toProtoMessage())); @@ -208,10 +215,8 @@ public class ProcessModel implements Model, PersistablePayload { Optional.ofNullable(tempTradePeerNodeAddress).ifPresent(e -> builder.setTempTradePeerNodeAddress(tempTradePeerNodeAddress.toProtoMessage())); Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e))); Optional.ofNullable(makerSignature).ifPresent(e -> builder.setMakerSignature(ByteString.copyFrom(e))); + Optional.ofNullable(tradeFeeAddress).ifPresent(e -> builder.setTradeFeeAddress(tradeFeeAddress)); Optional.ofNullable(multisigAddress).ifPresent(e -> builder.setMultisigAddress(multisigAddress)); - Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage())); - Optional.ofNullable(paymentReceivedMessage).ifPresent(e -> builder.setPaymentReceivedMessage(paymentReceivedMessage.toProtoNetworkEnvelope().getPaymentReceivedMessage())); - Optional.ofNullable(disputeClosedMessage).ifPresent(e -> builder.setDisputeClosedMessage(disputeClosedMessage.toProtoNetworkEnvelope().getDisputeClosedMessage())); return builder.build(); } @@ -225,21 +230,24 @@ public class ProcessModel implements Model, PersistablePayload { processModel.setFundsNeededForTrade(proto.getFundsNeededForTrade()); processModel.setBuyerPayoutAmountFromMediation(proto.getBuyerPayoutAmountFromMediation()); processModel.setSellerPayoutAmountFromMediation(proto.getSellerPayoutAmountFromMediation()); + processModel.setTradeProtocolErrorHeight(proto.getTradeProtocolErrorHeight()); // nullable processModel.setPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getPayoutTxSignature())); processModel.setTempTradePeerNodeAddress(proto.hasTempTradePeerNodeAddress() ? NodeAddress.fromProto(proto.getTempTradePeerNodeAddress()) : null); processModel.setMediatedPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMediatedPayoutTxSignature())); processModel.setMakerSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMakerSignature())); + processModel.setTradeFeeAddress(ProtoUtil.stringOrNullFromProto(proto.getTradeFeeAddress())); processModel.setMultisigAddress(ProtoUtil.stringOrNullFromProto(proto.getMultisigAddress())); String paymentSentMessageStateString = ProtoUtil.stringOrNullFromProto(proto.getPaymentSentMessageState()); MessageState paymentSentMessageState = ProtoUtil.enumFromProto(MessageState.class, paymentSentMessageStateString); processModel.setPaymentSentMessageState(paymentSentMessageState); - processModel.setPaymentSentMessage(proto.hasPaymentSentMessage() ? PaymentSentMessage.fromProto(proto.getPaymentSentMessage(), Version.getP2PMessageVersion()) : null); - processModel.setPaymentReceivedMessage(proto.hasPaymentReceivedMessage() ? PaymentReceivedMessage.fromProto(proto.getPaymentReceivedMessage(), Version.getP2PMessageVersion()) : null); - processModel.setDisputeClosedMessage(proto.hasDisputeClosedMessage() ? DisputeClosedMessage.fromProto(proto.getDisputeClosedMessage(), Version.getP2PMessageVersion()) : null); + String paymentSentMessageStateArbitratorString = ProtoUtil.stringOrNullFromProto(proto.getPaymentSentMessageStateArbitrator()); + MessageState paymentSentMessageStateArbitrator = ProtoUtil.enumFromProto(MessageState.class, paymentSentMessageStateArbitratorString); + processModel.setPaymentSentMessageStateArbitrator(paymentSentMessageStateArbitrator); + return processModel; } @@ -273,6 +281,13 @@ public class ProcessModel implements Model, PersistablePayload { setPaymentSentMessageState(messageState); } + void setPaymentSentAckMessageArbitrator(AckMessage ackMessage) { + MessageState messageState = ackMessage.isSuccess() ? + MessageState.ACKNOWLEDGED : + MessageState.FAILED; + setPaymentSentMessageStateArbitrator(messageState); + } + public void setPaymentSentMessageState(MessageState paymentSentMessageStateProperty) { this.paymentSentMessageStateProperty.set(paymentSentMessageStateProperty); if (tradeManager != null) { @@ -280,6 +295,13 @@ public class ProcessModel implements Model, PersistablePayload { } } + public void setPaymentSentMessageStateArbitrator(MessageState paymentSentMessageStateProperty) { + this.paymentSentMessageStatePropertyArbitrator.set(paymentSentMessageStateProperty); + if (tradeManager != null) { + tradeManager.requestPersistence(); + } + } + void setDepositTxSentAckMessage(AckMessage ackMessage) { MessageState messageState = ackMessage.isSuccess() ? MessageState.ACKNOWLEDGED : diff --git a/core/src/main/java/haveno/core/trade/protocol/ProcessModelServiceProvider.java b/core/src/main/java/haveno/core/trade/protocol/ProcessModelServiceProvider.java index ce5103a702..3447d803f2 100644 --- a/core/src/main/java/haveno/core/trade/protocol/ProcessModelServiceProvider.java +++ b/core/src/main/java/haveno/core/trade/protocol/ProcessModelServiceProvider.java @@ -17,6 +17,7 @@ package haveno.core.trade.protocol; +import com.google.inject.Inject; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.filter.FilterManager; @@ -33,8 +34,6 @@ import haveno.core.xmr.wallet.XmrWalletService; import haveno.network.p2p.P2PService; import lombok.Getter; -import javax.inject.Inject; - @Getter public class ProcessModelServiceProvider { private final OpenOfferManager openOfferManager; diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java index 6ebd8021aa..15d92ff785 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerAsMakerProtocol.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,12 +35,13 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.trade.SellerAsMakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.protocol.tasks.ApplyFilter; -import haveno.core.trade.protocol.tasks.MakerSendInitTradeRequest; +import haveno.core.trade.protocol.tasks.MakerSendInitTradeRequestToArbitrator; import haveno.core.trade.protocol.tasks.ProcessInitTradeRequest; import haveno.network.p2p.NodeAddress; import lombok.extern.slf4j.Slf4j; @@ -48,8 +66,8 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc NodeAddress peer, ErrorMessageHandler errorMessageHandler) { System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); - new Thread(() -> { - synchronized (trade) { + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; expect(phase(Trade.Phase.INIT) @@ -58,19 +76,19 @@ public class SellerAsMakerProtocol extends SellerProtocol implements MakerProtoc .setup(tasks( ApplyFilter.class, ProcessInitTradeRequest.class, - MakerSendInitTradeRequest.class) + MakerSendInitTradeRequestToArbitrator.class) .using(new TradeTaskRunner(trade, () -> { - startTimeout(TRADE_TIMEOUT); + startTimeout(); handleTaskRunnerSuccess(peer, message); }, errorMessage -> { handleTaskRunnerFault(peer, message, errorMessage); })) - .withTimeout(TRADE_TIMEOUT)) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) .executeTasks(true); awaitTradeLatch(); } - }).start(); + }, trade.getId()); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java index cb42c51bfa..2332ca2003 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerAsTakerProtocol.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,16 +35,20 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.trade.SellerAsTakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.handlers.TradeResultHandler; +import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.protocol.tasks.ApplyFilter; +import haveno.core.trade.protocol.tasks.ProcessInitTradeRequest; import haveno.core.trade.protocol.tasks.TakerReserveTradeFunds; import haveno.core.trade.protocol.tasks.TakerSendInitTradeRequestToArbitrator; +import haveno.core.trade.protocol.tasks.TakerSendInitTradeRequestToMaker; +import haveno.network.p2p.NodeAddress; import lombok.extern.slf4j.Slf4j; -// TODO (woodser): remove unused request handling @Slf4j public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtocol { @@ -47,37 +68,60 @@ public class SellerAsTakerProtocol extends SellerProtocol implements TakerProtoc @Override public void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { - System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); - new Thread(() -> { - synchronized (trade) { - latchTrade(); - this.tradeResultHandler = tradeResultHandler; - this.errorMessageHandler = errorMessageHandler; - expect(phase(Trade.Phase.INIT) - .with(TakerEvent.TAKE_OFFER) - .from(trade.getTradePeer().getNodeAddress())) - .setup(tasks( - ApplyFilter.class, - TakerReserveTradeFunds.class, - TakerSendInitTradeRequestToArbitrator.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - unlatchTrade(); - }, - errorMessage -> { - handleError(errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(true); - awaitTradeLatch(); - } - }).start(); + System.out.println(getClass().getSimpleName() + ".onTakeOffer()"); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + latchTrade(); + this.tradeResultHandler = tradeResultHandler; + this.errorMessageHandler = errorMessageHandler; + expect(phase(Trade.Phase.INIT) + .with(TakerEvent.TAKE_OFFER) + .from(trade.getTradePeer().getNodeAddress())) + .setup(tasks( + ApplyFilter.class, + TakerReserveTradeFunds.class, + TakerSendInitTradeRequestToMaker.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(); + unlatchTrade(); + }, + errorMessage -> { + handleError(errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); } @Override - protected void handleError(String errorMessage) { - trade.getXmrWalletService().resetAddressEntriesForOpenOffer(trade.getId()); - super.handleError(errorMessage); + public void handleInitTradeRequest(InitTradeRequest message, + NodeAddress peer) { + System.out.println(getClass().getCanonicalName() + ".handleInitTradeRequest()"); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + latchTrade(); + expect(phase(Trade.Phase.INIT) + .with(message) + .from(peer)) + .setup(tasks( + ApplyFilter.class, + ProcessInitTradeRequest.class, + TakerSendInitTradeRequestToArbitrator.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(); + handleTaskRunnerSuccess(peer, message); + }, + errorMessage -> { + handleTaskRunnerFault(peer, message, errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java index c6802aa3e6..4de8fa0d6a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/SellerProtocol.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,7 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.trade.SellerTrade; @@ -50,26 +68,30 @@ public class SellerProtocol extends DisputeProtocol { super.onInitialized(); // re-send payment received message if payout not published - synchronized (trade) { - if (trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal() && !trade.isPayoutPublished()) { - latchTrade(); - given(anyPhase(Trade.Phase.PAYMENT_RECEIVED) - .with(SellerEvent.STARTUP)) - .setup(tasks( - SellerSendPaymentReceivedMessageToBuyer.class, - SellerSendPaymentReceivedMessageToArbitrator.class) - .using(new TradeTaskRunner(trade, - () -> { - unlatchTrade(); - }, - (errorMessage) -> { - log.warn("Error sending PaymentReceivedMessage on startup: " + errorMessage); - unlatchTrade(); - }))) - .executeTasks(); - awaitTradeLatch(); + ThreadUtils.execute(() -> { + if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; + synchronized (trade.getLock()) { + if (trade.isShutDownStarted() || trade.isPayoutPublished()) return; + if (trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal() && !trade.isPayoutPublished()) { + latchTrade(); + given(anyPhase(Trade.Phase.PAYMENT_RECEIVED) + .with(SellerEvent.STARTUP)) + .setup(tasks( + SellerSendPaymentReceivedMessageToBuyer.class, + SellerSendPaymentReceivedMessageToArbitrator.class) + .using(new TradeTaskRunner(trade, + () -> { + unlatchTrade(); + }, + (errorMessage) -> { + log.warn("Error sending PaymentReceivedMessage on startup: " + errorMessage); + unlatchTrade(); + }))) + .executeTasks(); + awaitTradeLatch(); + } } - } + }, trade.getId()); } @Override @@ -94,8 +116,8 @@ public class SellerProtocol extends DisputeProtocol { public void onPaymentReceived(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { log.info("SellerProtocol.onPaymentReceived()"); - new Thread(() -> { - synchronized (trade) { + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { latchTrade(); this.errorMessageHandler = errorMessageHandler; SellerEvent event = SellerEvent.PAYMENT_RECEIVED; @@ -109,13 +131,16 @@ public class SellerProtocol extends DisputeProtocol { SellerSendPaymentReceivedMessageToBuyer.class, SellerSendPaymentReceivedMessageToArbitrator.class) .using(new TradeTaskRunner(trade, () -> { + stopTimeout(); this.errorMessageHandler = null; handleTaskRunnerSuccess(event); resultHandler.handleResult(); }, (errorMessage) -> { + log.warn("Error confirming payment received, reverting state to {}, error={}", Trade.State.BUYER_SENT_PAYMENT_SENT_MSG, errorMessage); + trade.setState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); handleTaskRunnerFault(event, errorMessage); }))) - .run(() -> trade.setState(Trade.State.SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT)) + .run(() -> trade.advanceState(Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT)) .executeTasks(true); } catch (Exception e) { errorMessageHandler.handleErrorMessage("Error confirming payment received: " + e.getMessage()); @@ -123,7 +148,7 @@ public class SellerProtocol extends DisputeProtocol { } awaitTradeLatch(); } - }).start(); + }, trade.getId()); } @SuppressWarnings("unchecked") diff --git a/core/src/main/java/haveno/core/trade/protocol/TakerProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TakerProtocol.java index 010890971a..ca863eb375 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TakerProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TakerProtocol.java @@ -1,27 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.trade.handlers.TradeResultHandler; +import haveno.core.trade.messages.InitTradeRequest; +import haveno.network.p2p.NodeAddress; public interface TakerProtocol extends TraderProtocol { void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler); + void handleInitTradeRequest(InitTradeRequest message, NodeAddress peer); enum TakerEvent implements FluentProtocol.Event { TAKE_OFFER diff --git a/core/src/main/java/haveno/core/trade/protocol/TradePeer.java b/core/src/main/java/haveno/core/trade/protocol/TradePeer.java index be8b1d8fe7..eeef2d4daf 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradePeer.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradePeer.java @@ -1,35 +1,39 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol; import com.google.protobuf.ByteString; import com.google.protobuf.Message; +import haveno.common.app.Version; import haveno.common.crypto.PubKeyRing; import haveno.common.proto.ProtoUtil; import haveno.common.proto.persistable.PersistablePayload; import haveno.core.account.witness.AccountAgeWitness; import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.proto.CoreProtoResolver; +import haveno.core.support.dispute.messages.DisputeClosedMessage; +import haveno.core.trade.messages.PaymentReceivedMessage; +import haveno.core.trade.messages.PaymentSentMessage; import haveno.network.p2p.NodeAddress; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import monero.daemon.model.MoneroTx; +import monero.wallet.model.MoneroTxWallet; import javax.annotation.Nullable; import java.math.BigInteger; @@ -52,7 +56,7 @@ public final class TradePeer implements PersistablePayload { @Setter @Nullable transient private byte[] preparedDepositTx; - transient private MoneroTx depositTx; + transient private MoneroTxWallet depositTx; // Persistable mutable @Nullable @@ -79,6 +83,19 @@ public final class TradePeer implements PersistablePayload { private String contractAsJson; @Nullable private byte[] contractSignature; + @Nullable + @Setter + @Getter + private PaymentSentMessage paymentSentMessage; + @Nullable + @Setter + @Getter + private PaymentReceivedMessage paymentReceivedMessage; + @Nullable + @Setter + @Getter + private DisputeClosedMessage disputeClosedMessage; + // added in v 0.6 @Nullable @@ -116,8 +133,14 @@ public final class TradePeer implements PersistablePayload { private String depositTxHex; @Nullable private String depositTxKey; + private long depositTxFee; private long securityDeposit; @Nullable + @Setter + private String unsignedPayoutTxHex; + private long payoutTxFee; + private long payoutAmount; + @Nullable private String updatedMultisigHex; @Getter @Setter @@ -126,6 +149,14 @@ public final class TradePeer implements PersistablePayload { public TradePeer() { } + public BigInteger getDepositTxFee() { + return BigInteger.valueOf(depositTxFee); + } + + public void setDepositTxFee(BigInteger depositTxFee) { + this.depositTxFee = depositTxFee.longValueExact(); + } + public BigInteger getSecurityDeposit() { return BigInteger.valueOf(securityDeposit); } @@ -134,6 +165,22 @@ public final class TradePeer implements PersistablePayload { this.securityDeposit = securityDeposit.longValueExact(); } + public BigInteger getPayoutTxFee() { + return BigInteger.valueOf(payoutTxFee); + } + + public void setPayoutTxFee(BigInteger payoutTxFee) { + this.payoutTxFee = payoutTxFee.longValueExact(); + } + + public BigInteger getPayoutAmount() { + return BigInteger.valueOf(payoutAmount); + } + + public void setPayoutAmount(BigInteger payoutAmount) { + this.payoutAmount = payoutAmount.longValueExact(); + } + @Override public Message toProtoMessage() { final protobuf.TradePeer.Builder builder = protobuf.TradePeer.newBuilder(); @@ -154,6 +201,9 @@ public final class TradePeer implements PersistablePayload { Optional.ofNullable(accountAgeWitnessSignature).ifPresent(e -> builder.setAccountAgeWitnessSignature(ByteString.copyFrom(e))); Optional.ofNullable(accountAgeWitness).ifPresent(e -> builder.setAccountAgeWitness(accountAgeWitness.toProtoAccountAgeWitness())); Optional.ofNullable(mediatedPayoutTxSignature).ifPresent(e -> builder.setMediatedPayoutTxSignature(ByteString.copyFrom(e))); + Optional.ofNullable(paymentSentMessage).ifPresent(e -> builder.setPaymentSentMessage(paymentSentMessage.toProtoNetworkEnvelope().getPaymentSentMessage())); + Optional.ofNullable(paymentReceivedMessage).ifPresent(e -> builder.setPaymentReceivedMessage(paymentReceivedMessage.toProtoNetworkEnvelope().getPaymentReceivedMessage())); + Optional.ofNullable(disputeClosedMessage).ifPresent(e -> builder.setDisputeClosedMessage(disputeClosedMessage.toProtoNetworkEnvelope().getDisputeClosedMessage())); Optional.ofNullable(reserveTxHash).ifPresent(e -> builder.setReserveTxHash(reserveTxHash)); Optional.ofNullable(reserveTxHex).ifPresent(e -> builder.setReserveTxHex(reserveTxHex)); Optional.ofNullable(reserveTxKey).ifPresent(e -> builder.setReserveTxKey(reserveTxKey)); @@ -161,11 +211,15 @@ public final class TradePeer implements PersistablePayload { Optional.ofNullable(preparedMultisigHex).ifPresent(e -> builder.setPreparedMultisigHex(preparedMultisigHex)); Optional.ofNullable(madeMultisigHex).ifPresent(e -> builder.setMadeMultisigHex(madeMultisigHex)); Optional.ofNullable(exchangedMultisigHex).ifPresent(e -> builder.setExchangedMultisigHex(exchangedMultisigHex)); + Optional.ofNullable(updatedMultisigHex).ifPresent(e -> builder.setUpdatedMultisigHex(updatedMultisigHex)); Optional.ofNullable(depositTxHash).ifPresent(e -> builder.setDepositTxHash(depositTxHash)); Optional.ofNullable(depositTxHex).ifPresent(e -> builder.setDepositTxHex(depositTxHex)); Optional.ofNullable(depositTxKey).ifPresent(e -> builder.setDepositTxKey(depositTxKey)); + Optional.ofNullable(depositTxFee).ifPresent(e -> builder.setDepositTxFee(depositTxFee)); Optional.ofNullable(securityDeposit).ifPresent(e -> builder.setSecurityDeposit(securityDeposit)); - Optional.ofNullable(updatedMultisigHex).ifPresent(e -> builder.setUpdatedMultisigHex(updatedMultisigHex)); + Optional.ofNullable(unsignedPayoutTxHex).ifPresent(e -> builder.setUnsignedPayoutTxHex(unsignedPayoutTxHex)); + Optional.ofNullable(payoutTxFee).ifPresent(e -> builder.setPayoutTxFee(payoutTxFee)); + Optional.ofNullable(payoutAmount).ifPresent(e -> builder.setPayoutAmount(payoutAmount)); builder.setDepositsConfirmedMessageAcked(depositsConfirmedMessageAcked); builder.setCurrentDate(currentDate); @@ -196,6 +250,9 @@ public final class TradePeer implements PersistablePayload { tradePeer.setAccountAgeWitness(protoAccountAgeWitness.getHash().isEmpty() ? null : AccountAgeWitness.fromProto(protoAccountAgeWitness)); tradePeer.setCurrentDate(proto.getCurrentDate()); tradePeer.setMediatedPayoutTxSignature(ProtoUtil.byteArrayOrNullFromProto(proto.getMediatedPayoutTxSignature())); + tradePeer.setPaymentSentMessage(proto.hasPaymentSentMessage() ? PaymentSentMessage.fromProto(proto.getPaymentSentMessage(), Version.getP2PMessageVersion()) : null); + tradePeer.setPaymentReceivedMessage(proto.hasPaymentReceivedMessage() ? PaymentReceivedMessage.fromProto(proto.getPaymentReceivedMessage(), Version.getP2PMessageVersion()) : null); + tradePeer.setDisputeClosedMessage(proto.hasDisputeClosedMessage() ? DisputeClosedMessage.fromProto(proto.getDisputeClosedMessage(), Version.getP2PMessageVersion()) : null); tradePeer.setReserveTxHash(ProtoUtil.stringOrNullFromProto(proto.getReserveTxHash())); tradePeer.setReserveTxHex(ProtoUtil.stringOrNullFromProto(proto.getReserveTxHex())); tradePeer.setReserveTxKey(ProtoUtil.stringOrNullFromProto(proto.getReserveTxKey())); @@ -203,12 +260,16 @@ public final class TradePeer implements PersistablePayload { tradePeer.setPreparedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getPreparedMultisigHex())); tradePeer.setMadeMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getMadeMultisigHex())); tradePeer.setExchangedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getExchangedMultisigHex())); + tradePeer.setUpdatedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex())); + tradePeer.setDepositsConfirmedMessageAcked(proto.getDepositsConfirmedMessageAcked()); tradePeer.setDepositTxHash(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHash())); tradePeer.setDepositTxHex(ProtoUtil.stringOrNullFromProto(proto.getDepositTxHex())); tradePeer.setDepositTxKey(ProtoUtil.stringOrNullFromProto(proto.getDepositTxKey())); + tradePeer.setDepositTxFee(BigInteger.valueOf(proto.getDepositTxFee())); tradePeer.setSecurityDeposit(BigInteger.valueOf(proto.getSecurityDeposit())); - tradePeer.setUpdatedMultisigHex(ProtoUtil.stringOrNullFromProto(proto.getUpdatedMultisigHex())); - tradePeer.setDepositsConfirmedMessageAcked(proto.getDepositsConfirmedMessageAcked()); + tradePeer.setUnsignedPayoutTxHex(ProtoUtil.stringOrNullFromProto(proto.getUnsignedPayoutTxHex())); + tradePeer.setPayoutTxFee(BigInteger.valueOf(proto.getPayoutTxFee())); + tradePeer.setPayoutAmount(BigInteger.valueOf(proto.getPayoutAmount())); return tradePeer; } } diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java index 77d6180a65..684dfb7c62 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocol.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,20 +34,21 @@ package haveno.core.trade.protocol; +import haveno.common.ThreadUtils; import haveno.common.Timer; import haveno.common.UserThread; +import haveno.common.config.Config; import haveno.common.crypto.PubKeyRing; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.proto.network.NetworkEnvelope; import haveno.common.taskrunner.Task; -import haveno.core.support.dispute.messages.DisputeClosedMessage; -import haveno.core.support.dispute.messages.DisputeOpenedMessage; import haveno.core.trade.ArbitratorTrade; import haveno.core.trade.BuyerTrade; import haveno.core.trade.HavenoUtils; import haveno.core.trade.SellerTrade; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; +import haveno.core.trade.TradeManager.MailboxMessageComparator; import haveno.core.trade.handlers.TradeResultHandler; import haveno.core.trade.messages.DepositRequest; import haveno.core.trade.messages.DepositResponse; @@ -50,9 +68,7 @@ import haveno.core.trade.protocol.tasks.ProcessInitMultisigRequest; import haveno.core.trade.protocol.tasks.ProcessPaymentReceivedMessage; import haveno.core.trade.protocol.tasks.ProcessPaymentSentMessage; import haveno.core.trade.protocol.tasks.ProcessSignContractRequest; -import haveno.core.trade.protocol.tasks.ProcessSignContractResponse; -import haveno.core.trade.protocol.tasks.RemoveOffer; -import haveno.core.trade.protocol.tasks.SellerPublishTradeStatistics; +import haveno.core.trade.protocol.tasks.SendDepositRequest; import haveno.core.trade.protocol.tasks.MaybeResendDisputeClosedMessageWithPayout; import haveno.core.trade.protocol.tasks.TradeTask; import haveno.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness; @@ -62,7 +78,6 @@ import haveno.network.p2p.AckMessageSourceType; import haveno.network.p2p.DecryptedDirectMessageListener; import haveno.network.p2p.DecryptedMessageWithPubKey; import haveno.network.p2p.NodeAddress; -import haveno.network.p2p.SendMailboxMessageListener; import haveno.network.p2p.mailbox.MailboxMessage; import haveno.network.p2p.mailbox.MailboxMessageService; import haveno.network.p2p.messaging.DecryptedMailboxListener; @@ -70,18 +85,17 @@ import lombok.extern.slf4j.Slf4j; import org.fxmisc.easybind.EasyBind; import javax.annotation.Nullable; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; -import java.util.List; import java.util.concurrent.CountDownLatch; @Slf4j public abstract class TradeProtocol implements DecryptedDirectMessageListener, DecryptedMailboxListener { - public static final int TRADE_TIMEOUT = 60; + public static final int TRADE_STEP_TIMEOUT_SECONDS = Config.baseCurrencyNetwork().isTestnet() ? 60 : 180; private static final String TIMEOUT_REACHED = "Timeout reached."; + public static final int MAX_ATTEMPTS = 5; // max attempts to create txs and other wallet functions + public static final long REPROCESS_DELAY_MS = 5000; protected final ProcessModel processModel; protected final Trade trade; @@ -91,6 +105,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D protected TradeResultHandler tradeResultHandler; protected ErrorMessageHandler errorMessageHandler; + private boolean depositsConfirmedTasksCalled; private int reprocessPaymentReceivedMessageCount; /////////////////////////////////////////////////////////////////////////////////////////// @@ -108,25 +123,23 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D /////////////////////////////////////////////////////////////////////////////////////////// protected void onTradeMessage(TradeMessage message, NodeAddress peerNodeAddress) { - log.info("Received {} as TradeMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid()); - handle(message, peerNodeAddress); + log.info("Received {} as TradeMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getOfferId(), message.getUid()); + ThreadUtils.execute(() -> handle(message, peerNodeAddress), trade.getId()); } protected void onMailboxMessage(TradeMessage message, NodeAddress peerNodeAddress) { - log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getTradeId(), message.getUid()); - handle(message, peerNodeAddress); + log.info("Received {} as MailboxMessage from {} with tradeId {} and uid {}", message.getClass().getSimpleName(), peerNodeAddress, message.getOfferId(), message.getUid()); + ThreadUtils.execute(() -> handle(message, peerNodeAddress), trade.getId()); } private void handle(TradeMessage message, NodeAddress peerNodeAddress) { - new Thread(() -> { - if (message instanceof DepositsConfirmedMessage) { - handle((DepositsConfirmedMessage) message, peerNodeAddress); - } else if (message instanceof PaymentSentMessage) { - handle((PaymentSentMessage) message, peerNodeAddress); - } else if (message instanceof PaymentReceivedMessage) { - handle((PaymentReceivedMessage) message, peerNodeAddress); - } - }).start(); + if (message instanceof DepositsConfirmedMessage) { + handle((DepositsConfirmedMessage) message, peerNodeAddress); + } else if (message instanceof PaymentSentMessage) { + handle((PaymentSentMessage) message, peerNodeAddress); + } else if (message instanceof PaymentReceivedMessage) { + handle((PaymentReceivedMessage) message, peerNodeAddress); + } } @Override @@ -136,7 +149,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D return; } - if (!isPubKeyValid(decryptedMessageWithPubKey, peer)) { + if (!isPubKeyValid(decryptedMessageWithPubKey)) { return; } @@ -145,7 +158,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // notify trade listeners // TODO (woodser): better way to register message notifications for trade? - if (((TradeMessage) networkEnvelope).getTradeId().equals(processModel.getOfferId())) { + if (((TradeMessage) networkEnvelope).getOfferId().equals(processModel.getOfferId())) { trade.onVerifiedTradeMessage((TradeMessage) networkEnvelope, peer); } } else if (networkEnvelope instanceof AckMessage) { @@ -156,7 +169,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D @Override public void onMailboxMessageAdded(DecryptedMessageWithPubKey decryptedMessageWithPubKey, NodeAddress peer) { - if (!isPubKeyValid(decryptedMessageWithPubKey, peer)) return; + if (!isPubKeyValid(decryptedMessageWithPubKey)) return; handleMailboxCollectionSkipValidation(Collections.singletonList(decryptedMessageWithPubKey)); } @@ -181,23 +194,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D .forEach(this::handleMailboxMessage); } - public static class MailboxMessageComparator implements Comparator<MailboxMessage> { - private static List<Class<? extends MailboxMessage>> messageOrder = Arrays.asList( - AckMessage.class, - DepositsConfirmedMessage.class, - PaymentSentMessage.class, - PaymentReceivedMessage.class, - DisputeOpenedMessage.class, - DisputeClosedMessage.class); - - @Override - public int compare(MailboxMessage m1, MailboxMessage m2) { - int idx1 = messageOrder.indexOf(m1.getClass()); - int idx2 = messageOrder.indexOf(m2.getClass()); - return idx1 - idx2; - } - } - private void handleMailboxMessage(MailboxMessage mailboxMessage) { if (mailboxMessage instanceof TradeMessage) { TradeMessage tradeMessage = (TradeMessage) mailboxMessage; @@ -247,264 +243,290 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D if (!trade.isCompleted()) processModel.getP2PService().addDecryptedDirectMessageListener(this); // initialize trade - trade.initialize(processModel.getProvider()); + synchronized (trade.getLock()) { + trade.initialize(processModel.getProvider()); - // process mailbox messages - MailboxMessageService mailboxMessageService = processModel.getP2PService().getMailboxMessageService(); - if (!trade.isCompleted()) mailboxMessageService.addDecryptedMailboxListener(this); - handleMailboxCollection(mailboxMessageService.getMyDecryptedMailboxMessages()); + // process mailbox messages + MailboxMessageService mailboxMessageService = processModel.getP2PService().getMailboxMessageService(); + if (!trade.isCompleted()) mailboxMessageService.addDecryptedMailboxListener(this); + handleMailboxCollection(mailboxMessageService.getMyDecryptedMailboxMessages()); + } // send deposits confirmed message if applicable - maybeSendDepositsConfirmedMessage(); + EasyBind.subscribe(trade.stateProperty(), state -> maybeSendDepositsConfirmedMessages()); } - private void maybeSendDepositsConfirmedMessage() { - if (trade.isDepositsConfirmed()) { - new Thread(() -> maybeSendDepositsConfirmedMessages()).start(); - } else { - EasyBind.subscribe(trade.stateProperty(), state -> { - if (trade.isDepositsConfirmed()) { - new Thread(() -> maybeSendDepositsConfirmedMessages()).start(); - } - }); - } + public void maybeSendDepositsConfirmedMessages() { + if (!trade.isInitialized() || trade.isShutDownStarted()) return; + ThreadUtils.execute(() -> { + if (!trade.isDepositsConfirmed() || trade.isDepositsConfirmedAcked() || trade.isPayoutPublished() || depositsConfirmedTasksCalled) return; + depositsConfirmedTasksCalled = true; + synchronized (trade.getLock()) { + if (!trade.isInitialized() || trade.isShutDownStarted()) return; // skip if shutting down + latchTrade(); + expect(new Condition(trade)) + .setup(tasks(getDepositsConfirmedTasks()) + .using(new TradeTaskRunner(trade, + () -> { + handleTaskRunnerSuccess(null, null, "maybeSendDepositsConfirmedMessages"); + }, + (errorMessage) -> { + handleTaskRunnerFault(null, null, "maybeSendDepositsConfirmedMessages", errorMessage); + }))) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); } public void maybeReprocessPaymentReceivedMessage(boolean reprocessOnError) { - synchronized (trade) { + if (trade.isShutDownStarted()) return; + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { - // skip if no need to reprocess - if (trade.isSeller() || trade.getProcessModel().getPaymentReceivedMessage() == null || trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal()) { - return; + // skip if no need to reprocess + if (trade.isSeller() || trade.getSeller().getPaymentReceivedMessage() == null || (trade.getState().ordinal() >= Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal() && trade.isPayoutPublished())) { + return; + } + + log.warn("Reprocessing payment received message for {} {}", trade.getClass().getSimpleName(), trade.getId()); + handle(trade.getSeller().getPaymentReceivedMessage(), trade.getSeller().getPaymentReceivedMessage().getSenderNodeAddress(), reprocessOnError); } - - log.warn("Reprocessing payment received message for {} {}", trade.getClass().getSimpleName(), trade.getId()); - new Thread(() -> handle(trade.getProcessModel().getPaymentReceivedMessage(), trade.getProcessModel().getPaymentReceivedMessage().getSenderNodeAddress(), reprocessOnError)).start(); - } + }, trade.getId()); } public void handleInitMultisigRequest(InitMultisigRequest request, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleInitMultisigRequest()"); - synchronized (trade) { + System.out.println(getClass().getSimpleName() + ".handleInitMultisigRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + trade.addInitProgressStep(); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { - // check trade - if (trade.hasFailed()) { - log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), request.getClass().getSimpleName(), sender, trade.getErrorMessage()); - return; + // check trade + if (trade.hasFailed()) { + log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), request.getClass().getSimpleName(), sender, trade.getErrorMessage()); + return; + } + Validator.checkTradeId(processModel.getOfferId(), request); + + // process message + latchTrade(); + processModel.setTradeMessage(request); + expect(anyPhase(Trade.Phase.INIT) + .with(request) + .from(sender)) + .setup(tasks( + ProcessInitMultisigRequest.class, + MaybeSendSignContractRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(); + handleTaskRunnerSuccess(sender, request); + }, + errorMessage -> { + handleTaskRunnerFault(sender, request, errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) + .executeTasks(true); + awaitTradeLatch(); } - Validator.checkTradeId(processModel.getOfferId(), request); - - // proocess message - latchTrade(); - processModel.setTradeMessage(request); - expect(anyPhase(Trade.Phase.INIT) - .with(request) - .from(sender)) - .setup(tasks( - ProcessInitMultisigRequest.class, - MaybeSendSignContractRequest.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - handleTaskRunnerSuccess(sender, request); - }, - errorMessage -> { - handleTaskRunnerFault(sender, request, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(true); - awaitTradeLatch(); - } + }, trade.getId()); } public void handleSignContractRequest(SignContractRequest message, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleSignContractRequest() " + trade.getId()); - synchronized (trade) { + System.out.println(getClass().getSimpleName() + ".handleSignContractRequest() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { - // check trade - if (trade.hasFailed()) { - log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), message.getClass().getSimpleName(), sender, trade.getErrorMessage()); - return; - } - Validator.checkTradeId(processModel.getOfferId(), message); - - // process message - if (trade.getState() == Trade.State.MULTISIG_COMPLETED || trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) { - latchTrade(); + // check trade + if (trade.hasFailed()) { + log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), message.getClass().getSimpleName(), sender, trade.getErrorMessage()); + return; + } Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(anyState(Trade.State.MULTISIG_COMPLETED, Trade.State.CONTRACT_SIGNATURE_REQUESTED) - .with(message) - .from(sender)) - .setup(tasks( - // TODO (woodser): validate request - ProcessSignContractRequest.class) - .using(new TradeTaskRunner(trade, - () -> { - startTimeout(TRADE_TIMEOUT); - handleTaskRunnerSuccess(sender, message); - }, - errorMessage -> { - handleTaskRunnerFault(sender, message, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) // extend timeout - .executeTasks(true); - awaitTradeLatch(); - } else { - // process sign contract request after multisig created - EasyBind.subscribe(trade.stateProperty(), state -> { - if (state == Trade.State.MULTISIG_COMPLETED) new Thread(() -> handleSignContractRequest(message, sender)).start(); // process notification without trade lock - }); + + // process message + if (trade.getState() == Trade.State.MULTISIG_COMPLETED || trade.getState() == Trade.State.CONTRACT_SIGNATURE_REQUESTED) { + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); + expect(anyState(Trade.State.MULTISIG_COMPLETED, Trade.State.CONTRACT_SIGNATURE_REQUESTED) + .with(message) + .from(sender)) + .setup(tasks( + // TODO (woodser): validate request + ProcessSignContractRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + handleTaskRunnerSuccess(sender, message); + }, + errorMessage -> { + handleTaskRunnerFault(sender, message, errorMessage); + }))) + .executeTasks(true); + awaitTradeLatch(); + } else { + + // process sign contract request after multisig created + EasyBind.subscribe(trade.stateProperty(), state -> { + if (state == Trade.State.MULTISIG_COMPLETED) ThreadUtils.execute(() -> handleSignContractRequest(message, sender), trade.getId()); // process notification without trade lock + }); + } } - } + }, trade.getId()); } public void handleSignContractResponse(SignContractResponse message, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleSignContractResponse() " + trade.getId()); - synchronized (trade) { + System.out.println(getClass().getSimpleName() + ".handleSignContractResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + trade.addInitProgressStep(); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { - // check trade - if (trade.hasFailed()) { - log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), message.getClass().getSimpleName(), sender, trade.getErrorMessage()); - return; - } - Validator.checkTradeId(processModel.getOfferId(), message); - - // process message - if (trade.getState() == Trade.State.CONTRACT_SIGNED) { - latchTrade(); + // check trade + if (trade.hasFailed()) { + log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), message.getClass().getSimpleName(), sender, trade.getErrorMessage()); + return; + } Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(state(Trade.State.CONTRACT_SIGNED) + + // process message + if (trade.getState() == Trade.State.CONTRACT_SIGNED) { + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); + expect(state(Trade.State.CONTRACT_SIGNED) + .with(message) + .from(sender)) + .setup(tasks( + // TODO (woodser): validate request + SendDepositRequest.class) + .using(new TradeTaskRunner(trade, + () -> { + startTimeout(); + handleTaskRunnerSuccess(sender, message); + }, + errorMessage -> { + handleTaskRunnerFault(sender, message, errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) // extend timeout + .executeTasks(true); + awaitTradeLatch(); + } else { + + // process sign contract response after contract signed + EasyBind.subscribe(trade.stateProperty(), state -> { + if (state == Trade.State.CONTRACT_SIGNED) ThreadUtils.execute(() -> handleSignContractResponse(message, sender), trade.getId()); // process notification without trade lock + }); + } + } + }, trade.getId()); + } + + public void handleDepositResponse(DepositResponse response, NodeAddress sender) { + System.out.println(getClass().getSimpleName() + ".handleDepositResponse() for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + trade.addInitProgressStep(); + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + Validator.checkTradeId(processModel.getOfferId(), response); + latchTrade(); + processModel.setTradeMessage(response); + expect(anyPhase(Trade.Phase.INIT, Trade.Phase.DEPOSIT_REQUESTED, Trade.Phase.DEPOSITS_PUBLISHED) + .with(response) + .from(sender)) + .setup(tasks( + ProcessDepositResponse.class) + .using(new TradeTaskRunner(trade, + () -> { + stopTimeout(); + this.errorMessageHandler = null; // TODO: set this when trade state is >= DEPOSIT_PUBLISHED + handleTaskRunnerSuccess(sender, response); + if (tradeResultHandler != null) tradeResultHandler.handleResult(trade); // trade is initialized + }, + errorMessage -> { + handleTaskRunnerFault(sender, response, errorMessage); + })) + .withTimeout(TRADE_STEP_TIMEOUT_SECONDS)) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); + } + + public void handle(DepositsConfirmedMessage message, NodeAddress sender) { + System.out.println(getClass().getSimpleName() + ".handle(DepositsConfirmedMessage) from " + sender + " for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + if (!trade.isInitialized() || trade.isShutDown()) return; + ThreadUtils.execute(() -> { + synchronized (trade.getLock()) { + if (!trade.isInitialized() || trade.isShutDown()) return; + latchTrade(); + this.errorMessageHandler = null; + expect(new Condition(trade) .with(message) .from(sender)) .setup(tasks( - // TODO (woodser): validate request - ProcessSignContractResponse.class) + ProcessDepositsConfirmedMessage.class, + VerifyPeersAccountAgeWitness.class, + MaybeResendDisputeClosedMessageWithPayout.class) .using(new TradeTaskRunner(trade, () -> { - startTimeout(TRADE_TIMEOUT); handleTaskRunnerSuccess(sender, message); }, errorMessage -> { handleTaskRunnerFault(sender, message, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) // extend timeout - .executeTasks(true); + }))) + .executeTasks(); awaitTradeLatch(); - } else { - // process sign contract response after contract signed - EasyBind.subscribe(trade.stateProperty(), state -> { - if (state == Trade.State.CONTRACT_SIGNED) new Thread(() -> handleSignContractResponse(message, sender)).start(); // process notification without trade lock - }); } - } - } - - public void handleDepositResponse(DepositResponse response, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handleDepositResponse()"); - synchronized (trade) { - - // check trade - if (trade.hasFailed()) { - log.warn("{} {} ignoring {} from {} because trade failed with previous error: {}", trade.getClass().getSimpleName(), trade.getId(), response.getClass().getSimpleName(), sender, trade.getErrorMessage()); - return; - } - Validator.checkTradeId(processModel.getOfferId(), response); - - // process message - latchTrade(); - processModel.setTradeMessage(response); - expect(anyState(Trade.State.SENT_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST, Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS, Trade.State.DEPOSIT_TXS_SEEN_IN_NETWORK) - .with(response) - .from(sender)) - .setup(tasks( - ProcessDepositResponse.class, - RemoveOffer.class, - SellerPublishTradeStatistics.class) - .using(new TradeTaskRunner(trade, - () -> { - stopTimeout(); - this.errorMessageHandler = null; - handleTaskRunnerSuccess(sender, response); - if (tradeResultHandler != null) tradeResultHandler.handleResult(trade); // trade is initialized - }, - errorMessage -> { - handleTaskRunnerFault(sender, response, errorMessage); - })) - .withTimeout(TRADE_TIMEOUT)) - .executeTasks(true); - awaitTradeLatch(); - } - } - - public void handle(DepositsConfirmedMessage response, NodeAddress sender) { - System.out.println(getClass().getSimpleName() + ".handle(DepositsConfirmedMessage)"); - synchronized (trade) { - latchTrade(); - expect(new Condition(trade) - .with(response) - .from(sender)) - .setup(tasks( - ProcessDepositsConfirmedMessage.class, - VerifyPeersAccountAgeWitness.class, - MaybeResendDisputeClosedMessageWithPayout.class) - .using(new TradeTaskRunner(trade, - () -> { - handleTaskRunnerSuccess(sender, response); - }, - errorMessage -> { - handleTaskRunnerFault(sender, response, errorMessage); - }))) - .executeTasks(); - awaitTradeLatch(); - } + }, trade.getId()); } // received by seller and arbitrator protected void handle(PaymentSentMessage message, NodeAddress peer) { - System.out.println(getClass().getSimpleName() + ".handle(PaymentSentMessage)"); + System.out.println(getClass().getSimpleName() + ".handle(PaymentSentMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + if (!trade.isInitialized() || trade.isShutDown()) return; if (!(trade instanceof SellerTrade || trade instanceof ArbitratorTrade)) { log.warn("Ignoring PaymentSentMessage since not seller or arbitrator"); return; } - // We are more tolerant with expected phase and allow also DEPOSITS_PUBLISHED as it can be the case - // that the wallet is still syncing and so the DEPOSITS_CONFIRMED state to yet triggered when we received - // a mailbox message with PaymentSentMessage. - // TODO A better fix would be to add a listener for the wallet sync state and process - // the mailbox msg once wallet is ready and trade state set. - synchronized (trade) { - if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_SENT.ordinal()) { - log.warn("Received another PaymentSentMessage which was already processed, ACKing"); - handleTaskRunnerSuccess(peer, message); - return; + ThreadUtils.execute(() -> { + // We are more tolerant with expected phase and allow also DEPOSITS_PUBLISHED as it can be the case + // that the wallet is still syncing and so the DEPOSITS_CONFIRMED state to yet triggered when we received + // a mailbox message with PaymentSentMessage. + // TODO A better fix would be to add a listener for the wallet sync state and process + // the mailbox msg once wallet is ready and trade state set. + synchronized (trade.getLock()) { + if (!trade.isInitialized() || trade.isShutDown()) return; + if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_SENT.ordinal()) { + log.warn("Received another PaymentSentMessage which was already processed for {} {}, ACKing", trade.getClass().getSimpleName(), trade.getId()); + handleTaskRunnerSuccess(peer, message); + return; + } + if (trade.getPayoutTx() != null) { + log.warn("We received a PaymentSentMessage but we have already created the payout tx " + + "so we ignore the message. This can happen if the ACK message to the peer did not " + + "arrive and the peer repeats sending us the message. We send another ACK msg."); + sendAckMessage(peer, message, true, null); + removeMailboxMessageAfterProcessing(message); + return; + } + latchTrade(); + expect(anyPhase(Trade.Phase.DEPOSITS_CONFIRMED, Trade.Phase.DEPOSITS_UNLOCKED) + .with(message) + .from(peer)) + .setup(tasks( + ApplyFilter.class, + ProcessPaymentSentMessage.class, + VerifyPeersAccountAgeWitness.class) + .using(new TradeTaskRunner(trade, + () -> { + handleTaskRunnerSuccess(peer, message); + }, + (errorMessage) -> { + handleTaskRunnerFault(peer, message, errorMessage); + }))) + .executeTasks(true); + awaitTradeLatch(); } - latchTrade(); - expect(anyPhase(Trade.Phase.DEPOSITS_CONFIRMED, Trade.Phase.DEPOSITS_UNLOCKED) - .with(message) - .from(peer) - .preCondition(trade.getPayoutTx() == null, - () -> { - log.warn("We received a PaymentSentMessage but we have already created the payout tx " + - "so we ignore the message. This can happen if the ACK message to the peer did not " + - "arrive and the peer repeats sending us the message. We send another ACK msg."); - sendAckMessage(peer, message, true, null); - removeMailboxMessageAfterProcessing(message); - })) - .setup(tasks( - ApplyFilter.class, - ProcessPaymentSentMessage.class, - VerifyPeersAccountAgeWitness.class) - .using(new TradeTaskRunner(trade, - () -> { - handleTaskRunnerSuccess(peer, message); - }, - (errorMessage) -> { - handleTaskRunnerFault(peer, message, errorMessage); - }))) - .executeTasks(true); - awaitTradeLatch(); - } + }, trade.getId()); } // received by buyer and arbitrator @@ -513,50 +535,61 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } private void handle(PaymentReceivedMessage message, NodeAddress peer, boolean reprocessOnError) { - System.out.println(getClass().getSimpleName() + ".handle(PaymentReceivedMessage)"); - if (!(trade instanceof BuyerTrade || trade instanceof ArbitratorTrade)) { - log.warn("Ignoring PaymentReceivedMessage since not buyer or arbitrator"); - return; - } - synchronized (trade) { - if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_RECEIVED.ordinal()) { - log.warn("Received another PaymentReceivedMessage which was already processed, ACKing"); - handleTaskRunnerSuccess(peer, message); + System.out.println(getClass().getSimpleName() + ".handle(PaymentReceivedMessage) for " + trade.getClass().getSimpleName() + " " + trade.getShortId()); + if (!trade.isInitialized() || trade.isShutDown()) return; + ThreadUtils.execute(() -> { + if (!(trade instanceof BuyerTrade || trade instanceof ArbitratorTrade)) { + log.warn("Ignoring PaymentReceivedMessage since not buyer or arbitrator"); return; } - latchTrade(); - Validator.checkTradeId(processModel.getOfferId(), message); - processModel.setTradeMessage(message); - expect(anyPhase( - trade.isBuyer() ? new Trade.Phase[] {Trade.Phase.PAYMENT_SENT, Trade.Phase.PAYMENT_RECEIVED} : - trade.isArbitrator() ? new Trade.Phase[] {Trade.Phase.DEPOSITS_CONFIRMED, Trade.Phase.DEPOSITS_UNLOCKED, Trade.Phase.PAYMENT_SENT} : // arbitrator syncs slowly after deposits confirmed - new Trade.Phase[] {Trade.Phase.DEPOSITS_UNLOCKED, Trade.Phase.PAYMENT_SENT}) - .with(message) - .from(peer)) - .setup(tasks( - ProcessPaymentReceivedMessage.class) - .using(new TradeTaskRunner(trade, - () -> { - handleTaskRunnerSuccess(peer, message); - }, - errorMessage -> { - log.warn("Error processing payment received message: " + errorMessage); - processModel.getTradeManager().requestPersistence(); + synchronized (trade.getLock()) { + if (!trade.isInitialized() || trade.isShutDown()) return; + latchTrade(); + Validator.checkTradeId(processModel.getOfferId(), message); + processModel.setTradeMessage(message); - // schedule to reprocess message unless deleted - if (trade.getProcessModel().getPaymentReceivedMessage() != null) { - UserThread.runAfter(() -> { - reprocessPaymentReceivedMessageCount++; - maybeReprocessPaymentReceivedMessage(reprocessOnError); - }, trade.getReprocessDelayInSeconds(reprocessPaymentReceivedMessageCount)); - } else { - handleTaskRunnerFault(peer, message, errorMessage); // otherwise send nack - } - unlatchTrade(); - }))) - .executeTasks(true); - awaitTradeLatch(); - } + // check minimum trade phase + if (trade.isBuyer() && trade.getPhase().ordinal() < Trade.Phase.PAYMENT_SENT.ordinal()) { + log.warn("Received PaymentReceivedMessage before payment sent for {} {}, ignoring", trade.getClass().getSimpleName(), trade.getId()); + return; + } + if (trade.isArbitrator() && trade.getPhase().ordinal() < Trade.Phase.DEPOSITS_CONFIRMED.ordinal()) { + log.warn("Received PaymentReceivedMessage before deposits confirmed for {} {}, ignoring", trade.getClass().getSimpleName(), trade.getId()); + return; + } + if (trade.isSeller() && trade.getPhase().ordinal() < Trade.Phase.DEPOSITS_UNLOCKED.ordinal()) { + log.warn("Received PaymentReceivedMessage before deposits unlocked for {} {}, ignoring", trade.getClass().getSimpleName(), trade.getId()); + return; + } + + expect(anyPhase() + .with(message) + .from(peer)) + .setup(tasks( + ProcessPaymentReceivedMessage.class) + .using(new TradeTaskRunner(trade, + () -> { + handleTaskRunnerSuccess(peer, message); + }, + errorMessage -> { + log.warn("Error processing payment received message: " + errorMessage); + processModel.getTradeManager().requestPersistence(); + + // schedule to reprocess message unless deleted + if (trade.getSeller().getPaymentReceivedMessage() != null) { + UserThread.runAfter(() -> { + reprocessPaymentReceivedMessageCount++; + maybeReprocessPaymentReceivedMessage(reprocessOnError); + }, trade.getReprocessDelayInSeconds(reprocessPaymentReceivedMessageCount)); + } else { + handleTaskRunnerFault(peer, message, errorMessage); // otherwise send nack + } + unlatchTrade(); + }))) + .executeTasks(true); + awaitTradeLatch(); + } + }, trade.getId()); } public void onWithdrawCompleted() { @@ -614,32 +647,41 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D // ACK msg /////////////////////////////////////////////////////////////////////////////////////////// - private void onAckMessage(AckMessage ackMessage, NodeAddress peer) { + private void onAckMessage(AckMessage ackMessage, NodeAddress sender) { // handle ack for PaymentSentMessage, which automatically re-sends if not ACKed in a certain time if (ackMessage.getSourceMsgClassName().equals(PaymentSentMessage.class.getSimpleName())) { - if (trade.getTradePeer(peer) == trade.getSeller()) { + if (trade.getTradePeer(sender) == trade.getSeller()) { processModel.setPaymentSentAckMessage(ackMessage); + trade.setStateIfValidTransitionTo(Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG); + processModel.getTradeManager().requestPersistence(); + } else if (trade.getTradePeer(sender) == trade.getArbitrator()) { + processModel.setPaymentSentAckMessageArbitrator(ackMessage); } else if (!ackMessage.isSuccess()) { - String err = "Received AckMessage with error state for " + ackMessage.getSourceMsgClassName() + " from "+ peer + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage(); + String err = "Received AckMessage with error state for " + ackMessage.getSourceMsgClassName() + " from "+ sender + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage(); log.warn(err); return; // log error and ignore nack if not seller } } if (ackMessage.isSuccess()) { - log.info("Received AckMessage for {} from {} with tradeId {} and uid {}", - ackMessage.getSourceMsgClassName(), peer, trade.getId(), ackMessage.getSourceUid()); + log.info("Received AckMessage for {}, sender={}, trade={} {}, messageUid={}", ackMessage.getSourceMsgClassName(), sender, trade.getClass().getSimpleName(), trade.getId(), ackMessage.getSourceUid()); // handle ack for DepositsConfirmedMessage, which automatically re-sends if not ACKed in a certain time if (ackMessage.getSourceMsgClassName().equals(DepositsConfirmedMessage.class.getSimpleName())) { - if (trade.getTradePeer(peer) != null) { - trade.getTradePeer(peer).setDepositsConfirmedMessageAcked(true); + TradePeer peer = trade.getTradePeer(sender); + if (peer == null) { + + // get the applicable peer based on the sourceUid + if (ackMessage.getSourceUid().equals(HavenoUtils.getDeterministicId(trade, DepositsConfirmedMessage.class, trade.getArbitrator().getNodeAddress()))) peer = trade.getArbitrator(); + else if (ackMessage.getSourceUid().equals(HavenoUtils.getDeterministicId(trade, DepositsConfirmedMessage.class, trade.getMaker().getNodeAddress()))) peer = trade.getMaker(); + else if (ackMessage.getSourceUid().equals(HavenoUtils.getDeterministicId(trade, DepositsConfirmedMessage.class, trade.getTaker().getNodeAddress()))) peer = trade.getTaker(); } + if (peer == null) log.warn("Received AckMesage for DepositsConfirmedMessage for unknown peer: " + sender); + else peer.setDepositsConfirmedMessageAcked(true); } } else { - String err = "Received AckMessage with error state for " + ackMessage.getSourceMsgClassName() + " from "+ peer + " with tradeId " + trade.getId() + " and errorMessage=" + ackMessage.getErrorMessage(); - log.warn(err); + log.warn("Received AckMessage with error state for {}, sender={}, trade={} {}, messageUid={}, errorMessage={}", ackMessage.getSourceMsgClassName(), sender, trade.getClass().getSimpleName(), trade.getId(), ackMessage.getSourceUid(), ackMessage.getErrorMessage()); // set trade state on deposit request nack if (ackMessage.getSourceMsgClassName().equals(DepositRequest.class.getSimpleName())) { @@ -647,7 +689,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D processModel.getTradeManager().requestPersistence(); } - handleError(err); + handleError(ackMessage.getErrorMessage()); } } @@ -660,49 +702,20 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D return; } - String tradeId = message.getTradeId(); - String sourceUid = message.getUid(); - AckMessage ackMessage = new AckMessage(processModel.getMyNodeAddress(), - AckMessageSourceType.TRADE_MESSAGE, - message.getClass().getSimpleName(), - sourceUid, - tradeId, - result, - errorMessage); - - log.info("Send AckMessage for {} to peer {}. tradeId={}, sourceUid={}", - ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid); - processModel.getP2PService().getMailboxMessageService().sendEncryptedMailboxMessage( - peer, - peersPubKeyRing, - ackMessage, - new SendMailboxMessageListener() { - @Override - public void onArrived() { - log.info("AckMessage for {} arrived at peer {}. tradeId={}, sourceUid={}", - ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid); - } - - @Override - public void onStoredInMailbox() { - log.info("AckMessage for {} stored in mailbox for peer {}. tradeId={}, sourceUid={}", - ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid); - } - - @Override - public void onFault(String errorMessage) { - log.error("AckMessage for {} failed. Peer {}. tradeId={}, sourceUid={}, errorMessage={}", - ackMessage.getSourceMsgClassName(), peer, tradeId, sourceUid, errorMessage); - } - } - ); + // send ack message + processModel.getTradeManager().sendAckMessage(peer, peersPubKeyRing, message, result, errorMessage); } + /////////////////////////////////////////////////////////////////////////////////////////// // Timeout /////////////////////////////////////////////////////////////////////////////////////////// - protected synchronized void startTimeout(long timeoutSec) { + public synchronized void startTimeout() { + startTimeout(TradeProtocol.TRADE_STEP_TIMEOUT_SECONDS); + } + + public synchronized void startTimeout(long timeoutSec) { synchronized (timeoutTimerLock) { stopTimeout(); timeoutTimer = UserThread.runAfter(() -> { @@ -753,19 +766,13 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D trade.setMyNodeAddress(); // TODO: this is a hack to update my node address before verifying the message TradePeer peer = trade.getTradePeer(address); if (peer == null) { - log.warn("Cannot get peer's pub key ring because peer is not maker, taker, or arbitrator. Their address might have changed: " + peer); + log.warn("Cannot get peer's pub key ring because peer is not maker, taker, or arbitrator. Their address might have changed: " + address); return null; } return peer.getPubKeyRing(); } - private boolean isPubKeyValid(DecryptedMessageWithPubKey message) { - MailboxMessage mailboxMessage = (MailboxMessage) message.getNetworkEnvelope(); - NodeAddress sender = mailboxMessage.getSenderNodeAddress(); - return isPubKeyValid(message, sender); - } - - private boolean isPubKeyValid(DecryptedMessageWithPubKey message, NodeAddress sender) { + public boolean isPubKeyValid(DecryptedMessageWithPubKey message) { if (this instanceof ArbitratorProtocol) { // valid if traders unknown @@ -789,7 +796,6 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } // invalid - log.error("SignaturePubKey in message does not match the SignaturePubKey we have set for our arbitrator or trading peer."); return false; } @@ -811,7 +817,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D } void handleTaskRunnerFault(NodeAddress ackReceiver, @Nullable TradeMessage message, String source, String errorMessage) { - log.error("Task runner failed with error {}. Triggered from {}. Monerod={}" , errorMessage, source, trade.getXmrWalletService().getConnectionsService().getConnection()); + log.error("Task runner failed with error {}. Triggered from {}. Monerod={}" , errorMessage, source, trade.getXmrWalletService().getXmrConnectionService().getConnection()); if (message != null) { sendAckMessage(ackReceiver, message, false, errorMessage); @@ -828,10 +834,12 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D trade.setErrorMessage(errorMessage); processModel.getTradeManager().requestPersistence(); if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage(errorMessage); + errorMessageHandler = null; unlatchTrade(); } protected void latchTrade() { + trade.awaitInitialized(); if (tradeLatch != null) throw new RuntimeException("Trade latch is not null. That should never happen."); if (trade.isShutDown()) throw new RuntimeException("Cannot latch trade " + trade.getId() + " for protocol because it's shut down"); tradeLatch = new CountDownLatch(1); @@ -851,7 +859,7 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D private boolean isMyMessage(NetworkEnvelope message) { if (message instanceof TradeMessage) { TradeMessage tradeMessage = (TradeMessage) message; - return tradeMessage.getTradeId().equals(trade.getId()); + return tradeMessage.getOfferId().equals(trade.getId()); } else if (message instanceof AckMessage) { AckMessage ackMessage = (AckMessage) message; return ackMessage.getSourceType() == AckMessageSourceType.TRADE_MESSAGE && ackMessage.getSourceId().equals(trade.getId()); @@ -859,23 +867,4 @@ public abstract class TradeProtocol implements DecryptedDirectMessageListener, D return false; } } - - public void maybeSendDepositsConfirmedMessages() { - synchronized (trade) { - if (trade.isDepositsConfirmedAcked()) return; - if (!trade.isInitialized() || trade.isShutDownStarted()) return; // skip if shutting down - latchTrade(); - expect(new Condition(trade)) - .setup(tasks(getDepositsConfirmedTasks()) - .using(new TradeTaskRunner(trade, - () -> { - handleTaskRunnerSuccess(null, null, "maybeSendDepositsConfirmedMessages"); - }, - (errorMessage) -> { - handleTaskRunnerFault(null, null, "maybeSendDepositsConfirmedMessages", errorMessage); - }))) - .executeTasks(true); - awaitTradeLatch(); - } - } } diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeProtocolFactory.java b/core/src/main/java/haveno/core/trade/protocol/TradeProtocolFactory.java index 642ea33b3e..ef8a0ab44d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeProtocolFactory.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeProtocolFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol; diff --git a/core/src/main/java/haveno/core/trade/protocol/TradeTaskRunner.java b/core/src/main/java/haveno/core/trade/protocol/TradeTaskRunner.java index 55903e63cd..695e3a6521 100644 --- a/core/src/main/java/haveno/core/trade/protocol/TradeTaskRunner.java +++ b/core/src/main/java/haveno/core/trade/protocol/TradeTaskRunner.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java index bdf21b2ac3..686f17f361 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ApplyFilter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks; @@ -53,7 +53,7 @@ public class ApplyFilter extends TradeTask { "Payment method=" + trade.getOffer().getPaymentMethod().getId()); } else if (filterManager.requireUpdateToNewVersionForTrading()) { failed("Your version of Haveno is not compatible for trading anymore. " + - "Please update to the latest Haveno version at https://haveno.exchange/downloads."); + "Please update to the latest Haveno version."); } else { complete(); } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java index 2235397eb6..5bd7ab9d80 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessDepositRequest.java @@ -22,7 +22,6 @@ import common.utils.JsonUtils; import haveno.common.app.Version; import haveno.common.crypto.PubKeyRing; import haveno.common.taskrunner.TaskRunner; -import haveno.common.util.Tuple2; import haveno.core.offer.Offer; import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; @@ -37,14 +36,16 @@ import monero.daemon.model.MoneroSubmitTxResult; import monero.daemon.model.MoneroTx; import java.math.BigInteger; -import java.util.Arrays; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.UUID; @Slf4j public class ArbitratorProcessDepositRequest extends TradeTask { - private boolean depositTxsRelayed = false; + private Throwable error; + private boolean depositResponsesSent; @SuppressWarnings({"unused"}) public ArbitratorProcessDepositRequest(TaskRunner taskHandler, Trade trade) { @@ -53,133 +54,193 @@ public class ArbitratorProcessDepositRequest extends TradeTask { @Override protected void run() { - MoneroDaemon daemon = trade.getXmrWalletService().getDaemon(); try { runInterceptHook(); - // get contract and signature - String contractAsJson = trade.getContractAsJson(); - DepositRequest request = (DepositRequest) processModel.getTradeMessage(); // TODO (woodser): verify response - byte[] signature = request.getContractSignature(); + // check if trade is failed + if (trade.getState() == Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED) throw new RuntimeException("Cannot process deposit request because trade is already failed, tradeId=" + trade.getId()); - // get trader info - TradePeer trader = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); - if (trader == null) throw new RuntimeException(request.getClass().getSimpleName() + " is not from maker, taker, or arbitrator"); - PubKeyRing peerPubKeyRing = trader.getPubKeyRing(); + // update trade state + trade.setStateIfValidTransitionTo(Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST); + processModel.getTradeManager().requestPersistence(); - // verify signature - if (!HavenoUtils.isSignatureValid(peerPubKeyRing, contractAsJson, signature)) { - throw new RuntimeException("Peer's contract signature is invalid"); - } + // process request + processDepositRequest(); + complete(); + } catch (Throwable t) { + this.error = t; + log.error("Error processing deposit request for trade {}: {}\n", trade.getId(), t.getMessage(), t); + trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED); + failed(t); + } + processModel.getTradeManager().requestPersistence(); + } - // set peer's signature - trader.setContractSignature(signature); + private void processDepositRequest() { - // collect expected values - Offer offer = trade.getOffer(); - boolean isFromTaker = trader == trade.getTaker(); - boolean isFromBuyer = trader == trade.getBuyer(); - BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee(); - BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount(); - BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); - String depositAddress = processModel.getMultisigAddress(); + // get contract and signature + String contractAsJson = trade.getContractAsJson(); + DepositRequest request = (DepositRequest) processModel.getTradeMessage(); // TODO (woodser): verify response + byte[] signature = request.getContractSignature(); - // verify deposit tx - Tuple2<MoneroTx, BigInteger> txResult; + // get trader info + TradePeer sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + if (sender == null) throw new RuntimeException(request.getClass().getSimpleName() + " is not from maker, taker, or arbitrator"); + PubKeyRing senderPubKeyRing = sender.getPubKeyRing(); + + // verify signature + if (!HavenoUtils.isSignatureValid(senderPubKeyRing, contractAsJson, signature)) { + throw new RuntimeException("Peer's contract signature is invalid"); + } + + // set peer's signature + sender.setContractSignature(signature); + + // collect expected values + Offer offer = trade.getOffer(); + boolean isFromTaker = sender == trade.getTaker(); + boolean isFromBuyer = sender == trade.getBuyer(); + BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee(); + BigInteger sendTradeAmount = isFromBuyer ? BigInteger.ZERO : trade.getAmount(); + BigInteger securityDeposit = isFromBuyer ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee(); + String depositAddress = processModel.getMultisigAddress(); + sender.setSecurityDeposit(securityDeposit); + + // verify deposit tx + boolean isFromBuyerAsTakerWithoutDeposit = isFromBuyer && isFromTaker && trade.hasBuyerAsTakerWithoutDeposit(); + if (!isFromBuyerAsTakerWithoutDeposit) { + MoneroTx verifiedTx; try { - txResult = trade.getXmrWalletService().verifyTradeTx( - offer.getId(), - tradeFee, - sendAmount, - securityDeposit, - depositAddress, - trader.getDepositTxHash(), - request.getDepositTxHex(), - request.getDepositTxKey(), - null); + verifiedTx = trade.getXmrWalletService().verifyDepositTx( + offer.getId(), + tradeFee, + trade.getProcessModel().getTradeFeeAddress(), + sendTradeAmount, + securityDeposit, + depositAddress, + sender.getDepositTxHash(), + request.getDepositTxHex(), + request.getDepositTxKey(), + null); } catch (Exception e) { - throw new RuntimeException("Error processing deposit tx from " + (isFromTaker ? "taker " : "maker ") + trader.getNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage()); + throw new RuntimeException("Error processing deposit tx from " + (isFromTaker ? "taker " : "maker ") + sender.getNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage()); } + + // update trade state + sender.setSecurityDeposit(sender.getSecurityDeposit().subtract(verifiedTx.getFee())); // subtract mining fee from security deposit + sender.setDepositTxFee(verifiedTx.getFee()); + sender.setDepositTxHex(request.getDepositTxHex()); + sender.setDepositTxKey(request.getDepositTxKey()); + } - // set deposit info - trader.setSecurityDeposit(txResult.second); - trader.setDepositTxHex(request.getDepositTxHex()); - trader.setDepositTxKey(request.getDepositTxKey()); - if (request.getPaymentAccountKey() != null) trader.setPaymentAccountKey(request.getPaymentAccountKey()); + // update trade state + if (request.getPaymentAccountKey() != null) sender.setPaymentAccountKey(request.getPaymentAccountKey()); + processModel.getTradeManager().requestPersistence(); - // relay deposit txs when both available - // TODO (woodser): add small delay so tx has head start against double spend attempts? - if (processModel.getMaker().getDepositTxHex() != null && processModel.getTaker().getDepositTxHex() != null) { + // relay deposit txs when both requests received + MoneroDaemon daemon = trade.getXmrWalletService().getDaemon(); + if (processModel.getMaker().getContractSignature() != null && processModel.getTaker().getContractSignature() != null) { + + // check timeout and extend just before relaying + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out before relaying deposit txs for {} {}" + trade.getClass().getSimpleName() + " " + trade.getShortId()); + trade.addInitProgressStep(); + + // relay deposit txs + boolean depositTxsRelayed = false; + List<String> txHashes = new ArrayList<>(); + try { + + // submit maker tx to pool but do not relay + MoneroSubmitTxResult makerResult = daemon.submitTxHex(processModel.getMaker().getDepositTxHex(), true); + if (!makerResult.isGood()) throw new RuntimeException("Error submitting maker deposit tx: " + JsonUtils.serialize(makerResult)); + txHashes.add(processModel.getMaker().getDepositTxHash()); + + // submit taker tx to pool but do not relay + if (!trade.hasBuyerAsTakerWithoutDeposit()) { + MoneroSubmitTxResult takerResult = daemon.submitTxHex(processModel.getTaker().getDepositTxHex(), true); + if (!takerResult.isGood()) throw new RuntimeException("Error submitting taker deposit tx: " + JsonUtils.serialize(takerResult)); + txHashes.add(processModel.getTaker().getDepositTxHash()); + } // relay txs - MoneroSubmitTxResult makerResult = daemon.submitTxHex(processModel.getMaker().getDepositTxHex(), true); - MoneroSubmitTxResult takerResult = daemon.submitTxHex(processModel.getTaker().getDepositTxHex(), true); - if (!makerResult.isGood()) throw new RuntimeException("Error submitting maker deposit tx: " + JsonUtils.serialize(makerResult)); - if (!takerResult.isGood()) throw new RuntimeException("Error submitting taker deposit tx: " + JsonUtils.serialize(takerResult)); - daemon.relayTxsByHash(Arrays.asList(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash())); + daemon.relayTxsByHash(txHashes); depositTxsRelayed = true; // update trade state - log.info("Arbitrator submitted deposit txs for trade " + trade.getId()); - trade.setState(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS); - processModel.getTradeManager().requestPersistence(); + log.info("Arbitrator published deposit txs for trade " + trade.getId()); + trade.setStateIfValidTransitionTo(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS); + } catch (Exception e) { + log.warn("Arbitrator error publishing deposit txs for trade {} {}: {}\n", trade.getClass().getSimpleName(), trade.getShortId(), e.getMessage(), e); + if (!depositTxsRelayed) { - // create deposit response - DepositResponse response = new DepositResponse( - trade.getOffer().getId(), - UUID.randomUUID().toString(), - Version.getP2PMessageVersion(), - new Date().getTime(), - null); - - // send deposit response to maker and taker - sendDepositResponse(trade.getMaker().getNodeAddress(), trade.getMaker().getPubKeyRing(), response); - sendDepositResponse(trade.getTaker().getNodeAddress(), trade.getTaker().getPubKeyRing(), response); - } else { - if (processModel.getMaker().getDepositTxHex() == null) log.info("Arbitrator waiting for deposit request from maker for trade " + trade.getId()); - if (processModel.getTaker().getDepositTxHex() == null) log.info("Arbitrator waiting for deposit request from taker for trade " + trade.getId()); - } - - complete(); - processModel.getTradeManager().requestPersistence(); - } catch (Throwable t) { - - // handle error before deposits relayed - if (!depositTxsRelayed) { - try { - daemon.flushTxPool(processModel.getMaker().getDepositTxHash(), processModel.getTaker().getDepositTxHash()); - } catch (Exception e) { - e.printStackTrace(); + // flush txs from pool + try { + daemon.flushTxPool(txHashes); + } catch (Exception e2) { + log.warn("Error flushing deposit txs from pool for trade {}: {}\n", trade.getId(), e2.getMessage(), e2); + } } - - // create deposit response with error - DepositResponse response = new DepositResponse( - trade.getOffer().getId(), - UUID.randomUUID().toString(), - Version.getP2PMessageVersion(), - new Date().getTime(), - t.getMessage()); - - // send deposit response to maker and taker - sendDepositResponse(trade.getMaker().getNodeAddress(), trade.getMaker().getPubKeyRing(), response); - sendDepositResponse(trade.getTaker().getNodeAddress(), trade.getTaker().getPubKeyRing(), response); + throw e; } - failed(t); + } else { + + // subscribe to trade state once to send responses with ack or nack + trade.stateProperty().addListener((obs, oldState, newState) -> { + if (oldState == newState) return; + if (newState == Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED) { + sendDepositResponsesOnce(error == null ? "Arbitrator failed to publish deposit txs within timeout for trade " + trade.getId() : error.getMessage()); + } else if (newState.ordinal() >= Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS.ordinal()) { + sendDepositResponsesOnce(null); + } + }); + + if (processModel.getMaker().getDepositTxHex() == null) log.info("Arbitrator waiting for deposit request from maker for trade " + trade.getId()); + if (processModel.getTaker().getDepositTxHex() == null && !trade.hasBuyerAsTakerWithoutDeposit()) log.info("Arbitrator waiting for deposit request from taker for trade " + trade.getId()); } } + private boolean isTimedOut() { + return !processModel.getTradeManager().hasOpenTrade(trade); + } + + private synchronized void sendDepositResponsesOnce(String errorMessage) { + + // skip if sent + if (depositResponsesSent) return; + depositResponsesSent = true; + + // log error + if (errorMessage != null) { + log.warn("Sending deposit responses with error={}", errorMessage); + Thread.dumpStack(); + } + + // create deposit response + DepositResponse response = new DepositResponse( + trade.getOffer().getId(), + UUID.randomUUID().toString(), + Version.getP2PMessageVersion(), + new Date().getTime(), + errorMessage, + trade.getBuyer().getSecurityDeposit().longValue(), + trade.getSeller().getSecurityDeposit().longValue()); + + // send deposit response to maker and taker + sendDepositResponse(trade.getMaker().getNodeAddress(), trade.getMaker().getPubKeyRing(), response); + sendDepositResponse(trade.getTaker().getNodeAddress(), trade.getTaker().getPubKeyRing(), response); + } + private void sendDepositResponse(NodeAddress nodeAddress, PubKeyRing pubKeyRing, DepositResponse response) { - log.info("Sending deposit response to trader={}; offerId={}", nodeAddress, trade.getId()); + log.info("Sending deposit response to trader={}; offerId={}, error={}", nodeAddress, trade.getId(), error); processModel.getP2PService().sendEncryptedDirectMessage(nodeAddress, pubKeyRing, response, new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), nodeAddress, trade.getId()); + log.info("{} arrived: trading peer={}; offerId={}; uid={}", response.getClass().getSimpleName(), nodeAddress, trade.getId(), trade.getUid()); } @Override public void onFault(String errorMessage) { log.error("Sending {} failed: uid={}; peer={}; error={}", response.getClass().getSimpleName(), nodeAddress, trade.getId(), errorMessage); appendToErrorMessage("Sending message failed: message=" + response + "\nerrorMessage=" + errorMessage); - failed(); } }); } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java index 4843cf5a54..18e97dd466 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorProcessReserveTx.java @@ -18,9 +18,9 @@ package haveno.core.trade.protocol.tasks; import haveno.common.taskrunner.TaskRunner; -import haveno.common.util.Tuple2; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitTradeRequest; import haveno.core.trade.protocol.TradePeer; @@ -29,6 +29,8 @@ import monero.daemon.model.MoneroTx; import java.math.BigInteger; +import org.apache.commons.lang3.exception.ExceptionUtils; + /** * Arbitrator verifies reserve tx from maker or taker. * @@ -48,39 +50,48 @@ public class ArbitratorProcessReserveTx extends TradeTask { runInterceptHook(); Offer offer = trade.getOffer(); InitTradeRequest request = (InitTradeRequest) processModel.getTradeMessage(); - boolean isFromTaker = request.getSenderNodeAddress().equals(trade.getTaker().getNodeAddress()); - boolean isFromBuyer = isFromTaker ? offer.getDirection() == OfferDirection.SELL : offer.getDirection() == OfferDirection.BUY; + TradePeer sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + boolean isFromMaker = sender == trade.getMaker(); + boolean isFromBuyer = isFromMaker ? offer.getDirection() == OfferDirection.BUY : offer.getDirection() == OfferDirection.SELL; + sender = isFromMaker ? processModel.getMaker() : processModel.getTaker(); + BigInteger securityDeposit = isFromMaker ? isFromBuyer ? offer.getMaxBuyerSecurityDeposit() : offer.getMaxSellerSecurityDeposit() : isFromBuyer ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee(); + sender.setSecurityDeposit(securityDeposit); - // TODO (woodser): if signer online, should never be called by maker + // TODO (woodser): if signer online, should never be called by maker? - // process reserve tx with expected values - BigInteger tradeFee = isFromTaker ? trade.getTakerFee() : trade.getMakerFee(); - BigInteger sendAmount = isFromBuyer ? BigInteger.valueOf(0) : offer.getAmount(); - BigInteger securityDeposit = isFromBuyer ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); - Tuple2<MoneroTx, BigInteger> txResult; - try { - txResult = trade.getXmrWalletService().verifyTradeTx( - offer.getId(), - tradeFee, - sendAmount, - securityDeposit, - request.getPayoutAddress(), - request.getReserveTxHash(), - request.getReserveTxHex(), - request.getReserveTxKey(), - null); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Error processing reserve tx from " + (isFromTaker ? "taker " : "maker ") + request.getSenderNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage()); + // process reserve tx unless from buyer as taker without deposit + boolean isFromBuyerAsTakerWithoutDeposit = isFromBuyer && !isFromMaker && trade.hasBuyerAsTakerWithoutDeposit(); + if (!isFromBuyerAsTakerWithoutDeposit) { + + // process reserve tx with expected values + BigInteger penaltyFee = HavenoUtils.multiply(isFromMaker ? offer.getAmount() : trade.getAmount(), offer.getPenaltyFeePct()); + BigInteger tradeFee = isFromMaker ? offer.getMaxMakerFee() : trade.getTakerFee(); + BigInteger sendAmount = isFromBuyer ? BigInteger.ZERO : isFromMaker ? offer.getAmount() : trade.getAmount(); // maker reserve tx is for offer amount + MoneroTx verifiedTx; + try { + verifiedTx = trade.getXmrWalletService().verifyReserveTx( + offer.getId(), + penaltyFee, + tradeFee, + sendAmount, + securityDeposit, + request.getPayoutAddress(), + request.getReserveTxHash(), + request.getReserveTxHex(), + request.getReserveTxKey(), + null); + } catch (Exception e) { + log.error(ExceptionUtils.getStackTrace(e)); + throw new RuntimeException("Error processing reserve tx from " + (isFromMaker ? "maker " : "taker ") + processModel.getTempTradePeerNodeAddress() + ", offerId=" + offer.getId() + ": " + e.getMessage()); + } + + // save reserve tx to model + sender.setSecurityDeposit(sender.getSecurityDeposit().subtract(verifiedTx.getFee())); // subtract mining fee from security deposit + sender.setReserveTxHash(request.getReserveTxHash()); + sender.setReserveTxHex(request.getReserveTxHex()); + sender.setReserveTxKey(request.getReserveTxKey()); } - // save reserve tx to model - TradePeer trader = isFromTaker ? processModel.getTaker() : processModel.getMaker(); - trader.setReserveTxHash(request.getReserveTxHash()); - trader.setReserveTxHex(request.getReserveTxHex()); - trader.setReserveTxKey(request.getReserveTxKey()); - trader.setSecurityDeposit(txResult.second); - // persist trade processModel.getTradeManager().requestPersistence(); complete(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java index 09339b4113..a846077db4 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ArbitratorSendInitTradeOrMultisigRequests.java @@ -20,9 +20,11 @@ package haveno.core.trade.protocol.tasks; import haveno.common.app.Version; import haveno.common.taskrunner.TaskRunner; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitMultisigRequest; import haveno.core.trade.messages.InitTradeRequest; +import haveno.core.trade.protocol.TradePeer; import haveno.network.p2p.SendDirectMessageListener; import lombok.extern.slf4j.Slf4j; import monero.wallet.MoneroWallet; @@ -49,21 +51,23 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { try { runInterceptHook(); InitTradeRequest request = (InitTradeRequest) processModel.getTradeMessage(); + TradePeer sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); - // handle request from taker - if (request.getSenderNodeAddress().equals(trade.getTaker().getNodeAddress())) { + // handle request from maker + if (sender == trade.getMaker()) { - // create request to initialize trade with maker - InitTradeRequest makerRequest = new InitTradeRequest( + // create request to taker + InitTradeRequest takerRequest = new InitTradeRequest( + request.getTradeProtocolVersion(), processModel.getOfferId(), - request.getSenderNodeAddress(), - request.getPubKeyRing(), trade.getAmount().longValueExact(), trade.getPrice().getValue(), - trade.getTakerFee().longValueExact(), - request.getAccountId(), - request.getPaymentAccountId(), request.getPaymentMethodId(), + request.getMakerAccountId(), + request.getTakerAccountId(), + request.getMakerPaymentAccountId(), + request.getTakerPaymentAccountId(), + request.getTakerPubKeyRing(), UUID.randomUUID().toString(), Version.getP2PMessageVersion(), request.getAccountAgeWitnessSignatureOfOfferId(), @@ -72,35 +76,35 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { trade.getTaker().getNodeAddress(), trade.getArbitrator().getNodeAddress(), null, - null, // do not include taker's reserve tx + null, null, null, null); - // send request to maker - log.info("Send {} with offerId {} and uid {} to maker {}", makerRequest.getClass().getSimpleName(), makerRequest.getTradeId(), makerRequest.getUid(), trade.getMaker().getNodeAddress()); + // send request to taker + log.info("Send {} with offerId {} and uid {} to taker {}", takerRequest.getClass().getSimpleName(), takerRequest.getOfferId(), takerRequest.getUid(), trade.getTaker().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( - trade.getMaker().getNodeAddress(), // TODO (woodser): maker's address might be different from original owner address if they disconnect and reconnect, need to validate and update address when requests received - trade.getMaker().getPubKeyRing(), - makerRequest, + trade.getTaker().getNodeAddress(), // TODO (woodser): maker's address might be different from original owner address if they disconnect and reconnect, need to validate and update address when requests received + trade.getTaker().getPubKeyRing(), + takerRequest, new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived at maker: offerId={}; uid={}", makerRequest.getClass().getSimpleName(), makerRequest.getTradeId(), makerRequest.getUid()); + log.info("{} arrived at taker: offerId={}; uid={}", takerRequest.getClass().getSimpleName(), takerRequest.getOfferId(), takerRequest.getUid()); complete(); } @Override public void onFault(String errorMessage) { - log.error("Sending {} failed: uid={}; peer={}; error={}", makerRequest.getClass().getSimpleName(), makerRequest.getUid(), trade.getArbitrator().getNodeAddress(), errorMessage); - appendToErrorMessage("Sending message failed: message=" + makerRequest + "\nerrorMessage=" + errorMessage); + log.error("Sending {} failed: uid={}; peer={}; error={}", takerRequest.getClass().getSimpleName(), takerRequest.getUid(), trade.getTaker().getNodeAddress(), errorMessage); + appendToErrorMessage("Sending message failed: message=" + takerRequest + "\nerrorMessage=" + errorMessage); failed(); } } ); } - // handle request from maker - else if (request.getSenderNodeAddress().equals(trade.getMaker().getNodeAddress())) { + // handle request from taker + else if (sender == trade.getTaker()) { sendInitMultisigRequests(); complete(); // TODO: wait for InitMultisigRequest arrivals? } else { @@ -113,10 +117,9 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { private void sendInitMultisigRequests() { - // ensure arbitrator has maker's reserve tx - if (processModel.getMaker().getReserveTxHash() == null) { - throw new RuntimeException("Arbitrator does not have maker's reserve tx after initializing trade"); - } + // ensure arbitrator has reserve txs + if (processModel.getMaker().getReserveTxHash() == null) throw new RuntimeException("Arbitrator does not have maker's reserve tx after initializing trade"); + if (processModel.getTaker().getReserveTxHash() == null && !trade.hasBuyerAsTakerWithoutDeposit()) throw new RuntimeException("Arbitrator does not have taker's reserve tx after initializing trade"); // create wallet for multisig MoneroWallet multisigWallet = trade.createWallet(); @@ -125,6 +128,12 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { String preparedHex = multisigWallet.prepareMultisig(); trade.getSelf().setPreparedMultisigHex(preparedHex); + // set trade fee address + String address = HavenoUtils.ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS ? trade.getXmrWalletService().getBaseAddressEntry().getAddressString() : HavenoUtils.getGlobalTradeFeeAddress(); + if (trade.getProcessModel().getTradeFeeAddress() == null) { + trade.getProcessModel().setTradeFeeAddress(address); + } + // create message to initialize multisig InitMultisigRequest initMultisigRequest = new InitMultisigRequest( processModel.getOffer().getId(), @@ -133,10 +142,11 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { new Date().getTime(), preparedHex, null, - null); + null, + trade.getProcessModel().getTradeFeeAddress()); // send request to maker - log.info("Send {} with offerId {} and uid {} to maker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid(), trade.getMaker().getNodeAddress()); + log.info("Send {} with offerId {} and uid {} to maker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid(), trade.getMaker().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( trade.getMaker().getNodeAddress(), trade.getMaker().getPubKeyRing(), @@ -144,7 +154,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived at maker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid()); + log.info("{} arrived at maker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid()); } @Override public void onFault(String errorMessage) { @@ -154,7 +164,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { ); // send request to taker - log.info("Send {} with offerId {} and uid {} to taker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid(), trade.getTaker().getNodeAddress()); + log.info("Send {} with offerId {} and uid {} to taker {}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid(), trade.getTaker().getNodeAddress()); processModel.getP2PService().sendEncryptedDirectMessage( trade.getTaker().getNodeAddress(), trade.getTaker().getPubKeyRing(), @@ -162,7 +172,7 @@ public class ArbitratorSendInitTradeOrMultisigRequests extends TradeTask { new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived at taker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getTradeId(), initMultisigRequest.getUid()); + log.info("{} arrived at taker: offerId={}; uid={}", initMultisigRequest.getClass().getSimpleName(), initMultisigRequest.getOfferId(), initMultisigRequest.getUid()); } @Override public void onFault(String errorMessage) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java index d108ec0870..05fee1374a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerPreparePaymentSentMessage.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -19,6 +36,7 @@ package haveno.core.trade.protocol.tasks; import com.google.common.base.Preconditions; import haveno.common.taskrunner.TaskRunner; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import lombok.extern.slf4j.Slf4j; import monero.wallet.MoneroWallet; @@ -45,34 +63,38 @@ public class BuyerPreparePaymentSentMessage extends TradeTask { try { runInterceptHook(); - // skip if already created - if (processModel.getPaymentSentMessage() != null) { - log.warn("Skipping preparation of payment sent message since it's already created for {} {}", trade.getClass().getSimpleName(), trade.getId()); - complete(); - return; + // skip if payout tx already created + if (trade.getSelf().getUnsignedPayoutTxHex() != null) { + log.warn("Skipping preparation of payment sent message because payout tx is already created for {} {}", trade.getClass().getSimpleName(), trade.getShortId()); + complete(); + return; } // validate state Preconditions.checkNotNull(trade.getSeller().getPaymentAccountPayload(), "Seller's payment account payload is null"); Preconditions.checkNotNull(trade.getAmount(), "trade.getTradeAmount() must not be null"); Preconditions.checkNotNull(trade.getMakerDepositTx(), "trade.getMakerDepositTx() must not be null"); - Preconditions.checkNotNull(trade.getTakerDepositTx(), "trade.getTakerDepositTx() must not be null"); + if (!trade.hasBuyerAsTakerWithoutDeposit()) Preconditions.checkNotNull(trade.getTakerDepositTx(), "trade.getTakerDepositTx() must not be null"); checkNotNull(trade.getOffer(), "offer must not be null"); // create payout tx if we have seller's updated multisig hex if (trade.getSeller().getUpdatedMultisigHex() != null) { - // import multisig hex - trade.importMultisigHex(); + // synchronize on lock for wallet operations + synchronized (trade.getWalletLock()) { + synchronized (HavenoUtils.getWalletFunctionLock()) { - // create payout tx - log.info("Buyer creating unsigned payout tx"); - MoneroTxWallet payoutTx = trade.createPayoutTx(); - trade.setPayoutTx(payoutTx); - trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + // import multisig hex + trade.importMultisigHex(); - // save wallet off thread - new Thread(() -> trade.saveWallet()).start(); + // create payout tx + log.info("Buyer creating unsigned payout tx for {} {} ", trade.getClass().getSimpleName(), trade.getShortId()); + MoneroTxWallet payoutTx = trade.createPayoutTx(); + trade.updatePayout(payoutTx); + trade.getSelf().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + trade.requestPersistence(); + } + } } complete(); @@ -93,101 +115,100 @@ public class BuyerPreparePaymentSentMessage extends TradeTask { */ public static class Pair<F, S> { - private F first; - private S second; + private F first; + private S second; - public Pair(F first, S second) { - super(); - this.first = first; - this.second = second; - } + public Pair(F first, S second) { + super(); + this.first = first; + this.second = second; + } - public F getFirst() { - return first; - } + public F getFirst() { + return first; + } - public void setFirst(F first) { - this.first = first; - } + public void setFirst(F first) { + this.first = first; + } - public S getSecond() { - return second; - } + public S getSecond() { + return second; + } - public void setSecond(S second) { - this.second = second; - } + public void setSecond(S second) { + this.second = second; + } } public static void printBalances(MoneroWallet wallet) { - // collect info about subaddresses - List<Pair<String, List<Object>>> pairs = new ArrayList<Pair<String, List<Object>>>(); - //if (wallet == null) wallet = TestUtils.getWalletJni(); - BigInteger balance = wallet.getBalance(); - BigInteger unlockedBalance = wallet.getUnlockedBalance(); - List<MoneroAccount> accounts = wallet.getAccounts(true); - System.out.println("Wallet balance: " + balance); - System.out.println("Wallet unlocked balance: " + unlockedBalance); - for (MoneroAccount account : accounts) { - add(pairs, "ACCOUNT", account.getIndex()); - add(pairs, "SUBADDRESS", ""); - add(pairs, "LABEL", ""); - add(pairs, "ADDRESS", ""); - add(pairs, "BALANCE", account.getBalance()); - add(pairs, "UNLOCKED", account.getUnlockedBalance()); - for (MoneroSubaddress subaddress : account.getSubaddresses()) { - add(pairs, "ACCOUNT", account.getIndex()); - add(pairs, "SUBADDRESS", subaddress.getIndex()); - add(pairs, "LABEL", subaddress.getLabel()); - add(pairs, "ADDRESS", subaddress.getAddress()); - add(pairs, "BALANCE", subaddress.getBalance()); - add(pairs, "UNLOCKED", subaddress.getUnlockedBalance()); + // collect info about subaddresses + List<Pair<String, List<Object>>> pairs = new ArrayList<Pair<String, List<Object>>>(); + //if (wallet == null) wallet = TestUtils.getWalletJni(); + BigInteger balance = wallet.getBalance(); + BigInteger unlockedBalance = wallet.getUnlockedBalance(); + List<MoneroAccount> accounts = wallet.getAccounts(true); + System.out.println("Wallet balance: " + balance); + System.out.println("Wallet unlocked balance: " + unlockedBalance); + for (MoneroAccount account : accounts) { + add(pairs, "ACCOUNT", account.getIndex()); + add(pairs, "SUBADDRESS", ""); + add(pairs, "LABEL", ""); + add(pairs, "ADDRESS", ""); + add(pairs, "BALANCE", account.getBalance()); + add(pairs, "UNLOCKED", account.getUnlockedBalance()); + for (MoneroSubaddress subaddress : account.getSubaddresses()) { + add(pairs, "ACCOUNT", account.getIndex()); + add(pairs, "SUBADDRESS", subaddress.getIndex()); + add(pairs, "LABEL", subaddress.getLabel()); + add(pairs, "ADDRESS", subaddress.getAddress()); + add(pairs, "BALANCE", subaddress.getBalance()); + add(pairs, "UNLOCKED", subaddress.getUnlockedBalance()); + } } - } - // convert info to csv - Integer length = null; - for (Pair<String, List<Object>> pair : pairs) { - if (length == null) length = pair.getSecond().size(); - } + // convert info to csv + Integer length = null; + for (Pair<String, List<Object>> pair : pairs) { + if (length == null) + length = pair.getSecond().size(); + } - System.out.println(pairsToCsv(pairs)); + System.out.println(pairsToCsv(pairs)); } private static void add(List<Pair<String, List<Object>>> pairs, String header, Object value) { - if (value == null) value = ""; - Pair<String, List<Object>> pair = null; - for (Pair<String, List<Object>> aPair : pairs) { - if (aPair.getFirst().equals(header)) { - pair = aPair; - break; + if (value == null) value = ""; + Pair<String, List<Object>> pair = null; + for (Pair<String, List<Object>> aPair : pairs) { + if (aPair.getFirst().equals(header)) { + pair = aPair; + break; + } } - } - if (pair == null) { - List<Object> vals = new ArrayList<Object>(); - pair = new Pair<String, List<Object>>(header, vals); - pairs.add(pair); - } - pair.getSecond().add(value); + if (pair == null) { + List<Object> vals = new ArrayList<Object>(); + pair = new Pair<String, List<Object>>(header, vals); + pairs.add(pair); + } + pair.getSecond().add(value); } private static String pairsToCsv(List<Pair<String, List<Object>>> pairs) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < pairs.size(); i++) { - sb.append(pairs.get(i).getFirst()); - if (i < pairs.size() - 1) sb.append(','); - else sb.append('\n'); - } - for (int i = 0; i < pairs.get(0).getSecond().size(); i++) { - for (int j = 0; j < pairs.size(); j++) { - sb.append(pairs.get(j).getSecond().get(i)); - if (j < pairs.size() - 1) sb.append(','); - else sb.append('\n'); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < pairs.size(); i++) { + sb.append(pairs.get(i).getFirst()); + if (i < pairs.size() - 1) sb.append(','); + else sb.append('\n'); } - } - return sb.toString(); + for (int i = 0; i < pairs.get(0).getSecond().size(); i++) { + for (int j = 0; j < pairs.size(); j++) { + sb.append(pairs.get(j).getSecond().get(i)); + if (j < pairs.size() - 1) sb.append(','); + else sb.append('\n'); + } + } + return sb.toString(); } } - - diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java index 5d52805a11..42206c8de0 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessage.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -28,6 +45,7 @@ import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.PaymentSentMessage; import haveno.core.trade.messages.TradeMailboxMessage; +import haveno.core.trade.protocol.TradePeer; import haveno.core.util.JsonUtil; import haveno.network.p2p.NodeAddress; import javafx.beans.value.ChangeListener; @@ -56,14 +74,29 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask super(taskHandler, trade); } - protected abstract NodeAddress getReceiverNodeAddress(); + protected abstract TradePeer getReceiver(); - protected abstract PubKeyRing getReceiverPubKeyRing(); + @Override + protected NodeAddress getReceiverNodeAddress() { + return getReceiver().getNodeAddress(); + } + + @Override + protected PubKeyRing getReceiverPubKeyRing() { + return getReceiver().getPubKeyRing(); + } @Override protected void run() { try { runInterceptHook(); + + // skip if already acked by receiver + if (isAckedByReceiver()) { + if (!isCompleted()) complete(); + return; + } + super.run(); } catch (Throwable t) { failed(t); @@ -72,7 +105,7 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask @Override protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) { - if (processModel.getPaymentSentMessage() == null) { + if (getReceiver().getPaymentSentMessage() == null) { // We do not use a real unique ID here as we want to be able to re-send the exact same message in case the // peer does not respond with an ACK msg in a certain time interval. To avoid that we get dangling mailbox @@ -87,7 +120,7 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask trade.getCounterCurrencyTxId(), trade.getCounterCurrencyExtraData(), deterministicId, - trade.getPayoutTxHex(), + trade.getSelf().getUnsignedPayoutTxHex(), trade.getSelf().getUpdatedMultisigHex(), trade.getSelf().getPaymentAccountKey(), trade.getTradePeer().getAccountAgeWitness() @@ -98,13 +131,13 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask String messageAsJson = JsonUtil.objectToJson(message); byte[] sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), messageAsJson); message.setBuyerSignature(sig); - processModel.setPaymentSentMessage(message); + getReceiver().setPaymentSentMessage(message); trade.requestPersistence(); } catch (Exception e) { throw new RuntimeException (e); } } - return processModel.getPaymentSentMessage(); + return getReceiver().getPaymentSentMessage(); } @Override @@ -144,7 +177,7 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask private void tryToSendAgainLater() { // skip if already acked - if (trade.getState().ordinal() >= Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal()) return; + if (isAckedByReceiver()) return; if (resendCounter >= MAX_RESEND_ATTEMPTS) { cleanup(); @@ -176,4 +209,6 @@ public abstract class BuyerSendPaymentSentMessage extends SendMailboxMessageTask cleanup(); } } + + protected abstract boolean isAckedByReceiver(); } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java index 16959e17f5..cc4113e342 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToArbitrator.java @@ -17,10 +17,10 @@ package haveno.core.trade.protocol.tasks; -import haveno.common.crypto.PubKeyRing; import haveno.common.taskrunner.TaskRunner; +import haveno.core.network.MessageState; import haveno.core.trade.Trade; -import haveno.network.p2p.NodeAddress; +import haveno.core.trade.protocol.TradePeer; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -32,12 +32,9 @@ public class BuyerSendPaymentSentMessageToArbitrator extends BuyerSendPaymentSen super(taskHandler, trade); } - protected NodeAddress getReceiverNodeAddress() { - return trade.getArbitrator().getNodeAddress(); - } - - protected PubKeyRing getReceiverPubKeyRing() { - return trade.getArbitrator().getPubKeyRing(); + @Override + protected TradePeer getReceiver() { + return trade.getArbitrator(); } @Override @@ -59,4 +56,9 @@ public class BuyerSendPaymentSentMessageToArbitrator extends BuyerSendPaymentSen protected void setStateArrived() { // state only updated on seller message } + + @Override + protected boolean isAckedByReceiver() { + return trade.getProcessModel().getPaymentSentMessageStatePropertyArbitrator().get() == MessageState.ACKNOWLEDGED; + } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java index 343e4e5514..caf402be0a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/BuyerSendPaymentSentMessageToSeller.java @@ -17,11 +17,11 @@ package haveno.core.trade.protocol.tasks; -import haveno.common.crypto.PubKeyRing; import haveno.common.taskrunner.TaskRunner; +import haveno.core.network.MessageState; import haveno.core.trade.Trade; import haveno.core.trade.messages.TradeMessage; -import haveno.network.p2p.NodeAddress; +import haveno.core.trade.protocol.TradePeer; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -33,12 +33,33 @@ public class BuyerSendPaymentSentMessageToSeller extends BuyerSendPaymentSentMes super(taskHandler, trade); } - protected NodeAddress getReceiverNodeAddress() { - return trade.getSeller().getNodeAddress(); + @Override + protected TradePeer getReceiver() { + return trade.getSeller(); + } + + @Override + protected void setStateSent() { + trade.getProcessModel().setPaymentSentMessageState(MessageState.SENT); + super.setStateSent(); } - protected PubKeyRing getReceiverPubKeyRing() { - return trade.getSeller().getPubKeyRing(); + @Override + protected void setStateArrived() { + trade.getProcessModel().setPaymentSentMessageState(MessageState.ARRIVED); + super.setStateArrived(); + } + + @Override + protected void setStateStoredInMailbox() { + trade.getProcessModel().setPaymentSentMessageState(MessageState.STORED_IN_MAILBOX); + super.setStateStoredInMailbox(); + } + + @Override + protected void setStateFault() { + trade.getProcessModel().setPaymentSentMessageState(MessageState.FAILED); + super.setStateFault(); } // continue execution on fault so payment sent message is sent to arbitrator @@ -48,4 +69,9 @@ public class BuyerSendPaymentSentMessageToSeller extends BuyerSendPaymentSentMes appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); complete(); } + + @Override + protected boolean isAckedByReceiver() { + return trade.getState().ordinal() >= Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal(); + } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java deleted file mode 100644 index a257d55070..0000000000 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequest.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.core.trade.protocol.tasks; - -import haveno.common.app.Version; -import haveno.common.taskrunner.TaskRunner; -import haveno.core.offer.Offer; -import haveno.core.trade.Trade; -import haveno.core.trade.messages.InitTradeRequest; -import haveno.core.xmr.model.XmrAddressEntry; -import haveno.network.p2p.SendDirectMessageListener; -import lombok.extern.slf4j.Slf4j; - -import java.util.UUID; - -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.core.util.Validator.checkTradeId; - -@Slf4j -public class MakerSendInitTradeRequest extends TradeTask { - @SuppressWarnings({"unused"}) - public MakerSendInitTradeRequest(TaskRunner taskHandler, Trade trade) { - super(taskHandler, trade); - } - - @Override - protected void run() { - try { - runInterceptHook(); - - // verify trade - InitTradeRequest makerRequest = (InitTradeRequest) processModel.getTradeMessage(); // arbitrator's InitTradeRequest to maker - checkNotNull(makerRequest); - checkTradeId(processModel.getOfferId(), makerRequest); - - // create request to arbitrator - Offer offer = processModel.getOffer(); - InitTradeRequest arbitratorRequest = new InitTradeRequest( - offer.getId(), - processModel.getMyNodeAddress(), - processModel.getPubKeyRing(), - trade.getAmount().longValueExact(), - trade.getPrice().getValue(), - offer.getMakerFee().longValueExact(), - trade.getProcessModel().getAccountId(), - offer.getMakerPaymentAccountId(), - offer.getOfferPayload().getPaymentMethodId(), - UUID.randomUUID().toString(), - Version.getP2PMessageVersion(), - null, - makerRequest.getCurrentDate(), - trade.getMaker().getNodeAddress(), - trade.getTaker().getNodeAddress(), - trade.getArbitrator().getNodeAddress(), - trade.getSelf().getReserveTxHash(), - trade.getSelf().getReserveTxHex(), - trade.getSelf().getReserveTxKey(), - model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString(), - null); - - // send request to arbitrator - log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getTradeId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); - processModel.getP2PService().sendEncryptedDirectMessage( - trade.getArbitrator().getNodeAddress(), - trade.getArbitrator().getPubKeyRing(), - arbitratorRequest, - new SendDirectMessageListener() { - @Override - public void onArrived() { - log.info("{} arrived at arbitrator: offerId={}", InitTradeRequest.class.getSimpleName(), trade.getId()); - complete(); - } - @Override - public void onFault(String errorMessage) { - log.warn("Failed to send {} to arbitrator, error={}.", InitTradeRequest.class.getSimpleName(), errorMessage); - failed(); - } - }); - } catch (Throwable t) { - failed(t); - } - } -} diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequestToArbitrator.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequestToArbitrator.java new file mode 100644 index 0000000000..9f191131ec --- /dev/null +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSendInitTradeRequestToArbitrator.java @@ -0,0 +1,154 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.trade.protocol.tasks; + +import haveno.common.app.Version; +import haveno.common.handlers.ErrorMessageHandler; +import haveno.common.handlers.ResultHandler; +import haveno.common.taskrunner.TaskRunner; +import haveno.core.offer.availability.DisputeAgentSelection; +import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; +import haveno.core.trade.HavenoUtils; +import haveno.core.trade.Trade; +import haveno.core.trade.messages.InitTradeRequest; +import haveno.core.xmr.model.XmrAddressEntry; +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.SendDirectMessageListener; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashSet; +import java.util.Set; + +@Slf4j +public class MakerSendInitTradeRequestToArbitrator extends TradeTask { + + @SuppressWarnings({"unused"}) + public MakerSendInitTradeRequestToArbitrator(TaskRunner taskHandler, Trade trade) { + super(taskHandler, trade); + } + + @Override + protected void run() { + try { + runInterceptHook(); + + // get least used arbitrator + Arbitrator leastUsedArbitrator = DisputeAgentSelection.getLeastUsedArbitrator(processModel.getTradeStatisticsManager(), processModel.getArbitratorManager()); + if (leastUsedArbitrator == null) { + failed("Could not get least used arbitrator to send " + InitTradeRequest.class.getSimpleName() + " for offer " + trade.getId()); + return; + } + + // send request to least used arbitrators until success + sendInitTradeRequests(leastUsedArbitrator.getNodeAddress(), new HashSet<NodeAddress>(), () -> { + trade.addInitProgressStep(); + complete(); + }, (errorMessage) -> { + log.warn("Cannot initialize trade with arbitrators: " + errorMessage); + failed(errorMessage); + }); + } catch (Throwable t) { + failed(t); + } + } + + private void sendInitTradeRequests(NodeAddress arbitratorNodeAddress, Set<NodeAddress> excludedArbitrators, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + sendInitTradeRequest(arbitratorNodeAddress, new SendDirectMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived at arbitrator: offerId={}", InitTradeRequest.class.getSimpleName(), trade.getId()); + + // check if trade still exists + if (!processModel.getTradeManager().hasOpenTrade(trade)) { + errorMessageHandler.handleErrorMessage("Trade protocol no longer exists, tradeId=" + trade.getId()); + return; + } + resultHandler.handleResult(); + } + + // if unavailable, try alternative arbitrator + @Override + public void onFault(String errorMessage) { + log.warn("Arbitrator unavailable: address={}, error={}", arbitratorNodeAddress, errorMessage); + excludedArbitrators.add(arbitratorNodeAddress); + + // check if trade still exists + if (!processModel.getTradeManager().hasOpenTrade(trade)) { + errorMessageHandler.handleErrorMessage("Trade protocol no longer exists, tradeId=" + trade.getId()); + return; + } + + Arbitrator altArbitrator = DisputeAgentSelection.getLeastUsedArbitrator(processModel.getTradeStatisticsManager(), processModel.getArbitratorManager(), excludedArbitrators); + if (altArbitrator == null) { + errorMessageHandler.handleErrorMessage("Cannot take offer because no arbitrators are available"); + return; + } + log.info("Using alternative arbitrator {}", altArbitrator.getNodeAddress()); + sendInitTradeRequests(altArbitrator.getNodeAddress(), excludedArbitrators, resultHandler, errorMessageHandler); + } + }); + } + + private void sendInitTradeRequest(NodeAddress arbitratorNodeAddress, SendDirectMessageListener listener) { + + // get registered arbitrator + Arbitrator arbitrator = processModel.getUser().getAcceptedArbitratorByAddress(arbitratorNodeAddress); + if (arbitrator == null) throw new RuntimeException("Node address " + arbitratorNodeAddress + " is not a registered arbitrator"); + + // set pub keys + processModel.getArbitrator().setPubKeyRing(arbitrator.getPubKeyRing()); + trade.getArbitrator().setNodeAddress(arbitratorNodeAddress); + trade.getArbitrator().setPubKeyRing(processModel.getArbitrator().getPubKeyRing()); + + // create request to arbitrator + InitTradeRequest takerRequest = (InitTradeRequest) processModel.getTradeMessage(); // taker's InitTradeRequest to maker + InitTradeRequest arbitratorRequest = new InitTradeRequest( + takerRequest.getTradeProtocolVersion(), + trade.getId(), + trade.getAmount().longValueExact(), + trade.getPrice().getValue(), + trade.getOffer().getOfferPayload().getPaymentMethodId(), + trade.getProcessModel().getAccountId(), + takerRequest.getTakerAccountId(), + trade.getOffer().getOfferPayload().getMakerPaymentAccountId(), + takerRequest.getTakerPaymentAccountId(), + trade.getTaker().getPubKeyRing(), + takerRequest.getUid(), + Version.getP2PMessageVersion(), + null, + takerRequest.getCurrentDate(), + trade.getMaker().getNodeAddress(), + trade.getTaker().getNodeAddress(), + trade.getArbitrator().getNodeAddress(), + trade.getSelf().getReserveTxHash(), + trade.getSelf().getReserveTxHex(), + trade.getSelf().getReserveTxKey(), + model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(), + trade.getChallenge()); + + // send request to arbitrator + log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getOfferId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); + processModel.getP2PService().sendEncryptedDirectMessage( + arbitratorNodeAddress, + arbitrator.getPubKeyRing(), + arbitratorRequest, + listener, + HavenoUtils.ARBITRATOR_ACK_TIMEOUT_SECONDS + ); + } +} diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSetLockTime.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSetLockTime.java index a22fa95c20..2ed9b06148 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSetLockTime.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MakerSetLockTime.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeResendDisputeClosedMessageWithPayout.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeResendDisputeClosedMessageWithPayout.java index 30c3e3d816..4dd914cbe4 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeResendDisputeClosedMessageWithPayout.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeResendDisputeClosedMessageWithPayout.java @@ -62,7 +62,7 @@ public class MaybeResendDisputeClosedMessageWithPayout extends TradeTask { HavenoUtils.arbitrationManager.closeDisputeTicket(dispute.getDisputeResultProperty().get(), dispute, dispute.getDisputeResultProperty().get().summaryNotesProperty().get(), () -> { completeAux(); }, (errMessage, err) -> { - err.printStackTrace(); + log.error("Failed to close dispute ticket for trade {}: {}\n", trade.getId(), errMessage, err); failed(err); }); ticketClosed = true; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java index 5ce230e2e6..e1c4cce5cc 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/MaybeSendSignContractRequest.java @@ -20,20 +20,21 @@ package haveno.core.trade.protocol.tasks; import haveno.common.app.Version; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.ArbitratorTrade; +import haveno.core.trade.BuyerTrade; import haveno.core.trade.HavenoUtils; import haveno.core.trade.MakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.Trade.State; import haveno.core.trade.messages.SignContractRequest; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; import haveno.network.p2p.SendDirectMessageListener; import lombok.extern.slf4j.Slf4j; -import monero.daemon.model.MoneroOutput; +import monero.common.MoneroRpcConnection; import monero.wallet.model.MoneroTxWallet; -import java.util.ArrayList; +import java.math.BigInteger; import java.util.Date; -import java.util.List; import java.util.UUID; // TODO (woodser): separate classes for deposit tx creation and contract request, or combine into ProcessInitMultisigRequest @@ -51,99 +52,156 @@ public class MaybeSendSignContractRequest extends TradeTask { @Override protected void run() { try { - runInterceptHook(); + runInterceptHook(); - // skip if arbitrator - if (trade instanceof ArbitratorTrade) { - complete(); - return; - } + // skip if arbitrator + if (trade instanceof ArbitratorTrade) { + complete(); + return; + } - // skip if multisig wallet not complete - if (processModel.getMultisigAddress() == null) { - complete(); - return; - } + // skip if multisig wallet not complete + if (processModel.getMultisigAddress() == null) { + complete(); + return; + } - // skip if deposit tx already created - if (processModel.getDepositTxXmr() != null) { - complete(); - return; - } + // skip if deposit tx already created + if (trade.getSelf().getDepositTx() != null) { + complete(); + return; + } - // initialize progress steps - trade.addInitProgressStep(); + // initialize progress steps + trade.addInitProgressStep(); - // create deposit tx and freeze inputs - Integer subaddressIndex = null; - boolean reserveExactAmount = false; - if (trade instanceof MakerTrade) { - reserveExactAmount = processModel.getOpenOfferManager().getOpenOfferById(trade.getId()).get().isReserveExactAmount(); - if (reserveExactAmount) subaddressIndex = model.getXmrWalletService().getAddressEntry(trade.getId(), XmrAddressEntry.Context.OFFER_FUNDING).get().getSubaddressIndex(); - } - MoneroTxWallet depositTx = trade.getXmrWalletService().createDepositTx(trade, reserveExactAmount, subaddressIndex); + // create deposit tx and freeze inputs + MoneroTxWallet depositTx = null; + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { - // collect reserved key images - List<String> reservedKeyImages = new ArrayList<String>(); - for (MoneroOutput input : depositTx.getInputs()) reservedKeyImages.add(input.getKeyImage().getHex()); + // check for timeout + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while getting lock to create deposit tx, tradeId=" + trade.getShortId()); + trade.startProtocolTimeout(); - // save process state - processModel.setDepositTxXmr(depositTx); // TODO: redundant with trade.getSelf().setDepositTx(), remove? - trade.getSelf().setDepositTx(depositTx); - trade.getSelf().setDepositTxHash(depositTx.getHash()); - trade.getSelf().setReserveTxKeyImages(reservedKeyImages); - trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getOrCreateAddressEntry(processModel.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString()); // TODO (woodser): allow custom payout address? - trade.getSelf().setPaymentAccountPayload(trade.getProcessModel().getPaymentAccountPayload(trade.getSelf().getPaymentAccountId())); + // collect info + Integer subaddressIndex = null; + boolean reserveExactAmount = false; + if (trade instanceof MakerTrade) { + reserveExactAmount = processModel.getOpenOfferManager().getOpenOfferById(trade.getId()).get().isReserveExactAmount(); + if (reserveExactAmount) subaddressIndex = model.getXmrWalletService().getAddressEntry(trade.getId(), XmrAddressEntry.Context.OFFER_FUNDING).get().getSubaddressIndex(); + } - // maker signs deposit hash nonce to avoid challenge protocol - byte[] sig = null; - if (trade instanceof MakerTrade) { - sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), depositTx.getHash()); - } + // thaw reserved outputs + if (trade.getSelf().getReserveTxKeyImages() != null) { + trade.getXmrWalletService().thawOutputs(trade.getSelf().getReserveTxKeyImages()); + } - // create request for peer and arbitrator to sign contract - SignContractRequest request = new SignContractRequest( - trade.getOffer().getId(), - UUID.randomUUID().toString(), - Version.getP2PMessageVersion(), - new Date().getTime(), - trade.getProcessModel().getAccountId(), - trade.getSelf().getPaymentAccountPayload().getHash(), - trade.getSelf().getPayoutAddressString(), - depositTx.getHash(), - sig); + // attempt creating deposit tx + if (!trade.isBuyerAsTakerWithoutDeposit()) { + try { + synchronized (HavenoUtils.getWalletFunctionLock()) { + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = trade.getXmrConnectionService().getConnection(); + try { + depositTx = trade.getXmrWalletService().createDepositTx(trade, reserveExactAmount, subaddressIndex); + } catch (Exception e) { + log.warn("Error creating deposit tx, tradeId={}, attempt={}/{}, error={}", trade.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + trade.getXmrWalletService().handleWalletError(e, sourceConnection); + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while creating deposit tx, tradeId=" + trade.getShortId()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + + // check for timeout + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while creating deposit tx, tradeId=" + trade.getShortId()); + if (depositTx != null) break; + } + } + } catch (Exception e) { + + // thaw deposit inputs + if (depositTx != null) { + trade.getXmrWalletService().thawOutputs(HavenoUtils.getInputKeyImages(depositTx)); + trade.getSelf().setReserveTxKeyImages(null); + } + + // re-freeze maker offer inputs + if (trade instanceof MakerTrade) { + trade.getXmrWalletService().freezeOutputs(trade.getOffer().getOfferPayload().getReserveTxKeyImages()); + } + + throw e; + } + } - // send request to trading peer - processModel.getP2PService().sendEncryptedDirectMessage(trade.getTradePeer().getNodeAddress(), trade.getTradePeer().getPubKeyRing(), request, new SendDirectMessageListener() { - @Override - public void onArrived() { - log.info("{} arrived: trading peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getTradePeer().getNodeAddress(), trade.getId()); - ack1 = true; - if (ack1 && ack2) completeAux(); - } - @Override - public void onFault(String errorMessage) { - log.error("Sending {} failed: uid={}; peer={}; error={}", request.getClass().getSimpleName(), trade.getTradePeer().getNodeAddress(), trade.getId(), errorMessage); - appendToErrorMessage("Sending message failed: message=" + request + "\nerrorMessage=" + errorMessage); - failed(); - } - }); + // reset protocol timeout + trade.addInitProgressStep(); - // send request to arbitrator - processModel.getP2PService().sendEncryptedDirectMessage(trade.getArbitrator().getNodeAddress(), trade.getArbitrator().getPubKeyRing(), request, new SendDirectMessageListener() { - @Override - public void onArrived() { - log.info("{} arrived: trading peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId()); - ack2 = true; - if (ack1 && ack2) completeAux(); - } - @Override - public void onFault(String errorMessage) { - log.error("Sending {} failed: uid={}; peer={}; error={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId(), errorMessage); - appendToErrorMessage("Sending message failed: message=" + request + "\nerrorMessage=" + errorMessage); - failed(); - } - }); + // update trade state + trade.getSelf().setPayoutAddressString(trade.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString()); // TODO (woodser): allow custom payout address? + trade.getSelf().setPaymentAccountPayload(trade.getProcessModel().getPaymentAccountPayload(trade.getSelf().getPaymentAccountId())); + trade.getSelf().setPaymentAccountPayloadHash(trade.getSelf().getPaymentAccountPayload().getHash()); + BigInteger securityDeposit = trade instanceof BuyerTrade ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee(); + if (depositTx == null) { + trade.getSelf().setSecurityDeposit(securityDeposit); + } else { + trade.getSelf().setSecurityDeposit(securityDeposit.subtract(depositTx.getFee())); + trade.getSelf().setDepositTx(depositTx); + trade.getSelf().setDepositTxHash(depositTx.getHash()); + trade.getSelf().setDepositTxFee(depositTx.getFee()); + trade.getSelf().setReserveTxKeyImages(HavenoUtils.getInputKeyImages(depositTx)); + } + } + + // maker signs deposit hash nonce to avoid challenge protocol + byte[] sig = null; + if (trade instanceof MakerTrade) { + sig = HavenoUtils.sign(processModel.getP2PService().getKeyRing(), depositTx.getHash()); + } + + // create request for peer and arbitrator to sign contract + SignContractRequest request = new SignContractRequest( + trade.getOffer().getId(), + UUID.randomUUID().toString(), + Version.getP2PMessageVersion(), + new Date().getTime(), + trade.getProcessModel().getAccountId(), + trade.getSelf().getPaymentAccountPayload().getHash(), + trade.getSelf().getPayoutAddressString(), + depositTx == null ? null : depositTx.getHash(), + sig); + + // send request to trading peer + processModel.getP2PService().sendEncryptedDirectMessage(trade.getTradePeer().getNodeAddress(), trade.getTradePeer().getPubKeyRing(), request, new SendDirectMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived: trading peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getTradePeer().getNodeAddress(), trade.getId()); + ack1 = true; + if (ack1 && ack2) completeAux(); + } + @Override + public void onFault(String errorMessage) { + log.error("Sending {} failed: uid={}; peer={}; error={}", request.getClass().getSimpleName(), trade.getTradePeer().getNodeAddress(), trade.getId(), errorMessage); + appendToErrorMessage("Sending message failed: message=" + request + "\nerrorMessage=" + errorMessage); + failed(); + } + }); + + // send request to arbitrator + processModel.getP2PService().sendEncryptedDirectMessage(trade.getArbitrator().getNodeAddress(), trade.getArbitrator().getPubKeyRing(), request, new SendDirectMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived: trading peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId()); + ack2 = true; + if (ack1 && ack2) completeAux(); + } + @Override + public void onFault(String errorMessage) { + log.error("Sending {} failed: uid={}; peer={}; error={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId(), errorMessage); + appendToErrorMessage("Sending message failed: message=" + request + "\nerrorMessage=" + errorMessage); + failed(); + } + }); } catch (Throwable t) { failed(t); } @@ -155,4 +213,8 @@ public class MaybeSendSignContractRequest extends TradeTask { processModel.getTradeManager().requestPersistence(); complete(); } + + private boolean isTimedOut() { + return !processModel.getTradeManager().hasOpenTrade(trade); + } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositResponse.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositResponse.java index c210f488b8..dcaf1a7e76 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositResponse.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositResponse.java @@ -18,6 +18,8 @@ package haveno.core.trade.protocol.tasks; +import java.math.BigInteger; + import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.Trade; import haveno.core.trade.messages.DepositResponse; @@ -39,14 +41,22 @@ public class ProcessDepositResponse extends TradeTask { // throw if error DepositResponse message = (DepositResponse) processModel.getTradeMessage(); if (message.getErrorMessage() != null) { + log.warn("Unregistering trade {} {} because deposit response has error message={}", trade.getClass().getSimpleName(), trade.getShortId(), message.getErrorMessage()); trade.setStateIfValidTransitionTo(Trade.State.PUBLISH_DEPOSIT_TX_REQUEST_FAILED); + processModel.getTradeManager().unregisterTrade(trade); throw new RuntimeException(message.getErrorMessage()); } + // record security deposits + trade.getBuyer().setSecurityDeposit(BigInteger.valueOf(message.getBuyerSecurityDeposit())); + trade.getSeller().setSecurityDeposit(BigInteger.valueOf(message.getSellerSecurityDeposit())); + // set success state trade.setStateIfValidTransitionTo(Trade.State.ARBITRATOR_PUBLISHED_DEPOSIT_TXS); - trade.addInitProgressStep(); processModel.getTradeManager().requestPersistence(); + + // update balances + trade.getXmrWalletService().updateBalanceListeners(); complete(); } catch (Throwable t) { failed(t); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java index 88af889432..c11df74fae 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessDepositsConfirmedMessage.java @@ -18,6 +18,7 @@ package haveno.core.trade.protocol.tasks; +import haveno.common.ThreadUtils; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.Trade; import haveno.core.trade.messages.DepositsConfirmedMessage; @@ -53,23 +54,29 @@ public class ProcessDepositsConfirmedMessage extends TradeTask { if (sender.getNodeAddress().equals(trade.getSeller().getNodeAddress()) && sender != trade.getSeller()) trade.getSeller().setNodeAddress(null); if (sender.getNodeAddress().equals(trade.getArbitrator().getNodeAddress()) && sender != trade.getArbitrator()) trade.getArbitrator().setNodeAddress(null); - // update multisig hex - sender.setUpdatedMultisigHex(request.getUpdatedMultisigHex()); - // decrypt seller payment account payload if key given if (request.getSellerPaymentAccountKey() != null && trade.getTradePeer().getPaymentAccountPayload() == null) { log.info(trade.getClass().getSimpleName() + " decrypting using seller payment account key"); trade.decryptPeerPaymentAccountPayload(request.getSellerPaymentAccountKey()); } - processModel.getTradeManager().requestPersistence(); // in case importing multisig hex fails - // import multisig hex - trade.importMultisigHex(); + // update multisig hex + if (sender.getUpdatedMultisigHex() == null) { + sender.setUpdatedMultisigHex(request.getUpdatedMultisigHex()); - // save wallet off thread - trade.saveWallet(); + // try to import multisig hex (retry later) + if (!trade.isPayoutPublished()) { + ThreadUtils.submitToPool(() -> { + try { + trade.importMultisigHex(); + } catch (Exception e) { + log.warn("Error importing multisig hex on deposits confirmed for trade " + trade.getId() + ": " + e.getMessage() + "\n", e); + } + }); + } + } - // persist and complete + // persist processModel.getTradeManager().requestPersistence(); complete(); } catch (Throwable t) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java index c8df4dd9cc..71b53c5dc5 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitMultisigRequest.java @@ -21,6 +21,7 @@ import haveno.common.app.Version; import haveno.common.crypto.PubKeyRing; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.ArbitratorTrade; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.MakerTrade; import haveno.core.trade.TakerTrade; import haveno.core.trade.Trade; @@ -31,6 +32,7 @@ import haveno.network.p2p.NodeAddress; import haveno.network.p2p.SendDirectMessageListener; import lombok.extern.slf4j.Slf4j; import monero.wallet.MoneroWallet; +import monero.wallet.model.MoneroMultisigInfo; import monero.wallet.model.MoneroMultisigInitResult; import java.util.Arrays; @@ -62,21 +64,29 @@ public class ProcessInitMultisigRequest extends TradeTask { checkTradeId(processModel.getOfferId(), request); XmrWalletService xmrWalletService = processModel.getProvider().getXmrWalletService(); - // get peer multisig participant - TradePeer multisigParticipant = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + // get sender + TradePeer sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + + // set trade fee address + if (HavenoUtils.ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS) { + if (request.getTradeFeeAddress() != null && sender == trade.getArbitrator()) { + trade.getProcessModel().setTradeFeeAddress(request.getTradeFeeAddress()); + } + } else { + trade.getProcessModel().setTradeFeeAddress(HavenoUtils.getGlobalTradeFeeAddress()); + } // reconcile peer's established multisig hex with message - if (multisigParticipant.getPreparedMultisigHex() == null) multisigParticipant.setPreparedMultisigHex(request.getPreparedMultisigHex()); - else if (request.getPreparedMultisigHex() != null && !multisigParticipant.getPreparedMultisigHex().equals(request.getPreparedMultisigHex())) throw new RuntimeException("Message's prepared multisig differs from previous messages, previous: " + multisigParticipant.getPreparedMultisigHex() + ", message: " + request.getPreparedMultisigHex()); - if (multisigParticipant.getMadeMultisigHex() == null) multisigParticipant.setMadeMultisigHex(request.getMadeMultisigHex()); - else if (request.getMadeMultisigHex() != null && !multisigParticipant.getMadeMultisigHex().equals(request.getMadeMultisigHex())) throw new RuntimeException("Message's made multisig differs from previous messages: " + request.getMadeMultisigHex() + " versus " + multisigParticipant.getMadeMultisigHex()); - if (multisigParticipant.getExchangedMultisigHex() == null) multisigParticipant.setExchangedMultisigHex(request.getExchangedMultisigHex()); - else if (request.getExchangedMultisigHex() != null && !multisigParticipant.getExchangedMultisigHex().equals(request.getExchangedMultisigHex())) throw new RuntimeException("Message's exchanged multisig differs from previous messages: " + request.getExchangedMultisigHex() + " versus " + multisigParticipant.getExchangedMultisigHex()); + if (sender.getPreparedMultisigHex() == null) sender.setPreparedMultisigHex(request.getPreparedMultisigHex()); + else if (request.getPreparedMultisigHex() != null && !sender.getPreparedMultisigHex().equals(request.getPreparedMultisigHex())) throw new RuntimeException("Message's prepared multisig differs from previous messages, previous: " + sender.getPreparedMultisigHex() + ", message: " + request.getPreparedMultisigHex()); + if (sender.getMadeMultisigHex() == null) sender.setMadeMultisigHex(request.getMadeMultisigHex()); + else if (request.getMadeMultisigHex() != null && !sender.getMadeMultisigHex().equals(request.getMadeMultisigHex())) throw new RuntimeException("Message's made multisig differs from previous messages: " + request.getMadeMultisigHex() + " versus " + sender.getMadeMultisigHex()); + if (sender.getExchangedMultisigHex() == null) sender.setExchangedMultisigHex(request.getExchangedMultisigHex()); + else if (request.getExchangedMultisigHex() != null && !sender.getExchangedMultisigHex().equals(request.getExchangedMultisigHex())) throw new RuntimeException("Message's exchanged multisig differs from previous messages: " + request.getExchangedMultisigHex() + " versus " + sender.getExchangedMultisigHex()); // prepare multisig if applicable boolean updateParticipants = false; if (trade.getSelf().getPreparedMultisigHex() == null) { - trade.addInitProgressStep(); log.info("Preparing multisig wallet for {} {}", trade.getClass().getSimpleName(), trade.getId()); multisigWallet = trade.createWallet(); trade.getSelf().setPreparedMultisigHex(multisigWallet.prepareMultisig()); @@ -109,8 +119,17 @@ public class ProcessInitMultisigRequest extends TradeTask { if (processModel.getMultisigAddress() == null && peers[0].getExchangedMultisigHex() != null && peers[1].getExchangedMultisigHex() != null) { log.info("Importing exchanged multisig hex for trade {}", trade.getId()); MoneroMultisigInitResult result = multisigWallet.exchangeMultisigKeys(Arrays.asList(peers[0].getExchangedMultisigHex(), peers[1].getExchangedMultisigHex()), xmrWalletService.getWalletPassword()); + + // check multisig state + MoneroMultisigInfo multisigInfo = multisigWallet.getMultisigInfo(); + if (!multisigInfo.isMultisig()) throw new RuntimeException("Multisig wallet is not multisig on completion"); + if (!multisigInfo.isReady()) throw new RuntimeException("Multisig wallet is not ready on completion"); + if (multisigInfo.getThreshold() != 2) throw new RuntimeException("Multisig wallet has unexpected threshold: " + multisigInfo.getThreshold()); + if (multisigInfo.getNumParticipants() != 3) throw new RuntimeException("Multisig wallet has unexpected number of participants: " + multisigInfo.getNumParticipants()); + + // set final address and save processModel.setMultisigAddress(result.getAddress()); - new Thread(() -> trade.saveWallet()).start(); // save multisig wallet off thread on completion + trade.saveWallet(); trade.setStateIfValidTransitionTo(Trade.State.MULTISIG_COMPLETED); } @@ -150,7 +169,7 @@ public class ProcessInitMultisigRequest extends TradeTask { sendInitMultisigRequest(peer1Address, peer1PubKeyRing, new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer1Address, request.getTradeId(), request.getUid()); + log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer1Address, request.getOfferId(), request.getUid()); ack1 = true; if (ack1 && ack2) completeAux(); } @@ -166,7 +185,7 @@ public class ProcessInitMultisigRequest extends TradeTask { sendInitMultisigRequest(peer2Address, peer2PubKeyRing, new SendDirectMessageListener() { @Override public void onArrived() { - log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer2Address, request.getTradeId(), request.getUid()); + log.info("{} arrived: peer={}; offerId={}; uid={}", request.getClass().getSimpleName(), peer2Address, request.getOfferId(), request.getUid()); ack2 = true; if (ack1 && ack2) completeAux(); } @@ -210,9 +229,10 @@ public class ProcessInitMultisigRequest extends TradeTask { new Date().getTime(), trade.getSelf().getPreparedMultisigHex(), trade.getSelf().getMadeMultisigHex(), - trade.getSelf().getExchangedMultisigHex()); + trade.getSelf().getExchangedMultisigHex(), + null); - log.info("Send {} with offerId {} and uid {} to peer {}", request.getClass().getSimpleName(), request.getTradeId(), request.getUid(), recipient); + log.info("Send {} with offerId {} and uid {} to peer {}", request.getClass().getSimpleName(), request.getOfferId(), request.getUid(), recipient); processModel.getP2PService().sendEncryptedDirectMessage(recipient, pubKeyRing, request, listener); } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitTradeRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitTradeRequest.java index d369e68d8b..61962ce1d2 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitTradeRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessInitTradeRequest.java @@ -21,11 +21,13 @@ import com.google.common.base.Charsets; import haveno.common.taskrunner.TaskRunner; import haveno.core.exceptions.TradePriceOutOfToleranceException; import haveno.core.offer.Offer; +import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.trade.ArbitratorTrade; -import haveno.core.trade.HavenoUtils; import haveno.core.trade.MakerTrade; +import haveno.core.trade.TakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitTradeRequest; +import haveno.core.trade.messages.TradeProtocolVersion; import haveno.core.trade.protocol.TradePeer; import lombok.extern.slf4j.Slf4j; @@ -50,58 +52,31 @@ public class ProcessInitTradeRequest extends TradeTask { runInterceptHook(); Offer offer = checkNotNull(trade.getOffer(), "Offer must not be null"); InitTradeRequest request = (InitTradeRequest) processModel.getTradeMessage(); + + // validate checkNotNull(request); checkTradeId(processModel.getOfferId(), request); - - // handle request as arbitrator - TradePeer multisigParticipant; - if (trade instanceof ArbitratorTrade) { - trade.getMaker().setPubKeyRing((trade.getOffer().getPubKeyRing())); - trade.getArbitrator().setPubKeyRing(processModel.getPubKeyRing()); // TODO (woodser): why duplicating field in process model - - // handle request from taker - if (request.getSenderNodeAddress().equals(request.getTakerNodeAddress())) { - multisigParticipant = processModel.getTaker(); - if (!trade.getTaker().getNodeAddress().equals(request.getTakerNodeAddress())) throw new RuntimeException("Init trade requests from maker and taker do not agree"); - if (trade.getTaker().getPubKeyRing() != null) throw new RuntimeException("Pub key ring should not be initialized before processing InitTradeRequest"); - trade.getTaker().setPubKeyRing(request.getPubKeyRing()); - if (!HavenoUtils.isMakerSignatureValid(request, request.getMakerSignature(), offer.getPubKeyRing())) throw new RuntimeException("Maker signature is invalid for the trade request"); // verify maker signature - - // check trade price - try { - long tradePrice = request.getTradePrice(); - offer.verifyTakersTradePrice(tradePrice); - trade.setPrice(tradePrice); - } catch (TradePriceOutOfToleranceException e) { - failed(e.getMessage()); - } catch (Throwable e2) { - failed(e2); - } - } - - // handle request from maker - else if (request.getSenderNodeAddress().equals(request.getMakerNodeAddress())) { - multisigParticipant = processModel.getMaker(); - if (!trade.getMaker().getNodeAddress().equals(request.getMakerNodeAddress())) throw new RuntimeException("Init trade requests from maker and taker do not agree"); // TODO (woodser): test when maker and taker do not agree, use proper handling, uninitialize trade for other takers - if (trade.getMaker().getPubKeyRing() == null) trade.getMaker().setPubKeyRing(request.getPubKeyRing()); - else if (!trade.getMaker().getPubKeyRing().equals(request.getPubKeyRing())) throw new RuntimeException("Init trade requests from maker and taker do not agree"); // TODO (woodser): proper handling - trade.getMaker().setPubKeyRing(request.getPubKeyRing()); - if (trade.getPrice().getValue() != request.getTradePrice()) throw new RuntimeException("Maker and taker price do not agree"); - } else { - throw new RuntimeException("Sender is not trade's maker or taker"); - } - } + checkArgument(request.getTradeAmount() > 0); + if (trade.getAmount().compareTo(trade.getOffer().getAmount()) > 0) throw new RuntimeException("Trade amount exceeds offer amount"); + if (trade.getAmount().compareTo(trade.getOffer().getMinAmount()) < 0) throw new RuntimeException("Trade amount is less than minimum offer amount"); + if (!request.getTakerNodeAddress().equals(trade.getTaker().getNodeAddress())) throw new RuntimeException("Trade's taker node address does not match request"); + if (!request.getMakerNodeAddress().equals(trade.getMaker().getNodeAddress())) throw new RuntimeException("Trade's maker node address does not match request"); + if (!request.getOfferId().equals(offer.getId())) throw new RuntimeException("Offer id does not match request's offer id"); // handle request as maker - else if (trade instanceof MakerTrade) { - multisigParticipant = processModel.getTaker(); - trade.getTaker().setNodeAddress(request.getSenderNodeAddress()); // arbitrator sends maker InitTradeRequest with taker's node address and pub key ring - trade.getTaker().setPubKeyRing(request.getPubKeyRing()); + TradePeer sender; + if (trade instanceof MakerTrade) { + sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + if (sender != trade.getTaker()) throw new RuntimeException("InitTradeRequest to maker is expected from taker"); + trade.getTaker().setPubKeyRing(request.getTakerPubKeyRing()); + + // check protocol version + if (request.getTradeProtocolVersion() != TradeProtocolVersion.MULTISIG_2_3) throw new RuntimeException("Trade protocol version is not supported"); // TODO: check if contained in supported versions // check trade price try { long tradePrice = request.getTradePrice(); - offer.verifyTakersTradePrice(tradePrice); + offer.verifyTradePrice(tradePrice); trade.setPrice(tradePrice); } catch (TradePriceOutOfToleranceException e) { failed(e.getMessage()); @@ -110,27 +85,78 @@ public class ProcessInitTradeRequest extends TradeTask { } } + // handle request as arbitrator + else if (trade instanceof ArbitratorTrade) { + trade.getMaker().setPubKeyRing((trade.getOffer().getPubKeyRing())); // TODO: why initializing this here fields here and + trade.getArbitrator().setPubKeyRing(processModel.getPubKeyRing()); // TODO: why duplicating field in process model? + if (!trade.getArbitrator().getNodeAddress().equals(request.getArbitratorNodeAddress())) throw new RuntimeException("Trade's arbitrator node address does not match request"); + + // check protocol version + if (request.getTradeProtocolVersion() != TradeProtocolVersion.MULTISIG_2_3) throw new RuntimeException("Trade protocol version is not supported"); // TODO: check consistent from maker and taker when multiple protocols supported + + // handle request from maker + sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + if (sender == trade.getMaker()) { + trade.getTaker().setPubKeyRing(request.getTakerPubKeyRing()); + + // check trade price + try { + long tradePrice = request.getTradePrice(); + offer.verifyTradePrice(tradePrice); + trade.setPrice(tradePrice); + } catch (TradePriceOutOfToleranceException e) { + failed(e.getMessage()); + } catch (Throwable e2) { + failed(e2); + } + } + + // handle request from taker + else if (sender == trade.getTaker()) { + if (!trade.getTaker().getPubKeyRing().equals(request.getTakerPubKeyRing())) throw new RuntimeException("Taker's pub key ring does not match request's pub key ring"); + if (request.getTradeAmount() != trade.getAmount().longValueExact()) throw new RuntimeException("Trade amount does not match request's trade amount"); + if (request.getTradePrice() != trade.getPrice().getValue()) throw new RuntimeException("Trade price does not match request's trade price"); + } + + // handle invalid sender + else { + throw new RuntimeException("Sender is not trade's maker or taker"); + } + } + + // handle request as taker + else if (trade instanceof TakerTrade) { + if (request.getTradeAmount() != trade.getAmount().longValueExact()) throw new RuntimeException("Trade amount does not match request's trade amount"); + if (request.getTradePrice() != trade.getPrice().getValue()) throw new RuntimeException("Trade price does not match request's trade price"); + Arbitrator arbitrator = processModel.getUser().getAcceptedArbitratorByAddress(request.getArbitratorNodeAddress()); + if (arbitrator == null) throw new RuntimeException("Arbitrator is not accepted by taker"); + trade.getArbitrator().setNodeAddress(request.getArbitratorNodeAddress()); + trade.getArbitrator().setPubKeyRing(arbitrator.getPubKeyRing()); + sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + if (sender != trade.getArbitrator()) throw new RuntimeException("InitTradeRequest to taker is expected from arbitrator"); + } + // handle invalid trade type else { throw new RuntimeException("Invalid trade type to process init trade request: " + trade.getClass().getName()); } // set trading peer info - if (multisigParticipant.getPaymentAccountId() == null) multisigParticipant.setPaymentAccountId(request.getPaymentAccountId()); - else if (multisigParticipant.getPaymentAccountId() != request.getPaymentAccountId()) throw new RuntimeException("Payment account id is different from previous"); - multisigParticipant.setPubKeyRing(checkNotNull(request.getPubKeyRing())); - multisigParticipant.setAccountId(nonEmptyStringOf(request.getAccountId())); - multisigParticipant.setPaymentMethodId(nonEmptyStringOf(request.getPaymentMethodId())); - multisigParticipant.setAccountAgeWitnessNonce(trade.getId().getBytes(Charsets.UTF_8)); - multisigParticipant.setAccountAgeWitnessSignature(request.getAccountAgeWitnessSignatureOfOfferId()); - multisigParticipant.setCurrentDate(request.getCurrentDate()); + if (trade.getMaker().getAccountId() == null) trade.getMaker().setAccountId(request.getMakerAccountId()); + else if (!trade.getMaker().getAccountId().equals(request.getMakerAccountId())) throw new RuntimeException("Maker account id is different from previous"); + if (trade.getTaker().getAccountId() == null) trade.getTaker().setAccountId(request.getTakerAccountId()); + else if (!trade.getTaker().getAccountId().equals(request.getTakerAccountId())) throw new RuntimeException("Taker account id is different from previous"); + if (trade.getMaker().getPaymentAccountId() == null) trade.getMaker().setPaymentAccountId(request.getMakerPaymentAccountId()); + else if (!trade.getMaker().getPaymentAccountId().equals(request.getMakerPaymentAccountId())) throw new RuntimeException("Maker payment account id is different from previous"); + if (trade.getTaker().getPaymentAccountId() == null) trade.getTaker().setPaymentAccountId(request.getTakerPaymentAccountId()); + else if (!trade.getTaker().getPaymentAccountId().equals(request.getTakerPaymentAccountId())) throw new RuntimeException("Taker payment account id is different from previous"); + sender.setPaymentMethodId(nonEmptyStringOf(request.getPaymentMethodId())); // TODO: move to process model? + sender.setAccountAgeWitnessNonce(trade.getId().getBytes(Charsets.UTF_8)); + sender.setAccountAgeWitnessSignature(request.getAccountAgeWitnessSignatureOfOfferId()); + sender.setCurrentDate(request.getCurrentDate()); // check peer's current date - processModel.getAccountAgeWitnessService().verifyPeersCurrentDate(new Date(multisigParticipant.getCurrentDate())); - - // check trade amount - checkArgument(request.getTradeAmount() > 0); - checkArgument(request.getTradeAmount() == trade.getAmount().longValueExact(), "Trade amount does not match request's trade amount"); + processModel.getAccountAgeWitnessService().verifyPeersCurrentDate(new Date(sender.getCurrentDate())); // persist trade trade.addInitProgressStep(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java index 5e67d2b9bb..2ce29828a4 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentReceivedMessage.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,7 +34,6 @@ package haveno.core.trade.protocol.tasks; -import common.utils.GenUtils; import haveno.common.taskrunner.TaskRunner; import haveno.core.account.sign.SignedWitness; import haveno.core.support.dispute.Dispute; @@ -26,9 +42,9 @@ import haveno.core.trade.BuyerTrade; import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.PaymentReceivedMessage; +import haveno.core.trade.messages.PaymentSentMessage; import haveno.core.util.Validator; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -53,47 +69,56 @@ public class ProcessPaymentReceivedMessage extends TradeTask { // verify signature of payment received message HavenoUtils.verifyPaymentReceivedMessage(trade, message); - // save message for reprocessing - processModel.setPaymentReceivedMessage(message); - trade.requestPersistence(); - - // set state - trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); - trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex()); - trade.getBuyer().setAccountAgeWitness(message.getBuyerAccountAgeWitness()); - // update to the latest peer address of our peer if message is correct trade.getSeller().setNodeAddress(processModel.getTempTradePeerNodeAddress()); if (trade.getSeller().getNodeAddress().equals(trade.getBuyer().getNodeAddress())) trade.getBuyer().setNodeAddress(null); // tests can reuse addresses - // close open disputes - if (trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_REQUESTED.ordinal()) { - trade.advanceDisputeState(Trade.DisputeState.DISPUTE_CLOSED); - for (Dispute dispute : trade.getDisputes()) { - dispute.setIsClosed(); - } + // ack and complete if already processed + if (trade.getPhase().ordinal() >= Trade.Phase.PAYMENT_RECEIVED.ordinal() && trade.isPayoutPublished()) { + log.warn("Received another PaymentReceivedMessage which was already processed, ACKing"); + complete(); + return; } - // process payout tx unless already unlocked - if (!trade.isPayoutUnlocked()) processPayoutTx(message); + // save message for reprocessing + trade.getSeller().setPaymentReceivedMessage(message); + // set state + trade.getSeller().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); + trade.getBuyer().setAccountAgeWitness(message.getBuyerAccountAgeWitness()); + if (trade.isArbitrator() && trade.getBuyer().getPaymentSentMessage() == null) { + checkNotNull(message.getPaymentSentMessage(), "PaymentSentMessage is null for arbitrator"); + trade.getBuyer().setPaymentSentMessage(message.getPaymentSentMessage()); + trade.getBuyer().setUpdatedMultisigHex(message.getPaymentSentMessage().getUpdatedMultisigHex()); + } + trade.requestPersistence(); + + // process payout tx if not confirmed + if (!trade.isPayoutConfirmed()) processPayoutTx(message); + + // close open disputes + if (trade.isPayoutPublished() && trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_REQUESTED.ordinal()) { + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_CLOSED); + for (Dispute dispute : trade.getDisputes()) dispute.setIsClosed(); + } + + // advance state, arbitrator auto completes when payout published + trade.advanceState(Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG); + + // buyer republishes signed witness for resilience SignedWitness signedWitness = message.getBuyerSignedWitness(); if (signedWitness != null && trade instanceof BuyerTrade) { - // We received the signedWitness from the seller and publish the data to the network. - // The signer has published it as well but we prefer to re-do it on our side as well to achieve higher - // resilience. processModel.getAccountAgeWitnessService().publishOwnSignedWitness(signedWitness); } // complete - trade.advanceState(Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG); // arbitrator auto completes when payout published trade.requestPersistence(); complete(); } catch (Throwable t) { // do not reprocess illegal argument - if (t instanceof IllegalArgumentException) { - processModel.setPaymentReceivedMessage(null); // do not reprocess + if (HavenoUtils.isIllegal(t)) { + trade.getSeller().setPaymentReceivedMessage(null); // do not reprocess trade.requestPersistence(); } @@ -103,48 +128,60 @@ public class ProcessPaymentReceivedMessage extends TradeTask { private void processPayoutTx(PaymentReceivedMessage message) { + // adapt from 1.0.6 to 1.0.7 which changes field usage + // TODO: remove after future updates to allow old trades to clear + if (trade.getPayoutTxHex() != null && trade.getBuyer().getPaymentSentMessage() != null && trade.getPayoutTxHex().equals(trade.getBuyer().getPaymentSentMessage().getPayoutTxHex())) { + log.warn("Nullifying payout tx hex after 1.0.7 update {} {}", trade.getClass().getSimpleName(), trade.getShortId()); + if (trade instanceof BuyerTrade) trade.getSelf().setUnsignedPayoutTxHex(trade.getPayoutTxHex()); + trade.setPayoutTxHex(null); + } + // update wallet trade.importMultisigHex(); trade.syncAndPollWallet(); - trade.saveWallet(); // handle if payout tx not published if (!trade.isPayoutPublished()) { - // wait to sign and publish payout tx if defer flag set (seller recently saw payout tx arrive at buyer) - boolean isSigned = message.getSignedPayoutTxHex() != null; - boolean deferSignAndPublish = trade instanceof ArbitratorTrade && !isSigned && message.isDeferPublishPayout(); - if (deferSignAndPublish) { - log.info("Deferring signing and publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); - GenUtils.waitFor(Trade.DEFER_PUBLISH_MS); - if (!trade.isPayoutUnlocked()) trade.syncAndPollWallet(); + // wait to publish payout tx if defer flag set from seller (payout is expected) + if (message.isDeferPublishPayout()) { + log.info("Deferring publishing payout tx for {} {}", trade.getClass().getSimpleName(), trade.getId()); + if (trade instanceof ArbitratorTrade) trade.pollWalletNormallyForMs(60000); // stop idling arbitrator + for (int i = 0; i < 5; i++) { + if (trade.isPayoutPublished()) break; + HavenoUtils.waitFor(Trade.DEFER_PUBLISH_MS / 5); + } + if (!trade.isPayoutPublished()) trade.syncAndPollWallet(); } // verify and publish payout tx if (!trade.isPayoutPublished()) { - if (isSigned) { - log.info("{} {} publishing signed payout tx from seller", trade.getClass().getSimpleName(), trade.getId()); - trade.verifyPayoutTx(message.getSignedPayoutTxHex(), false, true); - } else { - try { - if (trade.getProcessModel().getPaymentSentMessage() == null) throw new RuntimeException("Process model does not have payment sent message for " + trade.getClass().getSimpleName() + " " + trade.getId()); - if (StringUtils.equals(trade.getPayoutTxHex(), trade.getProcessModel().getPaymentSentMessage().getPayoutTxHex())) { // unsigned - log.info("{} {} verifying, signing, and publishing seller's payout tx", trade.getClass().getSimpleName(), trade.getId()); - trade.verifyPayoutTx(message.getUnsignedPayoutTxHex(), true, true); + try { + boolean isSigned = message.getSignedPayoutTxHex() != null; + if (isSigned) { + log.info("{} {} publishing signed payout tx from seller", trade.getClass().getSimpleName(), trade.getId()); + trade.processPayoutTx(message.getSignedPayoutTxHex(), false, true); + } else { + PaymentSentMessage paymentSentMessage = (trade.isArbitrator() ? trade.getBuyer() : trade.getArbitrator()).getPaymentSentMessage(); + if (paymentSentMessage == null) throw new RuntimeException("Process model does not have payment sent message for " + trade.getClass().getSimpleName() + " " + trade.getId()); + if (trade.getPayoutTxHex() == null) { // unsigned + log.info("{} {} verifying, signing, and publishing payout tx", trade.getClass().getSimpleName(), trade.getId()); + trade.processPayoutTx(message.getUnsignedPayoutTxHex(), true, true); } else { - log.info("{} {} re-verifying and publishing payout tx", trade.getClass().getSimpleName(), trade.getId()); - trade.verifyPayoutTx(trade.getPayoutTxHex(), false, true); + log.info("{} {} re-verifying and publishing signed payout tx", trade.getClass().getSimpleName(), trade.getId()); + trade.processPayoutTx(trade.getPayoutTxHex(), false, true); } - } catch (Exception e) { - trade.syncAndPollWallet(); - if (trade.isPayoutPublished()) log.info("Payout tx already published for {} {}", trade.getClass().getName(), trade.getId()); - else throw e; } + } catch (Exception e) { + HavenoUtils.waitFor(trade.getXmrConnectionService().getRefreshPeriodMs()); // wait to see published tx + trade.syncAndPollWallet(); + if (trade.isPayoutPublished()) log.info("Payout tx already published for {} {}", trade.getClass().getName(), trade.getId()); + else throw e; } } } else { log.info("Payout tx already published for {} {}", trade.getClass().getSimpleName(), trade.getId()); - if (message.getSignedPayoutTxHex() != null && !trade.isPayoutConfirmed()) trade.verifyPayoutTx(message.getSignedPayoutTxHex(), false, true); + if (message.getSignedPayoutTxHex() != null && !trade.isPayoutConfirmed()) trade.processPayoutTx(message.getSignedPayoutTxHex(), false, true); } } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java index d6cc42a8b6..93d1ce520a 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessPaymentSentMessage.java @@ -48,8 +48,7 @@ public class ProcessPaymentSentMessage extends TradeTask { trade.getBuyer().setNodeAddress(processModel.getTempTradePeerNodeAddress()); // update state from message - processModel.setPaymentSentMessage(message); - trade.setPayoutTxHex(message.getPayoutTxHex()); + trade.getBuyer().setPaymentSentMessage(message); trade.getBuyer().setUpdatedMultisigHex(message.getUpdatedMultisigHex()); trade.getSeller().setAccountAgeWitness(message.getSellerAccountAgeWitness()); String counterCurrencyTxId = message.getCounterCurrencyTxId(); @@ -59,13 +58,6 @@ public class ProcessPaymentSentMessage extends TradeTask { // if seller, decrypt buyer's payment account payload if (trade.isSeller()) trade.decryptPeerPaymentAccountPayload(message.getPaymentAccountKey()); - trade.requestPersistence(); - - // import multisig hex - trade.importMultisigHex(); - - // save wallet - trade.saveWallet(); // update state trade.advanceState(Trade.State.BUYER_SENT_PAYMENT_SENT_MSG); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java index 13b6ad9bdb..1ce805aca6 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractRequest.java @@ -63,21 +63,20 @@ public class ProcessSignContractRequest extends TradeTask { // extract fields from request // TODO (woodser): verify request and from maker or taker SignContractRequest request = (SignContractRequest) processModel.getTradeMessage(); - TradePeer trader = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); - trader.setDepositTxHash(request.getDepositTxHash()); - trader.setAccountId(request.getAccountId()); - trader.setPaymentAccountPayloadHash(request.getPaymentAccountPayloadHash()); - trader.setPayoutAddressString(request.getPayoutAddress()); + TradePeer sender = trade.getTradePeer(processModel.getTempTradePeerNodeAddress()); + sender.setDepositTxHash(request.getDepositTxHash()); + sender.setAccountId(request.getAccountId()); + sender.setPaymentAccountPayloadHash(request.getPaymentAccountPayloadHash()); + sender.setPayoutAddressString(request.getPayoutAddress()); // maker sends witness signature of deposit tx hash - if (trader == trade.getMaker()) { - trader.setAccountAgeWitnessNonce(request.getDepositTxHash().getBytes(Charsets.UTF_8)); - trader.setAccountAgeWitnessSignature(request.getAccountAgeWitnessSignatureOfDepositHash()); + if (sender == trade.getMaker()) { + sender.setAccountAgeWitnessNonce(request.getDepositTxHash().getBytes(Charsets.UTF_8)); + sender.setAccountAgeWitnessSignature(request.getAccountAgeWitnessSignatureOfDepositHash()); } - // sign contract only when both deposit txs hashes known - // TODO (woodser): remove makerDepositTxId and takerDepositTxId from Trade - if (processModel.getMaker().getDepositTxHash() == null || processModel.getTaker().getDepositTxHash() == null) { + // sign contract only when received from both peers + if (processModel.getMaker().getPaymentAccountPayloadHash() == null || processModel.getTaker().getPaymentAccountPayloadHash() == null) { complete(); return; } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/RemoveOffer.java b/core/src/main/java/haveno/core/trade/protocol/tasks/RemoveOffer.java deleted file mode 100644 index c5b8a3f5b2..0000000000 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/RemoveOffer.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.core.trade.protocol.tasks; - -import haveno.common.taskrunner.TaskRunner; -import haveno.core.trade.MakerTrade; -import haveno.core.trade.Trade; -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkNotNull; - -@Slf4j -public class RemoveOffer extends TradeTask { - public RemoveOffer(TaskRunner<Trade> taskHandler, Trade trade) { - super(taskHandler, trade); - } - - @Override - protected void run() { - try { - runInterceptHook(); - - if (trade instanceof MakerTrade) { - processModel.getOpenOfferManager().closeOpenOffer(checkNotNull(trade.getOffer())); - } else { - trade.getXmrWalletService().resetAddressEntriesForOpenOffer(trade.getId()); - } - - complete(); - } catch (Throwable t) { - failed(t); - } - } -} \ No newline at end of file diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java index ed2b0ad11c..1452104e8f 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPreparePaymentReceivedMessage.java @@ -18,6 +18,8 @@ package haveno.core.trade.protocol.tasks; import haveno.common.taskrunner.TaskRunner; +import haveno.core.support.dispute.Dispute; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import lombok.extern.slf4j.Slf4j; import monero.wallet.model.MoneroTxWallet; @@ -36,34 +38,66 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask { runInterceptHook(); // check connection - trade.checkDaemonConnection(); + trade.verifyDaemonConnection(); // handle first time preparation - if (processModel.getPaymentReceivedMessage() == null) { + if (trade.getArbitrator().getPaymentReceivedMessage() == null) { - // import multisig hex - trade.importMultisigHex(); - - // verify, sign, and publish payout tx if given. otherwise create payout tx - if (trade.getPayoutTxHex() != null) { - try { - log.info("Seller verifying, signing, and publishing payout tx for trade {}", trade.getId()); - trade.verifyPayoutTx(trade.getPayoutTxHex(), true, true); - } catch (Exception e) { - log.warn("Error verifying, signing, and publishing payout tx for trade {}: {}. Creating unsigned payout tx", trade.getId(), e.getMessage()); - createUnsignedPayoutTx(); - } - } else { - createUnsignedPayoutTx(); + // adapt from 1.0.6 to 1.0.7 which changes field usage + // TODO: remove after future updates to allow old trades to clear + if (trade.getPayoutTxHex() != null && trade.getPayoutTxHex().equals(trade.getBuyer().getPaymentSentMessage().getPayoutTxHex())) { + log.warn("Nullifying payout tx hex after 1.0.7 update {} {}", trade.getClass().getSimpleName(), trade.getShortId()); + trade.setPayoutTxHex(null); } - } else if (processModel.getPaymentReceivedMessage().getSignedPayoutTxHex() != null && !trade.isPayoutPublished()) { + + // synchronize on lock for wallet operations + synchronized (trade.getWalletLock()) { + synchronized (HavenoUtils.getWalletFunctionLock()) { + + // import multisig hex unless already signed + if (trade.getPayoutTxHex() == null) { + trade.importMultisigHex(); + } + + // verify, sign, and publish payout tx if given + if (trade.getBuyer().getPaymentSentMessage().getPayoutTxHex() != null) { + try { + if (trade.getPayoutTxHex() == null) { + log.info("Seller verifying, signing, and publishing payout tx for trade {}", trade.getId()); + trade.processPayoutTx(trade.getBuyer().getPaymentSentMessage().getPayoutTxHex(), true, true); + } else { + log.warn("Seller publishing previously signed payout tx for trade {}", trade.getId()); + trade.processPayoutTx(trade.getPayoutTxHex(), false, true); + } + } catch (IllegalArgumentException | IllegalStateException e) { + log.warn("Illegal state or argument verifying, signing, and publishing payout tx for {} {}. Creating new unsigned payout tx. error={}. ", trade.getClass().getSimpleName(), trade.getId(), e.getMessage(), e); + createUnsignedPayoutTx(); + } catch (Exception e) { + log.warn("Error verifying, signing, and publishing payout tx for trade {}: {}", trade.getId(), e.getMessage(), e); + throw e; + } + } + + // otherwise create unsigned payout tx + else if (trade.getSelf().getUnsignedPayoutTxHex() == null) { + createUnsignedPayoutTx(); + } + } + } + } else if (trade.getArbitrator().getPaymentReceivedMessage().getSignedPayoutTxHex() != null && !trade.isPayoutPublished()) { // republish payout tx from previous message - log.info("Seller re-verifying and publishing payout tx for trade {}", trade.getId()); - trade.verifyPayoutTx(processModel.getPaymentReceivedMessage().getSignedPayoutTxHex(), false, true); + log.info("Seller re-verifying and publishing signed payout tx for trade {}", trade.getId()); + trade.processPayoutTx(trade.getArbitrator().getPaymentReceivedMessage().getSignedPayoutTxHex(), false, true); } - processModel.getTradeManager().requestPersistence(); + // close open disputes + if (trade.isPayoutPublished() && trade.getDisputeState().ordinal() >= Trade.DisputeState.DISPUTE_REQUESTED.ordinal()) { + trade.advanceDisputeState(Trade.DisputeState.DISPUTE_CLOSED); + for (Dispute dispute : trade.getDisputes()) dispute.setIsClosed(); + } + + trade.requestPersistence(); complete(); } catch (Throwable t) { failed(t); @@ -73,7 +107,7 @@ public class SellerPreparePaymentReceivedMessage extends TradeTask { private void createUnsignedPayoutTx() { log.info("Seller creating unsigned payout tx for trade {}", trade.getId()); MoneroTxWallet payoutTx = trade.createPayoutTx(); - trade.setPayoutTx(payoutTx); - trade.setPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); + trade.updatePayout(payoutTx); + trade.getSelf().setUnsignedPayoutTxHex(payoutTx.getTxSet().getMultisigTxHex()); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishDepositTx.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishDepositTx.java deleted file mode 100644 index 36bd2a19d5..0000000000 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishDepositTx.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.core.trade.protocol.tasks; - -import haveno.common.taskrunner.TaskRunner; -import haveno.core.trade.Trade; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class SellerPublishDepositTx extends TradeTask { - public SellerPublishDepositTx(TaskRunner<Trade> taskHandler, Trade trade) { - super(taskHandler, trade); - } - - @Override - protected void run() { - try { - runInterceptHook(); - throw new RuntimeException("SellerPublishesDepositTx not implemented for xmr"); - -// final Transaction depositTx = processModel.getDepositTx(); -// processModel.getTradeWalletService().broadcastTx(depositTx, -// new TxBroadcaster.Callback() { -// @Override -// public void onSuccess(Transaction transaction) { -// if (!completed) { -// // Now as we have published the deposit tx we set it in trade -// trade.applyDepositTx(depositTx); -// -// trade.setState(Trade.State.SELLER_PUBLISHED_DEPOSIT_TX); -// -// processModel.getBtcWalletService().swapAddressEntryToAvailable(processModel.getOffer().getId(), -// AddressEntry.Context.RESERVED_FOR_TRADE); -// -// processModel.getTradeManager().requestPersistence(); -// -// complete(); -// } else { -// log.warn("We got the onSuccess callback called after the timeout has been triggered a complete()."); -// } -// } -// -// @Override -// public void onFailure(TxBroadcastException exception) { -// if (!completed) { -// failed(exception); -// } else { -// log.warn("We got the onFailure callback called after the timeout has been triggered a complete()."); -// } -// } -// }); - } catch (Throwable t) { - failed(t); - } - } -} diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java deleted file mode 100644 index af41cbe48e..0000000000 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerPublishTradeStatistics.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.core.trade.protocol.tasks; - -import haveno.common.app.Capability; -import haveno.common.taskrunner.TaskRunner; -import haveno.core.trade.SellerTrade; -import haveno.core.trade.Trade; -import haveno.core.trade.statistics.TradeStatistics3; -import haveno.network.p2p.network.TorNetworkNode; -import lombok.extern.slf4j.Slf4j; - -import static com.google.common.base.Preconditions.checkNotNull; - -@Slf4j -public class SellerPublishTradeStatistics extends TradeTask { - public SellerPublishTradeStatistics(TaskRunner<Trade> taskHandler, Trade trade) { - super(taskHandler, trade); - } - - @Override - protected void run() { - try { - runInterceptHook(); - - // skip if not seller - if (!(trade instanceof SellerTrade)) { - complete(); - return; - } - - checkNotNull(trade.getSeller().getDepositTx()); - processModel.getP2PService().findPeersCapabilities(trade.getTradePeer().getNodeAddress()) - .filter(capabilities -> capabilities.containsAll(Capability.TRADE_STATISTICS_3)) - .ifPresentOrElse(capabilities -> { - // Our peer has updated, so as we are the seller we will publish the trade statistics. - // The peer as buyer does not publish anymore with v.1.4.0 (where Capability.TRADE_STATISTICS_3 was added) - - String referralId = processModel.getReferralIdService().getOptionalReferralId().orElse(null); - boolean isTorNetworkNode = model.getProcessModel().getP2PService().getNetworkNode() instanceof TorNetworkNode; - TradeStatistics3 tradeStatistics = TradeStatistics3.from(trade, referralId, isTorNetworkNode); - if (tradeStatistics.isValid()) { - log.info("Publishing trade statistics"); - processModel.getP2PService().addPersistableNetworkPayload(tradeStatistics, true); - } else { - log.warn("Trade statistics are invalid. We do not publish. {}", tradeStatistics); - } - - complete(); - }, - () -> { - log.info("Our peer does not has updated yet, so they will publish the trade statistics. " + - "To avoid duplicates we do not publish from our side."); - complete(); - }); - } catch (Throwable t) { - failed(t); - } - } -} diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java index 477dbe7584..f08fe87946 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessage.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -27,26 +44,34 @@ import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; import haveno.core.trade.messages.PaymentReceivedMessage; import haveno.core.trade.messages.TradeMailboxMessage; +import haveno.core.trade.protocol.TradePeer; import haveno.core.util.JsonUtil; import haveno.network.p2p.NodeAddress; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; -import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkArgument; @Slf4j @EqualsAndHashCode(callSuper = true) public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessageTask { - PaymentReceivedMessage message = null; SignedWitness signedWitness = null; public SellerSendPaymentReceivedMessage(TaskRunner<Trade> taskHandler, Trade trade) { super(taskHandler, trade); } + + protected abstract TradePeer getReceiver(); + + @Override + protected NodeAddress getReceiverNodeAddress() { + return getReceiver().getNodeAddress(); + } - protected abstract NodeAddress getReceiverNodeAddress(); - - protected abstract PubKeyRing getReceiverPubKeyRing(); + @Override + protected PubKeyRing getReceiverPubKeyRing() { + return getReceiver().getPubKeyRing(); + } @Override protected void run() { @@ -60,14 +85,17 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag @Override protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) { - checkNotNull(trade.getPayoutTxHex(), "Payout tx must not be null"); - if (message == null) { + if (getReceiver().getPaymentReceivedMessage() == null) { // sign account witness AccountAgeWitnessService accountAgeWitnessService = processModel.getAccountAgeWitnessService(); if (accountAgeWitnessService.isSignWitnessTrade(trade)) { - accountAgeWitnessService.traderSignAndPublishPeersAccountAgeWitness(trade).ifPresent(witness -> signedWitness = witness); - log.info("{} {} signed and published peers account age witness", trade.getClass().getSimpleName(), trade.getId()); + try { + accountAgeWitnessService.traderSignAndPublishPeersAccountAgeWitness(trade).ifPresent(witness -> signedWitness = witness); + log.info("{} {} signed and published peers account age witness", trade.getClass().getSimpleName(), trade.getId()); + } catch (Exception e) { + log.warn("Failed to sign and publish peer's account age witness for {} {}, error={}\n", getClass().getSimpleName(), trade.getId(), e.getMessage(), e); + } } // We do not use a real unique ID here as we want to be able to re-send the exact same message in case the @@ -75,31 +103,33 @@ public abstract class SellerSendPaymentReceivedMessage extends SendMailboxMessag // messages where only the one which gets processed by the peer would be removed we use the same uid. All // other data stays the same when we re-send the message at any time later. String deterministicId = HavenoUtils.getDeterministicId(trade, PaymentReceivedMessage.class, getReceiverNodeAddress()); - message = new PaymentReceivedMessage( + boolean deferPublishPayout = trade.isPayoutPublished() || trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(); // informs receiver to expect payout so delay processing + PaymentReceivedMessage message = new PaymentReceivedMessage( tradeId, processModel.getMyNodeAddress(), deterministicId, - trade.isPayoutPublished() ? null : trade.getPayoutTxHex(), // unsigned - trade.isPayoutPublished() ? trade.getPayoutTxHex() : null, // signed + trade.getPayoutTxHex() == null ? trade.getSelf().getUnsignedPayoutTxHex() : null, // unsigned // TODO: phase in after next update to clear old style trades + trade.getPayoutTxHex() == null ? null : trade.getPayoutTxHex(), // signed trade.getSelf().getUpdatedMultisigHex(), - trade.getState().ordinal() >= Trade.State.SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG.ordinal(), // informs to expect payout + deferPublishPayout, trade.getTradePeer().getAccountAgeWitness(), signedWitness, - processModel.getPaymentSentMessage() + getReceiver() == trade.getArbitrator() ? trade.getBuyer().getPaymentSentMessage() : null // buyer already has payment sent message ); + checkArgument(message.getUnsignedPayoutTxHex() != null || message.getSignedPayoutTxHex() != null, "PaymentReceivedMessage does not include payout tx hex"); // sign message try { String messageAsJson = JsonUtil.objectToJson(message); byte[] sig = Sig.sign(processModel.getP2PService().getKeyRing().getSignatureKeyPair().getPrivate(), messageAsJson.getBytes(Charsets.UTF_8)); message.setSellerSignature(sig); - processModel.setPaymentReceivedMessage(message); + getReceiver().setPaymentReceivedMessage(message); trade.requestPersistence(); } catch (Exception e) { throw new RuntimeException(e); } } - return message; + return getReceiver().getPaymentReceivedMessage(); } @Override diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToArbitrator.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToArbitrator.java index 3d9f466b03..3ae2cea281 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToArbitrator.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToArbitrator.java @@ -17,10 +17,9 @@ package haveno.core.trade.protocol.tasks; -import haveno.common.crypto.PubKeyRing; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.Trade; -import haveno.network.p2p.NodeAddress; +import haveno.core.trade.protocol.TradePeer; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -32,11 +31,8 @@ public class SellerSendPaymentReceivedMessageToArbitrator extends SellerSendPaym super(taskHandler, trade); } - protected NodeAddress getReceiverNodeAddress() { - return trade.getArbitrator().getNodeAddress(); - } - - protected PubKeyRing getReceiverPubKeyRing() { - return trade.getArbitrator().getPubKeyRing(); + @Override + protected TradePeer getReceiver() { + return trade.getArbitrator(); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToBuyer.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToBuyer.java index f9d98e8fb3..7228b40307 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToBuyer.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SellerSendPaymentReceivedMessageToBuyer.java @@ -17,13 +17,10 @@ package haveno.core.trade.protocol.tasks; -import haveno.common.crypto.PubKeyRing; import haveno.common.taskrunner.TaskRunner; import haveno.core.trade.Trade; -import haveno.core.trade.messages.PaymentReceivedMessage; -import haveno.core.trade.messages.TradeMailboxMessage; import haveno.core.trade.messages.TradeMessage; -import haveno.network.p2p.NodeAddress; +import haveno.core.trade.protocol.TradePeer; import lombok.EqualsAndHashCode; import lombok.extern.slf4j.Slf4j; @@ -35,21 +32,9 @@ public class SellerSendPaymentReceivedMessageToBuyer extends SellerSendPaymentRe super(taskHandler, trade); } - @Override - protected TradeMailboxMessage getTradeMailboxMessage(String tradeId) { - if (processModel.getPaymentReceivedMessage() == null) { - processModel.setPaymentReceivedMessage((PaymentReceivedMessage) super.getTradeMailboxMessage(tradeId)); // save payment received message for buyer - } - return processModel.getPaymentReceivedMessage(); - } - - protected NodeAddress getReceiverNodeAddress() { - return trade.getBuyer().getNodeAddress(); - } - - protected PubKeyRing getReceiverPubKeyRing() { - return trade.getBuyer().getPubKeyRing(); + protected TradePeer getReceiver() { + return trade.getBuyer(); } // continue execution on fault so payment received message is sent to arbitrator diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositRequest.java similarity index 83% rename from core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java rename to core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositRequest.java index 8727f685bf..7101c488a5 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/ProcessSignContractResponse.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositRequest.java @@ -29,14 +29,16 @@ import haveno.core.trade.protocol.TradePeer; import haveno.network.p2p.SendDirectMessageListener; import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; import java.util.Date; +import java.util.List; import java.util.UUID; @Slf4j -public class ProcessSignContractResponse extends TradeTask { +public class SendDepositRequest extends TradeTask { @SuppressWarnings({"unused"}) - public ProcessSignContractResponse(TaskRunner taskHandler, Trade trade) { + public SendDepositRequest(TaskRunner taskHandler, Trade trade) { super(taskHandler, trade); } @@ -80,10 +82,14 @@ public class ProcessSignContractResponse extends TradeTask { Version.getP2PMessageVersion(), new Date().getTime(), trade.getSelf().getContractSignature(), - processModel.getDepositTxXmr().getFullHex(), - processModel.getDepositTxXmr().getKey(), + trade.getSelf().getDepositTx() == null ? null : trade.getSelf().getDepositTx().getFullHex(), + trade.getSelf().getDepositTx() == null ? null : trade.getSelf().getDepositTx().getKey(), trade.getSelf().getPaymentAccountKey()); + // update trade state + trade.setState(Trade.State.SENT_PUBLISH_DEPOSIT_TX_REQUEST); + processModel.getTradeManager().requestPersistence(); + // send request to arbitrator log.info("Sending {} to arbitrator {}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId(), request.getUid()); processModel.getP2PService().sendEncryptedDirectMessage(trade.getArbitrator().getNodeAddress(), trade.getArbitrator().getPubKeyRing(), request, new SendDirectMessageListener() { @@ -92,6 +98,7 @@ public class ProcessSignContractResponse extends TradeTask { log.info("{} arrived: arbitrator={}; offerId={}; uid={}", request.getClass().getSimpleName(), trade.getArbitrator().getNodeAddress(), trade.getId(), request.getUid()); trade.setStateIfValidTransitionTo(Trade.State.SAW_ARRIVED_PUBLISH_DEPOSIT_TX_REQUEST); processModel.getTradeManager().requestPersistence(); + trade.addInitProgressStep(); complete(); } @Override @@ -101,13 +108,12 @@ public class ProcessSignContractResponse extends TradeTask { failed(); } }); - - // deposit is requested - trade.setState(Trade.State.SENT_PUBLISH_DEPOSIT_TX_REQUEST); - trade.addInitProgressStep(); - processModel.getTradeManager().requestPersistence(); } else { - log.info("Waiting for another contract signatures to send deposit request"); + List<String> awaitingSignaturesFrom = new ArrayList<>(); + if (processModel.getArbitrator().getContractSignature() == null) awaitingSignaturesFrom.add("arbitrator"); + if (processModel.getMaker().getContractSignature() == null) awaitingSignaturesFrom.add("maker"); + if (processModel.getTaker().getContractSignature() == null) awaitingSignaturesFrom.add("taker"); + log.info("Waiting for contract signature from {} to send deposit request", awaitingSignaturesFrom); complete(); // does not yet have needed signatures } } catch (Throwable t) { diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositsConfirmedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositsConfirmedMessage.java index ae26f17b03..8be8f00da5 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositsConfirmedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SendDepositsConfirmedMessage.java @@ -53,8 +53,8 @@ public abstract class SendDepositsConfirmedMessage extends SendMailboxMessageTas runInterceptHook(); // skip if already acked by receiver - if (ackedByReceiver()) { - complete(); + if (isAckedByReceiver()) { + if (!isCompleted()) complete(); return; } @@ -76,8 +76,7 @@ public abstract class SendDepositsConfirmedMessage extends SendMailboxMessageTas // export multisig hex once if (trade.getSelf().getUpdatedMultisigHex() == null) { - trade.getSelf().setUpdatedMultisigHex(trade.getWallet().exportMultisigHex()); - processModel.getTradeManager().requestPersistence(); + trade.exportMultisigHex(); } // We do not use a real unique ID here as we want to be able to re-send the exact same message in case the @@ -125,8 +124,8 @@ public abstract class SendDepositsConfirmedMessage extends SendMailboxMessageTas private void tryToSendAgainLater() { - // skip if already acked - if (ackedByReceiver()) return; + // skip if already acked or payout published + if (isAckedByReceiver() || trade.isPayoutPublished()) return; if (resendCounter >= MAX_RESEND_ATTEMPTS) { cleanup(); @@ -151,7 +150,7 @@ public abstract class SendDepositsConfirmedMessage extends SendMailboxMessageTas resendCounter++; } - private boolean ackedByReceiver() { + private boolean isAckedByReceiver() { TradePeer peer = trade.getTradePeer(getReceiverNodeAddress()); return peer.isDepositsConfirmedMessageAcked(); } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java b/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java index be107ed4f2..157d797410 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/SendMailboxMessageTask.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks; @@ -69,20 +69,20 @@ public abstract class SendMailboxMessageTask extends TradeTask { new SendMailboxMessageListener() { @Override public void onArrived() { - log.info("{} arrived at peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} arrived at peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); setStateArrived(); if (!task.isCompleted()) complete(); } @Override public void onStoredInMailbox() { - log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); SendMailboxMessageTask.this.onStoredInMailbox(); } @Override public void onFault(String errorMessage) { - log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid(), errorMessage); + log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid(), errorMessage); SendMailboxMessageTask.this.onFault(errorMessage, message); } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java index 952487a24a..e6c71032f4 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerReserveTradeFunds.java @@ -19,15 +19,18 @@ package haveno.core.trade.protocol.tasks; import haveno.common.taskrunner.TaskRunner; import haveno.core.offer.OfferDirection; +import haveno.core.trade.HavenoUtils; +import haveno.core.trade.TakerTrade; import haveno.core.trade.Trade; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.xmr.model.XmrAddressEntry; -import monero.daemon.model.MoneroOutput; +import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroRpcConnection; import monero.wallet.model.MoneroTxWallet; import java.math.BigInteger; -import java.util.ArrayList; -import java.util.List; +@Slf4j public class TakerReserveTradeFunds extends TradeTask { public TakerReserveTradeFunds(TaskRunner taskHandler, Trade trade) { @@ -39,20 +42,72 @@ public class TakerReserveTradeFunds extends TradeTask { try { runInterceptHook(); - // create reserve tx - BigInteger takerFee = trade.getTakerFee(); - BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getAmount() : BigInteger.valueOf(0); - BigInteger securityDeposit = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getOffer().getSellerSecurityDeposit() : trade.getOffer().getBuyerSecurityDeposit(); - String returnAddress = model.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); - MoneroTxWallet reserveTx = model.getXmrWalletService().createReserveTx(takerFee, sendAmount, securityDeposit, returnAddress, false, null); + // taker trade expected + if (!(trade instanceof TakerTrade)) { + throw new RuntimeException("Expected taker trade but was " + trade.getClass().getSimpleName() + " " + trade.getShortId() + ". That should never happen."); + } - // collect reserved key images - List<String> reservedKeyImages = new ArrayList<String>(); - for (MoneroOutput input : reserveTx.getInputs()) reservedKeyImages.add(input.getKeyImage().getHex()); + // create reserve tx unless deposit not required from buyer as taker + MoneroTxWallet reserveTx = null; + if (!trade.isBuyerAsTakerWithoutDeposit()) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { + + // check for timeout + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while getting lock to create reserve tx, tradeId=" + trade.getShortId()); + trade.startProtocolTimeout(); + + // collect relevant info + BigInteger penaltyFee = HavenoUtils.multiply(trade.getAmount(), trade.getOffer().getPenaltyFeePct()); + BigInteger takerFee = trade.getTakerFee(); + BigInteger sendAmount = trade.getOffer().getDirection() == OfferDirection.BUY ? trade.getAmount() : BigInteger.ZERO; + BigInteger securityDeposit = trade.getSecurityDepositBeforeMiningFee(); + String returnAddress = trade.getXmrWalletService().getOrCreateAddressEntry(trade.getOffer().getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); + + // attempt creating reserve tx + try { + synchronized (HavenoUtils.getWalletFunctionLock()) { + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = trade.getXmrConnectionService().getConnection(); + try { + reserveTx = model.getXmrWalletService().createReserveTx(penaltyFee, takerFee, sendAmount, securityDeposit, returnAddress, false, null); + } catch (Exception e) { + log.warn("Error creating reserve tx, tradeId={}, attempt={}/{}, error={}", trade.getShortId(), i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + trade.getXmrWalletService().handleWalletError(e, sourceConnection); + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while creating reserve tx, tradeId=" + trade.getShortId()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + + // check for timeout + if (isTimedOut()) throw new RuntimeException("Trade protocol has timed out while creating reserve tx, tradeId=" + trade.getShortId()); + if (reserveTx != null) break; + } + } + } catch (Exception e) { + + // reset state with wallet lock + model.getXmrWalletService().resetAddressEntriesForTrade(trade.getId()); + if (reserveTx != null) { + model.getXmrWalletService().thawOutputs(HavenoUtils.getInputKeyImages(reserveTx)); + trade.getSelf().setReserveTxKeyImages(null); + } + + throw e; + } + + // reset protocol timeout + trade.startProtocolTimeout(); + + // update trade state + trade.getTaker().setReserveTxHash(reserveTx.getHash()); + trade.getTaker().setReserveTxHex(reserveTx.getFullHex()); + trade.getTaker().setReserveTxKey(reserveTx.getKey()); + trade.getTaker().setReserveTxKeyImages(HavenoUtils.getInputKeyImages(reserveTx)); + } + } // save process state - processModel.setReserveTx(reserveTx); - processModel.getTaker().setReserveTxKeyImages(reservedKeyImages); + processModel.setReserveTx(reserveTx); // TODO: remove this? how is it used? processModel.getTradeManager().requestPersistence(); trade.addInitProgressStep(); complete(); @@ -63,4 +118,8 @@ public class TakerReserveTradeFunds extends TradeTask { failed(t); } } + + private boolean isTimedOut() { + return !processModel.getTradeManager().hasOpenTrade(trade); + } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java index 2013531521..eb86f15109 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToArbitrator.java @@ -18,23 +18,22 @@ package haveno.core.trade.protocol.tasks; import haveno.common.app.Version; -import haveno.common.handlers.ErrorMessageHandler; -import haveno.common.handlers.ResultHandler; import haveno.common.taskrunner.TaskRunner; -import haveno.core.offer.availability.DisputeAgentSelection; -import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; +import haveno.core.offer.Offer; import haveno.core.trade.Trade; import haveno.core.trade.messages.InitTradeRequest; -import haveno.network.p2p.NodeAddress; +import haveno.core.trade.messages.TradeProtocolVersion; +import haveno.core.xmr.model.XmrAddressEntry; import haveno.network.p2p.SendDirectMessageListener; import lombok.extern.slf4j.Slf4j; -import java.util.HashSet; -import java.util.Set; +import java.util.UUID; + +import static com.google.common.base.Preconditions.checkNotNull; +import static haveno.core.util.Validator.checkTradeId; @Slf4j public class TakerSendInitTradeRequestToArbitrator extends TradeTask { - @SuppressWarnings({"unused"}) public TakerSendInitTradeRequestToArbitrator(TaskRunner taskHandler, Trade trade) { super(taskHandler, trade); @@ -45,93 +44,60 @@ public class TakerSendInitTradeRequestToArbitrator extends TradeTask { try { runInterceptHook(); - // get least used arbitrator - Arbitrator leastUsedArbitrator = DisputeAgentSelection.getLeastUsedArbitrator(processModel.getTradeStatisticsManager(), processModel.getArbitratorManager()); - if (leastUsedArbitrator == null) { - failed("Could not get least used arbitrator to send " + InitTradeRequest.class.getSimpleName() + " for offer " + trade.getId()); - return; + // verify trade state + InitTradeRequest sourceRequest = (InitTradeRequest) processModel.getTradeMessage(); // arbitrator's InitTradeRequest to taker + checkNotNull(sourceRequest); + checkTradeId(processModel.getOfferId(), sourceRequest); + if (!trade.isBuyerAsTakerWithoutDeposit() && trade.getSelf().getReserveTxHash() == null) { + throw new IllegalStateException("Taker reserve tx id is not initialized: " + trade.getSelf().getReserveTxHash()); } - // send request to least used arbitrators until success - sendInitTradeRequests(leastUsedArbitrator.getNodeAddress(), new HashSet<NodeAddress>(), () -> { - trade.addInitProgressStep(); - complete(); - }, (errorMessage) -> { - log.warn("Cannot initialize trade with arbitrators: " + errorMessage); - failed(errorMessage); - }); + // create request to arbitrator + Offer offer = processModel.getOffer(); + InitTradeRequest arbitratorRequest = new InitTradeRequest( + TradeProtocolVersion.MULTISIG_2_3, // TODO: use processModel.getTradeProtocolVersion(), select one of maker's supported versions + offer.getId(), + trade.getAmount().longValueExact(), + trade.getPrice().getValue(), + trade.getSelf().getPaymentMethodId(), + trade.getMaker().getAccountId(), + trade.getTaker().getAccountId(), + trade.getMaker().getPaymentAccountId(), + trade.getTaker().getPaymentAccountId(), + trade.getTaker().getPubKeyRing(), + UUID.randomUUID().toString(), + Version.getP2PMessageVersion(), + null, + sourceRequest.getCurrentDate(), + trade.getMaker().getNodeAddress(), + trade.getTaker().getNodeAddress(), + trade.getArbitrator().getNodeAddress(), + trade.getSelf().getReserveTxHash(), + trade.getSelf().getReserveTxHex(), + trade.getSelf().getReserveTxKey(), + model.getXmrWalletService().getAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).get().getAddressString(), + trade.getChallenge()); + + // send request to arbitrator + log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getOfferId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); + processModel.getP2PService().sendEncryptedDirectMessage( + trade.getArbitrator().getNodeAddress(), + trade.getArbitrator().getPubKeyRing(), + arbitratorRequest, + new SendDirectMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived at arbitrator: offerId={}", InitTradeRequest.class.getSimpleName(), trade.getId()); + complete(); + } + @Override + public void onFault(String errorMessage) { + log.warn("Failed to send {} to arbitrator, error={}.", InitTradeRequest.class.getSimpleName(), errorMessage); + failed(); + } + }); } catch (Throwable t) { - failed(t); + failed(t); } } - - private void sendInitTradeRequests(NodeAddress arbitratorNodeAddress, Set<NodeAddress> excludedArbitrators, ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { - sendInitTradeRequest(arbitratorNodeAddress, new SendDirectMessageListener() { - @Override - public void onArrived() { - log.info("{} arrived at arbitrator: offerId={}", InitTradeRequest.class.getSimpleName(), trade.getId()); - resultHandler.handleResult(); - } - - // if unavailable, try alternative arbitrator - @Override - public void onFault(String errorMessage) { - log.warn("Arbitrator {} unavailable: {}", arbitratorNodeAddress, errorMessage); - excludedArbitrators.add(arbitratorNodeAddress); - Arbitrator altArbitrator = DisputeAgentSelection.getLeastUsedArbitrator(processModel.getTradeStatisticsManager(), processModel.getArbitratorManager(), excludedArbitrators); - if (altArbitrator == null) { - errorMessageHandler.handleErrorMessage("Cannot take offer because no arbitrators are available"); - return; - } - log.info("Using alternative arbitrator {}", altArbitrator.getNodeAddress()); - sendInitTradeRequests(altArbitrator.getNodeAddress(), excludedArbitrators, resultHandler, errorMessageHandler); - } - }); - } - - private void sendInitTradeRequest(NodeAddress arbitratorNodeAddress, SendDirectMessageListener listener) { - - // get registered arbitrator - Arbitrator arbitrator = processModel.getUser().getAcceptedArbitratorByAddress(arbitratorNodeAddress); - if (arbitrator == null) throw new RuntimeException("Node address " + arbitratorNodeAddress + " is not a registered arbitrator"); - - // set pub keys - processModel.getArbitrator().setPubKeyRing(arbitrator.getPubKeyRing()); - trade.getArbitrator().setNodeAddress(arbitratorNodeAddress); - trade.getArbitrator().setPubKeyRing(processModel.getArbitrator().getPubKeyRing()); - - // create request to arbitrator - InitTradeRequest makerRequest = (InitTradeRequest) processModel.getTradeMessage(); // taker's InitTradeRequest to maker - InitTradeRequest arbitratorRequest = new InitTradeRequest( - makerRequest.getTradeId(), - makerRequest.getSenderNodeAddress(), - makerRequest.getPubKeyRing(), - makerRequest.getTradeAmount(), - makerRequest.getTradePrice(), - makerRequest.getTradeFee(), - makerRequest.getAccountId(), - makerRequest.getPaymentAccountId(), - makerRequest.getPaymentMethodId(), - makerRequest.getUid(), - Version.getP2PMessageVersion(), - makerRequest.getAccountAgeWitnessSignatureOfOfferId(), - makerRequest.getCurrentDate(), - makerRequest.getMakerNodeAddress(), - makerRequest.getTakerNodeAddress(), - trade.getArbitrator().getNodeAddress(), - processModel.getReserveTx().getHash(), - processModel.getReserveTx().getFullHex(), - processModel.getReserveTx().getKey(), - makerRequest.getPayoutAddress(), - processModel.getMakerSignature()); - - // send request to arbitrator - log.info("Sending {} with offerId {} and uid {} to arbitrator {}", arbitratorRequest.getClass().getSimpleName(), arbitratorRequest.getTradeId(), arbitratorRequest.getUid(), trade.getArbitrator().getNodeAddress()); - processModel.getP2PService().sendEncryptedDirectMessage( - arbitratorNodeAddress, - arbitrator.getPubKeyRing(), - arbitratorRequest, - listener - ); - } } diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToMaker.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToMaker.java new file mode 100644 index 0000000000..1118cc34a7 --- /dev/null +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TakerSendInitTradeRequestToMaker.java @@ -0,0 +1,112 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.trade.protocol.tasks; + +import haveno.common.app.Version; +import haveno.common.taskrunner.TaskRunner; +import haveno.core.offer.Offer; +import haveno.core.trade.HavenoUtils; +import haveno.core.trade.Trade; +import haveno.core.trade.messages.InitTradeRequest; +import haveno.core.trade.messages.TradeProtocolVersion; +import haveno.core.user.User; +import haveno.core.xmr.model.XmrAddressEntry; +import haveno.core.xmr.wallet.XmrWalletService; +import haveno.network.p2p.P2PService; +import haveno.network.p2p.SendDirectMessageListener; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.UUID; + +@Slf4j +public class TakerSendInitTradeRequestToMaker extends TradeTask { + @SuppressWarnings({"unused"}) + public TakerSendInitTradeRequestToMaker(TaskRunner taskHandler, Trade trade) { + super(taskHandler, trade); + } + + @Override + protected void run() { + try { + runInterceptHook(); + + // verify trade state + if (!trade.isBuyerAsTakerWithoutDeposit() && trade.getSelf().getReserveTxHash() == null) { + throw new IllegalStateException("Taker reserve tx id is not initialized: " + trade.getSelf().getReserveTxHash()); + } + + // collect fields + Offer offer = model.getOffer(); + User user = processModel.getUser(); + P2PService p2PService = processModel.getP2PService(); + XmrWalletService walletService = model.getXmrWalletService(); + String payoutAddress = walletService.getOrCreateAddressEntry(offer.getId(), XmrAddressEntry.Context.TRADE_PAYOUT).getAddressString(); + String challenge = model.getChallenge(); + + // taker signs offer using offer id as nonce to avoid challenge protocol + byte[] sig = HavenoUtils.sign(p2PService.getKeyRing(), offer.getId()); + + // create request to maker + InitTradeRequest makerRequest = new InitTradeRequest( + TradeProtocolVersion.MULTISIG_2_3, // TODO: use processModel.getTradeProtocolVersion(), select one of maker's supported versions + offer.getId(), + trade.getAmount().longValueExact(), + trade.getPrice().getValue(), + trade.getSelf().getPaymentMethodId(), + null, + user.getAccountId(), + trade.getMaker().getPaymentAccountId(), + trade.getTaker().getPaymentAccountId(), + p2PService.getKeyRing().getPubKeyRing(), + UUID.randomUUID().toString(), + Version.getP2PMessageVersion(), + sig, + new Date().getTime(), + offer.getMakerNodeAddress(), + P2PService.getMyNodeAddress(), + null, // maker selects arbitrator + null, // reserve tx not sent from taker to maker + null, + null, + payoutAddress, + challenge); + + // send request to maker + log.info("Sending {} with offerId {} and uid {} to maker {}", makerRequest.getClass().getSimpleName(), makerRequest.getOfferId(), makerRequest.getUid(), trade.getMaker().getNodeAddress()); + processModel.getP2PService().sendEncryptedDirectMessage( + trade.getMaker().getNodeAddress(), + trade.getMaker().getPubKeyRing(), + makerRequest, + new SendDirectMessageListener() { + @Override + public void onArrived() { + log.info("{} arrived at maker: offerId={}", InitTradeRequest.class.getSimpleName(), trade.getId()); + complete(); + } + @Override + public void onFault(String errorMessage) { + log.warn("Failed to send {} to maker, error={}.", InitTradeRequest.class.getSimpleName(), errorMessage); + failed(); + } + }); + } catch (Throwable t) { + failed(t); + } + } +} diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/TradeTask.java b/core/src/main/java/haveno/core/trade/protocol/tasks/TradeTask.java index b7e0b8d191..293b74f99d 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/TradeTask.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/TradeTask.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks; @@ -61,7 +61,7 @@ public abstract class TradeTask extends Task<Trade> { @Override protected void failed(Throwable t) { - t.printStackTrace(); + log.error("Trade task failed, error={}\n", t.getMessage(), t); appendExceptionToErrorMessage(t); trade.setErrorMessage(errorMessage); processModel.getTradeManager().requestPersistence(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java b/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java index 7b27486c79..b7d07190a8 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/VerifyPeersAccountAgeWitness.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/FinalizeMediatedPayoutTx.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/FinalizeMediatedPayoutTx.java index 90d44128c6..33bf7b8c58 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/FinalizeMediatedPayoutTx.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/FinalizeMediatedPayoutTx.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutSignatureMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutSignatureMessage.java index aaee1e5534..a4e29c43ff 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutSignatureMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutSignatureMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutTxPublishedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutTxPublishedMessage.java index aced532910..783e0436e2 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutTxPublishedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/ProcessMediatedPayoutTxPublishedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java index 1e863e7606..a11a3e8984 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutSignatureMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; @@ -53,8 +53,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { trade.getId(), p2PService.getAddress(), UUID.randomUUID().toString()); - log.info("Send {} to peer {}. tradeId={}, uid={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("Send {} to peer {}. offerId={}, uid={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); trade.setMediationResultState(MediationResultState.SIG_MSG_SENT); processModel.getTradeManager().requestPersistence(); @@ -64,8 +64,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { new SendMailboxMessageListener() { @Override public void onArrived() { - log.info("{} arrived at peer {}. tradeId={}, uid={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} arrived at peer {}. offerId={}, uid={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); trade.setMediationResultState(MediationResultState.SIG_MSG_ARRIVED); processModel.getTradeManager().requestPersistence(); @@ -74,8 +74,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { @Override public void onStoredInMailbox() { - log.info("{} stored in mailbox for peer {}. tradeId={}, uid={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid()); + log.info("{} stored in mailbox for peer {}. offerId={}, uid={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid()); trade.setMediationResultState(MediationResultState.SIG_MSG_IN_MAILBOX); processModel.getTradeManager().requestPersistence(); @@ -84,8 +84,8 @@ public class SendMediatedPayoutSignatureMessage extends TradeTask { @Override public void onFault(String errorMessage) { - log.error("{} failed: Peer {}. tradeId={}, uid={}, errorMessage={}", - message.getClass().getSimpleName(), peersNodeAddress, message.getTradeId(), message.getUid(), errorMessage); + log.error("{} failed: Peer {}. offerId={}, uid={}, errorMessage={}", + message.getClass().getSimpleName(), peersNodeAddress, message.getOfferId(), message.getUid(), errorMessage); trade.setMediationResultState(MediationResultState.SIG_MSG_SEND_FAILED); appendToErrorMessage("Sending message failed: message=" + message + "\nerrorMessage=" + errorMessage); processModel.getTradeManager().requestPersistence(); diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutTxPublishedMessage.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutTxPublishedMessage.java index bd7775d88f..906859e66e 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutTxPublishedMessage.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SendMediatedPayoutTxPublishedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java index 85d3d14067..2c5ceb8def 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SetupMediatedPayoutTxListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; diff --git a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SignMediatedPayoutTx.java b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SignMediatedPayoutTx.java index 9e33e08e3c..0b00899074 100644 --- a/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SignMediatedPayoutTx.java +++ b/core/src/main/java/haveno/core/trade/protocol/tasks/mediation/SignMediatedPayoutTx.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.protocol.tasks.mediation; diff --git a/core/src/main/java/haveno/core/trade/statistics/ReferralId.java b/core/src/main/java/haveno/core/trade/statistics/ReferralId.java index e6789f2e55..28d2455142 100644 --- a/core/src/main/java/haveno/core/trade/statistics/ReferralId.java +++ b/core/src/main/java/haveno/core/trade/statistics/ReferralId.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; diff --git a/core/src/main/java/haveno/core/trade/statistics/ReferralIdService.java b/core/src/main/java/haveno/core/trade/statistics/ReferralIdService.java index 976432b9cc..efe64307fc 100644 --- a/core/src/main/java/haveno/core/trade/statistics/ReferralIdService.java +++ b/core/src/main/java/haveno/core/trade/statistics/ReferralIdService.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; +import com.google.inject.Inject; import haveno.core.user.Preferences; - -import javax.annotation.Nullable; -import javax.inject.Inject; import java.util.Arrays; import java.util.Optional; +import javax.annotation.Nullable; public class ReferralIdService { private final Preferences preferences; diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java index 8d0defa480..209fad38cf 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; @@ -54,6 +54,8 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.Random; import static com.google.common.base.Preconditions.checkNotNull; @@ -67,10 +69,13 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl @JsonExclude private transient static final ZoneId ZONE_ID = ZoneId.systemDefault(); + private static final double FUZZ_AMOUNT_PCT = 0.05; + private static final int FUZZ_DATE_HOURS = 24; public static TradeStatistics3 from(Trade trade, @Nullable String referralId, - boolean isTorNetworkNode) { + boolean isTorNetworkNode, + boolean isFuzzed) { Map<String, String> extraDataMap = new HashMap<>(); if (referralId != null) { extraDataMap.put(OfferPayload.REFERRAL_ID, referralId); @@ -88,13 +93,30 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl Offer offer = checkNotNull(trade.getOffer()); return new TradeStatistics3(offer.getCurrencyCode(), trade.getPrice().getValue(), - trade.getAmount().longValueExact(), + isFuzzed ? fuzzTradeAmountReproducibly(trade) : trade.getAmount().longValueExact(), offer.getPaymentMethod().getId(), - trade.getTakeOfferDate().getTime(), + isFuzzed ? fuzzTradeDateReproducibly(trade) : trade.getTakeOfferDate().getTime(), truncatedArbitratorNodeAddress, extraDataMap); } + private static long fuzzTradeAmountReproducibly(Trade trade) { // randomize completed trade info #1099 + long originalTimestamp = trade.getTakeOfferDate().getTime(); + long exactAmount = trade.getAmount().longValueExact(); + Random random = new Random(originalTimestamp); // pseudo random generator seeded from take offer datestamp + long adjustedAmount = (long) random.nextDouble(exactAmount * (1.0 - FUZZ_AMOUNT_PCT), exactAmount * (1 + FUZZ_AMOUNT_PCT)); + log.debug("trade {} fuzzed trade amount for tradeStatistics is {}", trade.getShortId(), adjustedAmount); + return adjustedAmount; + } + + private static long fuzzTradeDateReproducibly(Trade trade) { // randomize completed trade info #1099 + long originalTimestamp = trade.getTakeOfferDate().getTime(); + Random random = new Random(originalTimestamp); // pseudo random generator seeded from take offer datestamp + long adjustedTimestamp = random.nextLong(originalTimestamp - TimeUnit.HOURS.toMillis(FUZZ_DATE_HOURS), originalTimestamp); + log.debug("trade {} fuzzed trade datestamp for tradeStatistics is {}", trade.getShortId(), new Date(adjustedTimestamp)); + return adjustedTimestamp; + } + // This enum must not change the order as we use the ordinal for storage to reduce data size. // The payment method string can be quite long and would consume 15% more space. // When we get a new payment method we can add it to the enum at the end. Old users would add it as string if not @@ -155,7 +177,8 @@ public final class TradeStatistics3 implements ProcessOncePersistableNetworkPayl TIKKIE, TRANSFERWISE_USD, ACH_TRANSFER, - DOMESTIC_WIRE_TRANSFER + DOMESTIC_WIRE_TRANSFER, + PAYPAL } @Getter diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3StorageService.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3StorageService.java index deb01a1482..2e6fc42d98 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3StorageService.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3StorageService.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; import haveno.network.p2p.storage.persistence.HistoricalDataStoreService; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; import java.io.File; +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3Store.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3Store.java index 3bf7039f34..2874b6ef59 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3Store.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatistics3Store.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java index f3a553fcfb..774726d259 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsForJson.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; diff --git a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java index 9e762a8e43..b85e6932e6 100644 --- a/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java +++ b/core/src/main/java/haveno/core/trade/statistics/TradeStatisticsManager.java @@ -1,49 +1,48 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade.statistics; import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.file.JsonFileManager; import haveno.core.locale.CurrencyTuple; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.provider.price.PriceFeedService; -import haveno.core.trade.BuyerTrade; import haveno.core.trade.Trade; import haveno.core.util.JsonUtil; import haveno.network.p2p.P2PService; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.persistence.AppendOnlyDataStoreService; -import javafx.collections.FXCollections; -import javafx.collections.ObservableSet; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Named; -import javax.inject.Singleton; import java.io.File; import java.time.Instant; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableSet; +import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j @@ -99,6 +98,11 @@ public class TradeStatisticsManager { .map(e -> (TradeStatistics3) e) .filter(TradeStatistics3::isValid) .collect(Collectors.toSet()); + + + // remove duplicates in early trades due to bug + deduplicateEarlyTradeStatistics(set); + synchronized (observableTradeStatisticsSet) { observableTradeStatisticsSet.addAll(set); priceFeedService.applyLatestHavenoMarketPrice(observableTradeStatisticsSet); @@ -106,6 +110,52 @@ public class TradeStatisticsManager { maybeDumpStatistics(); } + private void deduplicateEarlyTradeStatistics(Set<TradeStatistics3> tradeStats) { + + // collect trades before August 7, 2024 + Set<TradeStatistics3> earlyTrades = tradeStats.stream() + .filter(e -> e.getDate().toInstant().isBefore(Instant.parse("2024-08-07T00:00:00Z"))) + .collect(Collectors.toSet()); + + // collect duplicated trades + Set<TradeStatistics3> duplicates = new HashSet<TradeStatistics3>(); + Set<TradeStatistics3> deduplicates = new HashSet<TradeStatistics3>(); + for (TradeStatistics3 tradeStatistic : earlyTrades) { + TradeStatistics3 fuzzyDuplicate = findFuzzyDuplicate(tradeStatistic, deduplicates); + if (fuzzyDuplicate == null) deduplicates.add(tradeStatistic); + else duplicates.add(tradeStatistic); + } + + // remove duplicated trades + tradeStats.removeAll(duplicates); + } + + private TradeStatistics3 findFuzzyDuplicate(TradeStatistics3 tradeStatistics, Set<TradeStatistics3> set) { + return set.stream().filter(e -> isFuzzyDuplicate(tradeStatistics, e)).findFirst().orElse(null); + } + + private boolean isFuzzyDuplicate(TradeStatistics3 tradeStatistics1, TradeStatistics3 tradeStatistics2) { + if (!tradeStatistics1.getPaymentMethodId().equals(tradeStatistics2.getPaymentMethodId())) return false; + if (!tradeStatistics1.getCurrency().equals(tradeStatistics2.getCurrency())) return false; + if (tradeStatistics1.getPrice() != tradeStatistics2.getPrice()) return false; + return isFuzzyDuplicateV1(tradeStatistics1, tradeStatistics2) || isFuzzyDuplicateV2(tradeStatistics1, tradeStatistics2); + } + + // bug caused all peers to publish same trade with similar timestamps + private boolean isFuzzyDuplicateV1(TradeStatistics3 tradeStatistics1, TradeStatistics3 tradeStatistics2) { + boolean isWithin2Minutes = Math.abs(tradeStatistics1.getDate().getTime() - tradeStatistics2.getDate().getTime()) <= TimeUnit.MINUTES.toMillis(2); + return isWithin2Minutes; + } + + // bug caused sellers to re-publish their trades with randomized amounts + private static final double FUZZ_AMOUNT_PCT = 0.05; + private static final int FUZZ_DATE_HOURS = 24; + private boolean isFuzzyDuplicateV2(TradeStatistics3 tradeStatistics1, TradeStatistics3 tradeStatistics2) { + boolean isWithinFuzzedHours = Math.abs(tradeStatistics1.getDate().getTime() - tradeStatistics2.getDate().getTime()) <= TimeUnit.HOURS.toMillis(FUZZ_DATE_HOURS); + boolean isWithinFuzzedAmount = Math.abs(tradeStatistics1.getAmount() - tradeStatistics2.getAmount()) <= FUZZ_AMOUNT_PCT * tradeStatistics1.getAmount(); + return isWithinFuzzedHours && isWithinFuzzedAmount; + } + public ObservableSet<TradeStatistics3> getObservableTradeStatisticsSet() { return observableTradeStatisticsSet; } @@ -164,21 +214,30 @@ public class TradeStatisticsManager { long ts = System.currentTimeMillis(); Set<P2PDataStorage.ByteArray> hashes = tradeStatistics3StorageService.getMapOfAllData().keySet(); trades.forEach(trade -> { - if (trade instanceof BuyerTrade) { - log.debug("Trade: {} is a buyer trade, we only republish we have been seller.", - trade.getShortId()); + if (!trade.shouldPublishTradeStatistics()) { + log.debug("Trade: {} should not publish trade statistics", trade.getShortId()); return; } TradeStatistics3 tradeStatistics3 = null; try { - tradeStatistics3 = TradeStatistics3.from(trade, referralId, isTorNetworkNode); + tradeStatistics3 = TradeStatistics3.from(trade, referralId, isTorNetworkNode, false); } catch (Exception e) { log.warn("Error getting trade statistic for {} {}: {}", trade.getClass().getName(), trade.getId(), e.getMessage()); return; } + + TradeStatistics3 tradeStatistics3Fuzzed = null; + try { + tradeStatistics3Fuzzed = TradeStatistics3.from(trade, referralId, isTorNetworkNode, true); + } catch (Exception e) { + log.warn("Error getting trade statistic for {} {}: {}", trade.getClass().getName(), trade.getId(), e.getMessage()); + return; + } + boolean hasTradeStatistics3 = hashes.contains(new P2PDataStorage.ByteArray(tradeStatistics3.getHash())); - if (hasTradeStatistics3) { + boolean hasTradeStatistics3Fuzzed = hashes.contains(new P2PDataStorage.ByteArray(tradeStatistics3Fuzzed.getHash())); + if (hasTradeStatistics3 || hasTradeStatistics3Fuzzed) { log.debug("Trade: {}. We have already a tradeStatistics matching the hash of tradeStatistics3.", trade.getShortId()); return; diff --git a/core/src/main/java/haveno/core/user/AutoConfirmSettings.java b/core/src/main/java/haveno/core/user/AutoConfirmSettings.java index 7b0a2590ae..55f7db1722 100644 --- a/core/src/main/java/haveno/core/user/AutoConfirmSettings.java +++ b/core/src/main/java/haveno/core/user/AutoConfirmSettings.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; diff --git a/core/src/main/java/haveno/core/user/BlockChainExplorer.java b/core/src/main/java/haveno/core/user/BlockChainExplorer.java index 37b8274560..d574f51aff 100644 --- a/core/src/main/java/haveno/core/user/BlockChainExplorer.java +++ b/core/src/main/java/haveno/core/user/BlockChainExplorer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; diff --git a/core/src/main/java/haveno/core/user/Cookie.java b/core/src/main/java/haveno/core/user/Cookie.java index 8299482ca8..8976e9cbe0 100644 --- a/core/src/main/java/haveno/core/user/Cookie.java +++ b/core/src/main/java/haveno/core/user/Cookie.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; diff --git a/core/src/main/java/haveno/core/user/CookieKey.java b/core/src/main/java/haveno/core/user/CookieKey.java index 8276cfda76..d729529cce 100644 --- a/core/src/main/java/haveno/core/user/CookieKey.java +++ b/core/src/main/java/haveno/core/user/CookieKey.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; diff --git a/core/src/main/java/haveno/core/user/DontShowAgainLookup.java b/core/src/main/java/haveno/core/user/DontShowAgainLookup.java index c1ed8d9d48..3c9a499697 100644 --- a/core/src/main/java/haveno/core/user/DontShowAgainLookup.java +++ b/core/src/main/java/haveno/core/user/DontShowAgainLookup.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; diff --git a/core/src/main/java/haveno/core/user/Preferences.java b/core/src/main/java/haveno/core/user/Preferences.java index 4d08046a9b..a3756041bf 100644 --- a/core/src/main/java/haveno/core/user/Preferences.java +++ b/core/src/main/java/haveno/core/user/Preferences.java @@ -1,22 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.config.BaseCurrencyNetwork; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; @@ -26,15 +30,24 @@ import haveno.core.locale.Country; import haveno.core.locale.CountryUtil; import haveno.core.locale.CryptoCurrency; import haveno.core.locale.CurrencyUtil; -import haveno.core.locale.TraditionalCurrency; import haveno.core.locale.GlobalSettings; import haveno.core.locale.TradeCurrency; +import haveno.core.locale.TraditionalCurrency; import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccountUtil; -import haveno.core.xmr.MoneroNodeSettings; +import haveno.core.xmr.XmrNodeSettings; import haveno.core.xmr.nodes.XmrNodes; +import haveno.core.xmr.nodes.XmrNodes.MoneroNodesOption; +import haveno.core.xmr.nodes.XmrNodesSetupPreferences; import haveno.core.xmr.wallet.Restrictions; import haveno.network.p2p.network.BridgeAddressProvider; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -43,30 +56,17 @@ import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; import javafx.collections.ObservableMap; +import javax.annotation.Nullable; import lombok.Getter; import lombok.Setter; import lombok.experimental.Delegate; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; - @Slf4j @Singleton public final class Preferences implements PersistedDataHost, BridgeAddressProvider { - + public enum UseTorForXmr { AFTER_SYNC, OFF, @@ -131,8 +131,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid private final PersistenceManager<PreferencesPayload> persistenceManager; private final Config config; private final String xmrNodesFromOptions; + private final XmrNodes xmrNodes; @Getter private final BooleanProperty useStandbyModeProperty = new SimpleBooleanProperty(prefPayload.isUseStandbyMode()); + @Getter + private final BooleanProperty useSoundForNotificationsProperty = new SimpleBooleanProperty(prefPayload.isUseSoundForNotifications()); /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -141,11 +144,13 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid @Inject public Preferences(PersistenceManager<PreferencesPayload> persistenceManager, Config config, - @Named(Config.XMR_NODES) String xmrNodesFromOptions) { + @Named(Config.XMR_NODES) String xmrNodesFromOptions, + XmrNodes xmrNodes) { this.persistenceManager = persistenceManager; this.config = config; this.xmrNodesFromOptions = xmrNodesFromOptions; + this.xmrNodes = xmrNodes; useAnimationsProperty.addListener((ov) -> { prefPayload.setUseAnimations(useAnimationsProperty.get()); @@ -163,6 +168,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); }); + useSoundForNotificationsProperty.addListener((ov) -> { + prefPayload.setUseSoundForNotifications(useSoundForNotificationsProperty.get()); + requestPersistence(); + }); + traditionalCurrenciesAsObservable.addListener((javafx.beans.Observable ov) -> { prefPayload.getTraditionalCurrencies().clear(); prefPayload.getTraditionalCurrencies().addAll(traditionalCurrenciesAsObservable); @@ -260,14 +270,15 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid // set all properties useAnimationsProperty.set(prefPayload.isUseAnimations()); useStandbyModeProperty.set(prefPayload.isUseStandbyMode()); + useSoundForNotificationsProperty.set(prefPayload.isUseSoundForNotifications()); cssThemeProperty.set(prefPayload.getCssTheme()); - // if no valid Bitcoin block explorer is set, select the 1st valid Bitcoin block explorer - ArrayList<BlockChainExplorer> btcExplorers = getBlockChainExplorers(); + // if no valid Monero block explorer is set, select the 1st valid Monero block explorer + ArrayList<BlockChainExplorer> xmrExplorers = getBlockChainExplorers(); if (getBlockChainExplorer() == null || getBlockChainExplorer().name.length() == 0) { - setBlockChainExplorer(btcExplorers.get(0)); + setBlockChainExplorer(xmrExplorers.get(0)); } tradeCurrenciesAsObservable.addAll(prefPayload.getTraditionalCurrencies()); tradeCurrenciesAsObservable.addAll(prefPayload.getCryptoCurrencies()); @@ -277,10 +288,16 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid if (config.useTorForXmrOptionSetExplicitly) setUseTorForXmr(config.useTorForXmr); + // switch to public nodes if no provided nodes available + if (getMoneroNodesOptionOrdinal() == XmrNodes.MoneroNodesOption.PROVIDED.ordinal() && xmrNodes.selectPreferredNodes(new XmrNodesSetupPreferences(this)).isEmpty()) { + log.warn("No provided nodes available, switching to public nodes"); + setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.PUBLIC.ordinal()); + } + if (xmrNodesFromOptions != null && !xmrNodesFromOptions.isEmpty()) { if (getMoneroNodes() != null && !getMoneroNodes().equals(xmrNodesFromOptions)) { - log.warn("The Bitcoin node(s) from the program argument and the one(s) persisted in the UI are different. " + - "The Bitcoin node(s) {} from the program argument will be used.", xmrNodesFromOptions); + log.warn("The Monero node(s) from the program argument and the one(s) persisted in the UI are different. " + + "The Monero node(s) {} from the program argument will be used.", xmrNodesFromOptions); } setMoneroNodes(xmrNodesFromOptions); setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.CUSTOM.ordinal()); @@ -307,6 +324,12 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid }); } + // enable sounds by default for existing clients (protobuf does not express that new field is unset) + if (!prefPayload.isUseSoundForNotificationsInitialized()) { + prefPayload.setUseSoundForNotificationsInitialized(true); + setUseSoundForNotifications(true); + } + initialReadDone = true; requestPersistence(); } @@ -316,6 +339,10 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid // API /////////////////////////////////////////////////////////////////////////////////////////// + public MoneroNodesOption getMoneroNodesOption() { + return XmrNodes.MoneroNodesOption.values()[getMoneroNodesOptionOrdinal()]; + } + public void dontShowAgain(String key, boolean dontShowAgain) { prefPayload.getDontShowAgainMap().put(key, dontShowAgain); requestPersistence(); @@ -539,6 +566,16 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); } + public void setBuyScreenOtherCurrencyCode(String buyScreenCurrencyCode) { + prefPayload.setBuyScreenOtherCurrencyCode(buyScreenCurrencyCode); + requestPersistence(); + } + + public void setSellScreenOtherCurrencyCode(String sellScreenCurrencyCode) { + prefPayload.setSellScreenOtherCurrencyCode(sellScreenCurrencyCode); + requestPersistence(); + } + public void setIgnoreTradersList(List<String> ignoreTradersList) { prefPayload.setIgnoreTradersList(ignoreTradersList); requestPersistence(); @@ -564,8 +601,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); } - public void setMoneroNodes(String bitcoinNodes) { - prefPayload.setMoneroNodes(bitcoinNodes); + public void setMoneroNodes(String moneroNodes) { + prefPayload.setMoneroNodes(moneroNodes); requestPersistence(); } @@ -579,14 +616,14 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); } - public void setBuyerSecurityDepositAsPercent(double buyerSecurityDepositAsPercent, PaymentAccount paymentAccount) { - double max = Restrictions.getMaxBuyerSecurityDepositAsPercent(); - double min = Restrictions.getMinBuyerSecurityDepositAsPercent(); + public void setSecurityDepositAsPercent(double securityDepositAsPercent, PaymentAccount paymentAccount) { + double max = Restrictions.getMaxSecurityDepositAsPercent(); + double min = Restrictions.getMinSecurityDepositAsPercent(); if (PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount)) - prefPayload.setBuyerSecurityDepositAsPercentForCrypto(Math.min(max, Math.max(min, buyerSecurityDepositAsPercent))); + prefPayload.setSecurityDepositAsPercentForCrypto(Math.min(max, Math.max(min, securityDepositAsPercent))); else - prefPayload.setBuyerSecurityDepositAsPercent(Math.min(max, Math.max(min, buyerSecurityDepositAsPercent))); + prefPayload.setSecurityDepositAsPercent(Math.min(max, Math.max(min, securityDepositAsPercent))); requestPersistence(); } @@ -649,14 +686,14 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid prefPayload.setCustomBridges(customBridges); persistenceManager.forcePersistNow(); } - + public void setUseTorForXmrOrdinal(int useTorForXmrOrdinal) { prefPayload.setUseTorForXmrOrdinal(useTorForXmrOrdinal); requestPersistence(); } - public void setMoneroNodesOptionOrdinal(int bitcoinNodesOptionOrdinal) { - prefPayload.setMoneroNodesOptionOrdinal(bitcoinNodesOptionOrdinal); + public void setMoneroNodesOptionOrdinal(int moneroNodesOptionOrdinal) { + prefPayload.setMoneroNodesOptionOrdinal(moneroNodesOptionOrdinal); requestPersistence(); } @@ -694,6 +731,10 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid this.useStandbyModeProperty.set(useStandbyMode); } + public void setUseSoundForNotifications(boolean useSoundForNotifications) { + this.useSoundForNotificationsProperty.set(useSoundForNotifications); + } + public void setTakeOfferSelectedPaymentAccountId(String value) { prefPayload.setTakeOfferSelectedPaymentAccountId(value); requestPersistence(); @@ -714,6 +755,11 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); } + public void setShowPrivateOffers(boolean value) { + prefPayload.setShowPrivateOffers(value); + requestPersistence(); + } + public void setDenyApiTaker(boolean value) { prefPayload.setDenyApiTaker(value); requestPersistence(); @@ -724,8 +770,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid requestPersistence(); } - public void setMoneroNodeSettings(MoneroNodeSettings settings) { - prefPayload.setMoneroNodeSettings(settings); + public void setXmrNodeSettings(XmrNodeSettings settings) { + prefPayload.setXmrNodeSettings(settings); requestPersistence(); } @@ -797,16 +843,16 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid return prefPayload.isSplitOfferOutput(); } - public double getBuyerSecurityDepositAsPercent(PaymentAccount paymentAccount) { + public double getSecurityDepositAsPercent(PaymentAccount paymentAccount) { double value = PaymentAccountUtil.isCryptoCurrencyAccount(paymentAccount) ? - prefPayload.getBuyerSecurityDepositAsPercentForCrypto() : prefPayload.getBuyerSecurityDepositAsPercent(); + prefPayload.getSecurityDepositAsPercentForCrypto() : prefPayload.getSecurityDepositAsPercent(); - if (value < Restrictions.getMinBuyerSecurityDepositAsPercent()) { - value = Restrictions.getMinBuyerSecurityDepositAsPercent(); - setBuyerSecurityDepositAsPercent(value, paymentAccount); + if (value < Restrictions.getMinSecurityDepositAsPercent()) { + value = Restrictions.getMinSecurityDepositAsPercent(); + setSecurityDepositAsPercent(value, paymentAccount); } - return value == 0 ? Restrictions.getDefaultBuyerSecurityDepositAsPercent() : value; + return value == 0 ? Restrictions.getDefaultSecurityDepositAsPercent() : value; } @Override @@ -889,7 +935,7 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid void setSortMarketCurrenciesNumerically(boolean sortMarketCurrenciesNumerically); - void setMoneroNodes(String bitcoinNodes); + void setMoneroNodes(String moneroNodes); void setUseCustomWithdrawalTxFee(boolean useCustomWithdrawalTxFee); @@ -920,10 +966,10 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid void setTorTransportOrdinal(int torTransportOrdinal); void setCustomBridges(String customBridges); - + void setUseTorForXmrOrdinal(int useTorForXmrOrdinal); - void setMoneroNodesOptionOrdinal(int bitcoinNodesOption); + void setMoneroNodesOptionOrdinal(int moneroNodesOption); void setReferralId(String referralId); @@ -943,6 +989,8 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid void setUseStandbyMode(boolean useStandbyMode); + void setUseSoundForNotifications(boolean useSoundForNotifications); + void setTakeOfferSelectedPaymentAccountId(String value); void setIgnoreDustThreshold(int value); @@ -977,6 +1025,6 @@ public final class Preferences implements PersistedDataHost, BridgeAddressProvid void setNotifyOnPreRelease(boolean value); - void setMoneroNodeSettings(MoneroNodeSettings settings); + void setXmrNodeSettings(XmrNodeSettings settings); } } diff --git a/core/src/main/java/haveno/core/user/PreferencesPayload.java b/core/src/main/java/haveno/core/user/PreferencesPayload.java index f82034b53e..44e6aef509 100644 --- a/core/src/main/java/haveno/core/user/PreferencesPayload.java +++ b/core/src/main/java/haveno/core/user/PreferencesPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; @@ -28,7 +28,7 @@ import haveno.core.locale.TraditionalCurrency; import haveno.core.locale.TradeCurrency; import haveno.core.payment.PaymentAccount; import haveno.core.proto.CoreProtoResolver; -import haveno.core.xmr.MoneroNodeSettings; +import haveno.core.xmr.XmrNodeSettings; import lombok.AllArgsConstructor; import lombok.Data; import lombok.extern.slf4j.Slf4j; @@ -41,7 +41,7 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import static haveno.core.xmr.wallet.Restrictions.getDefaultBuyerSecurityDepositAsPercent; +import static haveno.core.xmr.wallet.Restrictions.getDefaultSecurityDepositAsPercent; @Slf4j @Data @@ -77,6 +77,10 @@ public final class PreferencesPayload implements PersistableEnvelope { private String buyScreenCryptoCurrencyCode; @Nullable private String sellScreenCryptoCurrencyCode; + @Nullable + private String buyScreenOtherCurrencyCode; + @Nullable + private String sellScreenOtherCurrencyCode; private int tradeStatisticsTickUnitIndex = 3; private boolean resyncSpvRequested; private boolean sortMarketCurrenciesNumerically = true; @@ -108,16 +112,18 @@ public final class PreferencesPayload implements PersistableEnvelope { private boolean useMarketNotifications = true; private boolean usePriceNotifications = true; private boolean useStandbyMode = false; + private boolean useSoundForNotifications = true; + private boolean useSoundForNotificationsInitialized = false; @Nullable private String rpcUser; @Nullable private String rpcPw; @Nullable private String takeOfferSelectedPaymentAccountId; - private double buyerSecurityDepositAsPercent = getDefaultBuyerSecurityDepositAsPercent(); + private double securityDepositAsPercent = getDefaultSecurityDepositAsPercent(); private int ignoreDustThreshold = 600; private int clearDataAfterDays = Preferences.CLEAR_DATA_AFTER_DAYS_INITIAL; - private double buyerSecurityDepositAsPercentForCrypto = getDefaultBuyerSecurityDepositAsPercent(); + private double securityDepositAsPercentForCrypto = getDefaultSecurityDepositAsPercent(); private int blockNotifyPort; private boolean tacAcceptedV120; private double bsqAverageTrimThreshold = 0.05; @@ -128,10 +134,11 @@ public final class PreferencesPayload implements PersistableEnvelope { // Added in 1.5.5 private boolean hideNonAccountPaymentMethods; private boolean showOffersMatchingMyAccounts; + private boolean showPrivateOffers; private boolean denyApiTaker; private boolean notifyOnPreRelease; - private MoneroNodeSettings moneroNodeSettings; + private XmrNodeSettings xmrNodeSettings = new XmrNodeSettings(); /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -185,10 +192,12 @@ public final class PreferencesPayload implements PersistableEnvelope { .setUseMarketNotifications(useMarketNotifications) .setUsePriceNotifications(usePriceNotifications) .setUseStandbyMode(useStandbyMode) - .setBuyerSecurityDepositAsPercent(buyerSecurityDepositAsPercent) + .setUseSoundForNotifications(useSoundForNotifications) + .setUseSoundForNotificationsInitialized(useSoundForNotificationsInitialized) + .setSecurityDepositAsPercent(securityDepositAsPercent) .setIgnoreDustThreshold(ignoreDustThreshold) .setClearDataAfterDays(clearDataAfterDays) - .setBuyerSecurityDepositAsPercentForCrypto(buyerSecurityDepositAsPercentForCrypto) + .setSecurityDepositAsPercentForCrypto(securityDepositAsPercentForCrypto) .setBlockNotifyPort(blockNotifyPort) .setTacAcceptedV120(tacAcceptedV120) .setBsqAverageTrimThreshold(bsqAverageTrimThreshold) @@ -197,6 +206,7 @@ public final class PreferencesPayload implements PersistableEnvelope { .collect(Collectors.toList())) .setHideNonAccountPaymentMethods(hideNonAccountPaymentMethods) .setShowOffersMatchingMyAccounts(showOffersMatchingMyAccounts) + .setShowPrivateOffers(showPrivateOffers) .setDenyApiTaker(denyApiTaker) .setNotifyOnPreRelease(notifyOnPreRelease); @@ -208,6 +218,8 @@ public final class PreferencesPayload implements PersistableEnvelope { Optional.ofNullable(sellScreenCurrencyCode).ifPresent(builder::setSellScreenCurrencyCode); Optional.ofNullable(buyScreenCryptoCurrencyCode).ifPresent(builder::setBuyScreenCryptoCurrencyCode); Optional.ofNullable(sellScreenCryptoCurrencyCode).ifPresent(builder::setSellScreenCryptoCurrencyCode); + Optional.ofNullable(buyScreenOtherCurrencyCode).ifPresent(builder::setBuyScreenOtherCurrencyCode); + Optional.ofNullable(sellScreenOtherCurrencyCode).ifPresent(builder::setSellScreenOtherCurrencyCode); Optional.ofNullable(selectedPaymentAccountForCreateOffer).ifPresent( account -> builder.setSelectedPaymentAccountForCreateOffer(selectedPaymentAccountForCreateOffer.toProtoMessage())); Optional.ofNullable(bridgeAddresses).ifPresent(builder::addAllBridgeAddresses); @@ -217,7 +229,7 @@ public final class PreferencesPayload implements PersistableEnvelope { Optional.ofNullable(rpcUser).ifPresent(builder::setRpcUser); Optional.ofNullable(rpcPw).ifPresent(builder::setRpcPw); Optional.ofNullable(takeOfferSelectedPaymentAccountId).ifPresent(builder::setTakeOfferSelectedPaymentAccountId); - Optional.ofNullable(moneroNodeSettings).ifPresent(settings -> builder.setMoneroNodeSettings(settings.toProtoMessage())); + Optional.ofNullable(xmrNodeSettings).ifPresent(settings -> builder.setXmrNodeSettings(settings.toProtoMessage())); return protobuf.PersistableEnvelope.newBuilder().setPreferencesPayload(builder).build(); } @@ -256,6 +268,8 @@ public final class PreferencesPayload implements PersistableEnvelope { ProtoUtil.stringOrNullFromProto(proto.getSellScreenCurrencyCode()), ProtoUtil.stringOrNullFromProto(proto.getBuyScreenCryptoCurrencyCode()), ProtoUtil.stringOrNullFromProto(proto.getSellScreenCryptoCurrencyCode()), + ProtoUtil.stringOrNullFromProto(proto.getBuyScreenOtherCurrencyCode()), + ProtoUtil.stringOrNullFromProto(proto.getSellScreenOtherCurrencyCode()), proto.getTradeStatisticsTickUnitIndex(), proto.getResyncSpvRequested(), proto.getSortMarketCurrenciesNumerically(), @@ -280,13 +294,15 @@ public final class PreferencesPayload implements PersistableEnvelope { proto.getUseMarketNotifications(), proto.getUsePriceNotifications(), proto.getUseStandbyMode(), + proto.getUseSoundForNotifications(), + proto.getUseSoundForNotificationsInitialized(), proto.getRpcUser().isEmpty() ? null : proto.getRpcUser(), proto.getRpcPw().isEmpty() ? null : proto.getRpcPw(), proto.getTakeOfferSelectedPaymentAccountId().isEmpty() ? null : proto.getTakeOfferSelectedPaymentAccountId(), - proto.getBuyerSecurityDepositAsPercent(), + proto.getSecurityDepositAsPercent(), proto.getIgnoreDustThreshold(), proto.getClearDataAfterDays(), - proto.getBuyerSecurityDepositAsPercentForCrypto(), + proto.getSecurityDepositAsPercentForCrypto(), proto.getBlockNotifyPort(), proto.getTacAcceptedV120(), proto.getBsqAverageTrimThreshold(), @@ -296,9 +312,10 @@ public final class PreferencesPayload implements PersistableEnvelope { .collect(Collectors.toList())), proto.getHideNonAccountPaymentMethods(), proto.getShowOffersMatchingMyAccounts(), + proto.getShowPrivateOffers(), proto.getDenyApiTaker(), proto.getNotifyOnPreRelease(), - MoneroNodeSettings.fromProto(proto.getMoneroNodeSettings()) + XmrNodeSettings.fromProto(proto.getXmrNodeSettings()) ); } } diff --git a/core/src/main/java/haveno/core/user/User.java b/core/src/main/java/haveno/core/user/User.java index 4a5e6cd56f..13eace6281 100644 --- a/core/src/main/java/haveno/core/user/User.java +++ b/core/src/main/java/haveno/core/user/User.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.KeyRing; import haveno.common.persistence.PersistenceManager; import haveno.common.proto.persistable.PersistedDataHost; @@ -31,26 +34,21 @@ import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.core.support.dispute.mediation.mediator.Mediator; import haveno.core.support.dispute.refund.refundagent.RefundAgent; import haveno.network.p2p.NodeAddress; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.ReadOnlyObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.FXCollections; -import javafx.collections.ObservableSet; -import javafx.collections.SetChangeListener; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ReadOnlyObjectProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.collections.FXCollections; +import javafx.collections.ObservableSet; +import javafx.collections.SetChangeListener; +import javax.annotation.Nullable; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; /** * The User is persisted locally. @@ -374,6 +372,11 @@ public class User implements PersistedDataHost { requestPersistence(); } + public void setWalletCreationDate(long walletCreationDate) { + userPayload.setWalletCreationDate(walletCreationDate); + requestPersistence(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// @@ -521,4 +524,8 @@ public class User implements PersistedDataHost { public Cookie getCookie() { return userPayload.getCookie(); } + + public long getWalletCreationDate() { + return userPayload.getWalletCreationDate(); + } } diff --git a/core/src/main/java/haveno/core/user/UserPayload.java b/core/src/main/java/haveno/core/user/UserPayload.java index 539b2e5247..934f987aed 100644 --- a/core/src/main/java/haveno/core/user/UserPayload.java +++ b/core/src/main/java/haveno/core/user/UserPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; @@ -82,6 +82,7 @@ public class UserPayload implements PersistableEnvelope { // Generic map for persisting various UI states. We keep values un-typed as string to // provide sufficient flexibility. private Cookie cookie = new Cookie(); + private long walletCreationDate; public UserPayload() { } @@ -122,6 +123,7 @@ public class UserPayload implements PersistableEnvelope { .ifPresent(e -> builder.addAllAcceptedRefundAgents(ProtoUtil.collectionToProto(acceptedRefundAgents, message -> ((protobuf.StoragePayload) message).getRefundAgent()))); Optional.ofNullable(cookie).ifPresent(e -> builder.putAllCookie(cookie.toProtoMessage())); + builder.setWalletCreationDate(walletCreationDate); return protobuf.PersistableEnvelope.newBuilder().setUserPayload(builder).build(); } @@ -153,7 +155,8 @@ public class UserPayload implements PersistableEnvelope { proto.getAcceptedRefundAgentsList().isEmpty() ? new ArrayList<>() : new ArrayList<>(proto.getAcceptedRefundAgentsList().stream() .map(RefundAgent::fromProto) .collect(Collectors.toList())), - Cookie.fromProto(proto.getCookieMap()) + Cookie.fromProto(proto.getCookieMap()), + proto.getWalletCreationDate() ); } } diff --git a/core/src/main/java/haveno/core/util/AveragePriceUtil.java b/core/src/main/java/haveno/core/util/AveragePriceUtil.java index 4790b9f3bd..b548c0120f 100644 --- a/core/src/main/java/haveno/core/util/AveragePriceUtil.java +++ b/core/src/main/java/haveno/core/util/AveragePriceUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; diff --git a/core/src/test/java/haveno/core/util/GenerateKeypairs.java b/core/src/main/java/haveno/core/util/GenerateKeyPairs.java similarity index 66% rename from core/src/test/java/haveno/core/util/GenerateKeypairs.java rename to core/src/main/java/haveno/core/util/GenerateKeyPairs.java index ce36afc586..94130b1b12 100644 --- a/core/src/test/java/haveno/core/util/GenerateKeypairs.java +++ b/core/src/main/java/haveno/core/util/GenerateKeyPairs.java @@ -12,29 +12,29 @@ import org.bitcoinj.core.Utils; import haveno.common.crypto.Encryption; /** - * This utility generates and prints public/private keypairs + * This utility generates and prints public/private key-pairs * which can be used to register arbitrators on the network. */ -public class GenerateKeypairs { - +public class GenerateKeyPairs { + public static void main(String[] args) { - - // generate public/private keypairs - List<SecretKey> secretKeys = new ArrayList<SecretKey>(); + + // generate public/private key-pairs + List<SecretKey> secretKeys = new ArrayList<>(); for (int i = 0; i < 20; i++) { secretKeys.add(Encryption.generateSecretKey(256)); } - // print keypairs + // print key-pairs System.out.println("Private keys:"); for (SecretKey sk : secretKeys) { - String privKey = Utils.HEX.encode(sk.getEncoded()); - System.out.println(privKey); + String privateKey = Utils.HEX.encode(sk.getEncoded()); + System.out.println(privateKey); } System.out.println("Corresponding public keys:"); for (SecretKey sk : secretKeys) { - String privKey = Utils.HEX.encode(sk.getEncoded()); - ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privKey))); + String privateKey = Utils.HEX.encode(sk.getEncoded()); + ECKey ecKey = ECKey.fromPrivate(new BigInteger(1, Utils.HEX.decode(privateKey))); String pubKey = Utils.HEX.encode(ecKey.getPubKey()); System.out.println(pubKey); } diff --git a/core/src/main/java/haveno/core/util/InlierUtil.java b/core/src/main/java/haveno/core/util/InlierUtil.java index 4b7e522a63..94d11799e4 100644 --- a/core/src/main/java/haveno/core/util/InlierUtil.java +++ b/core/src/main/java/haveno/core/util/InlierUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; diff --git a/core/src/main/java/haveno/core/util/JsonUtil.java b/core/src/main/java/haveno/core/util/JsonUtil.java index 04f5bb612a..014f170ef3 100644 --- a/core/src/main/java/haveno/core/util/JsonUtil.java +++ b/core/src/main/java/haveno/core/util/JsonUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; diff --git a/core/src/main/java/haveno/core/util/PriceUtil.java b/core/src/main/java/haveno/core/util/PriceUtil.java index e00806b331..35a6b0bec8 100644 --- a/core/src/main/java/haveno/core/util/PriceUtil.java +++ b/core/src/main/java/haveno/core/util/PriceUtil.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.util.MathUtils; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -29,17 +32,12 @@ import haveno.core.provider.price.MarketPrice; import haveno.core.provider.price.PriceFeedService; import haveno.core.trade.statistics.TradeStatisticsManager; import haveno.core.user.Preferences; -import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.AmountValidator4Decimals; +import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.MonetaryValidator; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.Optional; - -import static com.google.common.base.Preconditions.checkNotNull; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton @@ -196,10 +194,9 @@ public class PriceUtil { return FormattingUtils.formatRoundedDoubleWithPrecision(priceAsDouble, precision); } - public static String formatMarketPrice(long price, String currencyCode) { - int marketPricePrecision = getMarketPricePrecision(currencyCode); - double scaled = MathUtils.scaleDownByPowerOf10(price, marketPricePrecision); - return FormattingUtils.formatMarketPrice(scaled, marketPricePrecision); + public static String formatMarketPrice(long priceAsLong, String currencyCode) { + Price price = Price.valueOf(currencyCode, priceAsLong); + return FormattingUtils.formatPrice(price); } public static int getMarketPricePrecision(String currencyCode) { diff --git a/core/src/main/java/haveno/core/util/SimpleMarkdownParser.java b/core/src/main/java/haveno/core/util/SimpleMarkdownParser.java index 1e1e37b5a5..7a076059d6 100644 --- a/core/src/main/java/haveno/core/util/SimpleMarkdownParser.java +++ b/core/src/main/java/haveno/core/util/SimpleMarkdownParser.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; diff --git a/core/src/main/java/haveno/core/util/Validator.java b/core/src/main/java/haveno/core/util/Validator.java index b1f5edde1b..fa2807ab31 100644 --- a/core/src/main/java/haveno/core/util/Validator.java +++ b/core/src/main/java/haveno/core/util/Validator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; @@ -56,6 +56,6 @@ public class Validator { } public static boolean isTradeIdValid(String tradeId, TradeMessage tradeMessage) { - return tradeId.equals(tradeMessage.getTradeId()); + return tradeId.equals(tradeMessage.getOfferId()); } } diff --git a/core/src/main/java/haveno/core/util/VolumeUtil.java b/core/src/main/java/haveno/core/util/VolumeUtil.java index 816390a637..b74a70f226 100644 --- a/core/src/main/java/haveno/core/util/VolumeUtil.java +++ b/core/src/main/java/haveno/core/util/VolumeUtil.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -65,7 +82,7 @@ public class VolumeUtil { } public static Volume getRoundedVolumePrecise(Volume volumeByAmount) { - DecimalFormat decimalFormat = new DecimalFormat("#.####"); + DecimalFormat decimalFormat = new DecimalFormat("#.####", HavenoUtils.DECIMAL_FORMAT_SYMBOLS); double roundedVolume = Double.parseDouble(decimalFormat.format(Double.parseDouble(volumeByAmount.toString()))); return Volume.parse(String.valueOf(roundedVolume), volumeByAmount.getCurrencyCode()); } @@ -151,11 +168,11 @@ public class VolumeUtil { } public static String formatVolume(Volume volume, boolean appendCode) { - return formatVolume(volume, getMonetaryFormat(volume.getCurrencyCode()), appendCode); + return formatVolume(volume, volume == null ? null : getMonetaryFormat(volume.getCurrencyCode()), appendCode); } public static String formatAverageVolumeWithCode(Volume volume) { - return formatVolume(volume, getMonetaryFormat(volume.getCurrencyCode()).minDecimals(2), true); + return formatVolume(volume, volume == null ? null : getMonetaryFormat(volume.getCurrencyCode()).minDecimals(2), true); } public static String formatVolumeLabel(String currencyCode) { diff --git a/core/src/main/java/haveno/core/util/coin/CoinUtil.java b/core/src/main/java/haveno/core/util/coin/CoinUtil.java index 4ad5625141..bf194b3ea0 100644 --- a/core/src/main/java/haveno/core/util/coin/CoinUtil.java +++ b/core/src/main/java/haveno/core/util/coin/CoinUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.coin; @@ -29,6 +29,7 @@ import org.bitcoinj.core.Coin; import java.math.BigDecimal; import java.math.BigInteger; +import java.math.RoundingMode; import java.text.DecimalFormat; import static com.google.common.base.Preconditions.checkArgument; @@ -45,52 +46,47 @@ public class CoinUtil { return a.compareTo(b) >= 0 ? a : b; } - public static double getFeePerVbyte(Coin miningFee, int txVsize) { - double value = miningFee != null ? miningFee.value : 0; - return MathUtils.roundDouble((value / (double) txVsize), 2); - } - /** - * @param value Btc amount to be converted to percent value. E.g. 0.01 BTC is 1% (of 1 BTC) + * @param value Xmr amount to be converted to percent value. E.g. 0.01 XMR is 1% (of 1 XMR) * @return The percentage value as double (e.g. 1% is 0.01) */ - public static double getAsPercentPerBtc(BigInteger value) { - return getAsPercentPerBtc(value, HavenoUtils.xmrToAtomicUnits(1.0)); + public static double getAsPercentPerXmr(BigInteger value) { + return getAsPercentPerXmr(value, HavenoUtils.xmrToAtomicUnits(1.0)); } /** - * @param part Btc amount to be converted to percent value, based on total value passed. - * E.g. 0.1 BTC is 25% (of 0.4 BTC) - * @param total Total Btc amount the percentage part is calculated from + * @param part Xmr amount to be converted to percent value, based on total value passed. + * E.g. 0.1 XMR is 25% (of 0.4 XMR) + * @param total Total Xmr amount the percentage part is calculated from * * @return The percentage value as double (e.g. 1% is 0.01) */ - public static double getAsPercentPerBtc(BigInteger part, BigInteger total) { - return MathUtils.roundDouble(HavenoUtils.divide(part == null ? BigInteger.valueOf(0) : part, total == null ? BigInteger.valueOf(1) : total), 4); + public static double getAsPercentPerXmr(BigInteger part, BigInteger total) { + return MathUtils.roundDouble(HavenoUtils.divide(part == null ? BigInteger.ZERO : part, total == null ? BigInteger.valueOf(1) : total), 4); } /** * @param percent The percentage value as double (e.g. 1% is 0.01) * @param amount The amount as atomic units for the percentage calculation - * @return The percentage as atomic units (e.g. 1% of 1 BTC is 0.01 BTC) + * @return The percentage as atomic units (e.g. 1% of 1 XMR is 0.01 XMR) */ public static BigInteger getPercentOfAmount(double percent, BigInteger amount) { - if (amount == null) amount = BigInteger.valueOf(0); - return BigDecimal.valueOf(percent).multiply(new BigDecimal(amount)).toBigInteger(); + if (amount == null) amount = BigInteger.ZERO; + return BigDecimal.valueOf(percent).multiply(new BigDecimal(amount)).setScale(8, RoundingMode.DOWN).toBigInteger(); } - public static BigInteger getRoundedAmount(BigInteger amount, Price price, long maxTradeLimit, String currencyCode, String paymentMethodId) { + public static BigInteger getRoundedAmount(BigInteger amount, Price price, Long maxTradeLimit, String currencyCode, String paymentMethodId) { if (PaymentMethod.isRoundedForAtmCash(paymentMethodId)) { return getRoundedAtmCashAmount(amount, price, maxTradeLimit); } else if (CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode)) { return getRoundedAmountUnit(amount, price, maxTradeLimit); - } else if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - return getRoundedAmountPrecise(amount, price, maxTradeLimit); + } else if (CurrencyUtil.isFiatCurrency(currencyCode)) { + return getRoundedAmount4Decimals(amount, price, maxTradeLimit); } return amount; } - public static BigInteger getRoundedAtmCashAmount(BigInteger amount, Price price, long maxTradeLimit) { + public static BigInteger getRoundedAtmCashAmount(BigInteger amount, Price price, Long maxTradeLimit) { return getAdjustedAmount(amount, price, maxTradeLimit, 10); } @@ -103,11 +99,11 @@ public class CoinUtil { * @param maxTradeLimit The max. trade limit of the users account, in atomic units. * @return The adjusted amount */ - public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, long maxTradeLimit) { + public static BigInteger getRoundedAmountUnit(BigInteger amount, Price price, Long maxTradeLimit) { return getAdjustedAmount(amount, price, maxTradeLimit, 1); } - public static BigInteger getRoundedAmountPrecise(BigInteger amount, Price price, long maxTradeLimit) { + public static BigInteger getRoundedAmount4Decimals(BigInteger amount, Price price, Long maxTradeLimit) { DecimalFormat decimalFormat = new DecimalFormat("#.####"); double roundedXmrAmount = Double.parseDouble(decimalFormat.format(HavenoUtils.atomicUnitsToXmr(amount))); return HavenoUtils.xmrToAtomicUnits(roundedXmrAmount); @@ -125,10 +121,10 @@ public class CoinUtil { * @return The adjusted amount */ @VisibleForTesting - static BigInteger getAdjustedAmount(BigInteger amount, Price price, long maxTradeLimit, int factor) { + static BigInteger getAdjustedAmount(BigInteger amount, Price price, Long maxTradeLimit, int factor) { checkArgument( - amount.longValueExact() >= HavenoUtils.xmrToAtomicUnits(0.0001).longValueExact(), - "amount needs to be above minimum of 0.0001 xmr" // TODO: update amount for XMR + amount.longValueExact() >= Restrictions.getMinTradeAmount().longValueExact(), + "amount needs to be above minimum of " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr" ); checkArgument( factor > 0, @@ -138,15 +134,14 @@ public class CoinUtil { // 10 EUR in case of HalCash. Volume smallestUnitForVolume = Volume.parse(String.valueOf(factor), price.getCurrencyCode()); if (smallestUnitForVolume.getValue() <= 0) - return BigInteger.valueOf(0); + return BigInteger.ZERO; BigInteger smallestUnitForAmount = price.getAmountByVolume(smallestUnitForVolume); long minTradeAmount = Restrictions.getMinTradeAmount().longValueExact(); - // We use 10 000 satoshi as min allowed amount checkArgument( - minTradeAmount >= HavenoUtils.xmrToAtomicUnits(0.0001).longValueExact(), - "MinTradeAmount must be at least 0.0001 xmr" // TODO: update amount for XMR + minTradeAmount >= Restrictions.getMinTradeAmount().longValueExact(), + "MinTradeAmount must be at least " + HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount()) + " xmr" ); smallestUnitForAmount = BigInteger.valueOf(Math.max(minTradeAmount, smallestUnitForAmount.longValueExact())); // We don't allow smaller amount values than smallestUnitForAmount @@ -157,22 +152,24 @@ public class CoinUtil { ? getAdjustedVolumeUnit(price.getVolumeByAmount(smallestUnitForAmount), factor) : getAdjustedVolumeUnit(price.getVolumeByAmount(amount), factor); if (volume.getValue() <= 0) - return BigInteger.valueOf(0); + return BigInteger.ZERO; // From that adjusted volume we calculate back the amount. It might be a bit different as // the amount used as input before due rounding. BigInteger amountByVolume = price.getAmountByVolume(volume); // For the amount we allow only 4 decimal places - // TODO: remove rounding for XMR? - long adjustedAmount = HavenoUtils.centinerosToAtomicUnits(Math.round((double) HavenoUtils.atomicUnitsToCentineros(amountByVolume) / 10000d) * 10000).longValueExact(); + long adjustedAmount = HavenoUtils.centinerosToAtomicUnits(Math.round(HavenoUtils.atomicUnitsToCentineros(amountByVolume) / 10000d) * 10000).longValueExact(); // If we are above our trade limit we reduce the amount by the smallestUnitForAmount - while (adjustedAmount > maxTradeLimit) { - adjustedAmount -= smallestUnitForAmount.longValueExact(); + BigInteger smallestUnitForAmountUnadjusted = price.getAmountByVolume(smallestUnitForVolume); + if (maxTradeLimit != null) { + while (adjustedAmount > maxTradeLimit) { + adjustedAmount -= smallestUnitForAmountUnadjusted.longValueExact(); + } } adjustedAmount = Math.max(minTradeAmount, adjustedAmount); - adjustedAmount = Math.min(maxTradeLimit, adjustedAmount); + if (maxTradeLimit != null) adjustedAmount = Math.min(maxTradeLimit, adjustedAmount); return BigInteger.valueOf(adjustedAmount); } } diff --git a/core/src/main/java/haveno/core/util/coin/ImmutableCoinFormatter.java b/core/src/main/java/haveno/core/util/coin/ImmutableCoinFormatter.java index a685efab10..17ba9a7bc4 100644 --- a/core/src/main/java/haveno/core/util/coin/ImmutableCoinFormatter.java +++ b/core/src/main/java/haveno/core/util/coin/ImmutableCoinFormatter.java @@ -1,30 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.coin; +import com.google.inject.Inject; import haveno.core.util.FormattingUtils; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.Coin; import org.bitcoinj.utils.MonetaryFormat; -import javax.inject.Inject; - @Slf4j public class ImmutableCoinFormatter implements CoinFormatter { diff --git a/core/src/main/java/haveno/core/util/validation/AmountValidator4Decimals.java b/core/src/main/java/haveno/core/util/validation/AmountValidator4Decimals.java index 1c9a26a671..2cedb5673c 100644 --- a/core/src/main/java/haveno/core/util/validation/AmountValidator4Decimals.java +++ b/core/src/main/java/haveno/core/util/validation/AmountValidator4Decimals.java @@ -1,23 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; -import javax.inject.Inject; +import com.google.inject.Inject; public class AmountValidator4Decimals extends MonetaryValidator { @Override diff --git a/core/src/main/java/haveno/core/util/validation/AmountValidator8Decimals.java b/core/src/main/java/haveno/core/util/validation/AmountValidator8Decimals.java index 5a329918d1..6ed489c205 100644 --- a/core/src/main/java/haveno/core/util/validation/AmountValidator8Decimals.java +++ b/core/src/main/java/haveno/core/util/validation/AmountValidator8Decimals.java @@ -1,23 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; -import javax.inject.Inject; +import com.google.inject.Inject; public class AmountValidator8Decimals extends MonetaryValidator { @Override diff --git a/core/src/main/java/haveno/core/util/validation/BtcAddressValidator.java b/core/src/main/java/haveno/core/util/validation/BtcAddressValidator.java index c187a7f199..119351eb1f 100644 --- a/core/src/main/java/haveno/core/util/validation/BtcAddressValidator.java +++ b/core/src/main/java/haveno/core/util/validation/BtcAddressValidator.java @@ -1,29 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.core.locale.Res; import org.bitcoinj.core.Address; import org.bitcoinj.core.AddressFormatException; -import javax.inject.Inject; - public final class BtcAddressValidator extends InputValidator { @Inject diff --git a/core/src/main/java/haveno/core/util/validation/HexStringValidator.java b/core/src/main/java/haveno/core/util/validation/HexStringValidator.java index a8f45f0dad..f2626490ae 100644 --- a/core/src/main/java/haveno/core/util/validation/HexStringValidator.java +++ b/core/src/main/java/haveno/core/util/validation/HexStringValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/util/validation/InputValidator.java b/core/src/main/java/haveno/core/util/validation/InputValidator.java index 512ad7dc20..2f687ab284 100644 --- a/core/src/main/java/haveno/core/util/validation/InputValidator.java +++ b/core/src/main/java/haveno/core/util/validation/InputValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/util/validation/IntegerValidator.java b/core/src/main/java/haveno/core/util/validation/IntegerValidator.java index a1843bd115..a5ef3f9986 100644 --- a/core/src/main/java/haveno/core/util/validation/IntegerValidator.java +++ b/core/src/main/java/haveno/core/util/validation/IntegerValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/util/validation/MonetaryValidator.java b/core/src/main/java/haveno/core/util/validation/MonetaryValidator.java index a28e6cbbf0..e8e1c1e9a6 100644 --- a/core/src/main/java/haveno/core/util/validation/MonetaryValidator.java +++ b/core/src/main/java/haveno/core/util/validation/MonetaryValidator.java @@ -1,26 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; +import com.google.inject.Inject; import haveno.core.locale.Res; -import javax.inject.Inject; - public abstract class MonetaryValidator extends NumberValidator { public abstract double getMinValue(); diff --git a/core/src/main/java/haveno/core/util/validation/NumberValidator.java b/core/src/main/java/haveno/core/util/validation/NumberValidator.java index 89360e9f43..67c89fe097 100644 --- a/core/src/main/java/haveno/core/util/validation/NumberValidator.java +++ b/core/src/main/java/haveno/core/util/validation/NumberValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/util/validation/RegexValidatorFactory.java b/core/src/main/java/haveno/core/util/validation/RegexValidatorFactory.java index 0e3090ed90..c9a5d64304 100644 --- a/core/src/main/java/haveno/core/util/validation/RegexValidatorFactory.java +++ b/core/src/main/java/haveno/core/util/validation/RegexValidatorFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/util/validation/StringValidator.java b/core/src/main/java/haveno/core/util/validation/StringValidator.java index 33a51883a6..fe9b098ea9 100644 --- a/core/src/main/java/haveno/core/util/validation/StringValidator.java +++ b/core/src/main/java/haveno/core/util/validation/StringValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/util/validation/UrlInputValidator.java b/core/src/main/java/haveno/core/util/validation/UrlInputValidator.java index df97942dab..fb0e03b7d8 100644 --- a/core/src/main/java/haveno/core/util/validation/UrlInputValidator.java +++ b/core/src/main/java/haveno/core/util/validation/UrlInputValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.validation; diff --git a/core/src/main/java/haveno/core/xmr/Balances.java b/core/src/main/java/haveno/core/xmr/Balances.java index be607c0268..fe49b941fd 100644 --- a/core/src/main/java/haveno/core/xmr/Balances.java +++ b/core/src/main/java/haveno/core/xmr/Balances.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,33 +34,33 @@ package haveno.core.xmr; -import haveno.core.offer.OfferPayload; +import com.google.inject.Inject; + +import haveno.common.ThreadUtils; +import haveno.common.UserThread; +import haveno.core.api.model.XmrBalanceInfo; import haveno.core.offer.OpenOffer; import haveno.core.offer.OpenOfferManager; import haveno.core.support.dispute.Dispute; import haveno.core.support.dispute.refund.RefundManager; import haveno.core.trade.ClosedTradableManager; +import haveno.core.trade.HavenoUtils; +import haveno.core.trade.MakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; import haveno.core.trade.failed.FailedTradesManager; import haveno.core.xmr.listeners.XmrBalanceListener; import haveno.core.xmr.wallet.XmrWalletService; -import haveno.network.p2p.P2PService; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.collections.ListChangeListener; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; -import monero.common.MoneroError; -import monero.wallet.model.MoneroOutputQuery; -import monero.wallet.model.MoneroOutputWallet; -import monero.wallet.model.MoneroTxQuery; -import monero.wallet.model.MoneroTxWallet; - -import javax.inject.Inject; import java.math.BigInteger; import java.util.List; import java.util.stream.Collectors; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.collections.ListChangeListener; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import monero.wallet.model.MoneroOutputQuery; +import monero.wallet.model.MoneroOutputWallet; @Slf4j public class Balances { @@ -53,15 +70,18 @@ public class Balances { private final RefundManager refundManager; @Getter - private final ObjectProperty<BigInteger> availableBalance = new SimpleObjectProperty<>(); + private BigInteger availableBalance; @Getter - private final ObjectProperty<BigInteger> pendingBalance = new SimpleObjectProperty<>(); + private BigInteger pendingBalance; @Getter - private final ObjectProperty<BigInteger> reservedOfferBalance = new SimpleObjectProperty<>(); + private BigInteger reservedOfferBalance; @Getter - private final ObjectProperty<BigInteger> reservedTradeBalance = new SimpleObjectProperty<>(); + private BigInteger reservedTradeBalance; @Getter - private final ObjectProperty<BigInteger> reservedBalance = new SimpleObjectProperty<>(); // TODO (woodser): this balance is sum of reserved funds for offers and trade multisigs; remove? + private BigInteger reservedBalance; // TODO (woodser): this balance is sum of reserved funds for offers and trade multisigs; remove? + + @Getter + private final IntegerProperty updateCounter = new SimpleIntegerProperty(0); @Inject public Balances(TradeManager tradeManager, @@ -77,78 +97,92 @@ public class Balances { } public void onAllServicesInitialized() { - openOfferManager.getObservableList().addListener((ListChangeListener<OpenOffer>) c -> updatedBalances()); - tradeManager.getObservableList().addListener((ListChangeListener<Trade>) change -> updatedBalances()); - refundManager.getDisputesAsObservableList().addListener((ListChangeListener<Dispute>) c -> updatedBalances()); + openOfferManager.getObservableList().addListener((ListChangeListener<OpenOffer>) c -> updateBalances()); + tradeManager.getObservableList().addListener((ListChangeListener<Trade>) change -> updateBalances()); + refundManager.getDisputesAsObservableList().addListener((ListChangeListener<Dispute>) c -> updateBalances()); xmrWalletService.addBalanceListener(new XmrBalanceListener() { @Override public void onBalanceChanged(BigInteger balance) { - updatedBalances(); + updateBalances(); } }); - updatedBalances(); + doUpdateBalances(); } - private void updatedBalances() { - if (!xmrWalletService.isWalletReady()) return; - try { - updateAvailableBalance(); - updatePendingBalance(); - updateReservedOfferBalance(); - updateReservedTradeBalance(); - updateReservedBalance(); - } catch (Exception e) { - if (xmrWalletService.isWalletReady()) throw e; // ignore exception if wallet isn't ready + public XmrBalanceInfo getBalances() { + synchronized (this) { + if (availableBalance == null) return null; + return new XmrBalanceInfo(availableBalance.longValue() + pendingBalance.longValue(), + availableBalance.longValue(), + pendingBalance.longValue(), + reservedOfferBalance.longValue(), + reservedTradeBalance.longValue()); } } - // TODO (woodser): converting to long should generally be avoided since can lose precision, but in practice these amounts are below max value - - private void updateAvailableBalance() { - availableBalance.set(xmrWalletService.getWallet() == null ? BigInteger.valueOf(0) : xmrWalletService.getWallet().getUnlockedBalance(0)); + private void updateBalances() { + ThreadUtils.submitToPool(() -> doUpdateBalances()); } - private void updatePendingBalance() { - BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.valueOf(0) : xmrWalletService.getWallet().getBalance(0); - BigInteger unlockedBalance = xmrWalletService.getWallet() == null ? BigInteger.valueOf(0) : xmrWalletService.getWallet().getUnlockedBalance(0); - pendingBalance.set(balance.subtract(unlockedBalance)); - } + private void doUpdateBalances() { + synchronized (this) { + synchronized (HavenoUtils.xmrWalletService.getWalletLock()) { - private void updateReservedOfferBalance() { - BigInteger sum = BigInteger.valueOf(0); - if (xmrWalletService.getWallet() != null) { - List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getWallet().getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)); - for (MoneroOutputWallet frozenOutput : frozenOutputs) sum = sum.add(frozenOutput.getAmount()); - } - reservedOfferBalance.set(sum); - } + // get non-trade balance before + BigInteger balanceSumBefore = getNonTradeBalanceSum(); - private void updateReservedTradeBalance() { - BigInteger sum = BigInteger.valueOf(0); - List<Trade> openTrades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList()); - for (Trade trade : openTrades) { - try { - List<MoneroTxWallet> depositTxs = xmrWalletService.getWallet().getTxs(new MoneroTxQuery() - .setHash(trade.getSelf().getDepositTxHash()) - .setInTxPool(false)); // don't check pool - if (depositTxs.size() != 1 || !depositTxs.get(0).isConfirmed()) continue; // outputs are frozen until confirmed by arbitrator's broadcast - } catch (MoneroError e) { - continue; + // get wallet balances + BigInteger balance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getBalance(); + availableBalance = xmrWalletService.getWallet() == null ? BigInteger.ZERO : xmrWalletService.getAvailableBalance(); + + // calculate pending balance by adding frozen trade balances - reserved amounts + pendingBalance = balance.subtract(availableBalance); + List<Trade> trades = tradeManager.getTradesStreamWithFundsLockedIn().collect(Collectors.toList()); + for (Trade trade : trades) { + if (trade.getFrozenAmount().equals(new BigInteger("0"))) continue; + BigInteger tradeFee = trade instanceof MakerTrade ? trade.getMakerFee() : trade.getTakerFee(); + pendingBalance = pendingBalance.add(trade.getFrozenAmount()).subtract(trade.getReservedAmount()).subtract(tradeFee).subtract(trade.getSelf().getDepositTxFee()); + } + + // calculate reserved offer balance + reservedOfferBalance = BigInteger.ZERO; + if (xmrWalletService.getWallet() != null) { + List<MoneroOutputWallet> frozenOutputs = xmrWalletService.getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)); + for (MoneroOutputWallet frozenOutput : frozenOutputs) reservedOfferBalance = reservedOfferBalance.add(frozenOutput.getAmount()); + } + for (Trade trade : trades) { + reservedOfferBalance = reservedOfferBalance.subtract(trade.getFrozenAmount()); // subtract frozen trade balances + } + + // calculate reserved trade balance + reservedTradeBalance = BigInteger.ZERO; + for (Trade trade : trades) { + reservedTradeBalance = reservedTradeBalance.add(trade.getReservedAmount()); + } + + // calculate reserved balance + reservedBalance = reservedOfferBalance.add(reservedTradeBalance); + + // notify balance update + UserThread.execute(() -> { + + // check if funds received + boolean fundsReceived = balanceSumBefore != null && getNonTradeBalanceSum().compareTo(balanceSumBefore) > 0; + if (fundsReceived) { + HavenoUtils.playCashRegisterSound(); + } + + // increase counter to notify listeners + updateCounter.set(updateCounter.get() + 1); + }); } - if (trade.getContract() == null) continue; - Long reservedAmt; - OfferPayload offerPayload = trade.getContract().getOfferPayload(); - if (trade.getArbitratorNodeAddress().equals(P2PService.getMyNodeAddress())) { // TODO (woodser): this only works if node address does not change - reservedAmt = offerPayload.getAmount() + offerPayload.getBuyerSecurityDeposit() + offerPayload.getSellerSecurityDeposit(); // arbitrator reserved balance is sum of amounts sent to multisig - } else { - reservedAmt = trade.getContract().isMyRoleBuyer(tradeManager.getKeyRing().getPubKeyRing()) ? offerPayload.getBuyerSecurityDeposit() : offerPayload.getAmount() + offerPayload.getSellerSecurityDeposit(); - } - sum = sum.add(BigInteger.valueOf(reservedAmt)); } - reservedTradeBalance.set(sum); } - private void updateReservedBalance() { - reservedBalance.set(reservedOfferBalance.get().add(reservedTradeBalance.get())); + private BigInteger getNonTradeBalanceSum() { + synchronized (this) { + if (availableBalance == null) return null; + return availableBalance.add(pendingBalance).add(reservedOfferBalance); + } } } diff --git a/core/src/main/java/haveno/core/xmr/MoneroConnectionModule.java b/core/src/main/java/haveno/core/xmr/MoneroConnectionModule.java deleted file mode 100644 index 9f6ef91ed0..0000000000 --- a/core/src/main/java/haveno/core/xmr/MoneroConnectionModule.java +++ /dev/null @@ -1,22 +0,0 @@ -package haveno.core.xmr; - -import com.google.inject.Singleton; -import haveno.common.app.AppModule; -import haveno.common.config.Config; -import haveno.core.api.CoreMoneroConnectionsService; -import haveno.core.xmr.model.EncryptedConnectionList; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class MoneroConnectionModule extends AppModule { - - public MoneroConnectionModule(Config config) { - super(config); - } - - @Override - protected final void configure() { - bind(EncryptedConnectionList.class).in(Singleton.class); - bind(CoreMoneroConnectionsService.class).in(Singleton.class); - } -} diff --git a/core/src/main/java/haveno/core/xmr/MoneroNodeSettings.java b/core/src/main/java/haveno/core/xmr/MoneroNodeSettings.java deleted file mode 100644 index fa8fe1ec8e..0000000000 --- a/core/src/main/java/haveno/core/xmr/MoneroNodeSettings.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ -package haveno.core.xmr; - -import haveno.common.proto.persistable.PersistableEnvelope; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.extern.slf4j.Slf4j; - -import java.util.List; - -@Slf4j -@Data -@AllArgsConstructor -public class MoneroNodeSettings implements PersistableEnvelope { - - String blockchainPath; - String bootstrapUrl; - List<String> startupFlags; - - public static MoneroNodeSettings fromProto(protobuf.MoneroNodeSettings proto) { - return new MoneroNodeSettings( - proto.getBlockchainPath(), - proto.getBootstrapUrl(), - proto.getStartupFlagsList()); - } - - @Override - public protobuf.MoneroNodeSettings toProtoMessage() { - return protobuf.MoneroNodeSettings.newBuilder() - .setBlockchainPath(blockchainPath) - .setBootstrapUrl(bootstrapUrl) - .addAllStartupFlags(startupFlags).build(); - } -} diff --git a/core/src/main/java/haveno/core/xmr/XmrConnectionModule.java b/core/src/main/java/haveno/core/xmr/XmrConnectionModule.java new file mode 100644 index 0000000000..03a808dab2 --- /dev/null +++ b/core/src/main/java/haveno/core/xmr/XmrConnectionModule.java @@ -0,0 +1,39 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.xmr; + +import com.google.inject.Singleton; +import haveno.common.app.AppModule; +import haveno.common.config.Config; +import haveno.core.api.XmrConnectionService; +import haveno.core.xmr.model.EncryptedConnectionList; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class XmrConnectionModule extends AppModule { + + public XmrConnectionModule(Config config) { + super(config); + } + + @Override + protected final void configure() { + bind(EncryptedConnectionList.class).in(Singleton.class); + bind(XmrConnectionService.class).in(Singleton.class); + } +} diff --git a/core/src/main/java/haveno/core/xmr/MoneroModule.java b/core/src/main/java/haveno/core/xmr/XmrModule.java similarity index 83% rename from core/src/main/java/haveno/core/xmr/MoneroModule.java rename to core/src/main/java/haveno/core/xmr/XmrModule.java index ca535b3193..b039da557a 100644 --- a/core/src/main/java/haveno/core/xmr/MoneroModule.java +++ b/core/src/main/java/haveno/core/xmr/XmrModule.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -44,9 +61,9 @@ import static haveno.common.config.Config.PROVIDERS; import static haveno.common.config.Config.WALLET_DIR; import static haveno.common.config.Config.WALLET_RPC_BIND_PORT; -public class MoneroModule extends AppModule { +public class XmrModule extends AppModule { - public MoneroModule(Config config) { + public XmrModule(Config config) { super(config); } @@ -75,6 +92,7 @@ public class MoneroModule extends AppModule { bindConstant().annotatedWith(named(Config.XMR_NODE_USERNAME)).to(config.xmrNodeUsername); bindConstant().annotatedWith(named(Config.XMR_NODE_PASSWORD)).to(config.xmrNodePassword); bindConstant().annotatedWith(named(Config.XMR_NODES)).to(config.xmrNodes); + bindConstant().annotatedWith(named(Config.USE_NATIVE_XMR_WALLET)).to(config.useNativeXmrWallet); bindConstant().annotatedWith(named(Config.USER_AGENT)).to(config.userAgent); bindConstant().annotatedWith(named(Config.NUM_CONNECTIONS_FOR_BTC)).to(config.numConnectionsForBtc); bindConstant().annotatedWith(named(Config.USE_ALL_PROVIDED_NODES)).to(config.useAllProvidedNodes); diff --git a/core/src/main/java/haveno/core/xmr/XmrNodeSettings.java b/core/src/main/java/haveno/core/xmr/XmrNodeSettings.java new file mode 100644 index 0000000000..9802f036c3 --- /dev/null +++ b/core/src/main/java/haveno/core/xmr/XmrNodeSettings.java @@ -0,0 +1,61 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ +package haveno.core.xmr; + +import haveno.common.proto.persistable.PersistableEnvelope; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import java.util.List; +import java.util.Optional; +import javax.annotation.Nullable; + +@Slf4j +@Data +@AllArgsConstructor +public class XmrNodeSettings implements PersistableEnvelope { + + @Nullable + String blockchainPath; + @Nullable + String bootstrapUrl; + @Nullable + List<String> startupFlags; + @Nullable + Boolean syncBlockchain; + + public XmrNodeSettings() { + } + + public static XmrNodeSettings fromProto(protobuf.XmrNodeSettings proto) { + return new XmrNodeSettings( + proto.getBlockchainPath(), + proto.getBootstrapUrl(), + proto.getStartupFlagsList(), + proto.getSyncBlockchain()); + } + + @Override + public protobuf.XmrNodeSettings toProtoMessage() { + protobuf.XmrNodeSettings.Builder builder = protobuf.XmrNodeSettings.newBuilder(); + Optional.ofNullable(blockchainPath).ifPresent(e -> builder.setBlockchainPath(blockchainPath)); + Optional.ofNullable(bootstrapUrl).ifPresent(e -> builder.setBootstrapUrl(bootstrapUrl)); + Optional.ofNullable(startupFlags).ifPresent(e -> builder.addAllStartupFlags(startupFlags)); + Optional.ofNullable(syncBlockchain).ifPresent(e -> builder.setSyncBlockchain(syncBlockchain)); + return builder.build(); + } +} diff --git a/core/src/main/java/haveno/core/xmr/exceptions/AddressEntryException.java b/core/src/main/java/haveno/core/xmr/exceptions/AddressEntryException.java index c0cf37e589..6b59137326 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/AddressEntryException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/AddressEntryException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/InsufficientFundsException.java b/core/src/main/java/haveno/core/xmr/exceptions/InsufficientFundsException.java index cbdaeb122a..37e99d764f 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/InsufficientFundsException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/InsufficientFundsException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/InvalidHostException.java b/core/src/main/java/haveno/core/xmr/exceptions/InvalidHostException.java index 10542dfdee..69ecdbc7bd 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/InvalidHostException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/InvalidHostException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/RejectedTxException.java b/core/src/main/java/haveno/core/xmr/exceptions/RejectedTxException.java index ce74645a8b..0de9ba9e67 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/RejectedTxException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/RejectedTxException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/SigningException.java b/core/src/main/java/haveno/core/xmr/exceptions/SigningException.java index f2b6a3ba69..060c7fd096 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/SigningException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/SigningException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/TransactionVerificationException.java b/core/src/main/java/haveno/core/xmr/exceptions/TransactionVerificationException.java index af44a9eb6a..3481e59134 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/TransactionVerificationException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/TransactionVerificationException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastException.java b/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastException.java index be580b1a5a..0a2edbac6a 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastTimeoutException.java b/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastTimeoutException.java index bc5c35eba8..eaf2263518 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastTimeoutException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/TxBroadcastTimeoutException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/exceptions/WalletException.java b/core/src/main/java/haveno/core/xmr/exceptions/WalletException.java index 35fb31c596..47e6e3b7ab 100644 --- a/core/src/main/java/haveno/core/xmr/exceptions/WalletException.java +++ b/core/src/main/java/haveno/core/xmr/exceptions/WalletException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.exceptions; diff --git a/core/src/main/java/haveno/core/xmr/listeners/AddressConfidenceListener.java b/core/src/main/java/haveno/core/xmr/listeners/AddressConfidenceListener.java index c9ee142665..f4dd0b6440 100644 --- a/core/src/main/java/haveno/core/xmr/listeners/AddressConfidenceListener.java +++ b/core/src/main/java/haveno/core/xmr/listeners/AddressConfidenceListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.listeners; diff --git a/core/src/main/java/haveno/core/xmr/listeners/BalanceListener.java b/core/src/main/java/haveno/core/xmr/listeners/BalanceListener.java index 1eaa14ebc4..a5cc1c7bf5 100644 --- a/core/src/main/java/haveno/core/xmr/listeners/BalanceListener.java +++ b/core/src/main/java/haveno/core/xmr/listeners/BalanceListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.listeners; diff --git a/core/src/main/java/haveno/core/xmr/listeners/TxConfidenceListener.java b/core/src/main/java/haveno/core/xmr/listeners/TxConfidenceListener.java index 68b48be0d3..aa98da10a9 100644 --- a/core/src/main/java/haveno/core/xmr/listeners/TxConfidenceListener.java +++ b/core/src/main/java/haveno/core/xmr/listeners/TxConfidenceListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.listeners; diff --git a/core/src/main/java/haveno/core/xmr/listeners/XmrBalanceListener.java b/core/src/main/java/haveno/core/xmr/listeners/XmrBalanceListener.java index 75f9b9a2e2..e5ef43be34 100644 --- a/core/src/main/java/haveno/core/xmr/listeners/XmrBalanceListener.java +++ b/core/src/main/java/haveno/core/xmr/listeners/XmrBalanceListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.listeners; diff --git a/core/src/main/java/haveno/core/xmr/model/AddressEntry.java b/core/src/main/java/haveno/core/xmr/model/AddressEntry.java index 463b73aea4..18982afee7 100644 --- a/core/src/main/java/haveno/core/xmr/model/AddressEntry.java +++ b/core/src/main/java/haveno/core/xmr/model/AddressEntry.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.model; diff --git a/core/src/main/java/haveno/core/xmr/model/AddressEntryList.java b/core/src/main/java/haveno/core/xmr/model/AddressEntryList.java index 71b1bb4e8a..376e827f0e 100644 --- a/core/src/main/java/haveno/core/xmr/model/AddressEntryList.java +++ b/core/src/main/java/haveno/core/xmr/model/AddressEntryList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.model; diff --git a/core/src/main/java/haveno/core/xmr/model/EncryptedConnectionList.java b/core/src/main/java/haveno/core/xmr/model/EncryptedConnectionList.java index b5bd7e916f..b0cc843121 100644 --- a/core/src/main/java/haveno/core/xmr/model/EncryptedConnectionList.java +++ b/core/src/main/java/haveno/core/xmr/model/EncryptedConnectionList.java @@ -1,5 +1,6 @@ package haveno.core.xmr.model; +import com.google.inject.Inject; import com.google.protobuf.ByteString; import com.google.protobuf.Message; import haveno.common.crypto.CryptoException; @@ -10,12 +11,6 @@ import haveno.common.proto.persistable.PersistableEnvelope; import haveno.common.proto.persistable.PersistedDataHost; import haveno.core.api.CoreAccountService; import haveno.core.api.model.EncryptedConnection; -import lombok.NonNull; -import monero.common.MoneroRpcConnection; -import org.bitcoinj.crypto.KeyCrypterScrypt; - -import javax.crypto.SecretKey; -import javax.inject.Inject; import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.util.HashMap; @@ -28,6 +23,10 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; import java.util.stream.Collectors; +import javax.crypto.SecretKey; +import lombok.NonNull; +import monero.common.MoneroRpcConnection; +import org.bitcoinj.crypto.KeyCrypterScrypt; /** @@ -63,7 +62,7 @@ public class EncryptedConnectionList implements PersistableEnvelope, PersistedDa private final Map<String, EncryptedConnection> items = new HashMap<>(); private @NonNull String currentConnectionUrl = ""; private long refreshPeriod; // -1 means no refresh, 0 means default, >0 means custom - private boolean autoSwitch; + private boolean autoSwitch = true; @Inject public EncryptedConnectionList(PersistenceManager<EncryptedConnectionList> persistenceManager, diff --git a/core/src/main/java/haveno/core/xmr/model/InputsAndChangeOutput.java b/core/src/main/java/haveno/core/xmr/model/InputsAndChangeOutput.java index 00233a4435..183f12167d 100644 --- a/core/src/main/java/haveno/core/xmr/model/InputsAndChangeOutput.java +++ b/core/src/main/java/haveno/core/xmr/model/InputsAndChangeOutput.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.model; diff --git a/core/src/main/java/haveno/core/xmr/model/PreparedDepositTxAndMakerInputs.java b/core/src/main/java/haveno/core/xmr/model/PreparedDepositTxAndMakerInputs.java index c184ab82e7..96af9d024d 100644 --- a/core/src/main/java/haveno/core/xmr/model/PreparedDepositTxAndMakerInputs.java +++ b/core/src/main/java/haveno/core/xmr/model/PreparedDepositTxAndMakerInputs.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.model; diff --git a/core/src/main/java/haveno/core/xmr/model/RawTransactionInput.java b/core/src/main/java/haveno/core/xmr/model/RawTransactionInput.java index 940e9f3242..c5778f62d8 100644 --- a/core/src/main/java/haveno/core/xmr/model/RawTransactionInput.java +++ b/core/src/main/java/haveno/core/xmr/model/RawTransactionInput.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.model; diff --git a/core/src/main/java/haveno/core/xmr/model/XmrAddressEntry.java b/core/src/main/java/haveno/core/xmr/model/XmrAddressEntry.java index 451981fcd8..025d6cda69 100644 --- a/core/src/main/java/haveno/core/xmr/model/XmrAddressEntry.java +++ b/core/src/main/java/haveno/core/xmr/model/XmrAddressEntry.java @@ -37,12 +37,13 @@ import java.util.Optional; @EqualsAndHashCode @Slf4j public final class XmrAddressEntry implements PersistablePayload { + public enum Context { ARBITRATOR, BASE_ADDRESS, AVAILABLE, OFFER_FUNDING, - TRADE_PAYOUT + TRADE_PAYOUT; } // keyPair can be null in case the object is created from deserialization as it is transient. diff --git a/core/src/main/java/haveno/core/xmr/model/XmrAddressEntryList.java b/core/src/main/java/haveno/core/xmr/model/XmrAddressEntryList.java index 1796b7d12b..73f7379dfb 100644 --- a/core/src/main/java/haveno/core/xmr/model/XmrAddressEntryList.java +++ b/core/src/main/java/haveno/core/xmr/model/XmrAddressEntryList.java @@ -140,6 +140,11 @@ public final class XmrAddressEntryList implements PersistableEnvelope, Persisted return newAddressEntry; } + public void clear() { + entrySet.clear(); + requestPersistence(); + } + public void requestPersistence() { persistenceManager.requestPersistence(); } diff --git a/core/src/main/java/haveno/core/xmr/nodes/ProxySocketFactory.java b/core/src/main/java/haveno/core/xmr/nodes/ProxySocketFactory.java index cbb37842df..a477e85ac5 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/ProxySocketFactory.java +++ b/core/src/main/java/haveno/core/xmr/nodes/ProxySocketFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /** diff --git a/core/src/main/java/haveno/core/xmr/nodes/SeedPeersSocks5Dns.java b/core/src/main/java/haveno/core/xmr/nodes/SeedPeersSocks5Dns.java index f0608c9bd2..62268ac824 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/SeedPeersSocks5Dns.java +++ b/core/src/main/java/haveno/core/xmr/nodes/SeedPeersSocks5Dns.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /** diff --git a/core/src/main/java/haveno/core/xmr/nodes/XmrNetworkConfig.java b/core/src/main/java/haveno/core/xmr/nodes/XmrNetworkConfig.java index b4586e9fb7..89394ec435 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/XmrNetworkConfig.java +++ b/core/src/main/java/haveno/core/xmr/nodes/XmrNetworkConfig.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/main/java/haveno/core/xmr/nodes/XmrNodeConverter.java b/core/src/main/java/haveno/core/xmr/nodes/XmrNodeConverter.java index cc401308dc..16d4451d1b 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/XmrNodeConverter.java +++ b/core/src/main/java/haveno/core/xmr/nodes/XmrNodeConverter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/main/java/haveno/core/xmr/nodes/XmrNodes.java b/core/src/main/java/haveno/core/xmr/nodes/XmrNodes.java index ae32fda9a5..97217b0fe4 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/XmrNodes.java +++ b/core/src/main/java/haveno/core/xmr/nodes/XmrNodes.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,6 +35,7 @@ package haveno.core.xmr.nodes; import haveno.common.config.Config; +import haveno.core.trade.HavenoUtils; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -65,13 +83,15 @@ public class XmrNodes { ); case XMR_MAINNET: return Arrays.asList( - new XmrNode(MoneroNodesOption.PROVIDED, null, null, "127.0.0.1", 18081, 1, "@local"), - new XmrNode(MoneroNodesOption.PROVIDED, null, null, "xmr-node.cakewallet.com", 18081, 2, "@cakewallet"), - new XmrNode(MoneroNodesOption.PROVIDED, null, null, "xmr-node-eu.cakewallet.com", 18081, 2, "@cakewallet"), - new XmrNode(MoneroNodesOption.PROVIDED, null, null, "xmr-node-usa-east.cakewallet.com", 18081, 2, "@cakewallet"), - new XmrNode(MoneroNodesOption.PROVIDED, null, null, "xmr-node-uk.cakewallet.com", 18081, 2, "@cakewallet"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "127.0.0.1", 18081, 1, "@local"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "xmr-node.cakewallet.com", 18081, 2, "@cakewallet"), new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node.community.rino.io", 18081, 2, "@RINOwallet"), - new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node.sethforprivacy.com", 18089, 3, "@sethforprivacy") + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "nodes.hashvault.pro", 18080, 2, "@HashVault"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "p2pmd.xmrvsbeast.com", 18080, 2, "@xmrvsbeast"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node.monerodevs.org", 18089, 2, "@monerodevs.org"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "nodex.monerujo.io", 18081, 2, "@monerujo.io"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "rucknium.me", 18081, 2, "@Rucknium"), + new XmrNode(MoneroNodesOption.PUBLIC, null, null, "node.sethforprivacy.com", 18089, 2, "@sethforprivacy") ); default: throw new IllegalStateException("Unexpected base currency network: " + Config.baseCurrencyNetwork()); @@ -86,6 +106,10 @@ public class XmrNodes { return getXmrNodes(MoneroNodesOption.PUBLIC); } + public List<XmrNode> getCustomXmrNodes() { + return getXmrNodes(MoneroNodesOption.CUSTOM); + } + private List<XmrNode> getXmrNodes(MoneroNodesOption type) { List<XmrNode> nodes = new ArrayList<>(); for (XmrNode node : getAllXmrNodes()) if (node.getType() == type) nodes.add(node); @@ -102,7 +126,6 @@ public class XmrNodes { @EqualsAndHashCode @Getter public static class XmrNode { - private static final int DEFAULT_PORT = Config.baseCurrencyNetworkParameters().getPort(); private final MoneroNodesOption type; @Nullable @@ -113,7 +136,7 @@ public class XmrNodes { private final String operator; // null in case the user provides a list of custom btc nodes @Nullable private final String address; // IPv4 address - private int port = DEFAULT_PORT; + private int port = HavenoUtils.getDefaultMoneroPort(); private int priority = 0; /** @@ -124,11 +147,11 @@ public class XmrNodes { String[] parts = fullAddress.split("]"); checkArgument(parts.length > 0); String host = ""; - int port = DEFAULT_PORT; + int port = HavenoUtils.getDefaultMoneroPort(); if (parts[0].contains("[") && parts[0].contains(":")) { // IPv6 address and optional port number // address part delimited by square brackets e.g. [2a01:123:456:789::2]:8333 - host = parts[0].replace("[", "").replace("]", ""); + host = parts[0] + "]"; // keep the square brackets per RFC-2732 if (parts.length == 2) port = Integer.parseInt(parts[1].replace(":", "")); } else if (parts[0].contains(":") && !parts[0].contains(".")) { diff --git a/core/src/main/java/haveno/core/xmr/nodes/XmrNodesRepository.java b/core/src/main/java/haveno/core/xmr/nodes/XmrNodesRepository.java index 07ff67b043..581545f6e0 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/XmrNodesRepository.java +++ b/core/src/main/java/haveno/core/xmr/nodes/XmrNodesRepository.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/main/java/haveno/core/xmr/nodes/XmrNodesSetupPreferences.java b/core/src/main/java/haveno/core/xmr/nodes/XmrNodesSetupPreferences.java index 583a82c5ac..8dbe25fa2f 100644 --- a/core/src/main/java/haveno/core/xmr/nodes/XmrNodesSetupPreferences.java +++ b/core/src/main/java/haveno/core/xmr/nodes/XmrNodesSetupPreferences.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; @@ -49,15 +49,15 @@ public class XmrNodesSetupPreferences { log.warn("Custom nodes is set but no valid nodes are provided. " + "We fall back to provided nodes option."); preferences.setMoneroNodesOptionOrdinal(XmrNodes.MoneroNodesOption.PROVIDED.ordinal()); - result = nodes.getAllXmrNodes(); + result = nodes.getProvidedXmrNodes(); } break; case PUBLIC: - result = nodes.getPublicXmrNodes(); + result = nodes.getAllXmrNodes(); // public entails provided nodes break; case PROVIDED: default: - result = nodes.getAllXmrNodes(); + result = nodes.getProvidedXmrNodes(); break; } diff --git a/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java b/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java index ada82b0022..2b88b30cd7 100644 --- a/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java +++ b/core/src/main/java/haveno/core/xmr/setup/DownloadListener.java @@ -10,12 +10,12 @@ import java.util.Date; public class DownloadListener { private final DoubleProperty percentage = new SimpleDoubleProperty(-1); - public void progress(double percentage, int blocksLeft, Date date) { - UserThread.execute(() -> this.percentage.set(percentage / 100d)); + public void progress(double percentage, long blocksLeft, Date date) { + UserThread.await(() -> this.percentage.set(percentage)); } public void doneDownload() { - UserThread.execute(() -> this.percentage.set(1d)); + UserThread.await(() -> this.percentage.set(1d)); } public ReadOnlyDoubleProperty percentageProperty() { diff --git a/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainFactory.java b/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainFactory.java index 8947ff7ce9..ccf1b4c413 100644 --- a/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainFactory.java +++ b/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.setup; diff --git a/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainGroupStructure.java b/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainGroupStructure.java index cc080a8a95..310a701276 100644 --- a/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainGroupStructure.java +++ b/core/src/main/java/haveno/core/xmr/setup/HavenoKeyChainGroupStructure.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.setup; diff --git a/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java b/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java index 3afcb91544..c993ebd181 100644 --- a/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java +++ b/core/src/main/java/haveno/core/xmr/setup/MoneroWalletRpcManager.java @@ -1,3 +1,20 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.xmr.setup; import lombok.extern.slf4j.Slf4j; diff --git a/core/src/main/java/haveno/core/xmr/setup/RegTestHost.java b/core/src/main/java/haveno/core/xmr/setup/RegTestHost.java index 8eecb62e29..f5999c2fef 100644 --- a/core/src/main/java/haveno/core/xmr/setup/RegTestHost.java +++ b/core/src/main/java/haveno/core/xmr/setup/RegTestHost.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.setup; diff --git a/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java b/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java index c36a6333b5..362b764243 100644 --- a/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java +++ b/core/src/main/java/haveno/core/xmr/setup/WalletConfig.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.setup; @@ -22,7 +22,7 @@ import com.google.common.util.concurrent.AbstractIdleService; import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; import haveno.common.config.Config; import haveno.common.file.FileUtil; -import haveno.core.api.LocalMoneroNode; +import haveno.core.api.XmrLocalNode; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import lombok.Getter; @@ -32,7 +32,6 @@ import org.bitcoinj.core.Context; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.PeerAddress; import org.bitcoinj.core.PeerGroup; -import org.bitcoinj.core.listeners.DownloadProgressTracker; import org.bitcoinj.crypto.KeyCrypter; import org.bitcoinj.net.discovery.PeerDiscovery; import org.bitcoinj.script.Script; @@ -92,7 +91,6 @@ public class WalletConfig extends AbstractIdleService { protected volatile File vBtcWalletFile; protected PeerAddress[] peerAddresses; - protected DownloadListener downloadListener; protected InputStream checkpoints; protected String userAgent, version; @Nullable @@ -103,7 +101,7 @@ public class WalletConfig extends AbstractIdleService { protected volatile Context context; protected Config config; - protected LocalMoneroNode localMoneroNode; + protected XmrLocalNode xmrLocalNode; protected Socks5Proxy socks5Proxy; protected int numConnectionsForBtc; @Getter @@ -143,9 +141,9 @@ public class WalletConfig extends AbstractIdleService { return this; } - public WalletConfig setLocalMoneroNodeService(LocalMoneroNode localMoneroNode) { + public WalletConfig setXmrLocalNode(XmrLocalNode xmrLocalNode) { checkState(state() == State.NEW, "Cannot call after startup"); - this.localMoneroNode = localMoneroNode; + this.xmrLocalNode = xmrLocalNode; return this; } @@ -169,15 +167,6 @@ public class WalletConfig extends AbstractIdleService { return setPeerNodes(new PeerAddress(params, localHost, params.getPort())); } - /** - * If you want to learn about the sync process, you can provide a listener here. For instance, a - * {@link DownloadProgressTracker} is a good choice. - */ - public WalletConfig setDownloadListener(DownloadListener listener) { - this.downloadListener = listener; - return this; - } - /** * If set, the file is expected to contain a checkpoints file calculated with BuildCheckpoints. It makes initial * block sync faster for new users - please refer to the documentation on the bitcoinj website diff --git a/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java b/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java index d89f75b2a7..78d55c2d79 100644 --- a/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java +++ b/core/src/main/java/haveno/core/xmr/setup/WalletsSetup.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.setup; @@ -29,7 +29,7 @@ import haveno.common.config.Config; import haveno.common.file.FileUtil; import haveno.common.handlers.ExceptionHandler; import haveno.common.handlers.ResultHandler; -import haveno.core.api.LocalMoneroNode; +import haveno.core.api.XmrLocalNode; import haveno.core.user.Preferences; import haveno.core.xmr.exceptions.InvalidHostException; import haveno.core.xmr.model.AddressEntry; @@ -42,13 +42,7 @@ import haveno.core.xmr.nodes.XmrNodesSetupPreferences; import haveno.network.Socks5MultiDiscovery; import haveno.network.Socks5ProxyProvider; import javafx.beans.property.BooleanProperty; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.LongProperty; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.beans.property.SimpleLongProperty; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -100,16 +94,13 @@ public class WalletsSetup { private final Preferences preferences; private final Socks5ProxyProvider socks5ProxyProvider; private final Config config; - private final LocalMoneroNode localMoneroNode; + private final XmrLocalNode xmrLocalNode; private final XmrNodes xmrNodes; private final int numConnectionsForBtc; private final String userAgent; private final NetworkParameters params; private final File walletDir; private final int socks5DiscoverMode; - private final IntegerProperty numPeers = new SimpleIntegerProperty(0); - private final LongProperty chainHeight = new SimpleLongProperty(0); - private final DownloadListener downloadListener = new DownloadListener(); private final List<Runnable> setupTaskHandlers = new ArrayList<>(); private final List<Runnable> setupCompletedHandlers = new ArrayList<>(); public final BooleanProperty shutDownComplete = new SimpleBooleanProperty(); @@ -126,7 +117,7 @@ public class WalletsSetup { Preferences preferences, Socks5ProxyProvider socks5ProxyProvider, Config config, - LocalMoneroNode localMoneroNode, + XmrLocalNode xmrLocalNode, XmrNodes xmrNodes, @Named(Config.USER_AGENT) String userAgent, @Named(Config.WALLET_DIR) File walletDir, @@ -138,7 +129,7 @@ public class WalletsSetup { this.preferences = preferences; this.socks5ProxyProvider = socks5ProxyProvider; this.config = config; - this.localMoneroNode = localMoneroNode; + this.xmrLocalNode = xmrLocalNode; this.xmrNodes = xmrNodes; this.numConnectionsForBtc = numConnectionsForBtc; this.useAllProvidedNodes = useAllProvidedNodes; @@ -172,12 +163,12 @@ public class WalletsSetup { backupWallets(); final Socks5Proxy socks5Proxy = socks5ProxyProvider.getSocks5Proxy(); - log.info("Socks5Proxy for bitcoinj: socks5Proxy=" + socks5Proxy); + log.info("Using Socks5Proxy: " + socks5Proxy); walletConfig = new WalletConfig(params, walletDir, "haveno") { + @Override protected void onSetupCompleted() { - //We are here in the btcj thread Thread[ STARTING,5,main] super.onSetupCompleted(); // run external startup handlers @@ -195,7 +186,7 @@ public class WalletsSetup { }; walletConfig.setSocks5Proxy(socks5Proxy); walletConfig.setConfig(config); - walletConfig.setLocalMoneroNodeService(localMoneroNode); // TODO: adapt to xmr or remove + walletConfig.setXmrLocalNode(xmrLocalNode); // TODO: adapt to xmr or remove walletConfig.setUserAgent(userAgent, Version.VERSION); walletConfig.setNumConnectionsForBtc(numConnectionsForBtc); @@ -230,12 +221,12 @@ public class WalletsSetup { return; } } - } else if (localMoneroNode.shouldBeUsed()) { + } else if (xmrLocalNode.shouldBeUsed()) { walletConfig.setMinBroadcastConnections(1); walletConfig.connectToLocalHost(); } else { try { - //configPeerNodes(socks5Proxy); + configPeerNodes(socks5Proxy); } catch (IllegalArgumentException e) { timeoutTimer.stop(); walletsSetupFailed.set(true); @@ -244,8 +235,6 @@ public class WalletsSetup { } } - walletConfig.setDownloadListener(downloadListener); - // If seed is non-null it means we are restoring from backup. if (seed != null) { walletConfig.restoreWalletFromSeed(seed); @@ -430,26 +419,6 @@ public class WalletsSetup { return walletConfig; } - public ReadOnlyIntegerProperty numPeersProperty() { - return numPeers; - } - - public LongProperty chainHeightProperty() { - return chainHeight; - } - - public ReadOnlyDoubleProperty downloadPercentageProperty() { - return downloadListener.percentageProperty(); - } - - public boolean isDownloadComplete() { - return downloadPercentageProperty().get() == 1d; - } - - public boolean isChainHeightSyncedWithinTolerance() { - throw new RuntimeException("WalletsSetup.isChainHeightSyncedWithinTolerance() not implemented for BTC"); - } - public Set<Address> getAddressesByContext(@SuppressWarnings("SameParameterValue") AddressEntry.Context context) { return addressEntryList.getAddressEntriesAsListImmutable().stream() .filter(addressEntry -> addressEntry.getContext() == context) @@ -463,10 +432,6 @@ public class WalletsSetup { .collect(Collectors.toSet()); } - public boolean hasSufficientPeersForBroadcast() { - return numPeers.get() >= getMinBroadcastConnections(); - } - public int getMinBroadcastConnections() { return walletConfig.getMinBroadcastConnections(); } diff --git a/core/src/main/java/haveno/core/xmr/wallet/BtcCoinSelector.java b/core/src/main/java/haveno/core/xmr/wallet/BtcCoinSelector.java index 89188af788..733ccda75a 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/BtcCoinSelector.java +++ b/core/src/main/java/haveno/core/xmr/wallet/BtcCoinSelector.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; diff --git a/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java index 6a088f3b96..f92df7dbbc 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/BtcWalletService.java @@ -1,23 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; import com.google.common.base.Preconditions; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; import haveno.common.util.Tuple2; import haveno.core.user.Preferences; import haveno.core.xmr.exceptions.AddressEntryException; @@ -27,6 +30,13 @@ import haveno.core.xmr.exceptions.WalletException; import haveno.core.xmr.model.AddressEntry; import haveno.core.xmr.model.AddressEntryList; import haveno.core.xmr.setup.WalletsSetup; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javax.annotation.Nullable; import org.bitcoinj.core.Address; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; @@ -46,18 +56,6 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import javax.inject.Inject; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - public class BtcWalletService extends WalletService { private static final Logger log = LoggerFactory.getLogger(BtcWalletService.class); @@ -92,6 +90,10 @@ public class BtcWalletService extends WalletService { // Overridden Methods /////////////////////////////////////////////////////////////////////////////////////////// + public boolean isWalletSyncedWithinTolerance() { + throw new RuntimeException("Not implemented"); + } + @Override void decryptWallet(@NotNull KeyParameter key) { super.decryptWallet(key); diff --git a/core/src/main/java/haveno/core/xmr/wallet/HavenoDefaultCoinSelector.java b/core/src/main/java/haveno/core/xmr/wallet/HavenoDefaultCoinSelector.java index b8a3560341..d928c307ef 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/HavenoDefaultCoinSelector.java +++ b/core/src/main/java/haveno/core/xmr/wallet/HavenoDefaultCoinSelector.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; diff --git a/core/src/main/java/haveno/core/xmr/wallet/HavenoRiskAnalysis.java b/core/src/main/java/haveno/core/xmr/wallet/HavenoRiskAnalysis.java index e85e03d20c..f19ad622d0 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/HavenoRiskAnalysis.java +++ b/core/src/main/java/haveno/core/xmr/wallet/HavenoRiskAnalysis.java @@ -16,20 +16,20 @@ */ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; diff --git a/core/src/main/java/haveno/core/xmr/wallet/MoneroKeyImageListener.java b/core/src/main/java/haveno/core/xmr/wallet/MoneroKeyImageListener.java deleted file mode 100644 index 80dbca5522..0000000000 --- a/core/src/main/java/haveno/core/xmr/wallet/MoneroKeyImageListener.java +++ /dev/null @@ -1,13 +0,0 @@ -package haveno.core.xmr.wallet; - -import monero.daemon.model.MoneroKeyImageSpentStatus; - -import java.util.Map; - -public interface MoneroKeyImageListener { - - /** - * Called with changes to the spent status of key images. - */ - public void onSpentStatusChanged(Map<String, MoneroKeyImageSpentStatus> spentStatuses); -} diff --git a/core/src/main/java/haveno/core/xmr/wallet/NonBsqCoinSelector.java b/core/src/main/java/haveno/core/xmr/wallet/NonBsqCoinSelector.java index 8f3f5eeb0e..19b833e4bf 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/NonBsqCoinSelector.java +++ b/core/src/main/java/haveno/core/xmr/wallet/NonBsqCoinSelector.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; +import com.google.inject.Inject; import haveno.core.user.Preferences; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -24,8 +25,6 @@ import org.bitcoinj.core.Transaction; import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionOutput; -import javax.inject.Inject; - /** * We use a specialized version of the CoinSelector based on the DefaultCoinSelector implementation. * We lookup for spendable outputs which matches our address of our address. diff --git a/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java b/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java index 6312b395b5..b270762d3b 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java +++ b/core/src/main/java/haveno/core/xmr/wallet/Restrictions.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; @@ -24,11 +24,13 @@ import org.bitcoinj.core.Coin; import java.math.BigInteger; public class Restrictions { + + // configure restrictions + public static final double MIN_SECURITY_DEPOSIT_PCT = 0.15; + public static final double MAX_SECURITY_DEPOSIT_PCT = 0.5; public static BigInteger MIN_TRADE_AMOUNT = HavenoUtils.xmrToAtomicUnits(0.1); - public static BigInteger MIN_BUYER_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.1); - // For the seller we use a fixed one as there is no way the seller can cancel the trade - // To make it editable would just increase complexity. - public static BigInteger SELLER_SECURITY_DEPOSIT = MIN_BUYER_SECURITY_DEPOSIT; + public static BigInteger MIN_SECURITY_DEPOSIT = HavenoUtils.xmrToAtomicUnits(0.1); + // At mediation we require a min. payout to the losing party to keep incentive for the trader to accept the // mediated payout. For Refund agent cases we do not have that restriction. private static BigInteger MIN_REFUND_AT_MEDIATED_DISPUTE; @@ -53,31 +55,20 @@ public class Restrictions { return MIN_TRADE_AMOUNT; } - public static double getDefaultBuyerSecurityDepositAsPercent() { - return 0.15; // 15% of trade amount. + public static double getDefaultSecurityDepositAsPercent() { + return MIN_SECURITY_DEPOSIT_PCT; } - public static double getMinBuyerSecurityDepositAsPercent() { - return 0.15; // 15% of trade amount. + public static double getMinSecurityDepositAsPercent() { + return MIN_SECURITY_DEPOSIT_PCT; } - public static double getMaxBuyerSecurityDepositAsPercent() { - return 0.5; // 50% of trade amount. For a 1 BTC trade it is about 3500 USD @ 7000 USD/BTC + public static double getMaxSecurityDepositAsPercent() { + return MAX_SECURITY_DEPOSIT_PCT; } - // We use MIN_BUYER_SECURITY_DEPOSIT as well as lower bound in case of small trade amounts. - // So 0.0005 BTC is the min. buyer security deposit even with amount of 0.0001 BTC and 0.05% percentage value. - public static BigInteger getMinBuyerSecurityDeposit() { - return MIN_BUYER_SECURITY_DEPOSIT; - } - - - public static double getSellerSecurityDepositAsPercent() { - return 0.15; // 15% of trade amount. - } - - public static BigInteger getMinSellerSecurityDeposit() { - return SELLER_SECURITY_DEPOSIT; + public static BigInteger getMinSecurityDeposit() { + return MIN_SECURITY_DEPOSIT; } // This value must be lower than MIN_BUYER_SECURITY_DEPOSIT and SELLER_SECURITY_DEPOSIT diff --git a/core/src/main/java/haveno/core/xmr/wallet/TradeWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/TradeWalletService.java index 12dac1aa9f..55f94ddc1c 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/TradeWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/TradeWalletService.java @@ -1,23 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.common.util.Tuple2; import haveno.core.user.Preferences; @@ -29,6 +32,10 @@ import haveno.core.xmr.model.PreparedDepositTxAndMakerInputs; import haveno.core.xmr.model.RawTransactionInput; import haveno.core.xmr.setup.WalletConfig; import haveno.core.xmr.setup.WalletsSetup; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import javax.annotation.Nullable; import org.bitcoinj.core.Address; import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.Coin; @@ -55,15 +62,6 @@ import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - public class TradeWalletService { diff --git a/core/src/main/java/haveno/core/xmr/wallet/WalletService.java b/core/src/main/java/haveno/core/xmr/wallet/WalletService.java index ed4bc13f4f..bfd66c0723 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/WalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/WalletService.java @@ -1,26 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import com.google.common.collect.ImmutableMultiset; import com.google.common.collect.ImmutableSetMultimap; import com.google.common.collect.Multiset; import com.google.common.collect.SetMultimap; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.core.user.Preferences; import haveno.core.xmr.exceptions.TransactionVerificationException; @@ -29,8 +32,18 @@ import haveno.core.xmr.listeners.AddressConfidenceListener; import haveno.core.xmr.listeners.BalanceListener; import haveno.core.xmr.listeners.TxConfidenceListener; import haveno.core.xmr.setup.WalletsSetup; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; +import javax.annotation.Nullable; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import monero.wallet.MoneroWallet; @@ -73,21 +86,6 @@ import org.bitcoinj.wallet.listeners.WalletReorganizeEventListener; import org.bouncycastle.crypto.params.KeyParameter; import org.jetbrains.annotations.NotNull; -import javax.annotation.Nullable; -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Function; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.base.Preconditions.checkState; - /** * Abstract base class for BTC wallet. Provides all non-trade specific functionality. */ @@ -538,9 +536,7 @@ public abstract class WalletService { return isWalletReady() && chain != null ? chain.getBestChainHeight() : 0; } - public boolean isChainHeightSyncedWithinTolerance() { - return walletsSetup.isChainHeightSyncedWithinTolerance(); - } + public abstract boolean isWalletSyncedWithinTolerance(); public Transaction getClonedTransaction(Transaction tx) { return new Transaction(params, tx.bitcoinSerialize()); diff --git a/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java b/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java index 4ecdc1952a..eec7bebec9 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java +++ b/core/src/main/java/haveno/core/xmr/wallet/WalletsManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; @@ -97,7 +97,7 @@ public class WalletsManager { } public boolean areWalletsAvailable() { - return xmrWalletService.isWalletReady(); + return xmrWalletService.isWalletAvailable(); } public KeyCrypterScrypt getKeyCrypterScrypt() { diff --git a/core/src/main/java/haveno/core/api/LocalMoneroNodeListener.java b/core/src/main/java/haveno/core/xmr/wallet/XmrKeyImageListener.java similarity index 68% rename from core/src/main/java/haveno/core/api/LocalMoneroNodeListener.java rename to core/src/main/java/haveno/core/xmr/wallet/XmrKeyImageListener.java index 844a4598d4..79cb875416 100644 --- a/core/src/main/java/haveno/core/api/LocalMoneroNodeListener.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrKeyImageListener.java @@ -14,11 +14,17 @@ * You should have received a copy of the GNU Affero General Public License * along with Haveno. If not, see <http://www.gnu.org/licenses/>. */ -package haveno.core.api; -import monero.daemon.MoneroDaemonRpc; +package haveno.core.xmr.wallet; -public class LocalMoneroNodeListener { - public void onNodeStarted(MoneroDaemonRpc daemon) {} - public void onNodeStopped() {} +import monero.daemon.model.MoneroKeyImageSpentStatus; + +import java.util.Map; + +public interface XmrKeyImageListener { + + /** + * Called with changes to the spent status of key images. + */ + public void onSpentStatusChanged(Map<String, MoneroKeyImageSpentStatus> spentStatuses); } diff --git a/core/src/main/java/haveno/core/xmr/wallet/MoneroKeyImagePoller.java b/core/src/main/java/haveno/core/xmr/wallet/XmrKeyImagePoller.java similarity index 83% rename from core/src/main/java/haveno/core/xmr/wallet/MoneroKeyImagePoller.java rename to core/src/main/java/haveno/core/xmr/wallet/XmrKeyImagePoller.java index 71f90bf8a9..731c1311e0 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/MoneroKeyImagePoller.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrKeyImagePoller.java @@ -1,3 +1,20 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.xmr.wallet; import lombok.extern.slf4j.Slf4j; @@ -15,21 +32,24 @@ import java.util.List; import java.util.Map; import java.util.Set; +import haveno.core.trade.HavenoUtils; + /** * Poll for changes to the spent status of key images. * * TODO: move to monero-java? */ @Slf4j -public class MoneroKeyImagePoller { +public class XmrKeyImagePoller { private MoneroDaemon daemon; private long refreshPeriodMs; private List<String> keyImages = new ArrayList<String>(); - private Set<MoneroKeyImageListener> listeners = new HashSet<MoneroKeyImageListener>(); + private Set<XmrKeyImageListener> listeners = new HashSet<XmrKeyImageListener>(); private TaskLooper looper; private Map<String, MoneroKeyImageSpentStatus> lastStatuses = new HashMap<String, MoneroKeyImageSpentStatus>(); private boolean isPolling = false; + private Long lastLogPollErrorTimestamp; /** * Construct the listener. @@ -37,7 +57,7 @@ public class MoneroKeyImagePoller { * @param refreshPeriodMs - refresh period in milliseconds * @param keyImages - key images to listen to */ - public MoneroKeyImagePoller() { + public XmrKeyImagePoller() { looper = new TaskLooper(() -> poll()); } @@ -47,7 +67,7 @@ public class MoneroKeyImagePoller { * @param refreshPeriodMs - refresh period in milliseconds * @param keyImages - key images to listen to */ - public MoneroKeyImagePoller(MoneroDaemon daemon, long refreshPeriodMs, String... keyImages) { + public XmrKeyImagePoller(MoneroDaemon daemon, long refreshPeriodMs, String... keyImages) { looper = new TaskLooper(() -> poll()); setDaemon(daemon); setRefreshPeriodMs(refreshPeriodMs); @@ -59,7 +79,7 @@ public class MoneroKeyImagePoller { * * @param listener - the listener to add */ - public void addListener(MoneroKeyImageListener listener) { + public void addListener(XmrKeyImageListener listener) { listeners.add(listener); refreshPolling(); } @@ -69,7 +89,7 @@ public class MoneroKeyImagePoller { * * @param listener - the listener to remove */ - public void removeListener(MoneroKeyImageListener listener) { + public void removeListener(XmrKeyImageListener listener) { if (!listeners.contains(listener)) throw new MoneroError("Listener is not registered"); listeners.remove(listener); refreshPolling(); @@ -248,7 +268,12 @@ public class MoneroKeyImagePoller { spentStatuses = daemon.getKeyImageSpentStatuses(keyImages); // TODO monero-java: if order of getKeyImageSpentStatuses is guaranteed, then it should take list parameter } } catch (Exception e) { - log.warn("Error polling spent status of key images: " + e.getMessage()); + + // limit error logging + if (lastLogPollErrorTimestamp == null || System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS) { + log.warn("Error polling spent status of key images: " + e.getMessage()); + lastLogPollErrorTimestamp = System.currentTimeMillis(); + } return; } @@ -265,7 +290,7 @@ public class MoneroKeyImagePoller { // announce changes if (!changedStatuses.isEmpty()) { - for (MoneroKeyImageListener listener : new ArrayList<MoneroKeyImageListener>(listeners)) { + for (XmrKeyImageListener listener : new ArrayList<XmrKeyImageListener>(listeners)) { listener.onSpentStatusChanged(changedStatuses); } } diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java new file mode 100644 index 0000000000..81eada3295 --- /dev/null +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletBase.java @@ -0,0 +1,175 @@ +package haveno.core.xmr.wallet; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.exception.ExceptionUtils; + +import haveno.common.Timer; +import haveno.common.UserThread; +import haveno.core.api.XmrConnectionService; +import haveno.core.trade.HavenoUtils; +import haveno.core.xmr.setup.DownloadListener; +import javafx.beans.property.LongProperty; +import javafx.beans.property.SimpleLongProperty; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import monero.common.TaskLooper; +import monero.daemon.model.MoneroTx; +import monero.wallet.MoneroWallet; +import monero.wallet.MoneroWalletFull; +import monero.wallet.model.MoneroWalletListener; + +@Slf4j +public class XmrWalletBase { + + // constants + public static final int SYNC_PROGRESS_TIMEOUT_SECONDS = 120; + public static final int DIRECT_SYNC_WITHIN_BLOCKS = 100; + + // inherited + protected MoneroWallet wallet; + @Getter + protected final Object walletLock = new Object(); + @Getter + protected XmrConnectionService xmrConnectionService; + protected boolean wasWalletSynced; + protected final Map<String, Optional<MoneroTx>> txCache = new HashMap<String, Optional<MoneroTx>>(); + protected boolean isClosingWallet; + protected boolean isSyncingWithProgress; + protected Long syncStartHeight; + protected TaskLooper syncProgressLooper; + protected CountDownLatch syncProgressLatch; + protected Exception syncProgressError; + protected Timer syncProgressTimeout; + protected final DownloadListener downloadListener = new DownloadListener(); + protected final LongProperty walletHeight = new SimpleLongProperty(0); + @Getter + protected boolean isShutDownStarted; + @Getter + protected boolean isShutDown; + + // private + private boolean testReconnectOnStartup = false; // test reconnecting on startup while syncing so the wallet is blocked + private String testReconnectMonerod1 = "http://node.community.rino.io:18081"; + private String testReconnectMonerod2 = "http://nodex.monerujo.io:18081"; + + public XmrWalletBase() { + this.xmrConnectionService = HavenoUtils.xmrConnectionService; + } + + public void syncWithProgress() { + syncWithProgress(false); + } + + public void syncWithProgress(boolean repeatSyncToLatestHeight) { + synchronized (walletLock) { + + // set initial state + isSyncingWithProgress = true; + syncProgressError = null; + long targetHeightAtStart = xmrConnectionService.getTargetHeight(); + syncStartHeight = walletHeight.get(); + updateSyncProgress(syncStartHeight, targetHeightAtStart); + + // test connection changing on startup before wallet synced + if (testReconnectOnStartup) { + UserThread.runAfter(() -> { + log.warn("Testing connection change on startup before wallet synced"); + if (xmrConnectionService.getConnection().getUri().equals(testReconnectMonerod1)) xmrConnectionService.setConnection(testReconnectMonerod2); + else xmrConnectionService.setConnection(testReconnectMonerod1); + }, 1); + testReconnectOnStartup = false; // only run once + } + + // native wallet provides sync notifications + if (wallet instanceof MoneroWalletFull) { + if (testReconnectOnStartup) HavenoUtils.waitFor(1000); // delay sync to test + wallet.sync(new MoneroWalletListener() { + @Override + public void onSyncProgress(long height, long startHeight, long endHeight, double percentDone, String message) { + long appliedTargetHeight = repeatSyncToLatestHeight ? xmrConnectionService.getTargetHeight() : targetHeightAtStart; + updateSyncProgress(height, appliedTargetHeight); + } + }); + setWalletSyncedWithProgress(); + return; + } + + // start polling wallet for progress + syncProgressLatch = new CountDownLatch(1); + syncProgressLooper = new TaskLooper(() -> { + if (wallet == null) return; + long height; + try { + height = wallet.getHeight(); // can get read timeout while syncing + } catch (Exception e) { + log.warn("Error getting wallet height while syncing with progress: " + e.getMessage()); + if (wallet != null && !isShutDownStarted) log.warn(ExceptionUtils.getStackTrace(e)); + + // stop polling and release latch + syncProgressError = e; + syncProgressLatch.countDown(); + return; + } + long appliedTargetHeight = repeatSyncToLatestHeight ? xmrConnectionService.getTargetHeight() : targetHeightAtStart; + updateSyncProgress(height, appliedTargetHeight); + if (height >= appliedTargetHeight) { + setWalletSyncedWithProgress(); + syncProgressLatch.countDown(); + } + }); + wallet.startSyncing(xmrConnectionService.getRefreshPeriodMs()); + syncProgressLooper.start(1000); + + // wait for sync to complete + HavenoUtils.awaitLatch(syncProgressLatch); + + // stop polling + syncProgressLooper.stop(); + syncProgressTimeout.stop(); + if (wallet != null) wallet.stopSyncing(); // can become null if interrupted by force close + isSyncingWithProgress = false; + if (syncProgressError != null) throw new RuntimeException(syncProgressError); + } + } + + private void updateSyncProgress(long height, long targetHeight) { + resetSyncProgressTimeout(); + UserThread.execute(() -> { + + // set wallet height + walletHeight.set(height); + + // new wallet reports height 1 before synced + if (height == 1) { + downloadListener.progress(0, targetHeight - height, null); + return; + } + + // set progress + long blocksLeft = targetHeight - walletHeight.get(); + if (syncStartHeight == null) syncStartHeight = walletHeight.get(); + double percent = Math.min(1.0, targetHeight == syncStartHeight ? 1.0 : ((double) walletHeight.get() - syncStartHeight) / (double) (targetHeight - syncStartHeight)); + downloadListener.progress(percent, blocksLeft, null); + }); + } + + private synchronized void resetSyncProgressTimeout() { + if (syncProgressTimeout != null) syncProgressTimeout.stop(); + syncProgressTimeout = UserThread.runAfter(() -> { + if (isShutDownStarted) return; + syncProgressError = new RuntimeException("Sync progress timeout called"); + syncProgressLatch.countDown(); + }, SYNC_PROGRESS_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } + + private void setWalletSyncedWithProgress() { + wasWalletSynced = true; + isSyncingWithProgress = false; + syncProgressTimeout.stop(); + } +} diff --git a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java index 1bd7d53500..79e9248c64 100644 --- a/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java +++ b/core/src/main/java/haveno/core/xmr/wallet/XmrWalletService.java @@ -1,41 +1,89 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + package haveno.core.xmr.wallet; +import static com.google.common.base.Preconditions.checkState; import com.google.common.util.concurrent.Service.State; +import com.google.inject.Inject; import com.google.inject.name.Named; -import common.utils.GenUtils; import common.utils.JsonUtils; +import haveno.common.ThreadUtils; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.common.file.FileUtil; -import haveno.common.util.Tuple2; import haveno.common.util.Utilities; import haveno.core.api.AccountServiceListener; import haveno.core.api.CoreAccountService; -import haveno.core.api.CoreMoneroConnectionsService; -import haveno.core.offer.Offer; +import haveno.core.api.XmrConnectionService; +import haveno.core.offer.OpenOffer; import haveno.core.trade.BuyerTrade; import haveno.core.trade.HavenoUtils; import haveno.core.trade.MakerTrade; import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; import haveno.core.user.Preferences; +import haveno.core.user.User; import haveno.core.xmr.listeners.XmrBalanceListener; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.model.XmrAddressEntryList; import haveno.core.xmr.setup.MoneroWalletRpcManager; import haveno.core.xmr.setup.WalletsSetup; +import java.io.File; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.Callable; +import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import javafx.beans.property.LongProperty; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.value.ChangeListener; +import lombok.Getter; import monero.common.MoneroError; import monero.common.MoneroRpcConnection; import monero.common.MoneroRpcError; import monero.common.MoneroUtils; +import monero.common.TaskLooper; import monero.daemon.MoneroDaemonRpc; +import monero.daemon.model.MoneroDaemonInfo; import monero.daemon.model.MoneroFeeEstimate; +import monero.daemon.model.MoneroKeyImage; import monero.daemon.model.MoneroNetworkType; import monero.daemon.model.MoneroOutput; import monero.daemon.model.MoneroSubmitTxResult; import monero.daemon.model.MoneroTx; import monero.wallet.MoneroWallet; +import monero.wallet.MoneroWalletFull; import monero.wallet.MoneroWalletRpc; import monero.wallet.model.MoneroCheckTx; import monero.wallet.model.MoneroDestination; @@ -49,46 +97,23 @@ import monero.wallet.model.MoneroTxPriority; import monero.wallet.model.MoneroTxQuery; import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroWalletConfig; -import monero.wallet.model.MoneroWalletListener; import monero.wallet.model.MoneroWalletListenerI; - import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.inject.Inject; -import java.io.File; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.Callable; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import static com.google.common.base.Preconditions.checkState; -public class XmrWalletService { +public class XmrWalletService extends XmrWalletBase { private static final Logger log = LoggerFactory.getLogger(XmrWalletService.class); - // Monero configuration + // monero configuration public static final int NUM_BLOCKS_UNLOCK = 10; - public static final String MONERO_WALLET_RPC_DIR = Config.baseCurrencyNetwork().isTestnet() ? System.getProperty("user.dir") + File.separator + ".localnet" : Config.appDataDir().getAbsolutePath(); // .localnet contains monero-wallet-rpc and wallet files + public static final String MONERO_BINS_DIR = Config.appDataDir().getAbsolutePath(); public static final String MONERO_WALLET_RPC_NAME = Utilities.isWindows() ? "monero-wallet-rpc.exe" : "monero-wallet-rpc"; - public static final String MONERO_WALLET_RPC_PATH = MONERO_WALLET_RPC_DIR + File.separator + MONERO_WALLET_RPC_NAME; + public static final String MONERO_WALLET_RPC_PATH = MONERO_BINS_DIR + File.separator + MONERO_WALLET_RPC_NAME; public static final double MINER_FEE_TOLERANCE = 0.25; // miner fee must be within percent of estimated fee public static final MoneroTxPriority PROTOCOL_FEE_PRIORITY = MoneroTxPriority.ELEVATED; + public static final int MONERO_LOG_LEVEL = -1; // monero library log level, -1 to disable private static final MoneroNetworkType MONERO_NETWORK_TYPE = getMoneroNetworkType(); private static final MoneroWalletRpcManager MONERO_WALLET_RPC_MANAGER = new MoneroWalletRpcManager(); private static final String MONERO_WALLET_RPC_USERNAME = "haveno_user"; @@ -96,49 +121,71 @@ public class XmrWalletService { private static final String MONERO_WALLET_NAME = "haveno_XMR"; private static final String KEYS_FILE_POSTFIX = ".keys"; private static final String ADDRESS_FILE_POSTFIX = ".address.txt"; - private static final int NUM_MAX_BACKUP_WALLETS = 1; - private static final int MONERO_LOG_LEVEL = 0; - private static final boolean PRINT_STACK_TRACE = false; + private static final int NUM_MAX_WALLET_BACKUPS = 2; + private static final int MAX_SYNC_ATTEMPTS = 3; + private static final boolean PRINT_RPC_STACK_TRACE = false; + private static final String THREAD_ID = XmrWalletService.class.getSimpleName(); + private static final long SHUTDOWN_TIMEOUT_MS = 60000; + private static final long NUM_BLOCKS_BEHIND_TOLERANCE = 5; + private static final long POLL_TXS_TOLERANCE_MS = 1000 * 60 * 3; // request connection switch if txs not updated within 3 minutes + private final User user; private final Preferences preferences; private final CoreAccountService accountService; - private final CoreMoneroConnectionsService connectionsService; private final XmrAddressEntryList xmrAddressEntryList; private final WalletsSetup walletsSetup; private final File walletDir; - private final File xmrWalletFile; private final int rpcBindPort; + private final boolean useNativeXmrWallet; protected final CopyOnWriteArraySet<XmrBalanceListener> balanceListeners = new CopyOnWriteArraySet<>(); protected final CopyOnWriteArraySet<MoneroWalletListenerI> walletListeners = new CopyOnWriteArraySet<>(); + private ChangeListener<? super Number> walletInitListener; private TradeManager tradeManager; - private MoneroWalletRpc wallet; - private Object walletLock = new Object(); - private boolean wasWalletSynced = false; - private final Map<String, Optional<MoneroTx>> txCache = new HashMap<String, Optional<MoneroTx>>(); - private boolean isShutDownStarted = false; private ExecutorService syncWalletThreadPool = Executors.newFixedThreadPool(10); // TODO: adjust based on connection type + @Getter + public final Object lock = new Object(); + private TaskLooper pollLooper; + private boolean pollInProgress; + private Long pollPeriodMs; + private long lastLogDaemonNotSyncedTimestamp; + private long lastLogPollErrorTimestamp; + private long lastPollTxsTimestamp; + private final Object pollLock = new Object(); + private Long cachedHeight; + private BigInteger cachedBalance; + private BigInteger cachedAvailableBalance = null; + private List<MoneroSubaddress> cachedSubaddresses; + private List<MoneroOutputWallet> cachedOutputs; + private List<MoneroTxWallet> cachedTxs; + + @SuppressWarnings("unused") @Inject - XmrWalletService(Preferences preferences, + XmrWalletService(User user, + Preferences preferences, CoreAccountService accountService, - CoreMoneroConnectionsService connectionsService, + XmrConnectionService xmrConnectionService, WalletsSetup walletsSetup, XmrAddressEntryList xmrAddressEntryList, @Named(Config.WALLET_DIR) File walletDir, - @Named(Config.WALLET_RPC_BIND_PORT) int rpcBindPort) { + @Named(Config.WALLET_RPC_BIND_PORT) int rpcBindPort, + @Named(Config.USE_NATIVE_XMR_WALLET) boolean useNativeXmrWallet) { + this.user = user; this.preferences = preferences; this.accountService = accountService; - this.connectionsService = connectionsService; this.walletsSetup = walletsSetup; this.xmrAddressEntryList = xmrAddressEntryList; this.walletDir = walletDir; this.rpcBindPort = rpcBindPort; - this.xmrWalletFile = new File(walletDir, MONERO_WALLET_NAME); + this.useNativeXmrWallet = useNativeXmrWallet; + HavenoUtils.xmrWalletService = this; + HavenoUtils.xmrConnectionService = xmrConnectionService; + this.xmrConnectionService = xmrConnectionService; // TODO: super's is null unless set here from injection // set monero logging - MoneroUtils.setLogLevel(MONERO_LOG_LEVEL); + if (MONERO_LOG_LEVEL >= 0) MoneroUtils.setLogLevel(MONERO_LOG_LEVEL); // initialize after account open and basic setup walletsSetup.addSetupTaskHandler(() -> { // TODO: use something better than legacy WalletSetup for notification to initialize @@ -151,19 +198,19 @@ public class XmrWalletService { @Override public void onAccountCreated() { - log.info(getClass().getSimpleName() + ".accountService.onAccountCreated()"); + log.info("onAccountCreated()"); initialize(); } @Override public void onAccountOpened() { - log.info(getClass().getSimpleName() + ".accountService.onAccountOpened()"); + log.info("onAccountOpened()"); initialize(); } @Override public void onAccountClosed() { - log.info(getClass().getSimpleName() + ".accountService.onAccountClosed()"); + log.info("onAccountClosed()"); closeMainWallet(true); } @@ -189,15 +236,28 @@ public class XmrWalletService { return wallet; } + /** + * Get the wallet creation date in seconds since epoch. + * + * @return the wallet creation date in seconds since epoch + */ + public long getWalletCreationDate() { + return user.getWalletCreationDate(); + } + public void saveMainWallet() { - saveMainWallet(true); + saveMainWallet(!(Utilities.isWindows() && wallet != null)); } public void saveMainWallet(boolean backup) { saveWallet(getWallet(), backup); } - public boolean isWalletReady() { + public void requestSaveMainWallet() { + ThreadUtils.submitToPool(() -> saveMainWallet()); // save wallet off main thread + } + + public boolean isWalletAvailable() { try { return getWallet() != null; } catch (Exception e) { @@ -209,16 +269,40 @@ public class XmrWalletService { return accountService.getPassword() != null; } - public MoneroDaemonRpc getDaemon() { - return connectionsService.getDaemon(); + public ReadOnlyDoubleProperty downloadPercentageProperty() { + return downloadListener.percentageProperty(); } - public CoreMoneroConnectionsService getConnectionsService() { - return connectionsService; + private void doneDownload() { + downloadListener.doneDownload(); } - + + public boolean isDownloadComplete() { + return downloadPercentageProperty().get() == 1d; + } + + public LongProperty walletHeightProperty() { + return walletHeight; + } + + public boolean isSyncedWithinTolerance() { + if (!xmrConnectionService.isSyncedWithinTolerance()) return false; + Long targetHeight = xmrConnectionService.getTargetHeight(); + if (targetHeight == null) return false; + if (targetHeight - walletHeight.get() <= NUM_BLOCKS_BEHIND_TOLERANCE) return true; // synced if within a few blocks of target height + return false; + } + + public MoneroDaemonRpc getDaemon() { + return xmrConnectionService.getDaemon(); + } + + public boolean isProxyApplied() { + return isProxyApplied(wasWalletSynced); + } + public boolean isProxyApplied(boolean wasWalletSynced) { - return preferences.isProxyApplied(wasWalletSynced); + return preferences.isProxyApplied(wasWalletSynced) && xmrConnectionService.isProxyApplied(); } public String getWalletPassword() { @@ -230,41 +314,70 @@ public class XmrWalletService { return new File(path + KEYS_FILE_POSTFIX).exists(); } - public MoneroWalletRpc createWallet(String walletName) { - log.info("{}.createWallet({})", getClass().getSimpleName(), walletName); - if (isShutDownStarted) throw new IllegalStateException("Cannot create wallet because shutting down"); - return createWalletRpc(new MoneroWalletConfig() - .setPath(walletName) - .setPassword(getWalletPassword()), - null); + public MoneroWallet createWallet(String walletName) { + return createWallet(walletName, null); } - public MoneroWalletRpc openWallet(String walletName, boolean applyProxyUri) { + public MoneroWallet createWallet(String walletName, Integer walletRpcPort) { + log.info("{}.createWallet({})", getClass().getSimpleName(), walletName); + if (isShutDownStarted) throw new IllegalStateException("Cannot create wallet because shutting down"); + MoneroWalletConfig config = getWalletConfig(walletName); + return isNativeLibraryApplied() ? createWalletFull(config) : createWalletRpc(config, walletRpcPort); + } + + public MoneroWallet openWallet(String walletName, boolean applyProxyUri) { + return openWallet(walletName, null, applyProxyUri); + } + + public MoneroWallet openWallet(String walletName, Integer walletRpcPort, boolean applyProxyUri) { log.info("{}.openWallet({})", getClass().getSimpleName(), walletName); if (isShutDownStarted) throw new IllegalStateException("Cannot open wallet because shutting down"); - return openWalletRpc(new MoneroWalletConfig() - .setPath(walletName) - .setPassword(getWalletPassword()), - null, - applyProxyUri); + MoneroWalletConfig config = getWalletConfig(walletName); + return isNativeLibraryApplied() ? openWalletFull(config, applyProxyUri) : openWalletRpc(config, walletRpcPort, applyProxyUri); + } + + private MoneroWalletConfig getWalletConfig(String walletName) { + MoneroWalletConfig config = new MoneroWalletConfig().setPath(getWalletPath(walletName)).setPassword(getWalletPassword()); + if (isNativeLibraryApplied()) config.setNetworkType(getMoneroNetworkType()); + return config; + } + + private String getWalletPath(String walletName) { + return (isNativeLibraryApplied() ? walletDir.getPath() + File.separator : "") + walletName; + } + + private static String getWalletName(String walletPath) { + return walletPath.substring(walletPath.lastIndexOf(File.separator) + 1); + } + + private boolean isNativeLibraryApplied() { + return useNativeXmrWallet && MoneroUtils.isNativeLibraryLoaded(); } /** * Sync the given wallet in a thread pool with other wallets. */ public MoneroSyncResult syncWallet(MoneroWallet wallet) { - Callable<MoneroSyncResult> task = () -> wallet.sync(); - Future<MoneroSyncResult> future = syncWalletThreadPool.submit(task); - try { - return future.get(); - } catch (Exception e) { - throw new MoneroError(e.getMessage()); + synchronized (HavenoUtils.getDaemonLock()) { // TODO: lock defeats purpose of thread pool + Callable<MoneroSyncResult> task = () -> { + return wallet.sync(); + }; + Future<MoneroSyncResult> future = syncWalletThreadPool.submit(task); + try { + return future.get(); + } catch (Exception e) { + throw new MoneroError(e.getMessage()); + } } } + public void saveWallet(MoneroWallet wallet) { + saveWallet(wallet, false); + } + public void saveWallet(MoneroWallet wallet, boolean backup) { wallet.save(); - if (backup) backupWallet(wallet.getPath()); + if (backup) backupWallet(getWalletName(wallet.getPath())); } public void closeWallet(MoneroWallet wallet, boolean save) { @@ -273,23 +386,30 @@ public class XmrWalletService { String path = wallet.getPath(); try { wallet.close(save); - if (save) backupWallet(path); + if (save) backupWallet(getWalletName(path)); } catch (MoneroError e) { err = e; } - stopWallet(wallet, path); + + // stop wallet rpc instance if applicable + if (wallet instanceof MoneroWalletRpc) MONERO_WALLET_RPC_MANAGER.stopInstance((MoneroWalletRpc) wallet, path, false); if (err != null) throw err; } - public void stopWallet(MoneroWallet wallet, String path) { - stopWallet(wallet, path, false); - } - - public void stopWallet(MoneroWallet wallet, String path, boolean force) { - MONERO_WALLET_RPC_MANAGER.stopInstance((MoneroWalletRpc) wallet, path, force); + public void forceCloseWallet(MoneroWallet wallet, String path) { + if (wallet == null) { + log.warn("Ignoring force close wallet because wallet is null, path={}", path); + return; + } + if (wallet instanceof MoneroWalletRpc) { + MONERO_WALLET_RPC_MANAGER.stopInstance((MoneroWalletRpc) wallet, path, true); + } else { + wallet.close(false); + } } public void deleteWallet(String walletName) { + assertNotPath(walletName); log.info("{}.deleteWallet({})", getClass().getSimpleName(), walletName); if (!walletExists(walletName)) throw new Error("Wallet does not exist at path: " + walletName); String path = walletDir.toString() + File.separator + walletName; @@ -299,44 +419,178 @@ public class XmrWalletService { } public void backupWallet(String walletName) { - FileUtil.rollingBackup(walletDir, walletName, NUM_MAX_BACKUP_WALLETS); - FileUtil.rollingBackup(walletDir, walletName + KEYS_FILE_POSTFIX, NUM_MAX_BACKUP_WALLETS); - FileUtil.rollingBackup(walletDir, walletName + ADDRESS_FILE_POSTFIX, NUM_MAX_BACKUP_WALLETS); + assertNotPath(walletName); + FileUtil.rollingBackup(walletDir, walletName, NUM_MAX_WALLET_BACKUPS); + FileUtil.rollingBackup(walletDir, walletName + KEYS_FILE_POSTFIX, NUM_MAX_WALLET_BACKUPS); + FileUtil.rollingBackup(walletDir, walletName + ADDRESS_FILE_POSTFIX, NUM_MAX_WALLET_BACKUPS); } public void deleteWalletBackups(String walletName) { + assertNotPath(walletName); FileUtil.deleteRollingBackup(walletDir, walletName); FileUtil.deleteRollingBackup(walletDir, walletName + KEYS_FILE_POSTFIX); FileUtil.deleteRollingBackup(walletDir, walletName + ADDRESS_FILE_POSTFIX); } - public MoneroTxWallet createTx(List<MoneroDestination> destinations) { + private static void assertNotPath(String name) { + if (name.contains(File.separator)) throw new IllegalArgumentException("Path not expected: " + name); + } + + public MoneroTxWallet createTx(MoneroTxConfig txConfig) { synchronized (walletLock) { - try { - MoneroTxWallet tx = wallet.createTx(new MoneroTxConfig().setAccountIndex(0).setDestinations(destinations).setRelay(false).setCanSplit(false)); - //printTxs("XmrWalletService.createTx", tx); + synchronized (HavenoUtils.getWalletFunctionLock()) { + MoneroTxWallet tx = wallet.createTx(txConfig); + if (Boolean.TRUE.equals(txConfig.getRelay())) { + cachedTxs.addFirst(tx); + cacheWalletInfo(); + requestSaveMainWallet(); + } return tx; - } catch (Exception e) { - throw e; } } } + public String relayTx(String metadata) { + synchronized (walletLock) { + String txId = wallet.relayTx(metadata); + requestSaveMainWallet(); + return txId; + } + } + + public MoneroTxWallet createTx(List<MoneroDestination> destinations) { + MoneroTxWallet tx = createTx(new MoneroTxConfig().setAccountIndex(0).setDestinations(destinations).setRelay(false).setCanSplit(false)); + //printTxs("XmrWalletService.createTx", tx); + return tx; + } + + /** + * Freeze reserved outputs and thaw unreserved outputs. + */ + public void fixReservedOutputs() { + synchronized (walletLock) { + + // collect reserved outputs + Set<String> reservedKeyImages = new HashSet<String>(); + for (Trade trade : tradeManager.getOpenTrades()) { + if (trade.getSelf().getReserveTxKeyImages() == null) continue; + reservedKeyImages.addAll(trade.getSelf().getReserveTxKeyImages()); + } + for (OpenOffer openOffer : tradeManager.getOpenOfferManager().getOpenOffers()) { + if (openOffer.getOffer().getOfferPayload().getReserveTxKeyImages() == null) continue; + reservedKeyImages.addAll(openOffer.getOffer().getOfferPayload().getReserveTxKeyImages()); + } + + freezeReservedOutputs(reservedKeyImages); + thawUnreservedOutputs(reservedKeyImages); + } + } + + private void freezeReservedOutputs(Set<String> reservedKeyImages) { + synchronized (walletLock) { + + // ensure wallet is open + if (wallet == null) { + log.warn("Cannot freeze reserved outputs because wallet not open"); + return; + } + + // freeze reserved outputs + Set<String> reservedUnfrozenKeyImages = getOutputs(new MoneroOutputQuery() + .setIsFrozen(false) + .setIsSpent(false)) + .stream() + .map(output -> output.getKeyImage().getHex()) + .collect(Collectors.toSet()); + reservedUnfrozenKeyImages.retainAll(reservedKeyImages); + if (!reservedUnfrozenKeyImages.isEmpty()) { + log.warn("Freezing unfrozen outputs which are reserved for offer or trade: " + reservedUnfrozenKeyImages); + freezeOutputs(reservedUnfrozenKeyImages); + } + } + } + + private void thawUnreservedOutputs(Set<String> reservedKeyImages) { + synchronized (walletLock) { + + // ensure wallet is open + if (wallet == null) { + log.warn("Cannot thaw unreserved outputs because wallet not open"); + return; + } + + // thaw unreserved outputs + Set<String> unreservedFrozenKeyImages = getOutputs(new MoneroOutputQuery() + .setIsFrozen(true) + .setIsSpent(false)) + .stream() + .map(output -> output.getKeyImage().getHex()) + .collect(Collectors.toSet()); + unreservedFrozenKeyImages.removeAll(reservedKeyImages); + if (!unreservedFrozenKeyImages.isEmpty()) { + log.warn("Thawing frozen outputs which are not reserved for offer or trade: " + unreservedFrozenKeyImages); + thawOutputs(unreservedFrozenKeyImages); + } + } + } + + /** + * Freeze the given outputs with a lock on the wallet. + * + * @param keyImages the key images to freeze (ignored if null or empty) + */ + public void freezeOutputs(Collection<String> keyImages) { + if (keyImages == null || keyImages.isEmpty()) return; + synchronized (walletLock) { + + // collect outputs to freeze + List<String> unfrozenKeyImages = getOutputs(new MoneroOutputQuery().setIsFrozen(false).setIsSpent(false)).stream() + .map(output -> output.getKeyImage().getHex()) + .collect(Collectors.toList()); + unfrozenKeyImages.retainAll(keyImages); + + // freeze outputs + for (String keyImage : unfrozenKeyImages) wallet.freezeOutput(keyImage); + cacheWalletInfo(); + requestSaveMainWallet(); + } + } + /** * Thaw the given outputs with a lock on the wallet. * - * @param keyImages the key images to thaw + * @param keyImages the key images to thaw (ignored if null or empty) */ public void thawOutputs(Collection<String> keyImages) { + if (keyImages == null || keyImages.isEmpty()) return; synchronized (walletLock) { - for (String keyImage : keyImages) wallet.thawOutput(keyImage); + + // collect outputs to thaw + List<String> frozenKeyImages = getOutputs(new MoneroOutputQuery().setIsFrozen(true).setIsSpent(false)).stream() + .map(output -> output.getKeyImage().getHex()) + .collect(Collectors.toList()); + frozenKeyImages.retainAll(keyImages); + + // thaw outputs + for (String keyImage : frozenKeyImages) wallet.thawOutput(keyImage); + cacheWalletInfo(); + requestSaveMainWallet(); } } + public BigInteger getOutputsAmount(Collection<String> keyImages) { + BigInteger sum = BigInteger.ZERO; + for (String keyImage : keyImages) { + List<MoneroOutputWallet> outputs = getOutputs(new MoneroOutputQuery().setIsSpent(false).setKeyImage(new MoneroKeyImage(keyImage))); + if (!outputs.isEmpty()) sum = sum.add(outputs.get(0).getAmount()); + } + return sum; + } + private List<Integer> getSubaddressesWithExactInput(BigInteger amount) { // fetch unspent, unfrozen, unlocked outputs - List<MoneroOutputWallet> exactOutputs = wallet.getOutputs(new MoneroOutputQuery() + List<MoneroOutputWallet> exactOutputs = getOutputs(new MoneroOutputQuery() .setAmount(amount) .setIsSpent(false) .setIsFrozen(false) @@ -350,25 +604,31 @@ public class XmrWalletService { /** * Create the reserve tx and freeze its inputs. The full amount is returned - * to the sender's payout address less the security deposit and mining fee. + * to the sender's payout address less the penalty and mining fees. * + * @param penaltyFee penalty fee for breaking protocol * @param tradeFee trade fee - * @param sendAmount amount to give peer + * @param sendTradeAmount trade amount to send peer * @param securityDeposit security deposit amount * @param returnAddress return address for reserved funds * @param reserveExactAmount specifies to reserve the exact input amount * @param preferredSubaddressIndex preferred source subaddress to spend from (optional) - * @return a transaction to reserve a trade + * @return the reserve tx */ - public MoneroTxWallet createReserveTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String returnAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { - log.info("Creating reserve tx with preferred subaddress index={}, return address={}", preferredSubaddressIndex, returnAddress); - long time = System.currentTimeMillis(); - MoneroTxWallet reserveTx = createTradeTx(tradeFee, sendAmount, securityDeposit, returnAddress, reserveExactAmount, preferredSubaddressIndex); - log.info("Done creating reserve tx in {} ms", System.currentTimeMillis() - time); - return reserveTx; + public MoneroTxWallet createReserveTx(BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendTradeAmount, BigInteger securityDeposit, String returnAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { + synchronized (walletLock) { + synchronized (HavenoUtils.getWalletFunctionLock()) { + log.info("Creating reserve tx with preferred subaddress index={}, return address={}", preferredSubaddressIndex, returnAddress); + long time = System.currentTimeMillis(); + BigInteger sendAmount = sendTradeAmount.add(securityDeposit).add(tradeFee).subtract(penaltyFee); + MoneroTxWallet reserveTx = createTradeTx(penaltyFee, HavenoUtils.getBurnAddress(), sendAmount, returnAddress, reserveExactAmount, preferredSubaddressIndex); + log.info("Done creating reserve tx in {} ms", System.currentTimeMillis() - time); + return reserveTx; + } + } } - /**s + /** * Create the multisig deposit tx and freeze its inputs. * * @param trade the trade to create a deposit tx from @@ -378,34 +638,30 @@ public class XmrWalletService { */ public MoneroTxWallet createDepositTx(Trade trade, boolean reserveExactAmount, Integer preferredSubaddressIndex) { synchronized (walletLock) { - - // thaw reserved outputs - if (trade.getSelf().getReserveTxKeyImages() != null) { - thawOutputs(trade.getSelf().getReserveTxKeyImages()); + synchronized (HavenoUtils.getWalletFunctionLock()) { + BigInteger feeAmount = trade instanceof MakerTrade ? trade.getMakerFee() : trade.getTakerFee(); + String feeAddress = trade.getProcessModel().getTradeFeeAddress(); + BigInteger sendTradeAmount = trade instanceof BuyerTrade ? BigInteger.ZERO : trade.getAmount(); + BigInteger securityDeposit = trade instanceof BuyerTrade ? trade.getBuyerSecurityDepositBeforeMiningFee() : trade.getSellerSecurityDepositBeforeMiningFee(); + BigInteger sendAmount = sendTradeAmount.add(securityDeposit); + String multisigAddress = trade.getProcessModel().getMultisigAddress(); + long time = System.currentTimeMillis(); + log.info("Creating deposit tx for trade {} {} with multisig address={}", trade.getClass().getSimpleName(), trade.getShortId(), multisigAddress); + MoneroTxWallet depositTx = createTradeTx(feeAmount, feeAddress, sendAmount, multisigAddress, reserveExactAmount, preferredSubaddressIndex); + log.info("Done creating deposit tx for trade {} {} in {} ms", trade.getClass().getSimpleName(), trade.getShortId(), System.currentTimeMillis() - time); + return depositTx; } - - // create deposit tx - Offer offer = trade.getProcessModel().getOffer(); - String multisigAddress = trade.getProcessModel().getMultisigAddress(); - BigInteger tradeFee = trade instanceof MakerTrade ? trade.getOffer().getMakerFee() : trade.getTakerFee(); - BigInteger sendAmount = trade instanceof BuyerTrade ? BigInteger.valueOf(0) : offer.getAmount(); - BigInteger securityDeposit = trade instanceof BuyerTrade ? offer.getBuyerSecurityDeposit() : offer.getSellerSecurityDeposit(); - long time = System.currentTimeMillis(); - log.info("Creating deposit tx with multisig address={}", multisigAddress); - MoneroTxWallet depositTx = createTradeTx(tradeFee, sendAmount, securityDeposit, multisigAddress, reserveExactAmount, preferredSubaddressIndex); - log.info("Done creating deposit tx for trade {} {} in {} ms", trade.getClass().getSimpleName(), trade.getId(), System.currentTimeMillis() - time); - return depositTx; } } - private MoneroTxWallet createTradeTx(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean reserveExactAmount, Integer preferredSubaddressIndex) { + private MoneroTxWallet createTradeTx(BigInteger feeAmount, String feeAddress, BigInteger sendAmount, String sendAddress, boolean reserveExactAmount, Integer preferredSubaddressIndex) { synchronized (walletLock) { MoneroWallet wallet = getWallet(); // create a list of subaddresses to attempt spending from in preferred order List<Integer> subaddressIndices = new ArrayList<Integer>(); if (reserveExactAmount) { - BigInteger exactInputAmount = tradeFee.add(sendAmount).add(securityDeposit); + BigInteger exactInputAmount = feeAmount.add(sendAmount); List<Integer> subaddressIndicesWithExactInput = getSubaddressesWithExactInput(exactInputAmount); if (preferredSubaddressIndex != null) subaddressIndicesWithExactInput.remove(preferredSubaddressIndex); Collections.sort(subaddressIndicesWithExactInput); @@ -413,7 +669,7 @@ public class XmrWalletService { subaddressIndices.addAll(subaddressIndicesWithExactInput); } if (preferredSubaddressIndex != null) { - if (wallet.getBalance(0, preferredSubaddressIndex).compareTo(BigInteger.valueOf(0)) > 0) { + if (wallet.getBalance(0, preferredSubaddressIndex).compareTo(BigInteger.ZERO) > 0) { subaddressIndices.add(0, preferredSubaddressIndex); // try preferred subaddress first if funded } else if (reserveExactAmount) { subaddressIndices.add(preferredSubaddressIndex); // otherwise only try preferred subaddress if using exact output @@ -423,66 +679,68 @@ public class XmrWalletService { // first try preferred subaddressess for (int i = 0; i < subaddressIndices.size(); i++) { try { - return createTradeTxFromSubaddress(tradeFee, sendAmount, securityDeposit, address, reserveExactAmount, subaddressIndices.get(i)); + return createTradeTxFromSubaddress(feeAmount, feeAddress, sendAmount, sendAddress, subaddressIndices.get(i)); } catch (Exception e) { - if (i == subaddressIndices.size() - 1 && reserveExactAmount) throw e; // throw if no subaddress with exact output + log.info("Cannot create trade tx from preferred subaddress index " + subaddressIndices.get(i) + ": " + e.getMessage()); } } // try any subaddress - return createTradeTxFromSubaddress(tradeFee, sendAmount, securityDeposit, address, reserveExactAmount, null); + if (!subaddressIndices.isEmpty()) log.info("Could not create trade tx from preferred subaddresses, trying any subaddress"); + return createTradeTxFromSubaddress(feeAmount, feeAddress, sendAmount, sendAddress, null); } } - private MoneroTxWallet createTradeTxFromSubaddress(BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, boolean reserveExactAmount, Integer subaddressIndex) { + private MoneroTxWallet createTradeTxFromSubaddress(BigInteger feeAmount, String feeAddress, BigInteger sendAmount, String sendAddress, Integer subaddressIndex) { // create tx - MoneroTxWallet tradeTx = wallet.createTx(new MoneroTxConfig() + MoneroTxConfig txConfig = new MoneroTxConfig() .setAccountIndex(0) .setSubaddressIndices(subaddressIndex) - .addDestination(HavenoUtils.getTradeFeeAddress(), tradeFee) - .addDestination(address, sendAmount.add(securityDeposit)) - .setSubtractFeeFrom(1) - .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY)); // pay fee from security deposit - - // check if tx uses exact input, since wallet2 can prefer to spend 2 outputs - if (reserveExactAmount) { - BigInteger exactInputAmount = tradeFee.add(sendAmount).add(securityDeposit); - BigInteger inputSum = BigInteger.valueOf(0); - for (MoneroOutputWallet txInput : tradeTx.getInputsWallet()) { - MoneroOutputWallet input = wallet.getOutputs(new MoneroOutputQuery().setKeyImage(txInput.getKeyImage())).get(0); - inputSum = inputSum.add(input.getAmount()); - } - if (inputSum.compareTo(exactInputAmount) > 0) throw new RuntimeException("Cannot create transaction with exact input amount"); - } + .addDestination(sendAddress, sendAmount) + .setSubtractFeeFrom(0) // pay mining fee from send amount + .setPriority(XmrWalletService.PROTOCOL_FEE_PRIORITY); + if (!BigInteger.valueOf(0).equals(feeAmount)) txConfig.addDestination(feeAddress, feeAmount); + MoneroTxWallet tradeTx = createTx(txConfig); // freeze inputs - for (MoneroOutput input : tradeTx.getInputs()) wallet.freezeOutput(input.getKeyImage().getHex()); - saveMainWallet(); + List<String> keyImages = new ArrayList<String>(); + for (MoneroOutput input : tradeTx.getInputs()) keyImages.add(input.getKeyImage().getHex()); + freezeOutputs(keyImages); return tradeTx; } + public MoneroTx verifyReserveTx(String offerId, BigInteger penaltyFee, BigInteger tradeFee, BigInteger sendTradeAmount, BigInteger securityDeposit, String returnAddress, String txHash, String txHex, String txKey, List<String> keyImages) { + BigInteger sendAmount = sendTradeAmount.add(securityDeposit).add(tradeFee).subtract(penaltyFee); + return verifyTradeTx(offerId, penaltyFee, HavenoUtils.getBurnAddress(), sendAmount, returnAddress, txHash, txHex, txKey, keyImages); + } + + public MoneroTx verifyDepositTx(String offerId, BigInteger feeAmount, String feeAddress, BigInteger sendTradeAmount, BigInteger securityDeposit, String multisigAddress, String txHash, String txHex, String txKey, List<String> keyImages) { + BigInteger sendAmount = sendTradeAmount.add(securityDeposit); + return verifyTradeTx(offerId, feeAmount, feeAddress, sendAmount, multisigAddress, txHash, txHex, txKey, keyImages); + } + /** * Verify a reserve or deposit transaction. * Checks double spends, trade fee, deposit amount and destination, and miner fee. * The transaction is submitted to the pool then flushed without relaying. * - * @param tradeFee trade fee - * @param sendAmount amount to give peer - * @param securityDeposit security deposit amount - * @param address expected destination address for the deposit amount + * @param offerId id of offer to verify trade tx + * @param tradeFeeAmount amount sent to fee address + * @param feeAddress fee address + * @param sendAmount amount sent to transfer address + * @param sendAddress transfer address * @param txHash transaction hash * @param txHex transaction hex * @param txKey transaction key * @param keyImages expected key images of inputs, ignored if null - * @return tuple with the verified tx and its actual security deposit + * @return the verified tx */ - public Tuple2<MoneroTx, BigInteger> verifyTradeTx(String offerId, BigInteger tradeFee, BigInteger sendAmount, BigInteger securityDeposit, String address, String txHash, String txHex, String txKey, List<String> keyImages) { + public MoneroTx verifyTradeTx(String offerId, BigInteger tradeFeeAmount, String feeAddress, BigInteger sendAmount, String sendAddress, String txHash, String txHex, String txKey, List<String> keyImages) { if (txHash == null) throw new IllegalArgumentException("Cannot verify trade tx with null id"); MoneroDaemonRpc daemon = getDaemon(); MoneroWallet wallet = getWallet(); MoneroTx tx = null; - BigInteger actualSecurityDeposit = null; synchronized (daemon) { try { @@ -506,44 +764,36 @@ public class XmrWalletService { } // verify unlock height - if (!BigInteger.valueOf(0).equals(tx.getUnlockTime())) throw new RuntimeException("Unlock height must be 0"); + if (!BigInteger.ZERO.equals(tx.getUnlockTime())) throw new RuntimeException("Unlock height must be 0"); // verify miner fee - BigInteger feeEstimate = getElevatedFeeEstimate(tx.getWeight()); - double feeDiff = tx.getFee().subtract(feeEstimate).abs().doubleValue() / feeEstimate.doubleValue(); - if (feeDiff > MINER_FEE_TOLERANCE) throw new Error("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + feeEstimate + " but was " + tx.getFee()); - log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), feeDiff); + BigInteger minerFeeEstimate = getElevatedFeeEstimate(tx.getWeight()); + double minerFeeDiff = tx.getFee().subtract(minerFeeEstimate).abs().doubleValue() / minerFeeEstimate.doubleValue(); + if (minerFeeDiff > MINER_FEE_TOLERANCE) throw new Error("Miner fee is not within " + (MINER_FEE_TOLERANCE * 100) + "% of estimated fee, expected " + minerFeeEstimate + " but was " + tx.getFee()); + log.info("Trade tx fee {} is within tolerance, diff%={}", tx.getFee(), minerFeeDiff); - // verify transfer proof to fee address - MoneroCheckTx tradeFeeCheck = wallet.checkTxKey(txHash, txKey, HavenoUtils.getTradeFeeAddress()); - if (!tradeFeeCheck.isGood()) throw new RuntimeException("Invalid proof to trade fee address"); - - // verify transfer proof to address - MoneroCheckTx transferCheck = wallet.checkTxKey(txHash, txKey, address); - if (!transferCheck.isGood()) throw new RuntimeException("Invalid proof to transfer address"); - - // collect actual trade fee, send amount, and security deposit - BigInteger actualTradeFee = tradeFeeCheck.getReceivedAmount(); - actualSecurityDeposit = transferCheck.getReceivedAmount().subtract(sendAmount); - BigInteger actualSendAmount = transferCheck.getReceivedAmount().subtract(actualSecurityDeposit); - - // verify trade fee - if (actualTradeFee.compareTo(tradeFee) < 0) { - throw new RuntimeException("Insufficient trade fee, expected=" + tradeFee + ", actual=" + actualTradeFee + ", transfer address check=" + JsonUtils.serialize(transferCheck) + ", trade fee address check=" + JsonUtils.serialize(tradeFeeCheck)); + // verify proof to fee address + BigInteger actualTradeFee = BigInteger.ZERO; + if (tradeFeeAmount.compareTo(BigInteger.ZERO) > 0) { + MoneroCheckTx tradeFeeCheck = wallet.checkTxKey(txHash, txKey, feeAddress); + if (!tradeFeeCheck.isGood()) throw new RuntimeException("Invalid proof to trade fee address"); + actualTradeFee = tradeFeeCheck.getReceivedAmount(); } + // verify proof to transfer address + MoneroCheckTx transferCheck = wallet.checkTxKey(txHash, txKey, sendAddress); + if (!transferCheck.isGood()) throw new RuntimeException("Invalid proof to transfer address"); + BigInteger actualSendAmount = transferCheck.getReceivedAmount(); + + // verify trade fee amount + if (!actualTradeFee.equals(tradeFeeAmount)) throw new RuntimeException("Invalid trade fee amount, expected " + tradeFeeAmount + " but was " + actualTradeFee); + // verify send amount - if (!actualSendAmount.equals(sendAmount)) { - throw new RuntimeException("Unexpected send amount, expected " + sendAmount + " but was " + actualSendAmount); - } - - // verify security deposit - BigInteger expectedSecurityDeposit = securityDeposit.subtract(tx.getFee()); // fee is paid from security deposit - if (!actualSecurityDeposit.equals(expectedSecurityDeposit)) { - throw new RuntimeException("Unexpected security deposit amount, expected " + expectedSecurityDeposit + " but was " + actualSecurityDeposit); - } + BigInteger expectedSendAmount = sendAmount.subtract(tx.getFee()); + if (!actualSendAmount.equals(expectedSendAmount)) throw new RuntimeException("Invalid send amount, expected " + expectedSendAmount + " but was " + actualSendAmount + " with tx fee " + tx.getFee()); + return tx; } catch (Exception e) { - log.warn("Error verifying trade tx with offer id=" + offerId + (tx == null ? "" : ", tx=" + tx) + ": " + e.getMessage()); + log.warn("Error verifying trade tx with offer id=" + offerId + (tx == null ? "" : ", tx=\n" + tx) + ": " + e.getMessage()); throw e; } finally { try { @@ -553,7 +803,6 @@ public class XmrWalletService { throw err.getCode().equals(-32601) ? new RuntimeException("Failed to flush tx from pool. Arbitrator must use trusted, unrestricted daemon") : err; } } - return new Tuple2<>(tx, actualSecurityDeposit); } } @@ -569,7 +818,7 @@ public class XmrWalletService { MoneroFeeEstimate feeEstimates = getDaemon().getFeeEstimate(); BigInteger baseFeeEstimate = feeEstimates.getFees().get(2); // get elevated fee per kB BigInteger qmask = feeEstimates.getQuantizationMask(); - log.info("Monero base fee estimate={}, qmask={}: " + baseFeeEstimate, qmask); + log.info("Monero base fee estimate={}, qmask={}", baseFeeEstimate, qmask); // get tx base fee BigInteger baseFee = baseFeeEstimate.multiply(BigInteger.valueOf(txWeight)); @@ -577,20 +826,20 @@ public class XmrWalletService { // round up to multiple of quantization mask BigInteger[] quotientAndRemainder = baseFee.divideAndRemainder(qmask); BigInteger feeEstimate = qmask.multiply(quotientAndRemainder[0]); - if (quotientAndRemainder[1].compareTo(BigInteger.valueOf(0)) > 0) feeEstimate = feeEstimate.add(qmask); + if (quotientAndRemainder[1].compareTo(BigInteger.ZERO) > 0) feeEstimate = feeEstimate.add(qmask); return feeEstimate; } - public MoneroTx getTx(String txHash) { - List<MoneroTx> txs = getTxs(Arrays.asList(txHash)); + public MoneroTx getDaemonTx(String txHash) { + List<MoneroTx> txs = getDaemonTxs(Arrays.asList(txHash)); return txs.isEmpty() ? null : txs.get(0); } - public List<MoneroTx> getTxs(List<String> txHashes) { + public List<MoneroTx> getDaemonTxs(List<String> txHashes) { synchronized (txCache) { // fetch txs - if (getDaemon() == null) connectionsService.verifyConnection(); // will throw + if (getDaemon() == null) xmrConnectionService.verifyConnection(); // will throw List<MoneroTx> txs = getDaemon().getTxs(txHashes, true); // store to cache @@ -601,17 +850,17 @@ public class XmrWalletService { synchronized (txCache) { for (MoneroTx tx : txs) txCache.remove(tx.getHash()); } - }, connectionsService.getRefreshPeriodMs() / 1000); + }, xmrConnectionService.getRefreshPeriodMs() / 1000); return txs; } } - public MoneroTx getTxWithCache(String txHash) { - List<MoneroTx> cachedTxs = getTxsWithCache(Arrays.asList(txHash)); + public MoneroTx getDaemonTxWithCache(String txHash) { + List<MoneroTx> cachedTxs = getDaemonTxsWithCache(Arrays.asList(txHash)); return cachedTxs.isEmpty() ? null : cachedTxs.get(0); } - public List<MoneroTx> getTxsWithCache(List<String> txHashes) { + public List<MoneroTx> getDaemonTxsWithCache(List<String> txHashes) { synchronized (txCache) { try { // get cached txs @@ -623,7 +872,7 @@ public class XmrWalletService { } // return txs from cache if available, otherwise fetch - return uncachedTxHashes.isEmpty() ? cachedTxs : getTxs(txHashes); + return uncachedTxHashes.isEmpty() ? cachedTxs : getDaemonTxs(txHashes); } catch (Exception e) { if (!isShutDownStarted) throw e; return null; @@ -634,306 +883,55 @@ public class XmrWalletService { public void onShutDownStarted() { log.info("XmrWalletService.onShutDownStarted()"); this.isShutDownStarted = true; - - // remove listeners which stops polling wallet - // TODO monero-java: wallet.stopPolling()? - if (wallet != null) { - for (MoneroWalletListenerI listener : new HashSet<>(wallet.getListeners())) { - wallet.removeListener(listener); - } - } - - // prepare trades for shut down - if (tradeManager != null) tradeManager.onShutDownStarted(); } public void shutDown() { log.info("Shutting down {}", getClass().getSimpleName()); - // shut down trade and main wallets at same time - walletListeners.clear(); - List<Runnable> tasks = new ArrayList<Runnable>(); - if (tradeManager != null) tasks.add(() -> tradeManager.shutDown()); - tasks.add(() -> closeMainWallet(true)); - HavenoUtils.executeTasks(tasks); - log.info("Done shutting down all wallets"); - } + // create task to shut down + Runnable shutDownTask = () -> { - // ------------------------------ PRIVATE HELPERS ------------------------- - - private void initialize() { - - // initialize main wallet if connected or previously created - maybeInitMainWallet(true); - - // set and listen to daemon connection - connectionsService.addConnectionListener(newConnection -> onConnectionChanged(newConnection)); - } - - private void maybeInitMainWallet(boolean sync) { - synchronized (walletLock) { - - // open or create wallet main wallet - if (wallet == null) { - MoneroDaemonRpc daemon = connectionsService.getDaemon(); - log.info("Initializing main wallet with monerod=" + (daemon == null ? "null" : daemon.getRpcConnection().getUri())); - MoneroWalletConfig walletConfig = new MoneroWalletConfig().setPath(MONERO_WALLET_NAME).setPassword(getWalletPassword()); - if (MoneroUtils.walletExists(xmrWalletFile.getPath())) { - wallet = openWalletRpc(walletConfig, rpcBindPort, isProxyApplied(wasWalletSynced)); - } else if (connectionsService.getConnection() != null && Boolean.TRUE.equals(connectionsService.getConnection().isConnected())) { - wallet = createWalletRpc(walletConfig, rpcBindPort); + // remove listeners + synchronized (walletLock) { + if (wallet != null) { + for (MoneroWalletListenerI listener : new HashSet<>(wallet.getListeners())) { + wallet.removeListener(listener); + } } + walletListeners.clear(); } - // sync wallet and register listener + // shut down threads + synchronized (getLock()) { + List<Runnable> shutDownThreads = new ArrayList<>(); + shutDownThreads.add(() -> ThreadUtils.shutDown(THREAD_ID)); + ThreadUtils.awaitTasks(shutDownThreads); + } + + // shut down main wallet if (wallet != null) { - log.info("Monero wallet uri={}, path={}", wallet.getRpcConnection().getUri(), wallet.getPath()); - if (sync) { - int maxAttempts = 3; - for (int i = 0; i < maxAttempts; i++) { - try { - - // sync main wallet - log.info("Syncing main wallet"); - long time = System.currentTimeMillis(); - wallet.sync(); // blocking - wasWalletSynced = true; - log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms"); - wallet.startSyncing(connectionsService.getRefreshPeriodMs()); - if (getMoneroNetworkType() != MoneroNetworkType.MAINNET) log.info("Monero wallet balance={}, unlocked balance={}", wallet.getBalance(0), wallet.getUnlockedBalance(0)); - - // reapply connection after wallet synced - onConnectionChanged(connectionsService.getConnection()); - - // TODO: using this to signify both daemon and wallet synced, use separate sync handlers? - connectionsService.doneDownload(); - - // notify setup that main wallet is initialized - // TODO: app fully initializes after this is set to true, even though wallet might not be initialized if unconnected. wallet will be created when connection detected - // refactor startup to call this and sync off main thread? but the calls to e.g. getBalance() fail with 'wallet and network is not yet initialized' - HavenoUtils.havenoSetup.getWalletInitialized().set(true); - - // save but skip backup on initialization - saveMainWallet(false); - break; - } catch (Exception e) { - log.warn("Error syncing main wallet: {}", e.getMessage()); - if (i == maxAttempts - 1) { - log.warn("Failed to sync main wallet after {} attempts. Opening app without syncing", maxAttempts); - HavenoUtils.havenoSetup.getWalletInitialized().set(true); - saveMainWallet(false); - - // reschedule to init main wallet - UserThread.runAfter(() -> { - new Thread(() -> { - log.warn("Restarting attempts to sync main wallet"); - maybeInitMainWallet(true); - }); - }, connectionsService.getRefreshPeriodMs() / 1000); - } else { - log.warn("Trying again in {} seconds", connectionsService.getRefreshPeriodMs() / 1000); - GenUtils.waitFor(connectionsService.getRefreshPeriodMs()); - } - } - } + try { + closeMainWallet(true); + } catch (Exception e) { + log.warn("Error closing main wallet: {}. Was Haveno stopped manually with ctrl+c?", e.getMessage()); } - - // register internal listener to notify external listeners - wallet.addListener(new XmrWalletListener()); } - } - } + }; - private MoneroWalletRpc createWalletRpc(MoneroWalletConfig config, Integer port) { - - // must be connected to daemon - MoneroRpcConnection connection = connectionsService.getConnection(); - if (connection == null || !Boolean.TRUE.equals(connection.isConnected())) throw new RuntimeException("Must be connected to daemon before creating wallet"); - - // create wallet - MoneroWalletRpc walletRpc = null; + // shut down with timeout try { - - // start monero-wallet-rpc instance - walletRpc = startWalletRpcInstance(port, isProxyApplied(false)); - walletRpc.getRpcConnection().setPrintStackTrace(PRINT_STACK_TRACE); - - // prevent wallet rpc from syncing - walletRpc.stopSyncing(); - - // create wallet - log.info("Creating wallet " + config.getPath() + " connected to daemon " + connection.getUri()); - long time = System.currentTimeMillis(); - walletRpc.createWallet(config.setServer(connection)); - walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_STACK_TRACE); - log.info("Done creating wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms"); - return walletRpc; + ThreadUtils.awaitTask(shutDownTask, SHUTDOWN_TIMEOUT_MS); } catch (Exception e) { - e.printStackTrace(); - if (walletRpc != null) stopWallet(walletRpc, config.getPath()); - throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes, and restart Haveno."); + log.warn("Error shutting down {}: {}\n", getClass().getSimpleName(), e.getMessage(), e); + + // force close wallet + forceCloseMainWallet(); } + + log.info("Done shutting down {}", getClass().getSimpleName()); } - private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port, boolean applyProxyUri) { - MoneroWalletRpc walletRpc = null; - try { - - // start monero-wallet-rpc instance - walletRpc = startWalletRpcInstance(port, applyProxyUri); - walletRpc.getRpcConnection().setPrintStackTrace(PRINT_STACK_TRACE); - - // prevent wallet rpc from syncing - walletRpc.stopSyncing(); - - // configure connection - MoneroRpcConnection connection = new MoneroRpcConnection(connectionsService.getConnection()); - if (!applyProxyUri) connection.setProxyUri(null); - - // open wallet - walletRpc.openWallet(config.setServer(connection)); - if (walletRpc.getDaemonConnection() != null) walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_STACK_TRACE); - log.info("Done opening wallet " + config.getPath()); - return walletRpc; - } catch (Exception e) { - e.printStackTrace(); - if (walletRpc != null) stopWallet(walletRpc, config.getPath()); - throw new IllegalStateException("Could not open wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes, and restart Haveno."); - } - } - - private MoneroWalletRpc startWalletRpcInstance(Integer port, boolean applyProxyUri) { - - // check if monero-wallet-rpc exists - if (!new File(MONERO_WALLET_RPC_PATH).exists()) throw new Error("monero-wallet-rpc executable doesn't exist at path " + MONERO_WALLET_RPC_PATH - + "; copy monero-wallet-rpc to the project root or set WalletConfig.java MONERO_WALLET_RPC_PATH for your system"); - - // build command to start monero-wallet-rpc - List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list - MONERO_WALLET_RPC_PATH, - "--rpc-login", - MONERO_WALLET_RPC_USERNAME + ":" + getWalletPassword(), - "--wallet-dir", walletDir.toString())); - - // omit --mainnet flag since it does not exist - if (MONERO_NETWORK_TYPE != MoneroNetworkType.MAINNET) { - cmd.add("--" + MONERO_NETWORK_TYPE.toString().toLowerCase()); - } - - MoneroRpcConnection connection = connectionsService.getConnection(); - if (connection != null) { - cmd.add("--daemon-address"); - cmd.add(connection.getUri()); - if (applyProxyUri && connection.getProxyUri() != null) { // TODO: only apply proxy if wallet is already synced, so we need a flag passed here - cmd.add("--proxy"); - cmd.add(connection.getProxyUri()); - if (!connection.isOnion()) cmd.add("--daemon-ssl-allow-any-cert"); // necessary to use proxy with clearnet mmonerod - } - if (connection.getUsername() != null) { - cmd.add("--daemon-login"); - cmd.add(connection.getUsername() + ":" + connection.getPassword()); - } - } - if (port != null && port > 0) { - cmd.add("--rpc-bind-port"); - cmd.add(Integer.toString(port)); - } - - // start monero-wallet-rpc instance and return connected client - return MONERO_WALLET_RPC_MANAGER.startInstance(cmd); - } - - private void onConnectionChanged(MoneroRpcConnection connection) { - synchronized (walletLock) { - if (isShutDownStarted) return; - if (wallet != null && HavenoUtils.connectionConfigsEqual(connection, wallet.getDaemonConnection())) return; - String oldProxyUri = wallet == null || wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getProxyUri(); - String newProxyUri = connection == null ? null : connection.getProxyUri(); - log.info("Setting daemon connection for main wallet: uri={}, proxyUri={}", connection == null ? null : connection.getUri(), newProxyUri); - if (wallet == null) maybeInitMainWallet(false); - else if (wallet instanceof MoneroWalletRpc && !StringUtils.equals(oldProxyUri, newProxyUri)) { - log.info("Restarting main wallet because proxy URI has changed, old={}, new={}", oldProxyUri, newProxyUri); - closeMainWallet(true); - maybeInitMainWallet(false); - } else { - wallet.setDaemonConnection(connection); - } - - // sync wallet on new thread - if (connection != null) { - wallet.getDaemonConnection().setPrintStackTrace(PRINT_STACK_TRACE); - new Thread(() -> { - try { - if (!Boolean.FALSE.equals(connection.isConnected())) wallet.sync(); - wallet.startSyncing(connectionsService.getRefreshPeriodMs()); - } catch (Exception e) { - log.warn("Failed to sync main wallet after setting daemon connection: " + e.getMessage()); - } - }).start(); - } - - log.info("Done setting main wallet daemon connection: " + (connection == null ? null : connection.getUri())); - } - } - - private void notifyBalanceListeners() { - for (XmrBalanceListener balanceListener : balanceListeners) { - BigInteger balance; - if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex()); - else balance = getAvailableBalance(); - UserThread.execute(new Runnable() { // TODO (woodser): don't execute on UserThread - @Override - public void run() { - try { - balanceListener.onBalanceChanged(balance); - } catch (Exception e) { - log.warn("Failed to notify balance listener of change"); - e.printStackTrace(); - } - } - }); - } - } - - private void changeWalletPasswords(String oldPassword, String newPassword) { - - // create task to change main wallet password - List<Runnable> tasks = new ArrayList<Runnable>(); - tasks.add(() -> { - try { - wallet.changePassword(oldPassword, newPassword); - saveMainWallet(); - } catch (Exception e) { - e.printStackTrace(); - throw e; - } - }); - - // create tasks to change trade wallet passwords - List<Trade> trades = tradeManager.getAllTrades(); - for (Trade trade : trades) { - tasks.add(() -> { - if (trade.walletExists()) { - trade.changeWalletPassword(oldPassword, newPassword); // TODO (woodser): this unnecessarily connects and syncs unopen wallets and leaves open - } - }); - } - - // excute tasks in parallel - HavenoUtils.executeTasks(tasks, Math.min(10, 1 + trades.size())); - log.info("Done changing all wallet passwords"); - } - - private void closeMainWallet(boolean save) { - try { - if (wallet != null) { - closeWallet(wallet, true); - wallet = null; - } - } catch (Exception e) { - log.warn("Error closing main monero-wallet-rpc subprocess: " + e.getMessage() + ". Was Haveno stopped manually with ctrl+c?"); - } - } + // -------------------------- ADDRESS ENTRIES ----------------------------- public synchronized XmrAddressEntry getNewAddressEntry() { return getNewAddressEntryAux(null, XmrAddressEntry.Context.AVAILABLE); @@ -943,14 +941,12 @@ public class XmrWalletService { // try to use available and not yet used entries try { - List<MoneroTxWallet> incomingTxs = getTxsWithIncomingOutputs(); // prefetch all incoming txs to avoid query per subaddress - List<XmrAddressEntry> unusedAddressEntries = getUnusedAddressEntries(incomingTxs); + List<XmrAddressEntry> unusedAddressEntries = getUnusedAddressEntries(); if (!unusedAddressEntries.isEmpty()) return xmrAddressEntryList.swapAvailableToAddressEntryWithOfferId(unusedAddressEntries.get(0), context, offerId); } catch (Exception e) { - log.warn("Error getting new address entry based on incoming transactions"); - e.printStackTrace(); + log.warn("Error getting new address entry based on incoming transactions: {}\n", e.getMessage(), e); } - + // create new entry return getNewAddressEntryAux(offerId, context); } @@ -969,12 +965,6 @@ public class XmrWalletService { else return unusedAddressEntries.get(0); } - public synchronized XmrAddressEntry getFreshAddressEntry(List<MoneroTxWallet> cachedTxs) { - List<XmrAddressEntry> unusedAddressEntries = getUnusedAddressEntries(cachedTxs); - if (unusedAddressEntries.isEmpty()) return getNewAddressEntry(); - else return unusedAddressEntries.get(0); - } - public synchronized XmrAddressEntry recoverAddressEntry(String offerId, String address, XmrAddressEntry.Context context) { var available = findAddressEntry(address, XmrAddressEntry.Context.AVAILABLE); if (!available.isPresent()) return null; @@ -987,14 +977,6 @@ public class XmrWalletService { else return getNewAddressEntry(offerId, context); } - public synchronized XmrAddressEntry getArbitratorAddressEntry() { - XmrAddressEntry.Context context = XmrAddressEntry.Context.ARBITRATOR; - Optional<XmrAddressEntry> addressEntry = getAddressEntryListAsImmutableList().stream() - .filter(e -> context == e.getContext()) - .findAny(); - return addressEntry.isPresent() ? addressEntry.get() : getNewAddressEntryAux(null, context); - } - public synchronized Optional<XmrAddressEntry> getAddressEntry(String offerId, XmrAddressEntry.Context context) { List<XmrAddressEntry> entries = getAddressEntryListAsImmutableList().stream().filter(e -> offerId.equals(e.getOfferId())).filter(e -> context == e.getContext()).collect(Collectors.toList()); if (entries.size() > 1) throw new RuntimeException("Multiple address entries exist with offer ID " + offerId + " and context " + context + ". That should never happen."); @@ -1052,13 +1034,16 @@ public class XmrWalletService { return getAddressEntryListAsImmutableList().stream().filter(addressEntry -> context == addressEntry.getContext()).collect(Collectors.toList()); } + public XmrAddressEntry getBaseAddressEntry() { + return getAddressEntryListAsImmutableList().stream().filter(e -> e.getContext() == XmrAddressEntry.Context.BASE_ADDRESS).findAny().orElse(null); + } + public List<XmrAddressEntry> getFundedAvailableAddressEntries() { - return getAvailableAddressEntries().stream().filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.valueOf(0)) > 0).collect(Collectors.toList()); + return getAvailableAddressEntries().stream().filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.ZERO) > 0).collect(Collectors.toList()); } public List<XmrAddressEntry> getAddressEntryListAsImmutableList() { - List<MoneroSubaddress> subaddresses = wallet.getSubaddresses(0); - for (MoneroSubaddress subaddress : subaddresses) { + for (MoneroSubaddress subaddress : cachedSubaddresses) { boolean exists = xmrAddressEntryList.getAddressEntriesAsListImmutable().stream().filter(addressEntry -> addressEntry.getAddressString().equals(subaddress.getAddress())).findAny().isPresent(); if (!exists) { XmrAddressEntry entry = new XmrAddressEntry(subaddress.getIndex(), subaddress.getAddress(), subaddress.getIndex() == 0 ? XmrAddressEntry.Context.BASE_ADDRESS : XmrAddressEntry.Context.AVAILABLE, null, null); @@ -1069,38 +1054,36 @@ public class XmrWalletService { } public List<XmrAddressEntry> getUnusedAddressEntries() { - return getUnusedAddressEntries(getTxsWithIncomingOutputs()); - } - - public List<XmrAddressEntry> getUnusedAddressEntries(List<MoneroTxWallet> cachedTxs) { return getAvailableAddressEntries().stream() - .filter(e -> e.getContext() == XmrAddressEntry.Context.AVAILABLE && !subaddressHasIncomingTransfers(e.getSubaddressIndex(), cachedTxs)) + .filter(e -> e.getContext() == XmrAddressEntry.Context.AVAILABLE && !subaddressHasIncomingTransfers(e.getSubaddressIndex())) .collect(Collectors.toList()); } public boolean subaddressHasIncomingTransfers(int subaddressIndex) { - return subaddressHasIncomingTransfers(subaddressIndex, null); + return getNumOutputsForSubaddress(subaddressIndex) > 0; } - private boolean subaddressHasIncomingTransfers(int subaddressIndex, List<MoneroTxWallet> incomingTxs) { - return getNumOutputsForSubaddress(subaddressIndex, incomingTxs) > 0; - } - - public int getNumOutputsForSubaddress(int subaddressIndex, List<MoneroTxWallet> incomingTxs) { - incomingTxs = getTxsWithIncomingOutputs(subaddressIndex, incomingTxs); + public int getNumOutputsForSubaddress(int subaddressIndex) { int numUnspentOutputs = 0; - for (MoneroTxWallet tx : incomingTxs) { + for (MoneroTxWallet tx : cachedTxs) { //if (tx.getTransfers(new MoneroTransferQuery().setSubaddressIndex(subaddressIndex)).isEmpty()) continue; // TODO monero-project: transfers are occluded by transfers from/to same account, so this will return unused when used - numUnspentOutputs += tx.isConfirmed() ? tx.getOutputsWallet(new MoneroOutputQuery().setAccountIndex(0).setSubaddressIndex(subaddressIndex)).size() : 1; // TODO: monero-project does not provide outputs for unconfirmed txs + numUnspentOutputs += tx.getOutputsWallet(new MoneroOutputQuery().setAccountIndex(0).setSubaddressIndex(subaddressIndex)).size(); // TODO: monero-project does not provide outputs for unconfirmed txs } - boolean positiveBalance = wallet.getBalance(0, subaddressIndex).compareTo(BigInteger.valueOf(0)) > 0; + boolean positiveBalance = getBalanceForSubaddress(subaddressIndex).compareTo(BigInteger.ZERO) > 0; if (positiveBalance && numUnspentOutputs == 0) return 1; // outputs do not appear until confirmed and internal transfers are occluded, so report 1 if positive balance return numUnspentOutputs; } - public int getNumTxsWithIncomingOutputs(int subaddressIndex, List<MoneroTxWallet> txs) { - List<MoneroTxWallet> txsWithIncomingOutputs = getTxsWithIncomingOutputs(subaddressIndex, txs); - if (txsWithIncomingOutputs.isEmpty() && subaddressHasIncomingTransfers(subaddressIndex, txsWithIncomingOutputs)) return 1; // outputs do not appear until confirmed and internal transfers are occluded, so report 1 if positive balance + private MoneroSubaddress getSubaddress(int subaddressIndex) { + for (MoneroSubaddress subaddress : cachedSubaddresses) { + if (subaddress.getIndex() == subaddressIndex) return subaddress; + } + return null; + } + + public int getNumTxsWithIncomingOutputs(int subaddressIndex) { + List<MoneroTxWallet> txsWithIncomingOutputs = getTxsWithIncomingOutputs(subaddressIndex); + if (txsWithIncomingOutputs.isEmpty() && subaddressHasIncomingTransfers(subaddressIndex)) return 1; // outputs do not appear until confirmed and internal transfers are occluded, so report 1 if positive balance return txsWithIncomingOutputs.size(); } @@ -1109,13 +1092,8 @@ public class XmrWalletService { } public List<MoneroTxWallet> getTxsWithIncomingOutputs(Integer subaddressIndex) { - return getTxsWithIncomingOutputs(subaddressIndex, null); - } - - public List<MoneroTxWallet> getTxsWithIncomingOutputs(Integer subaddressIndex, List<MoneroTxWallet> txs) { - if (txs == null) txs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true)); List<MoneroTxWallet> incomingTxs = new ArrayList<>(); - for (MoneroTxWallet tx : txs) { + for (MoneroTxWallet tx : cachedTxs) { boolean isIncoming = false; if (tx.getIncomingTransfers() != null) { for (MoneroIncomingTransfer transfer : tx.getIncomingTransfers()) { @@ -1143,30 +1121,13 @@ public class XmrWalletService { } public BigInteger getBalanceForSubaddress(int subaddressIndex) { - synchronized (walletLock) { - return wallet.getBalance(0, subaddressIndex); - } + MoneroSubaddress subaddress = getSubaddress(subaddressIndex); + return subaddress == null ? BigInteger.ZERO : subaddress.getBalance(); } public BigInteger getAvailableBalanceForSubaddress(int subaddressIndex) { - synchronized (walletLock) { - if (wallet == null) throw new IllegalStateException("Cannot get available balance for subaddress because main wallet is null"); - return wallet.getUnlockedBalance(0, subaddressIndex); - } - } - - public BigInteger getBalance() { - synchronized (walletLock) { - if (wallet == null) throw new IllegalStateException("Cannot get balance because main wallet is null"); - return wallet.getBalance(0); - } - } - - public BigInteger getAvailableBalance() { - synchronized (walletLock) { - if (wallet == null) throw new IllegalStateException("Cannot get available balance because main wallet is null"); - return wallet.getUnlockedBalance(0); - } + MoneroSubaddress subaddress = getSubaddress(subaddressIndex); + return subaddress == null ? BigInteger.ZERO : subaddress.getUnlockedBalance(); } public Stream<XmrAddressEntry> getAddressEntriesForAvailableBalanceStream() { @@ -1174,16 +1135,20 @@ public class XmrWalletService { available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.ARBITRATOR).stream()); available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.OFFER_FUNDING).stream().filter(entry -> !tradeManager.getOpenOfferManager().getOpenOfferById(entry.getOfferId()).isPresent())); available = Stream.concat(available, getAddressEntries(XmrAddressEntry.Context.TRADE_PAYOUT).stream().filter(entry -> tradeManager.getTrade(entry.getOfferId()) == null || tradeManager.getTrade(entry.getOfferId()).isPayoutUnlocked())); - return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.valueOf(0)) > 0); + return available.filter(addressEntry -> getBalanceForSubaddress(addressEntry.getSubaddressIndex()).compareTo(BigInteger.ZERO) > 0); } public void addWalletListener(MoneroWalletListenerI listener) { - walletListeners.add(listener); + synchronized (walletListeners) { + walletListeners.add(listener); + } } public void removeWalletListener(MoneroWalletListenerI listener) { - if (!walletListeners.contains(listener)) throw new RuntimeException("Listener is not registered with wallet"); - walletListeners.remove(listener); + synchronized (walletListeners) { + if (!walletListeners.contains(listener)) throw new RuntimeException("Listener is not registered with wallet"); + walletListeners.remove(listener); + } } // TODO (woodser): update balance and other listening @@ -1195,12 +1160,94 @@ public class XmrWalletService { balanceListeners.remove(listener); } + public void updateBalanceListeners() { + BigInteger availableBalance = getAvailableBalance(); + for (XmrBalanceListener balanceListener : balanceListeners) { + BigInteger balance; + if (balanceListener.getSubaddressIndex() != null && balanceListener.getSubaddressIndex() != 0) balance = getBalanceForSubaddress(balanceListener.getSubaddressIndex()); + else balance = availableBalance; + ThreadUtils.submitToPool(() -> { + try { + balanceListener.onBalanceChanged(balance); + } catch (Exception e) { + log.warn("Failed to notify balance listener of change: {}\n", e.getMessage(), e); + } + }); + } + } + public void saveAddressEntryList() { xmrAddressEntryList.requestPersistence(); } - public List<MoneroTxWallet> getTransactions(boolean includeDead) { - return wallet.getTxs(new MoneroTxQuery().setIsFailed(includeDead ? null : false)); + public long getHeight() { + return walletHeight.get(); + } + + public List<MoneroTxWallet> getTxs(boolean includeFailed) { + List<MoneroTxWallet> txs = getTxs(); + if (includeFailed) return txs; + return txs.stream().filter(tx -> !tx.isFailed()).collect(Collectors.toList()); + } + + public List<MoneroTxWallet> getTxs() { + return getTxs(new MoneroTxQuery().setIncludeOutputs(true)); + } + + public List<MoneroTxWallet> getTxs(MoneroTxQuery query) { + if (cachedTxs == null) { + log.warn("Transactions not cached, fetching from wallet"); + cachedTxs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true)); // fetches from pool + } + return cachedTxs.stream().filter(tx -> query.meetsCriteria(tx)).collect(Collectors.toList()); + } + + public List<MoneroTxWallet> getTxs(List<String> txIds) { + return getTxs(new MoneroTxQuery().setHashes(txIds)); + } + + public MoneroTxWallet getTx(String txId) { + List<MoneroTxWallet> txs = getTxs(new MoneroTxQuery().setHash(txId)); + return txs.isEmpty() ? null : txs.get(0); + } + + public BigInteger getBalance() { + return cachedBalance; + } + + public BigInteger getAvailableBalance() { + return cachedAvailableBalance; + } + + public boolean hasAddress(String address) { + for (MoneroSubaddress subaddress : getSubaddresses()) { + if (subaddress.getAddress().equals(address)) return true; + } + return false; + } + + public List<MoneroSubaddress> getSubaddresses() { + return cachedSubaddresses; + } + + public BigInteger getAmountSentToSelf(MoneroTxWallet tx) { + BigInteger sentToSelfAmount = BigInteger.ZERO; + if (tx.getOutgoingTransfer() != null && tx.getOutgoingTransfer().getDestinations() != null) { + for (MoneroDestination destination : tx.getOutgoingTransfer().getDestinations()) { + if (hasAddress(destination.getAddress())) { + sentToSelfAmount = sentToSelfAmount.add(destination.getAmount()); + } + } + } + return sentToSelfAmount; + } + + public List<MoneroOutputWallet> getOutputs(MoneroOutputQuery query) { + List<MoneroOutputWallet> filteredOutputs = new ArrayList<MoneroOutputWallet>(); + for (MoneroOutputWallet output : cachedOutputs) { + if (query == null || query.meetsCriteria(output)) filteredOutputs.add(output); + } + return filteredOutputs; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1226,62 +1273,793 @@ public class XmrWalletService { log.info("\n" + tracePrefix + ":" + sb.toString()); } - // -------------------------------- HELPERS ------------------------------- + // ------------------------------ PRIVATE HELPERS ------------------------- - /** - * Relays wallet notifications to external listeners. - */ - private class XmrWalletListener extends MoneroWalletListener { + private void initialize() { - @Override - public void onSyncProgress(long height, long startHeight, long endHeight, double percentDone, String message) { - UserThread.execute(new Runnable() { - @Override - public void run() { - for (MoneroWalletListenerI listener : walletListeners) listener.onSyncProgress(height, startHeight, endHeight, percentDone, message); - } - }); + // try to load native monero library + if (useNativeXmrWallet && !MoneroUtils.isNativeLibraryLoaded()) { + try { + MoneroUtils.loadNativeLibrary(); + } catch (Exception | UnsatisfiedLinkError e) { + log.warn("Failed to load Monero native libraries: " + e.getMessage()); + } } + String appliedMsg = "Monero native libraries applied: " + isNativeLibraryApplied(); + if (useNativeXmrWallet && !isNativeLibraryApplied()) log.warn(appliedMsg); + else log.info(appliedMsg); - @Override - public void onNewBlock(long height) { - UserThread.execute(new Runnable() { - @Override - public void run() { - for (MoneroWalletListenerI listener : walletListeners) listener.onNewBlock(height); - } - }); - } + // listen for connection changes + xmrConnectionService.addConnectionListener(connection -> { + if (wasWalletSynced && !isSyncingWithProgress) { + ThreadUtils.execute(() -> { + onConnectionChanged(connection); + }, THREAD_ID); + } else { - @Override - public void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) { - UserThread.execute(new Runnable() { - @Override - public void run() { - for (MoneroWalletListenerI listener : walletListeners) listener.onBalancesChanged(newBalance, newUnlockedBalance); - notifyBalanceListeners(); + // force restart main wallet if connection changed while syncing + if (wallet != null) { + log.warn("Force restarting main wallet because connection changed while syncing"); + forceRestartMainWallet(); } - }); - } + } + }); - @Override - public void onOutputReceived(MoneroOutputWallet output) { - UserThread.execute(new Runnable() { - @Override - public void run() { - for (MoneroWalletListenerI listener : walletListeners) listener.onOutputReceived(output); - } - }); - } + // initialize main wallet when daemon synced + walletInitListener = (obs, oldVal, newVal) -> initMainWalletIfConnected(); + xmrConnectionService.downloadPercentageProperty().addListener(walletInitListener); + initMainWalletIfConnected(); + } - @Override - public void onOutputSpent(MoneroOutputWallet output) { - UserThread.execute(new Runnable() { - @Override - public void run() { - for (MoneroWalletListenerI listener : walletListeners) listener.onOutputSpent(output); - } - }); + private void initMainWalletIfConnected() { + if (wallet == null && xmrConnectionService.downloadPercentageProperty().get() == 1 && !isShutDownStarted) { + maybeInitMainWallet(true); } } + + private void maybeInitMainWallet(boolean sync) { + maybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS); + } + + private void maybeInitMainWallet(boolean sync, int numAttempts) { + ThreadUtils.execute(() -> { + try { + doMaybeInitMainWallet(sync, MAX_SYNC_ATTEMPTS); + } catch (Exception e) { + log.warn("Error initializing main wallet: {}\n", e.getMessage(), e); + HavenoUtils.setTopError(e.getMessage()); + throw e; + } + }, THREAD_ID); + } + + private void doMaybeInitMainWallet(boolean sync, int numAttempts) { + synchronized (walletLock) { + if (isShutDownStarted) return; + + // open or create wallet main wallet + if (wallet == null) { + MoneroDaemonRpc daemon = xmrConnectionService.getDaemon(); + log.info("Initializing main wallet with monerod=" + (daemon == null ? "null" : daemon.getRpcConnection().getUri())); + if (walletExists(MONERO_WALLET_NAME)) { + wallet = openWallet(MONERO_WALLET_NAME, rpcBindPort, isProxyApplied(wasWalletSynced)); + } else if (Boolean.TRUE.equals(xmrConnectionService.isConnected())) { + wallet = createWallet(MONERO_WALLET_NAME, rpcBindPort); + + // set wallet creation date to yesterday to guarantee complete restore + LocalDateTime localDateTime = LocalDate.now().atStartOfDay().minusDays(1); + long date = localDateTime.toEpochSecond(ZoneOffset.UTC); + user.setWalletCreationDate(date); + } + walletHeight.set(wallet.getHeight()); + isClosingWallet = false; + } + + // sync wallet and register listener + if (wallet != null && !isShutDownStarted) { + log.info("Monero wallet path={}", wallet.getPath()); + + // sync main wallet if applicable + // TODO: error handling and re-initialization is jenky, refactor + if (sync && numAttempts > 0) { + try { + + // switch connection if disconnected + if (!wallet.isConnectedToDaemon()) { + log.warn("Switching connection before syncing with progress because disconnected"); + if (requestSwitchToNextBestConnection()) return; // calls back to this method + } + + // sync main wallet + log.info("Syncing main wallet"); + long time = System.currentTimeMillis(); + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + syncWithProgress(true); // repeat sync to latest target height + } catch (Exception e) { + log.warn("Error syncing wallet with progress on startup: " + e.getMessage()); + forceCloseMainWallet(); + requestSwitchToNextBestConnection(sourceConnection); + maybeInitMainWallet(true, numAttempts - 1); // re-initialize wallet and sync again + return; + } + log.info("Done syncing main wallet in " + (System.currentTimeMillis() - time) + " ms"); + + // poll wallet + doPollWallet(true); + if (walletInitListener != null) xmrConnectionService.downloadPercentageProperty().removeListener(walletInitListener); + + // log wallet balances + if (getMoneroNetworkType() != MoneroNetworkType.MAINNET) { + BigInteger balance = getBalance(); + BigInteger unlockedBalance = getAvailableBalance(); + log.info("Monero wallet unlocked balance={}, pending balance={}, total balance={}", unlockedBalance, balance.subtract(unlockedBalance), balance); + } + + // reapply connection after wallet synced (might reinitialize wallet on new thread) + ThreadUtils.execute(() -> onConnectionChanged(xmrConnectionService.getConnection()), THREAD_ID); + + // reset internal state if main wallet was swapped + resetIfWalletChanged(); + + // signal that main wallet is synced + doneDownload(); + + // notify setup that main wallet is initialized + // TODO: app fully initializes after this is set to true, even though wallet might not be initialized if unconnected. wallet will be created when connection detected + // refactor startup to call this and sync off main thread? but the calls to e.g. getBalance() fail with 'wallet and network is not yet initialized' + HavenoUtils.havenoSetup.getWalletInitialized().set(true); + + // save but skip backup on initialization + saveMainWallet(false); + } catch (Exception e) { + if (isClosingWallet || isShutDownStarted || HavenoUtils.havenoSetup.getWalletInitialized().get()) return; // ignore if wallet closing, shut down started, or app already initialized + log.warn("Error initially syncing main wallet: {}", e.getMessage()); + if (numAttempts <= 1) { + log.warn("Failed to sync main wallet. Opening app without syncing", numAttempts); + HavenoUtils.havenoSetup.getWalletInitialized().set(true); + saveMainWallet(false); + + // reschedule to init main wallet + UserThread.runAfter(() -> { + maybeInitMainWallet(true, MAX_SYNC_ATTEMPTS); + }, xmrConnectionService.getRefreshPeriodMs() / 1000); + } else { + log.warn("Trying again in {} seconds", xmrConnectionService.getRefreshPeriodMs() / 1000); + UserThread.runAfter(() -> { + maybeInitMainWallet(true, numAttempts - 1); + }, xmrConnectionService.getRefreshPeriodMs() / 1000); + } + } + } + + // start polling main wallet + startPolling(); + } + } + } + + private void resetIfWalletChanged() { + getAddressEntryListAsImmutableList(); // TODO: using getter to create base address if necessary + List<XmrAddressEntry> baseAddresses = getAddressEntries(XmrAddressEntry.Context.BASE_ADDRESS); + if (baseAddresses.size() > 1 || (baseAddresses.size() == 1 && !baseAddresses.get(0).getAddressString().equals(wallet.getPrimaryAddress()))) { + String warningMsg = "New Monero wallet detected. Resetting internal state."; + if (!tradeManager.getOpenTrades().isEmpty()) warningMsg += "\n\nWARNING: Your open trades will settle to the payout address in the OLD wallet!"; // TODO: allow payout address to be updated in PaymentSentMessage, PaymentReceivedMessage, and DisputeOpenedMessage? + HavenoUtils.setTopError(warningMsg); + + // reset address entries + xmrAddressEntryList.clear(); + getAddressEntryListAsImmutableList(); // recreate base address + + // cancel offers + tradeManager.getOpenOfferManager().removeAllOpenOffers(null); + } + } + + private MoneroWalletFull createWalletFull(MoneroWalletConfig config) { + + // must be connected to daemon + if (!Boolean.TRUE.equals(xmrConnectionService.isConnected())) throw new RuntimeException("Must be connected to daemon before creating wallet"); + + // create wallet + MoneroWalletFull walletFull = null; + try { + + // create wallet + MoneroRpcConnection connection = xmrConnectionService.getConnection(); + log.info("Creating full wallet " + config.getPath() + " connected to monerod=" + connection.getUri()); + long time = System.currentTimeMillis(); + config.setServer(connection); + walletFull = MoneroWalletFull.createWallet(config); + walletFull.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + log.info("Done creating full wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms"); + return walletFull; + } catch (Exception e) { + String errorMsg = "Could not create wallet '" + config.getPath() + "': " + e.getMessage(); + log.warn(errorMsg + "\n", e); + if (walletFull != null) forceCloseWallet(walletFull, config.getPath()); + throw new IllegalStateException(errorMsg); + } + } + + private MoneroWalletFull openWalletFull(MoneroWalletConfig config, boolean applyProxyUri) { + MoneroWalletFull walletFull = null; + try { + + // configure connection + MoneroRpcConnection connection = new MoneroRpcConnection(xmrConnectionService.getConnection()); + if (!applyProxyUri) connection.setProxyUri(null); + + // try opening wallet + config.setNetworkType(getMoneroNetworkType()); + config.setServer(connection); + log.info("Opening full wallet " + config.getPath() + " with monerod=" + connection.getUri() + ", proxyUri=" + connection.getProxyUri()); + try { + walletFull = MoneroWalletFull.openWallet(config); + } catch (Exception e) { + log.warn("Failed to open full wallet '{}', attempting to use backup cache files, error={}", config.getPath(), e.getMessage()); + boolean retrySuccessful = false; + try { + + // rename wallet cache to backup + String cachePath = walletDir.toString() + File.separator + getWalletName(config.getPath()); + File originalCacheFile = new File(cachePath); + if (originalCacheFile.exists()) originalCacheFile.renameTo(new File(cachePath + ".backup")); + + // try opening wallet with backup cache files in descending order + List<File> backupCacheFiles = FileUtil.getBackupFiles(walletDir, getWalletName(config.getPath())); + Collections.reverse(backupCacheFiles); + for (File backupCacheFile : backupCacheFiles) { + try { + FileUtil.copyFile(backupCacheFile, new File(cachePath)); + walletFull = MoneroWalletFull.openWallet(config); + log.warn("Successfully opened full wallet using backup cache"); + retrySuccessful = true; + break; + } catch (Exception e2) { + + // delete cache file if failed to open + File cacheFile = new File(cachePath); + if (cacheFile.exists()) cacheFile.delete(); + File unportableCacheFile = new File(cachePath + ".unportable"); + if (unportableCacheFile.exists()) unportableCacheFile.delete(); + } + } + + // handle success or failure + File originalCacheBackup = new File(cachePath + ".backup"); + if (retrySuccessful) { + if (originalCacheBackup.exists()) originalCacheBackup.delete(); // delete original wallet cache backup + } else { + + // retry opening wallet after cache deleted + try { + log.warn("Failed to open full wallet using backup cache files, retrying with cache deleted"); + walletFull = MoneroWalletFull.openWallet(config); + log.warn("Successfully opened full wallet after cache deleted"); + retrySuccessful = true; + } catch (Exception e2) { + // ignore + } + + // handle success or failure + if (retrySuccessful) { + if (originalCacheBackup.exists()) originalCacheBackup.delete(); // delete original wallet cache backup + } else { + + // restore original wallet cache + log.warn("Failed to open full wallet after deleting cache, restoring original cache"); + File cacheFile = new File(cachePath); + if (cacheFile.exists()) cacheFile.delete(); + if (originalCacheBackup.exists()) originalCacheBackup.renameTo(new File(cachePath)); + + // throw original exception + throw e; + } + } + } catch (Exception e2) { + throw e; // throw original exception + } + } + if (walletFull.getDaemonConnection() != null) walletFull.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + log.info("Done opening full wallet " + config.getPath()); + return walletFull; + } catch (Exception e) { + String errorMsg = "Could not open full wallet '" + config.getPath() + "': " + e.getMessage(); + log.warn(errorMsg + "\n", e); + if (walletFull != null) forceCloseWallet(walletFull, config.getPath()); + throw new IllegalStateException(errorMsg); + } + } + + private MoneroWalletRpc createWalletRpc(MoneroWalletConfig config, Integer port) { + + // must be connected to daemon + if (!Boolean.TRUE.equals(xmrConnectionService.isConnected())) throw new RuntimeException("Must be connected to daemon before creating wallet"); + + // create wallet + MoneroWalletRpc walletRpc = null; + try { + + // start monero-wallet-rpc instance + walletRpc = startWalletRpcInstance(port, isProxyApplied(false)); + walletRpc.getRpcConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + + // prevent wallet rpc from syncing + walletRpc.stopSyncing(); + + // create wallet + MoneroRpcConnection connection = xmrConnectionService.getConnection(); + log.info("Creating RPC wallet " + config.getPath() + " connected to monerod=" + connection.getUri()); + long time = System.currentTimeMillis(); + config.setServer(connection); + walletRpc.createWallet(config); + walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + log.info("Done creating RPC wallet " + config.getPath() + " in " + (System.currentTimeMillis() - time) + " ms"); + return walletRpc; + } catch (Exception e) { + log.warn("Could not create wallet '" + config.getPath() + "': " + e.getMessage() + "\n", e); + if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath()); + throw new IllegalStateException("Could not create wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno."); + } + } + + private MoneroWalletRpc openWalletRpc(MoneroWalletConfig config, Integer port, boolean applyProxyUri) { + MoneroWalletRpc walletRpc = null; + try { + + // start monero-wallet-rpc instance + walletRpc = startWalletRpcInstance(port, applyProxyUri); + walletRpc.getRpcConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + + // prevent wallet rpc from syncing + walletRpc.stopSyncing(); + + // configure connection + MoneroRpcConnection connection = new MoneroRpcConnection(xmrConnectionService.getConnection()); + if (!applyProxyUri) connection.setProxyUri(null); + + // try opening wallet + log.info("Opening RPC wallet " + config.getPath() + " with monerod=" + connection.getUri() + ", proxyUri=" + connection.getProxyUri()); + config.setServer(connection); + try { + walletRpc.openWallet(config); + } catch (Exception e) { + log.warn("Failed to open RPC wallet '{}', attempting to use backup cache files, error={}", config.getPath(), e.getMessage()); + boolean retrySuccessful = false; + try { + + // rename wallet cache to backup + String cachePath = walletDir.toString() + File.separator + config.getPath(); + File originalCacheFile = new File(cachePath); + if (originalCacheFile.exists()) originalCacheFile.renameTo(new File(cachePath + ".backup")); + + // try opening wallet with backup cache files in descending order + List<File> backupCacheFiles = FileUtil.getBackupFiles(walletDir, config.getPath()); + Collections.reverse(backupCacheFiles); + for (File backupCacheFile : backupCacheFiles) { + try { + FileUtil.copyFile(backupCacheFile, new File(cachePath)); + walletRpc.openWallet(config); + log.warn("Successfully opened RPC wallet using backup cache"); + retrySuccessful = true; + break; + } catch (Exception e2) { + + // delete cache file if failed to open + File cacheFile = new File(cachePath); + if (cacheFile.exists()) cacheFile.delete(); + File unportableCacheFile = new File(cachePath + ".unportable"); + if (unportableCacheFile.exists()) unportableCacheFile.delete(); + } + } + + // handle success or failure + File originalCacheBackup = new File(cachePath + ".backup"); + if (retrySuccessful) { + if (originalCacheBackup.exists()) originalCacheBackup.delete(); // delete original wallet cache backup + } else { + + // retry opening wallet after cache deleted + try { + log.warn("Failed to open RPC wallet using backup cache files, retrying with cache deleted"); + walletRpc.openWallet(config); + log.warn("Successfully opened RPC wallet after cache deleted"); + retrySuccessful = true; + } catch (Exception e2) { + // ignore + } + + // handle success or failure + if (retrySuccessful) { + if (originalCacheBackup.exists()) originalCacheBackup.delete(); // delete original wallet cache backup + } else { + + // restore original wallet cache + log.warn("Failed to open RPC wallet after deleting cache, restoring original cache"); + File cacheFile = new File(cachePath); + if (cacheFile.exists()) cacheFile.delete(); + if (originalCacheBackup.exists()) originalCacheBackup.renameTo(new File(cachePath)); + + // throw original exception + throw e; + } + } + } catch (Exception e2) { + throw e; // throw original exception + } + } + if (walletRpc.getDaemonConnection() != null) walletRpc.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + log.info("Done opening RPC wallet " + config.getPath()); + return walletRpc; + } catch (Exception e) { + log.warn("Could not open wallet '" + config.getPath() + "': " + e.getMessage() + "\n", e); + if (walletRpc != null) forceCloseWallet(walletRpc, config.getPath()); + throw new IllegalStateException("Could not open wallet '" + config.getPath() + "'. Please close Haveno, stop all monero-wallet-rpc processes in your task manager, and restart Haveno.\n\nError message: " + e.getMessage()); + } + } + + private MoneroWalletRpc startWalletRpcInstance(Integer port, boolean applyProxyUri) { + + // check if monero-wallet-rpc exists + if (!new File(MONERO_WALLET_RPC_PATH).exists()) throw new Error("monero-wallet-rpc executable doesn't exist at path " + MONERO_WALLET_RPC_PATH + + "; copy monero-wallet-rpc to the project root or set WalletConfig.java MONERO_WALLET_RPC_PATH for your system"); + + // build command to start monero-wallet-rpc + List<String> cmd = new ArrayList<>(Arrays.asList( // modifiable list + MONERO_WALLET_RPC_PATH, + "--rpc-login", + MONERO_WALLET_RPC_USERNAME + ":" + getWalletPassword(), + "--wallet-dir", walletDir.toString())); + + // omit --mainnet flag since it does not exist + if (MONERO_NETWORK_TYPE != MoneroNetworkType.MAINNET) { + cmd.add("--" + MONERO_NETWORK_TYPE.toString().toLowerCase()); + } + + // set connection flags + MoneroRpcConnection connection = xmrConnectionService.getConnection(); + if (connection != null) { + cmd.add("--daemon-address"); + cmd.add(connection.getUri()); + if (applyProxyUri && connection.getProxyUri() != null) { // TODO: only apply proxy if wallet is already synced, so we need a flag passed here + cmd.add("--proxy"); + cmd.add(connection.getProxyUri()); + if (!connection.isOnion()) cmd.add("--daemon-ssl-allow-any-cert"); // necessary to use proxy with clearnet mmonerod + } + if (connection.getUsername() != null) { + cmd.add("--daemon-login"); + cmd.add(connection.getUsername() + ":" + connection.getPassword()); + } + } + if (port != null && port > 0) { + cmd.add("--rpc-bind-port"); + cmd.add(Integer.toString(port)); + } + + // start monero-wallet-rpc instance and return connected client + return MONERO_WALLET_RPC_MANAGER.startInstance(cmd); + } + + private void onConnectionChanged(MoneroRpcConnection connection) { + synchronized (walletLock) { + + // use current connection + connection = xmrConnectionService.getConnection(); + + // check if ignored + if (wallet == null || isShutDownStarted) return; + if (HavenoUtils.connectionConfigsEqual(connection, wallet.getDaemonConnection())) { + updatePollPeriod(); + return; + } + + // update connection + String oldProxyUri = wallet == null || wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getProxyUri(); + String newProxyUri = connection == null ? null : connection.getProxyUri(); + log.info("Setting daemon connection for main wallet, monerod={}, proxyUri={}", connection == null ? null : connection.getUri(), newProxyUri); + if (wallet instanceof MoneroWalletRpc) { + if (StringUtils.equals(oldProxyUri, newProxyUri)) { + wallet.setDaemonConnection(connection); + } else { + log.info("Restarting main wallet because proxy URI has changed, old={}, new={}", oldProxyUri, newProxyUri); // TODO: set proxy without restarting wallet + closeMainWallet(true); + doMaybeInitMainWallet(false, MAX_SYNC_ATTEMPTS); + return; // wallet re-initializes off thread + } + } else { + wallet.setDaemonConnection(connection); + wallet.setProxyUri(connection.getProxyUri()); + } + + // switch if wallet disconnected + if (Boolean.TRUE.equals(connection.isConnected() && !wallet.isConnectedToDaemon())) { + log.warn("Switching to next best connection because main wallet is disconnected"); + if (requestSwitchToNextBestConnection()) return; // calls back to this method + } + + // update poll period + if (connection != null && !isShutDownStarted) { + wallet.getDaemonConnection().setPrintStackTrace(PRINT_RPC_STACK_TRACE); + updatePollPeriod(); + } + + log.info("Done setting daemon connection for main wallet, monerod=" + (wallet.getDaemonConnection() == null ? null : wallet.getDaemonConnection().getUri())); + } + } + + private void changeWalletPasswords(String oldPassword, String newPassword) { + + // create task to change main wallet password + List<Runnable> tasks = new ArrayList<Runnable>(); + tasks.add(() -> { + try { + wallet.changePassword(oldPassword, newPassword); + saveMainWallet(); + } catch (Exception e) { + log.warn("Error changing main wallet password: " + e.getMessage() + "\n", e); + throw e; + } + }); + + // create tasks to change trade wallet passwords + List<Trade> trades = tradeManager.getAllTrades(); + for (Trade trade : trades) { + tasks.add(() -> { + if (trade.walletExists()) { + trade.changeWalletPassword(oldPassword, newPassword); // TODO (woodser): this unnecessarily connects and syncs unopen wallets and leaves open + } + }); + } + + // execute tasks in parallel + ThreadUtils.awaitTasks(tasks, Math.min(10, 1 + trades.size())); + log.info("Done changing all wallet passwords"); + } + + private void closeMainWallet(boolean save) { + stopPolling(); + synchronized (walletLock) { + try { + if (wallet != null) { + isClosingWallet = true; + closeWallet(wallet, true); + wallet = null; + } + } catch (Exception e) { + log.warn("Error closing main wallet: {}. Was Haveno stopped manually with ctrl+c?", e.getMessage()); + } + } + } + + private void forceCloseMainWallet() { + stopPolling(); + if (wallet != null && !isClosingWallet) { + isClosingWallet = true; + forceCloseWallet(wallet, getWalletPath(MONERO_WALLET_NAME)); + wallet = null; + } + } + + public void forceRestartMainWallet() { + log.warn("Force restarting main wallet"); + if (isClosingWallet) return; + forceCloseMainWallet(); + maybeInitMainWallet(true); + } + + public void handleWalletError(Exception e, MoneroRpcConnection sourceConnection) { + if (HavenoUtils.isUnresponsive(e)) forceCloseMainWallet(); // wallet can be stuck a while + if (xmrConnectionService.isConnected()) requestSwitchToNextBestConnection(sourceConnection); + getWallet(); // re-open wallet + } + + private void startPolling() { + synchronized (walletLock) { + if (isShutDownStarted || isPolling()) return; + updatePollPeriod(); + pollLooper = new TaskLooper(() -> pollWallet()); + pollLooper.start(pollPeriodMs); + } + } + + private void stopPolling() { + if (isPolling()) { + pollLooper.stop(); + pollLooper = null; + } + } + + private boolean isPolling() { + return pollLooper != null; + } + + public void updatePollPeriod() { + if (isShutDownStarted) return; + setPollPeriodMs(getPollPeriodMs()); + } + + private long getPollPeriodMs() { + return xmrConnectionService.getRefreshPeriodMs(); + } + + private void setPollPeriodMs(long pollPeriodMs) { + synchronized (walletLock) { + if (this.isShutDownStarted) return; + if (this.pollPeriodMs != null && this.pollPeriodMs == pollPeriodMs) return; + this.pollPeriodMs = pollPeriodMs; + if (isPolling()) { + stopPolling(); + startPolling(); + } + } + } + + private void pollWallet() { + synchronized (pollLock) { + if (pollInProgress) return; + } + doPollWallet(true); + } + + private void doPollWallet(boolean updateTxs) { + + // skip if shut down started + if (isShutDownStarted) return; + + // set poll in progress + boolean pollInProgressSet = false; + synchronized (pollLock) { + if (!pollInProgress) pollInProgressSet = true; + pollInProgress = true; + } + + // poll wallet + try { + + // skip if daemon not synced + MoneroDaemonInfo lastInfo = xmrConnectionService.getLastInfo(); + if (lastInfo == null) { + log.warn("Last daemon info is null"); + return; + } + if (!xmrConnectionService.isSyncedWithinTolerance()) { + + // throttle warnings + if (System.currentTimeMillis() - lastLogDaemonNotSyncedTimestamp > HavenoUtils.LOG_DAEMON_NOT_SYNCED_WARN_PERIOD_MS) { + log.warn("Monero daemon is not synced within tolerance, height={}, targetHeight={}, monerod={}", xmrConnectionService.chainHeightProperty().get(), xmrConnectionService.getTargetHeight(), xmrConnectionService.getConnection() == null ? null : xmrConnectionService.getConnection().getUri()); + lastLogDaemonNotSyncedTimestamp = System.currentTimeMillis(); + } + return; + } + + // sync wallet if behind daemon + if (walletHeight.get() < xmrConnectionService.getTargetHeight()) { + synchronized (walletLock) { // avoid long sync from blocking other operations + + // TODO: local tests have timing failures unless sync called directly + if (xmrConnectionService.getTargetHeight() - walletHeight.get() < XmrWalletBase.DIRECT_SYNC_WITHIN_BLOCKS) { + syncMainWallet(); + } else { + syncWithProgress(); + } + } + } + + // fetch transactions from pool and store to cache + // TODO: ideally wallet should sync every poll and then avoid updating from pool on fetching txs? + if (updateTxs) { + synchronized (walletLock) { // avoid long fetch from blocking other operations + synchronized (HavenoUtils.getDaemonLock()) { + MoneroRpcConnection sourceConnection = xmrConnectionService.getConnection(); + try { + cachedTxs = wallet.getTxs(new MoneroTxQuery().setIncludeOutputs(true)); + lastPollTxsTimestamp = System.currentTimeMillis(); + } catch (Exception e) { // fetch from pool can fail + if (!isShutDownStarted) { + + // throttle error handling + if (System.currentTimeMillis() - lastLogPollErrorTimestamp > HavenoUtils.LOG_POLL_ERROR_PERIOD_MS) { + log.warn("Error polling main wallet's transactions from the pool: {}", e.getMessage()); + lastLogPollErrorTimestamp = System.currentTimeMillis(); + if (System.currentTimeMillis() - lastPollTxsTimestamp > POLL_TXS_TOLERANCE_MS) requestSwitchToNextBestConnection(sourceConnection); + } + } + } + } + } + } + } catch (Exception e) { + if (wallet == null || isShutDownStarted) return; + if (HavenoUtils.isUnresponsive(e)) forceRestartMainWallet(); + else if (isWalletConnectedToDaemon()) { + log.warn("Error polling main wallet, errorMessage={}. Monerod={}", e.getMessage(), getXmrConnectionService().getConnection()); + //e.printStackTrace(); + } + } finally { + if (pollInProgressSet) { + synchronized (pollLock) { + pollInProgress = false; + } + } + + // cache wallet info last + synchronized (walletLock) { + if (wallet != null && !isShutDownStarted) { + try { + cacheWalletInfo(); + requestSaveMainWallet(); + } catch (Exception e) { + log.warn("Error caching wallet info: " + e.getMessage() + "\n", e); + } + } + } + } + } + + private MoneroSyncResult syncMainWallet() { + synchronized (walletLock) { + MoneroSyncResult result = syncWallet(wallet); + walletHeight.set(wallet.getHeight()); + return result; + } + } + + public boolean isWalletConnectedToDaemon() { + synchronized (walletLock) { + try { + if (wallet == null) return false; + return wallet.isConnectedToDaemon(); + } catch (Exception e) { + return false; + } + } + } + + private boolean requestSwitchToNextBestConnection() { + return requestSwitchToNextBestConnection(null); + } + + public boolean requestSwitchToNextBestConnection(MoneroRpcConnection sourceConnection) { + return xmrConnectionService.requestSwitchToNextBestConnection(sourceConnection); + } + + private void onNewBlock(long height) { + UserThread.execute(() -> { + walletHeight.set(height); + for (MoneroWalletListenerI listener : walletListeners) ThreadUtils.submitToPool(() -> listener.onNewBlock(height)); + }); + } + + private void cacheWalletInfo() { + + // get basic wallet info + long height = wallet.getHeight(); + BigInteger balance = wallet.getBalance(); + BigInteger unlockedBalance = wallet.getUnlockedBalance(); + cachedSubaddresses = wallet.getSubaddresses(0); + cachedOutputs = wallet.getOutputs(); + + // cache and notify changes + if (cachedHeight == null) { + cachedHeight = height; + cachedBalance = balance; + cachedAvailableBalance = unlockedBalance; + onNewBlock(height); + onBalancesChanged(balance, unlockedBalance); + } else { + boolean heightChanged = height != cachedHeight; + boolean balancesChanged = !balance.equals(cachedBalance) || !unlockedBalance.equals(cachedAvailableBalance); + cachedHeight = height; + cachedBalance = balance; + cachedAvailableBalance = unlockedBalance; + if (heightChanged) onNewBlock(height); + if (balancesChanged) onBalancesChanged(balance, unlockedBalance); + } + } + + private void onBalancesChanged(BigInteger newBalance, BigInteger newUnlockedBalance) { + updateBalanceListeners(); + for (MoneroWalletListenerI listener : walletListeners) ThreadUtils.submitToPool(() -> listener.onBalancesChanged(newBalance, newUnlockedBalance)); + } } diff --git a/core/src/main/resources/bip39_english.txt b/core/src/main/resources/bip39_english.txt new file mode 100644 index 0000000000..942040ed50 --- /dev/null +++ b/core/src/main/resources/bip39_english.txt @@ -0,0 +1,2048 @@ +abandon +ability +able +about +above +absent +absorb +abstract +absurd +abuse +access +accident +account +accuse +achieve +acid +acoustic +acquire +across +act +action +actor +actress +actual +adapt +add +addict +address +adjust +admit +adult +advance +advice +aerobic +affair +afford +afraid +again +age +agent +agree +ahead +aim +air +airport +aisle +alarm +album +alcohol +alert +alien +all +alley +allow +almost +alone +alpha +already +also +alter +always +amateur +amazing +among +amount +amused +analyst +anchor +ancient +anger +angle +angry +animal +ankle +announce +annual +another +answer +antenna +antique +anxiety +any +apart +apology +appear +apple +approve +april +arch +arctic +area +arena +argue +arm +armed +armor +army +around +arrange +arrest +arrive +arrow +art +artefact +artist +artwork +ask +aspect +assault +asset +assist +assume +asthma +athlete +atom +attack +attend +attitude +attract +auction +audit +august +aunt +author +auto +autumn +average +avocado +avoid +awake +aware +away +awesome +awful +awkward +axis +baby +bachelor +bacon +badge +bag +balance +balcony +ball +bamboo +banana +banner +bar +barely +bargain +barrel +base +basic +basket +battle +beach +bean +beauty +because +become +beef +before +begin +behave +behind +believe +below +belt +bench +benefit +best +betray +better +between +beyond +bicycle +bid +bike +bind +biology +bird +birth +bitter +black +blade +blame +blanket +blast +bleak +bless +blind +blood +blossom +blouse +blue +blur +blush +board +boat +body +boil +bomb +bone +bonus +book +boost +border +boring +borrow +boss +bottom +bounce +box +boy +bracket +brain +brand +brass +brave +bread +breeze +brick +bridge +brief +bright +bring +brisk +broccoli +broken +bronze +broom +brother +brown +brush +bubble +buddy +budget +buffalo +build +bulb +bulk +bullet +bundle +bunker +burden +burger +burst +bus +business +busy +butter +buyer +buzz +cabbage +cabin +cable +cactus +cage +cake +call +calm +camera +camp +can +canal +cancel +candy +cannon +canoe +canvas +canyon +capable +capital +captain +car +carbon +card +cargo +carpet +carry +cart +case +cash +casino +castle +casual +cat +catalog +catch +category +cattle +caught +cause +caution +cave +ceiling +celery +cement +census +century +cereal +certain +chair +chalk +champion +change +chaos +chapter +charge +chase +chat +cheap +check +cheese +chef +cherry +chest +chicken +chief +child +chimney +choice +choose +chronic +chuckle +chunk +churn +cigar +cinnamon +circle +citizen +city +civil +claim +clap +clarify +claw +clay +clean +clerk +clever +click +client +cliff +climb +clinic +clip +clock +clog +close +cloth +cloud +clown +club +clump +cluster +clutch +coach +coast +coconut +code +coffee +coil +coin +collect +color +column +combine +come +comfort +comic +common +company +concert +conduct +confirm +congress +connect +consider +control +convince +cook +cool +copper +copy +coral +core +corn +correct +cost +cotton +couch +country +couple +course +cousin +cover +coyote +crack +cradle +craft +cram +crane +crash +crater +crawl +crazy +cream +credit +creek +crew +cricket +crime +crisp +critic +crop +cross +crouch +crowd +crucial +cruel +cruise +crumble +crunch +crush +cry +crystal +cube +culture +cup +cupboard +curious +current +curtain +curve +cushion +custom +cute +cycle +dad +damage +damp +dance +danger +daring +dash +daughter +dawn +day +deal +debate +debris +decade +december +decide +decline +decorate +decrease +deer +defense +define +defy +degree +delay +deliver +demand +demise +denial +dentist +deny +depart +depend +deposit +depth +deputy +derive +describe +desert +design +desk +despair +destroy +detail +detect +develop +device +devote +diagram +dial +diamond +diary +dice +diesel +diet +differ +digital +dignity +dilemma +dinner +dinosaur +direct +dirt +disagree +discover +disease +dish +dismiss +disorder +display +distance +divert +divide +divorce +dizzy +doctor +document +dog +doll +dolphin +domain +donate +donkey +donor +door +dose +double +dove +draft +dragon +drama +drastic +draw +dream +dress +drift +drill +drink +drip +drive +drop +drum +dry +duck +dumb +dune +during +dust +dutch +duty +dwarf +dynamic +eager +eagle +early +earn +earth +easily +east +easy +echo +ecology +economy +edge +edit +educate +effort +egg +eight +either +elbow +elder +electric +elegant +element +elephant +elevator +elite +else +embark +embody +embrace +emerge +emotion +employ +empower +empty +enable +enact +end +endless +endorse +enemy +energy +enforce +engage +engine +enhance +enjoy +enlist +enough +enrich +enroll +ensure +enter +entire +entry +envelope +episode +equal +equip +era +erase +erode +erosion +error +erupt +escape +essay +essence +estate +eternal +ethics +evidence +evil +evoke +evolve +exact +example +excess +exchange +excite +exclude +excuse +execute +exercise +exhaust +exhibit +exile +exist +exit +exotic +expand +expect +expire +explain +expose +express +extend +extra +eye +eyebrow +fabric +face +faculty +fade +faint +faith +fall +false +fame +family +famous +fan +fancy +fantasy +farm +fashion +fat +fatal +father +fatigue +fault +favorite +feature +february +federal +fee +feed +feel +female +fence +festival +fetch +fever +few +fiber +fiction +field +figure +file +film +filter +final +find +fine +finger +finish +fire +firm +first +fiscal +fish +fit +fitness +fix +flag +flame +flash +flat +flavor +flee +flight +flip +float +flock +floor +flower +fluid +flush +fly +foam +focus +fog +foil +fold +follow +food +foot +force +forest +forget +fork +fortune +forum +forward +fossil +foster +found +fox +fragile +frame +frequent +fresh +friend +fringe +frog +front +frost +frown +frozen +fruit +fuel +fun +funny +furnace +fury +future +gadget +gain +galaxy +gallery +game +gap +garage +garbage +garden +garlic +garment +gas +gasp +gate +gather +gauge +gaze +general +genius +genre +gentle +genuine +gesture +ghost +giant +gift +giggle +ginger +giraffe +girl +give +glad +glance +glare +glass +glide +glimpse +globe +gloom +glory +glove +glow +glue +goat +goddess +gold +good +goose +gorilla +gospel +gossip +govern +gown +grab +grace +grain +grant +grape +grass +gravity +great +green +grid +grief +grit +grocery +group +grow +grunt +guard +guess +guide +guilt +guitar +gun +gym +habit +hair +half +hammer +hamster +hand +happy +harbor +hard +harsh +harvest +hat +have +hawk +hazard +head +health +heart +heavy +hedgehog +height +hello +helmet +help +hen +hero +hidden +high +hill +hint +hip +hire +history +hobby +hockey +hold +hole +holiday +hollow +home +honey +hood +hope +horn +horror +horse +hospital +host +hotel +hour +hover +hub +huge +human +humble +humor +hundred +hungry +hunt +hurdle +hurry +hurt +husband +hybrid +ice +icon +idea +identify +idle +ignore +ill +illegal +illness +image +imitate +immense +immune +impact +impose +improve +impulse +inch +include +income +increase +index +indicate +indoor +industry +infant +inflict +inform +inhale +inherit +initial +inject +injury +inmate +inner +innocent +input +inquiry +insane +insect +inside +inspire +install +intact +interest +into +invest +invite +involve +iron +island +isolate +issue +item +ivory +jacket +jaguar +jar +jazz +jealous +jeans +jelly +jewel +job +join +joke +journey +joy +judge +juice +jump +jungle +junior +junk +just +kangaroo +keen +keep +ketchup +key +kick +kid +kidney +kind +kingdom +kiss +kit +kitchen +kite +kitten +kiwi +knee +knife +knock +know +lab +label +labor +ladder +lady +lake +lamp +language +laptop +large +later +latin +laugh +laundry +lava +law +lawn +lawsuit +layer +lazy +leader +leaf +learn +leave +lecture +left +leg +legal +legend +leisure +lemon +lend +length +lens +leopard +lesson +letter +level +liar +liberty +library +license +life +lift +light +like +limb +limit +link +lion +liquid +list +little +live +lizard +load +loan +lobster +local +lock +logic +lonely +long +loop +lottery +loud +lounge +love +loyal +lucky +luggage +lumber +lunar +lunch +luxury +lyrics +machine +mad +magic +magnet +maid +mail +main +major +make +mammal +man +manage +mandate +mango +mansion +manual +maple +marble +march +margin +marine +market +marriage +mask +mass +master +match +material +math +matrix +matter +maximum +maze +meadow +mean +measure +meat +mechanic +medal +media +melody +melt +member +memory +mention +menu +mercy +merge +merit +merry +mesh +message +metal +method +middle +midnight +milk +million +mimic +mind +minimum +minor +minute +miracle +mirror +misery +miss +mistake +mix +mixed +mixture +mobile +model +modify +mom +moment +monitor +monkey +monster +month +moon +moral +more +morning +mosquito +mother +motion +motor +mountain +mouse +move +movie +much +muffin +mule +multiply +muscle +museum +mushroom +music +must +mutual +myself +mystery +myth +naive +name +napkin +narrow +nasty +nation +nature +near +neck +need +negative +neglect +neither +nephew +nerve +nest +net +network +neutral +never +news +next +nice +night +noble +noise +nominee +noodle +normal +north +nose +notable +note +nothing +notice +novel +now +nuclear +number +nurse +nut +oak +obey +object +oblige +obscure +observe +obtain +obvious +occur +ocean +october +odor +off +offer +office +often +oil +okay +old +olive +olympic +omit +once +one +onion +online +only +open +opera +opinion +oppose +option +orange +orbit +orchard +order +ordinary +organ +orient +original +orphan +ostrich +other +outdoor +outer +output +outside +oval +oven +over +own +owner +oxygen +oyster +ozone +pact +paddle +page +pair +palace +palm +panda +panel +panic +panther +paper +parade +parent +park +parrot +party +pass +patch +path +patient +patrol +pattern +pause +pave +payment +peace +peanut +pear +peasant +pelican +pen +penalty +pencil +people +pepper +perfect +permit +person +pet +phone +photo +phrase +physical +piano +picnic +picture +piece +pig +pigeon +pill +pilot +pink +pioneer +pipe +pistol +pitch +pizza +place +planet +plastic +plate +play +please +pledge +pluck +plug +plunge +poem +poet +point +polar +pole +police +pond +pony +pool +popular +portion +position +possible +post +potato +pottery +poverty +powder +power +practice +praise +predict +prefer +prepare +present +pretty +prevent +price +pride +primary +print +priority +prison +private +prize +problem +process +produce +profit +program +project +promote +proof +property +prosper +protect +proud +provide +public +pudding +pull +pulp +pulse +pumpkin +punch +pupil +puppy +purchase +purity +purpose +purse +push +put +puzzle +pyramid +quality +quantum +quarter +question +quick +quit +quiz +quote +rabbit +raccoon +race +rack +radar +radio +rail +rain +raise +rally +ramp +ranch +random +range +rapid +rare +rate +rather +raven +raw +razor +ready +real +reason +rebel +rebuild +recall +receive +recipe +record +recycle +reduce +reflect +reform +refuse +region +regret +regular +reject +relax +release +relief +rely +remain +remember +remind +remove +render +renew +rent +reopen +repair +repeat +replace +report +require +rescue +resemble +resist +resource +response +result +retire +retreat +return +reunion +reveal +review +reward +rhythm +rib +ribbon +rice +rich +ride +ridge +rifle +right +rigid +ring +riot +ripple +risk +ritual +rival +river +road +roast +robot +robust +rocket +romance +roof +rookie +room +rose +rotate +rough +round +route +royal +rubber +rude +rug +rule +run +runway +rural +sad +saddle +sadness +safe +sail +salad +salmon +salon +salt +salute +same +sample +sand +satisfy +satoshi +sauce +sausage +save +say +scale +scan +scare +scatter +scene +scheme +school +science +scissors +scorpion +scout +scrap +screen +script +scrub +sea +search +season +seat +second +secret +section +security +seed +seek +segment +select +sell +seminar +senior +sense +sentence +series +service +session +settle +setup +seven +shadow +shaft +shallow +share +shed +shell +sheriff +shield +shift +shine +ship +shiver +shock +shoe +shoot +shop +short +shoulder +shove +shrimp +shrug +shuffle +shy +sibling +sick +side +siege +sight +sign +silent +silk +silly +silver +similar +simple +since +sing +siren +sister +situate +six +size +skate +sketch +ski +skill +skin +skirt +skull +slab +slam +sleep +slender +slice +slide +slight +slim +slogan +slot +slow +slush +small +smart +smile +smoke +smooth +snack +snake +snap +sniff +snow +soap +soccer +social +sock +soda +soft +solar +soldier +solid +solution +solve +someone +song +soon +sorry +sort +soul +sound +soup +source +south +space +spare +spatial +spawn +speak +special +speed +spell +spend +sphere +spice +spider +spike +spin +spirit +split +spoil +sponsor +spoon +sport +spot +spray +spread +spring +spy +square +squeeze +squirrel +stable +stadium +staff +stage +stairs +stamp +stand +start +state +stay +steak +steel +stem +step +stereo +stick +still +sting +stock +stomach +stone +stool +story +stove +strategy +street +strike +strong +struggle +student +stuff +stumble +style +subject +submit +subway +success +such +sudden +suffer +sugar +suggest +suit +summer +sun +sunny +sunset +super +supply +supreme +sure +surface +surge +surprise +surround +survey +suspect +sustain +swallow +swamp +swap +swarm +swear +sweet +swift +swim +swing +switch +sword +symbol +symptom +syrup +system +table +tackle +tag +tail +talent +talk +tank +tape +target +task +taste +tattoo +taxi +teach +team +tell +ten +tenant +tennis +tent +term +test +text +thank +that +theme +then +theory +there +they +thing +this +thought +three +thrive +throw +thumb +thunder +ticket +tide +tiger +tilt +timber +time +tiny +tip +tired +tissue +title +toast +tobacco +today +toddler +toe +together +toilet +token +tomato +tomorrow +tone +tongue +tonight +tool +tooth +top +topic +topple +torch +tornado +tortoise +toss +total +tourist +toward +tower +town +toy +track +trade +traffic +tragic +train +transfer +trap +trash +travel +tray +treat +tree +trend +trial +tribe +trick +trigger +trim +trip +trophy +trouble +truck +true +truly +trumpet +trust +truth +try +tube +tuition +tumble +tuna +tunnel +turkey +turn +turtle +twelve +twenty +twice +twin +twist +two +type +typical +ugly +umbrella +unable +unaware +uncle +uncover +under +undo +unfair +unfold +unhappy +uniform +unique +unit +universe +unknown +unlock +until +unusual +unveil +update +upgrade +uphold +upon +upper +upset +urban +urge +usage +use +used +useful +useless +usual +utility +vacant +vacuum +vague +valid +valley +valve +van +vanish +vapor +various +vast +vault +vehicle +velvet +vendor +venture +venue +verb +verify +version +very +vessel +veteran +viable +vibrant +vicious +victory +video +view +village +vintage +violin +virtual +virus +visa +visit +visual +vital +vivid +vocal +voice +void +volcano +volume +vote +voyage +wage +wagon +wait +walk +wall +walnut +want +warfare +warm +warrior +wash +wasp +waste +water +wave +way +wealth +weapon +wear +weasel +weather +web +wedding +weekend +weird +welcome +west +wet +whale +what +wheat +wheel +when +where +whip +whisper +wide +width +wife +wild +will +win +window +wine +wing +wink +winner +winter +wire +wisdom +wise +wish +witness +wolf +woman +wonder +wood +wool +word +work +world +worry +worth +wrap +wreck +wrestle +wrist +write +wrong +yard +year +yellow +you +young +youth +zebra +zero +zone +zoo diff --git a/core/src/main/resources/btc_mainnet.seednodes b/core/src/main/resources/btc_mainnet.seednodes deleted file mode 100644 index cfe18becc7..0000000000 --- a/core/src/main/resources/btc_mainnet.seednodes +++ /dev/null @@ -1,17 +0,0 @@ -# nodeaddress.onion:port [(@owner,@backup)] -wizseedscybbttk4bmb2lzvbuk2jtect37lcpva4l3twktmkzemwbead.onion:8000 (@wiz) -wizseed3d376esppbmbjxk2fhk2jg5fpucddrzj2kxtbxbx4vrnwclad.onion:8000 (@wiz) -wizseed7ab2gi3x267xahrp2pkndyrovczezzb46jk6quvguciuyqrid.onion:8000 (@wiz) -devinv3rhon24gqf5v6ondoqgyrbzyqihzyouzv7ptltsewhfmox2zqd.onion:8000 (@devinbileck) -devinsn2teu33efff62bnvwbxmfgbfjlgqsu3ad4b4fudx3a725eqnyd.onion:8000 (@devinbileck) -devinsn3xuzxhj6pmammrxpydhwwmwp75qkksedo5dn2tlmu7jggo7id.onion:8000 (@devinbileck) -sn3emzy56u3mxzsr4geysc52feoq5qt7ja56km6gygwnszkshunn2sid.onion:8000 (@emzy) -sn4emzywye3dhjouv7jig677qepg7fnusjidw74fbwneieruhmi7fuyd.onion:8000 (@emzy) -sn5emzyvxuildv34n6jewfp2zeota4aq63fsl5yyilnvksezr3htveqd.onion:8000 (@emzy) -sn2havenoad7ncazupgbd3dcedqh5ptirgwofw63djwpdtftwhddo75oid.onion:8000 (@miker) -sn3bsq3evqkpshdmc3sbdxafkhfnk7ctop44jsxbxyys5ridsaw5abyd.onion:8000 (@miker) -sn4bsqpc7eb2ntvpsycxbzqt6fre72l4krp2fl5svphfh2eusrqtq3qd.onion:8000 (@miker) -5quyxpxheyvzmb2d.onion:8000 (@miker) -rm7b56wbrcczpjvl.onion:8000 (@miker) -s67qglwhkgkyvr74.onion:8000 (@emzy) -fl3mmribyxgrv63c.onion:8000 (@devinbileck) diff --git a/core/src/main/resources/btc_regtest.seednodes b/core/src/main/resources/btc_regtest.seednodes deleted file mode 100644 index 44cd4ec296..0000000000 --- a/core/src/main/resources/btc_regtest.seednodes +++ /dev/null @@ -1,3 +0,0 @@ -# nodeaddress.onion:port [(@owner,@backup)] -localhost:2002 (@devtest1) -localhost:3002 (@devtest2) diff --git a/core/src/main/resources/btc_testnet.seednodes b/core/src/main/resources/btc_testnet.seednodes deleted file mode 100644 index 4051e84128..0000000000 --- a/core/src/main/resources/btc_testnet.seednodes +++ /dev/null @@ -1,2 +0,0 @@ -# nodeaddress.onion:port [(@owner)] -m5izk3fvjsjbmkqi.onion:8001 diff --git a/core/src/main/resources/cash_register.wav b/core/src/main/resources/cash_register.wav new file mode 100644 index 0000000000..c11d914655 Binary files /dev/null and b/core/src/main/resources/cash_register.wav differ diff --git a/core/src/main/resources/chime.wav b/core/src/main/resources/chime.wav new file mode 100644 index 0000000000..c2ba1ab089 Binary files /dev/null and b/core/src/main/resources/chime.wav differ diff --git a/core/src/main/resources/haveno.policy b/core/src/main/resources/haveno.policy index 7fbd04b250..43b4b00810 100644 --- a/core/src/main/resources/haveno.policy +++ b/core/src/main/resources/haveno.policy @@ -16,7 +16,7 @@ grant { permission "java.util.PropertyPermission" "maxConnections", "read"; permission "java.util.PropertyPermission" "networkId", "read"; permission "java.util.PropertyPermission" "banList", "read"; - permission "java.util.PropertyPermission" "socks5ProxyBtcAddress", "read"; + permission "java.util.PropertyPermission" "socks5ProxyXmrAddress", "read"; permission "java.util.PropertyPermission" "socks5ProxyHttpAddress", "read"; permission "java.util.PropertyPermission" "useragent.name", "read"; permission "java.util.PropertyPermission" "useragent.version", "read"; @@ -64,7 +64,7 @@ grant { permission "java.lang.RuntimePermission" "getenv.maxConnections"; permission "java.lang.RuntimePermission" "getenv.networkId"; permission "java.lang.RuntimePermission" "getenv.banList"; - permission "java.lang.RuntimePermission" "getenv.socks5ProxyBtcAddress"; + permission "java.lang.RuntimePermission" "getenv.socks5ProxyXmrAddress"; permission "java.lang.RuntimePermission" "getenv.socks5ProxyHttpAddress"; permission "java.lang.RuntimePermission" "getenv.useragent.name"; permission "java.lang.RuntimePermission" "getenv.useragent.version"; diff --git a/core/src/main/resources/help/canceloffer-help.txt b/core/src/main/resources/help/canceloffer-help.txt index 82ef2ebf29..c9e14361a5 100644 --- a/core/src/main/resources/help/canceloffer-help.txt +++ b/core/src/main/resources/help/canceloffer-help.txt @@ -2,7 +2,7 @@ canceloffer NAME ---- -canceloffer - cancel an existing offer to buy or sell BTC +canceloffer - cancel an existing offer to buy or sell XMR SYNOPSIS -------- diff --git a/core/src/main/resources/help/confirmpaymentreceived-help.txt b/core/src/main/resources/help/confirmpaymentreceived-help.txt index e7ba06f7bd..e1a9ef8e22 100644 --- a/core/src/main/resources/help/confirmpaymentreceived-help.txt +++ b/core/src/main/resources/help/confirmpaymentreceived-help.txt @@ -11,8 +11,8 @@ confirmpaymentreceived DESCRIPTION ----------- -After the seller receives payment from the BTC buyer, confirmpaymentreceived notifies -the buyer the payment has arrived. The seller can release locked BTC only after the +After the seller receives payment from the XMR buyer, confirmpaymentreceived notifies +the buyer the payment has arrived. The seller can release locked XMR only after the this confirmation message has been sent. OPTIONS @@ -22,6 +22,6 @@ OPTIONS EXAMPLES -------- -A BTC seller has taken an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and has recently +A XMR seller has taken an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and has recently received the required fiat payment from the buyer's fiat account: $ ./haveno-cli --password=xyz --port=9998 confirmpaymentreceived --trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea diff --git a/core/src/main/resources/help/confirmpaymentstarted-help.txt b/core/src/main/resources/help/confirmpaymentstarted-help.txt index 6133f6cd28..7eee257ff2 100644 --- a/core/src/main/resources/help/confirmpaymentstarted-help.txt +++ b/core/src/main/resources/help/confirmpaymentstarted-help.txt @@ -11,7 +11,7 @@ confirmpaymentsent DESCRIPTION ----------- -After the buyer initiates payment to the BTC seller, confirmpaymentsent notifies +After the buyer initiates payment to the XMR seller, confirmpaymentsent notifies the seller to begin watching for a funds deposit in her payment account. OPTIONS @@ -21,6 +21,6 @@ OPTIONS EXAMPLES -------- -A BTC buyer has taken an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and has recently +A XMR buyer has taken an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and has recently initiated the required fiat payment to the seller's fiat account: $ ./haveno-cli --password=xyz --port=9998 confirmpaymentsent --trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea diff --git a/core/src/main/resources/help/createoffer-help.txt b/core/src/main/resources/help/createoffer-help.txt index dcf2f00de0..901f44dc9a 100644 --- a/core/src/main/resources/help/createoffer-help.txt +++ b/core/src/main/resources/help/createoffer-help.txt @@ -2,7 +2,7 @@ createoffer NAME ---- -createoffer - create offer to buy or sell BTC +createoffer - create offer to buy or sell XMR SYNOPSIS -------- @@ -18,7 +18,7 @@ createoffer DESCRIPTION ----------- -Create and place an offer to buy or sell BTC using a fiat account. +Create and place an offer to buy or sell XMR using a fiat account. OPTIONS ------- @@ -29,54 +29,54 @@ OPTIONS The direction of the trade (BUY or SELL). --currency-code - The three letter code for the fiat used to buy or sell BTC, e.g., EUR, USD, BRL, ... + The three letter code for the fiat used to buy or sell XMR, e.g., EUR, USD, BRL, ... --market-price-margin - The % above or below market BTC price, e.g., 1.00 (1%). + The % above or below market XMR price, e.g., 1.00 (1%). If --market-price-margin is not present, --fixed-price must be. --fixed-price - The fixed BTC price in fiat used to buy or sell BTC, e.g., 34000 (USD). + The fixed XMR price in fiat used to buy or sell XMR, e.g., 34000 (USD). If --fixed-price is not present, --market-price-margin must be. --amount - The amount of BTC to buy or sell, e.g., 0.125. + The amount of XMR to buy or sell, e.g., 0.125. --min-amount - The minimum amount of BTC to buy or sell, e.g., 0.006. + The minimum amount of XMR to buy or sell, e.g., 0.006. If --min-amount is not present, it defaults to the --amount value. --security-deposit - The percentage of the BTC amount being traded for the security deposit, e.g., 60.0 (60%). + The percentage of the XMR amount being traded for the security deposit, e.g., 60.0 (60%). --fee-currency - The wallet currency used to pay the Haveno trade maker fee (BTC). Default is BTC + The wallet currency used to pay the Haveno trade maker fee (XMR). Default is XMR EXAMPLES -------- -To create a BUY 0.125 BTC with EUR offer +To create a BUY 0.125 XMR with EUR offer at the current market price, using a payment account with ID 7413d263-225a-4f1b-837a-1e3094dc0d77, putting up a 30 percent security deposit, - and paying the Haveno maker trading fee in BTC: + and paying the Haveno maker trading fee in XMR: $ ./haveno-cli --password=xyz --port=9998 createoffer --payment-account=7413d263-225a-4f1b-837a-1e3094dc0d77 \ --direction=buy \ --currency-code=eur \ --amount=0.125 \ --market-price-margin=0.00 \ --security-deposit=30.0 \ - --fee-currency=btc + --fee-currency=xmr -To create a SELL 0.006 BTC for USD offer +To create a SELL 0.006 XMR for USD offer at a fixed price of 40,000 USD, using a payment account with ID 7413d263-225a-4f1b-837a-1e3094dc0d77, putting up a 25 percent security deposit, - and paying the Haveno maker trading fee in BTC: + and paying the Haveno maker trading fee in XMR: $ ./haveno-cli --password=xyz --port=9998 createoffer --payment-account=7413d263-225a-4f1b-837a-1e3094dc0d77 \ --direction=sell \ --currency-code=usd \ --amount=0.006 \ --fixed-price=40000 \ --security-deposit=25.0 \ - --fee-currency=btc + --fee-currency=xmr diff --git a/core/src/main/resources/help/getaddressbalance-help.txt b/core/src/main/resources/help/getaddressbalance-help.txt index b2084cdf6e..a391f1db0c 100644 --- a/core/src/main/resources/help/getaddressbalance-help.txt +++ b/core/src/main/resources/help/getaddressbalance-help.txt @@ -11,12 +11,12 @@ getaddressbalance DESCRIPTION ----------- -Returns the balance of a BTC address in the Haveno server's wallet. +Returns the balance of a XMR address in the Haveno server's wallet. OPTIONS ------- --address=<btc-address> - The BTC address. + The XMR address. EXAMPLES -------- diff --git a/core/src/main/resources/help/getbalance-help.txt b/core/src/main/resources/help/getbalance-help.txt index 7d4b4b3717..003705b0b3 100644 --- a/core/src/main/resources/help/getbalance-help.txt +++ b/core/src/main/resources/help/getbalance-help.txt @@ -11,7 +11,7 @@ getbalance DESCRIPTION ----------- -Returns full balance information for Haveno BTC wallets. +Returns full balance information for Haveno XMR wallets. OPTIONS ------- @@ -20,11 +20,11 @@ OPTIONS EXAMPLES -------- -Show full BTC wallet balance information: +Show full XMR wallet balance information: $ ./haveno-cli --password=xyz --port=9998 getbalance Show full wallet balance information: $ ./haveno-cli --password=xyz --port=9998 getbalance --currency-code=bsq -Show full BTC wallet balance information: +Show full XMR wallet balance information: $ ./haveno-cli --password=xyz --port=9998 getbalance --currency-code=btc diff --git a/core/src/main/resources/help/getfundingaddresses-help.txt b/core/src/main/resources/help/getfundingaddresses-help.txt index 42d2a96c67..eb9fb32921 100644 --- a/core/src/main/resources/help/getfundingaddresses-help.txt +++ b/core/src/main/resources/help/getfundingaddresses-help.txt @@ -2,7 +2,7 @@ getfundingaddresses NAME ---- -getfundingaddresses - list BTC receiving address +getfundingaddresses - list XMR receiving address SYNOPSIS -------- @@ -10,7 +10,7 @@ getfundingaddresses DESCRIPTION ----------- -Returns a list of receiving BTC addresses. +Returns a list of receiving XMR addresses. EXAMPLES -------- diff --git a/core/src/main/resources/help/getmyoffer-help.txt b/core/src/main/resources/help/getmyoffer-help.txt index cda2108363..c9ae78a733 100644 --- a/core/src/main/resources/help/getmyoffer-help.txt +++ b/core/src/main/resources/help/getmyoffer-help.txt @@ -2,7 +2,7 @@ getmyoffer NAME ---- -getmyoffer - get your offer to buy or sell BTC +getmyoffer - get your offer to buy or sell XMR SYNOPSIS -------- diff --git a/core/src/main/resources/help/getmyoffers-help.txt b/core/src/main/resources/help/getmyoffers-help.txt index 5bc12b19cd..9b211849ec 100644 --- a/core/src/main/resources/help/getmyoffers-help.txt +++ b/core/src/main/resources/help/getmyoffers-help.txt @@ -2,7 +2,7 @@ getmyoffers NAME ---- -getmyoffers - get your own buy or sell BTC offers for a fiat currency +getmyoffers - get your own buy or sell XMR offers for a fiat currency SYNOPSIS -------- @@ -20,7 +20,7 @@ OPTIONS The direction of the offer (BUY or SELL). --currency-code - The three letter code for the fiat used to buy or sell BTC, e.g., EUR, USD, BRL, ... + The three letter code for the fiat used to buy or sell XMR, e.g., EUR, USD, BRL, ... EXAMPLES -------- diff --git a/core/src/main/resources/help/getoffer-help.txt b/core/src/main/resources/help/getoffer-help.txt index 6193e3a61d..f04ed69102 100644 --- a/core/src/main/resources/help/getoffer-help.txt +++ b/core/src/main/resources/help/getoffer-help.txt @@ -2,7 +2,7 @@ getoffer NAME ---- -getoffer - get an offer to buy or sell BTC +getoffer - get an offer to buy or sell XMR SYNOPSIS -------- diff --git a/core/src/main/resources/help/getoffers-help.txt b/core/src/main/resources/help/getoffers-help.txt index df6c030e77..368dd5db05 100644 --- a/core/src/main/resources/help/getoffers-help.txt +++ b/core/src/main/resources/help/getoffers-help.txt @@ -2,7 +2,7 @@ getoffers NAME ---- -getoffers - get available buy or sell BTC offers for a fiat currency +getoffers - get available buy or sell XMR offers for a fiat currency SYNOPSIS -------- @@ -22,17 +22,17 @@ OPTIONS The direction of the offer (BUY or SELL). --currency-code - The three letter code for the fiat used to buy or sell BTC, e.g., EUR, USD, BRL, ... + The three letter code for the fiat used to buy or sell XMR, e.g., EUR, USD, BRL, ... EXAMPLES -------- You have one Brazilian Real payment account with a face-to-face payment method type. -To view available offers to BUY BTC with BRL, created by other users with the same +To view available offers to BUY XMR with BRL, created by other users with the same face-to-fact account type: $ ./haveno-cli --password=xyz --port=9998 getoffers --direction=buy --currency-code=brl You have several EUR payment accounts, each with a different payment method type. -To view available offers to SELL BTC with EUR, created by other users having at +To view available offers to SELL XMR with EUR, created by other users having at least one payment account that matches any of your own: $ ./haveno-cli --password=xyz --port=9998 getoffers --direction=sell --currency-code=eur diff --git a/core/src/main/resources/help/gettrade-help.txt b/core/src/main/resources/help/gettrade-help.txt index c495c24197..ced8cf3755 100644 --- a/core/src/main/resources/help/gettrade-help.txt +++ b/core/src/main/resources/help/gettrade-help.txt @@ -2,7 +2,7 @@ gettrade NAME ---- -gettrade - get a buy or sell BTC trade +gettrade - get a buy or sell XMR trade SYNOPSIS -------- diff --git a/core/src/main/resources/help/gettransaction-help.txt b/core/src/main/resources/help/gettransaction-help.txt index 44f513d09e..8f87780d9f 100644 --- a/core/src/main/resources/help/gettransaction-help.txt +++ b/core/src/main/resources/help/gettransaction-help.txt @@ -11,14 +11,14 @@ gettransaction DESCRIPTION ----------- -Returns a very brief summary of a BTC transaction created by the Haveno server. +Returns a very brief summary of a XMR transaction created by the Haveno server. -To see full transaction details, use a bitcoin-core client or an online block explorer. +To see full transaction details, use a monero-core client or an online block explorer. OPTIONS ------- --transaction-id - The ID of the BTC transaction. + The ID of the XMR transaction. EXAMPLES -------- diff --git a/core/src/main/resources/help/gettxfeerate-help.txt b/core/src/main/resources/help/gettxfeerate-help.txt index a9889a9847..98492a00c1 100644 --- a/core/src/main/resources/help/gettxfeerate-help.txt +++ b/core/src/main/resources/help/gettxfeerate-help.txt @@ -10,7 +10,7 @@ gettxfeerate DESCRIPTION ----------- -Returns the most recent bitcoin network transaction fee the Haveno server could find. +Returns the most recent monero network transaction fee the Haveno server could find. EXAMPLES -------- diff --git a/core/src/main/resources/help/getbtcprice-help.txt b/core/src/main/resources/help/getxmrprice-help.txt similarity index 73% rename from core/src/main/resources/help/getbtcprice-help.txt rename to core/src/main/resources/help/getxmrprice-help.txt index bb7c351eea..dc880a11a4 100644 --- a/core/src/main/resources/help/getbtcprice-help.txt +++ b/core/src/main/resources/help/getxmrprice-help.txt @@ -11,7 +11,7 @@ getbtcprice DESCRIPTION ----------- -Returns the current market BTC price for the given currency-code. +Returns the current market XMR price for the given currency-code. OPTIONS ------- @@ -21,10 +21,10 @@ OPTIONS EXAMPLES -------- -Get the current BTC market price in Euros: +Get the current XMR market price in Euros: $ ./haveno-cli --password=xyz --port=9998 getbtcprice --currency-code=eur -Get the current BTC market price in Brazilian Reais: +Get the current XMR market price in Brazilian Reais: $ ./haveno-cli --password=xyz --port=9998 getbtcprice --currency-code=brl diff --git a/core/src/main/resources/help/keepfunds-help.txt b/core/src/main/resources/help/keepfunds-help.txt index caddadf74e..4f023be5bc 100644 --- a/core/src/main/resources/help/keepfunds-help.txt +++ b/core/src/main/resources/help/keepfunds-help.txt @@ -2,7 +2,7 @@ keepfunds NAME ---- -keepfunds - keep BTC received during a trade in Haveno wallet +keepfunds - keep XMR received during a trade in Haveno wallet SYNOPSIS -------- @@ -11,12 +11,12 @@ keepfunds DESCRIPTION ----------- -A BTC buyer completes the final step in the trade protocol by keeping received BTC in his +A XMR buyer completes the final step in the trade protocol by keeping received XMR in his Haveno wallet. This step may not seem necessary from the buyer's perspective, but it is necessary for correct transition of a trade's state to CLOSED, within the Haveno server. -The alternative way to close out the trade is to send the received BTC to an external -BTC wallet, using the withdrawfunds command. +The alternative way to close out the trade is to send the received XMR to an external +XMR wallet, using the withdrawfunds command. OPTIONS ------- @@ -25,7 +25,7 @@ OPTIONS EXAMPLES -------- -A BTC seller has informed the buyer that fiat payment has been received for trade with ID -83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and locked BTC has been released to the buyer. -The BTC buyer closes out the trade by keeping the received BTC in her Haveno wallet: +A XMR seller has informed the buyer that fiat payment has been received for trade with ID +83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and locked XMR has been released to the buyer. +The XMR buyer closes out the trade by keeping the received XMR in her Haveno wallet: $ ./haveno-cli --password=xyz --port=9998 keepfunds --trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea diff --git a/core/src/main/resources/help/sendbtc-help.txt b/core/src/main/resources/help/sendxmr-help.txt similarity index 76% rename from core/src/main/resources/help/sendbtc-help.txt rename to core/src/main/resources/help/sendxmr-help.txt index f41469b85e..6819614716 100644 --- a/core/src/main/resources/help/sendbtc-help.txt +++ b/core/src/main/resources/help/sendxmr-help.txt @@ -2,7 +2,7 @@ sendbtc NAME ---- -sendbtc - send BTC to an external wallet +sendbtc - send XMR to an external wallet SYNOPSIS -------- @@ -14,15 +14,15 @@ sendbtc DESCRIPTION ----------- -Send BTC from your Haveno wallet to an external BTC address. +Send XMR from your Haveno wallet to an external XMR address. OPTIONS ------- --address - The destination BTC address for the send transaction. + The destination XMR address for the send transaction. --amount - The amount of BTC to send. + The amount of XMR to send. --tx-fee-rate An optional transaction fee rate (sats/byte) for the transaction. The user is @@ -35,16 +35,16 @@ OPTIONS EXAMPLES -------- -Send 0.10 BTC to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a default +Send 0.10 XMR to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a default transaction fee rate: $ ./haveno-cli --password=xyz --port=9998 sendbtc --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 --amount=0.10 -Send 0.05 BTC to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a transaction +Send 0.05 XMR to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a transaction fee rate of 10 sats/byte: $ ./haveno-cli --password=xyz --port=9998 sendbtc --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 --amount=0.05 \ --tx-fee-rate=10 -Send 0.005 BTC to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a transaction +Send 0.005 XMR to address bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 with a transaction fee rate of 40 sats/byte, and save a memo with the send transaction: $ ./haveno-cli --password=xyz --port=9998 sendbtc --address=bcrt1qygvsqmyt8jyhtp7l3zwqm7s7v3nar6vkc2luz3 --amount=0.005 \ --tx-fee-rate=40 \ diff --git a/core/src/main/resources/help/takeoffer-help.txt b/core/src/main/resources/help/takeoffer-help.txt index 126e55f1a7..7c1acdff9c 100644 --- a/core/src/main/resources/help/takeoffer-help.txt +++ b/core/src/main/resources/help/takeoffer-help.txt @@ -2,7 +2,7 @@ takeoffer NAME ---- -takeoffer - take an offer to buy or sell BTC +takeoffer - take an offer to buy or sell XMR SYNOPSIS -------- @@ -13,7 +13,7 @@ takeoffer DESCRIPTION ----------- -Take an existing offer using a matching payment method. The Haveno trade fee can be paid in BTC. +Take an existing offer using a matching payment method. The Haveno trade fee can be paid in XMR. OPTIONS ------- @@ -25,13 +25,13 @@ OPTIONS The payment account's payment method must match that of the offer. --fee-currency - The wallet currency used to pay the Haveno trade taker fee (BTC). Default is BTC + The wallet currency used to pay the Haveno trade taker fee (XMR). Default is XMR EXAMPLES -------- To take an offer with ID 83e8b2e2-51b6-4f39-a748-3ebd29c22aea using a payment account with ID fe20cdbd-22be-4b8a-a4b6-d2608ff09d6e, - and paying the Haveno trading fee in BTC: + and paying the Haveno trading fee in XMR: $ ./haveno-cli --password=xyz --port=9998 takeoffer --offer-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea \ --payment-account=fe20cdbd-22be-4b8a-a4b6-d2608ff09d6e \ -fee-currency=btc diff --git a/core/src/main/resources/help/withdrawfunds-help.txt b/core/src/main/resources/help/withdrawfunds-help.txt index 6caf30ba48..bccc2b08a0 100644 --- a/core/src/main/resources/help/withdrawfunds-help.txt +++ b/core/src/main/resources/help/withdrawfunds-help.txt @@ -2,7 +2,7 @@ withdrawfunds NAME ---- -withdrawfunds - send BTC received during a trade to an external BTC wallet +withdrawfunds - send XMR received during a trade to an external XMR wallet SYNOPSIS -------- @@ -13,10 +13,10 @@ withdrawfunds DESCRIPTION ----------- -A BTC buyer completes the final step in the trade protocol by sending received BTC to -an external BTC wallet. +A XMR buyer completes the final step in the trade protocol by sending received XMR to +an external XMR wallet. -The alternative way to close out the trade is to keep the received BTC in the Haveno wallet, +The alternative way to close out the trade is to keep the received XMR in the Haveno wallet, using the keepfunds command. The buyer needs to complete the trade protocol using the keepfunds or withdrawfunds or command. @@ -37,14 +37,14 @@ OPTIONS EXAMPLES -------- -A BTC seller has informed the buyer that fiat payment has been received for trade with ID -83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and locked BTC has been released to the buyer. -The BTC buyer closes out the trade by sending the received BTC to an external BTC wallet: +A XMR seller has informed the buyer that fiat payment has been received for trade with ID +83e8b2e2-51b6-4f39-a748-3ebd29c22aea, and locked XMR has been released to the buyer. +The XMR buyer closes out the trade by sending the received XMR to an external XMR wallet: $ ./haveno-cli --password=xyz --port=9998 withdrawfunds --trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea \ - --address=2N5J6MyjAsWnashimGiNwoRzUXThsQzRmbv (bitcoin regtest address) + --address=2N5J6MyjAsWnashimGiNwoRzUXThsQzRmbv (monero stagetnet address) -A seller sends a trade's BTC proceeds to an external wallet, and includes an optional memo: +A seller sends a trade's XMR proceeds to an external wallet, and includes an optional memo: $ ./haveno-cli --password=xyz --port=9998 withdrawfunds --trade-id=83e8b2e2-51b6-4f39-a748-3ebd29c22aea \ --address=2N5J6MyjAsWnashimGiNwoRzUXThsQzRmbv \ --memo="note to self" diff --git a/core/src/main/resources/i18n/displayStrings.properties b/core/src/main/resources/i18n/displayStrings.properties index b13788170b..71ed6e3164 100644 --- a/core/src/main/resources/i18n/displayStrings.properties +++ b/core/src/main/resources/i18n/displayStrings.properties @@ -39,12 +39,14 @@ shared.continueAnyway=Continue anyway shared.na=N/A shared.shutDown=Shut down shared.reportBug=Report bug on GitHub -shared.buyBitcoin=Buy Monero -shared.sellBitcoin=Sell Monero +shared.buyMonero=Buy Monero +shared.sellMonero=Sell Monero shared.buyCurrency=Buy {0} shared.sellCurrency=Sell {0} -shared.buyingBTCWith=buying XMR with {0} -shared.sellingBTCFor=selling XMR for {0} +shared.buyCurrencyLocked=Buy {0} 🔒 +shared.sellCurrencyLocked=Sell {0} 🔒 +shared.buyingXMRWith=buying XMR with {0} +shared.sellingXMRFor=selling XMR for {0} shared.buyingCurrency=buying {0} (selling XMR) shared.sellingCurrency=selling {0} (buying XMR) shared.buy=buy @@ -97,7 +99,7 @@ shared.amountMinMax=Amount (min - max) shared.amountHelp=If an offer has a minimum and a maximum amount set, then you can trade any amount within this range. shared.remove=Remove shared.goTo=Go to {0} -shared.BTCMinMax=XMR (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Remove offer shared.dontRemoveOffer=Don't remove offer shared.editOffer=Edit offer @@ -107,7 +109,7 @@ shared.chooseTradingAccount=Choose trading account shared.faq=Visit FAQ page shared.yesCancel=Yes, cancel shared.nextStep=Next step -shared.fundFromSavingsWalletButton=Transfer funds from Haveno wallet +shared.fundFromSavingsWalletButton=Apply funds from Haveno wallet shared.fundFromExternalWalletButton=Open your external wallet for funding shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=Below % from market price @@ -120,7 +122,7 @@ shared.yourDepositTransactionId=Your deposit transaction ID shared.peerDepositTransactionId=Peer's deposit transaction ID shared.makerDepositTransactionId=Maker's deposit transaction ID shared.takerDepositTransactionId=Taker's deposit transaction ID -shared.TheBTCBuyer=The XMR buyer +shared.TheXMRBuyer=The XMR buyer shared.You=You shared.preparingConfirmation=Preparing confirmation... shared.sendingConfirmation=Sending confirmation... @@ -150,6 +152,7 @@ shared.addNewAccount=Add new account shared.ExportAccounts=Export Accounts shared.importAccounts=Import Accounts shared.createNewAccount=Create new account +shared.createNewAccountDescription=Your account details are stored locally on your device and shared only with your trading peer and the arbitrator if a dispute is opened. shared.saveNewAccount=Save new account shared.selectedAccount=Selected account shared.deleteAccount=Delete account @@ -173,6 +176,7 @@ shared.acceptedTakerCountries=Accepted taker countries shared.tradePrice=Trade price shared.tradeAmount=Trade amount shared.tradeVolume=Trade volume +shared.reservedAmount=Reserved amount shared.invalidKey=The key you entered was not correct. shared.enterPrivKey=Enter private key to unlock shared.payoutTxId=Payout transaction ID @@ -189,14 +193,14 @@ shared.messageSendingFailed=Message sending failed. Error: {0} shared.unlock=Unlock shared.toReceive=to receive shared.toSpend=to spend -shared.btcAmount=XMR amount +shared.xmrAmount=XMR amount shared.yourLanguage=Your languages shared.addLanguage=Add language shared.total=Total shared.totalsNeeded=Funds needed shared.tradeWalletAddress=Trade wallet address shared.tradeWalletBalance=Trade wallet balance -shared.reserveExactAmount=Reserve exact amount for offer. Requires a mining fee and 10 confirmations (~20 minutes) before your offer is live. +shared.reserveExactAmount=Reserve only the necessary funds. Requires a mining fee and ~20 minutes before your offer goes live. shared.makerTxFee=Maker: {0} shared.takerTxFee=Taker: {0} shared.iConfirm=I confirm @@ -206,6 +210,7 @@ shared.crypto=Crypto shared.traditional=Traditional shared.otherAssets=other assets shared.other=Other +shared.preciousMetals=Precious Metals shared.all=All shared.edit=Edit shared.advancedOptions=Advanced options @@ -244,8 +249,8 @@ shared.taker=Taker #################################################################### mainView.menu.market=Market -mainView.menu.buy=Buy -mainView.menu.sell=Sell +mainView.menu.buyXmr=Buy XMR +mainView.menu.sellXmr=Sell XMR mainView.menu.portfolio=Portfolio mainView.menu.funds=Funds mainView.menu.support=Support @@ -264,12 +269,15 @@ mainView.balance.reserved.short=Reserved mainView.balance.pending.short=Pending mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Connecting to Monero network +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=Connecting to Haveno network mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrInfo.connectedTo=Connected to {0} at block {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Synchronizing wallet with {0} at block: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Synced with {0} at block {1} mainView.footer.xmrInfo.connectingTo=Connecting to mainView.footer.xmrInfo.connectionFailed=Connection failed to mainView.footer.xmrPeers=Monero network peers: {0} @@ -293,7 +301,7 @@ mainView.walletServiceErrorMsg.connectionError=Connection to the Monero network mainView.walletServiceErrorMsg.rejectedTxException=A transaction was rejected from the network.\n\n{0} mainView.networkWarning.allConnectionsLost=You lost the connection to all {0} network peers.\nMaybe you lost your internet connection or your computer was in standby mode. -mainView.networkWarning.localhostBitcoinLost=You lost the connection to the localhost Monero node.\nPlease restart the Haveno application to connect to other Monero nodes or restart the localhost Monero node. +mainView.networkWarning.localhostMoneroLost=You lost the connection to the localhost Monero node.\nPlease restart the Haveno application to connect to other Monero nodes or restart the localhost Monero node. mainView.version.update=(Update available) mainView.status.connections=Inbound connections: {0}\nOutbound connections: {1} @@ -307,11 +315,14 @@ market.tabs.spreadCurrency=Offers by Currency market.tabs.spreadPayment=Offers by Payment Method market.tabs.trades=Trades +# OfferBookView +market.offerBook.filterPrompt=Filter + # OfferBookChartView market.offerBook.sellOffersHeaderLabel=Sell {0} to market.offerBook.buyOffersHeaderLabel=Buy {0} from -market.offerBook.buy=I want to buy bitcoin -market.offerBook.sell=I want to sell bitcoin +market.offerBook.buy=I want to buy monero +market.offerBook.sell=I want to sell monero # SpreadView market.spread.numberOfOffersColumn=All offers ({0}) @@ -340,6 +351,7 @@ market.trades.showVolumeInUSD=Show volume in USD offerbook.createOffer=Create offer offerbook.takeOffer=Take offer offerbook.takeOffer.createAccount=Create account and take offer +offerbook.takeOffer.enterChallenge=Enter the offer passphrase offerbook.trader=Trader offerbook.offerersBankId=Maker''s bank ID (BIC/SWIFT): {0} offerbook.offerersBankName=Maker''s bank name: {0} @@ -351,6 +363,8 @@ offerbook.availableOffersToSell=Sell {0} for {1} offerbook.filterByCurrency=Choose currency offerbook.filterByPaymentMethod=Choose payment method offerbook.matchingOffers=Offers matching my accounts +offerbook.filterNoDeposit=No deposit +offerbook.noDepositOffers=Offers with no deposit (passphrase required) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts offerbook.timeSinceSigning.info.peer=signed by a peer, waiting %d days for limits to be lifted @@ -364,10 +378,12 @@ offerbook.timeSinceSigning.tooltip.accountLimitLifted=Account limit lifted offerbook.timeSinceSigning.tooltip.info.unsigned=This account hasn't been signed yet offerbook.timeSinceSigning.tooltip.info.signed=This account has been signed offerbook.timeSinceSigning.tooltip.info.signedAndLifted=This account has been signed and can sign peer accounts -offerbook.timeSinceSigning.tooltip.checkmark.buyBtc=buy BTC from a signed account +offerbook.timeSinceSigning.tooltip.checkmark.buyXmr=buy XMR from a signed account offerbook.timeSinceSigning.tooltip.checkmark.wait=wait a minimum of {0} days offerbook.timeSinceSigning.tooltip.learnMore=Learn more offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=Buy XMR with: +offerbook.sellXmrFor=Sell XMR for: offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n\ {0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. @@ -379,10 +395,10 @@ shared.notSigned.noNeedAlts=Cryptocurrency accounts do not feature signing or ag offerbook.nrOffers=No. of offers: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. -offerbook.createNewOffer=Create new offer to {0} {1} +offerbook.createNewOffer=Create offer to {0} {1} offerbook.createOfferDisabled.tooltip=You can only create one offer at a time offerbook.takeOfferButton.tooltip=Take offer for {0} @@ -403,7 +419,7 @@ offerbook.warning.counterpartyTradeRestrictions=This offer cannot be taken due t offerbook.warning.newVersionAnnouncement=With this version of the software, trading peers can verify and sign each others' payment accounts to create a network of trusted payment accounts.\n\n\ After successfully trading with a peer with a verified payment account, your payment account will be signed and trading limits will be lifted after a certain time interval (length of this interval is based on the verification method).\n\n\ - For more information on account signing, please see the documentation at [HYPERLINK:https://bisq.wiki/Account_limits#Account_signing]. + For more information on account signing, please see the documentation at [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits/#account-signing]. popup.warning.tradeLimitDueAccountAgeRestriction.seller=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n\ - The buyer''s account has not been signed by an arbitrator or a peer\n\ @@ -413,6 +429,8 @@ popup.warning.tradeLimitDueAccountAgeRestriction.buyer=The allowed trade amount - Your account has not been signed by an arbitrator or a peer\n\ - The time since signing of your account is not at least 30 days\n\ - The payment method for this offer is considered risky for bank chargebacks\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=This payment method is temporarily limited to {0} until {1} because all buyers have new accounts.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Your offer will be limited to buyers with signed and aged accounts because it exceeds {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=That offer requires a different protocol version as the one used in your version of the software.\n\nPlease check if you have the latest version installed, otherwise the user who created the offer has used an older version.\n\nUsers cannot trade with an incompatible trade protocol version. offerbook.warning.userIgnored=You have added that user's onion address to your ignore list. @@ -421,7 +439,7 @@ offerbook.warning.currencyBanned=The currency used in that offer was blocked by offerbook.warning.paymentMethodBanned=The payment method used in that offer was blocked by the Haveno developers.\nPlease visit the Haveno Forum for more information. offerbook.warning.nodeBlocked=The onion address of that trader was blocked by the Haveno developers.\nProbably there is an unhandled bug causing issues when taking offers from that trader. offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\n\ - Please update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. + Please update to the latest Haveno version. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. \ It could be that your previous take-offer attempt resulted in a failed trade. @@ -468,7 +486,7 @@ createOffer.info.sellAboveMarketPrice=You will always get {0}% more than the cur createOffer.info.buyBelowMarketPrice=You will always pay {0}% less than the current market price as the price of your offer will be continuously updated. createOffer.warning.sellBelowMarketPrice=You will always get {0}% less than the current market price as the price of your offer will be continuously updated. createOffer.warning.buyAboveMarketPrice=You will always pay {0}% more than the current market price as the price of your offer will be continuously updated. -createOffer.tradeFee.descriptionBTCOnly=Trade fee +createOffer.tradeFee.descriptionXMROnly=Trade fee createOffer.tradeFee.description=Trade fee createOffer.triggerPrice.prompt=Set optional trigger price @@ -514,21 +532,24 @@ createOffer.setDepositAsBuyer=Set my security deposit as buyer (%) createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=Your buyer''s security deposit will be {0} createOffer.securityDepositInfoAsBuyer=Your security deposit as buyer will be {0} -createOffer.minSecurityDepositUsed=Min. buyer security deposit is used +createOffer.minSecurityDepositUsed=Minimum security deposit is used +createOffer.buyerAsTakerWithoutDeposit=No deposit required from buyer (passphrase protected) +createOffer.myDeposit=My security deposit (%) +createOffer.myDepositInfo=Your security deposit will be {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Enter amount in BTC +takeOffer.amount.prompt=Enter amount in XMR takeOffer.amountPriceBox.buy.amountDescription=Amount of XMR to sell takeOffer.amountPriceBox.sell.amountDescription=Amount of XMR to buy takeOffer.amountPriceBox.buy.amountDescriptionCrypto=Amount of XMR to sell takeOffer.amountPriceBox.sell.amountDescriptionCrypto=Amount of XMR to buy -takeOffer.amountPriceBox.priceDescription=Price per bitcoin in {0} +takeOffer.amountPriceBox.priceDescription=Price per monero in {0} takeOffer.amountPriceBox.amountRangeDescription=Possible amount range -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=The amount you have entered exceeds the number of allowed decimal places.\nThe amount has been adjusted to 4 decimal places. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=The amount you have entered exceeds the number of allowed decimal places.\nThe amount has been adjusted to 4 decimal places. takeOffer.validation.amountSmallerThanMinAmount=Amount cannot be smaller than minimum amount defined in the offer. takeOffer.validation.amountLargerThanOfferAmount=Input amount cannot be higher than the amount defined in the offer. takeOffer.validation.amountLargerThanOfferAmountMinusFee=That input amount would create dust change for the XMR seller. @@ -537,9 +558,11 @@ takeOffer.fundsBox.isOfferAvailable=Checking if the offer is still available ... takeOffer.fundsBox.tradeAmount=Amount to sell takeOffer.fundsBox.offerFee=Trade fee takeOffer.fundsBox.networkFee=Total mining fees -takeOffer.fundsBox.takeOfferSpinnerInfo=Take offer in progress ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Taking offer: {0} takeOffer.fundsBox.paymentLabel=Haveno trade with ID {0} takeOffer.fundsBox.fundsStructure=({0} security deposit, {1} trade fee) +takeOffer.fundsBox.noFundingRequiredTitle=No funding required +takeOffer.fundsBox.noFundingRequiredDescription=Get the offer passphrase from the seller outside Haveno to take this offer. takeOffer.success.headline=You have successfully taken an offer. takeOffer.success.info=You can see the status of your trade at \"Portfolio/Open trades\". takeOffer.error.message=An error occurred when taking the offer.\n\n{0} @@ -557,6 +580,7 @@ takeOffer.setAmountPrice=Set amount takeOffer.alreadyFunded.askCancel=You have already funded that offer.\nIf you cancel now, your funds will remain in your local Haveno wallet and are available for withdrawal in the \"Funds/Send funds\" screen.\nAre you sure you want to cancel? takeOffer.failed.offerNotAvailable=Take offer request failed because the offer is not available anymore. Maybe another trader has taken the offer in the meantime. takeOffer.failed.offerTaken=You cannot take that offer because the offer was already taken by another trader. +takeOffer.failed.offerInvalid=You cannot take that offer because the maker's signature is invalid. takeOffer.failed.offerRemoved=You cannot take that offer because the offer has been removed in the meantime. takeOffer.failed.offererNotOnline=Take offer request failed because maker is not online anymore. takeOffer.failed.offererOffline=You cannot take that offer because the maker is offline. @@ -657,37 +681,37 @@ portfolio.pending.step1.openForDispute=The deposit transaction is still not conf portfolio.pending.step2.confReached=Your trade has reached 10 confirmations.\n\n portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field \ - empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. \ + empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. \ You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees.swift=Make sure to use the SHA (shared fee model) to send the SWIFT payment. \ - See more details at [HYPERLINK:https://bisq.wiki/SWIFT#Use_the_correct_fee_option]. + See more details at [HYPERLINK:https://haveno.exchange/wiki/SWIFT#Use_the_correct_fee_option]. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Please transfer from your external {0} wallet\n{1} to the BTC seller.\n\n +portfolio.pending.step2_buyer.crypto=Please transfer from your external {0} wallet\n{1} to the XMR seller.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Please go to a bank and pay {0} to the BTC seller.\n\n -portfolio.pending.step2_buyer.cash.extra=IMPORTANT REQUIREMENT:\nAfter you have done the payment write on the paper receipt: NO REFUNDS.\nThen tear it in 2 parts, make a photo and send it to the BTC seller's email address. +portfolio.pending.step2_buyer.cash=Please go to a bank and pay {0} to the XMR seller.\n\n +portfolio.pending.step2_buyer.cash.extra=IMPORTANT REQUIREMENT:\nAfter you have done the payment write on the paper receipt: NO REFUNDS.\nThen tear it in 2 parts, make a photo and send it to the XMR seller's email address. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Please pay {0} to the BTC seller by using MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=IMPORTANT REQUIREMENT:\nAfter you have done the payment send the Authorisation number and a photo of the receipt by email to the BTC seller.\n\ +portfolio.pending.step2_buyer.moneyGram=Please pay {0} to the XMR seller by using MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=IMPORTANT REQUIREMENT:\nAfter you have done the payment send the Authorisation number and a photo of the receipt by email to the XMR seller.\n\ The receipt must clearly show the seller''s full name, country, state and the amount. The seller''s email is: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Please pay {0} to the BTC seller by using Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=IMPORTANT REQUIREMENT:\nAfter you have done the payment send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller.\n\ +portfolio.pending.step2_buyer.westernUnion=Please pay {0} to the XMR seller by using Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=IMPORTANT REQUIREMENT:\nAfter you have done the payment send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller.\n\ The receipt must clearly show the seller''s full name, city, country and the amount. The seller''s email is: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Please send {0} by \"US Postal Money Order\" to the BTC seller.\n\n +portfolio.pending.step2_buyer.postal=Please send {0} by \"US Postal Money Order\" to the XMR seller.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. \ +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. \ Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. \ - See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n + See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Please contact the BTC seller by the provided contact and arrange a meeting to pay {0}.\n\n +portfolio.pending.step2_buyer.f2f=Please contact the XMR seller by the provided contact and arrange a meeting to pay {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Start payment using {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=Amount to transfer @@ -721,9 +745,9 @@ portfolio.pending.step2_buyer.confirmStart.msg=Did you initiate the {0} payment portfolio.pending.step2_buyer.confirmStart.yes=Yes, I have started the payment portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\n\ - By not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\n\ + By not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\n\ Beside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the arbitrator in case of a dispute.\n\ - See more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. + See more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=Wait for payment @@ -842,7 +866,7 @@ portfolio.pending.step5_buyer.takersMiningFee=Total mining fees portfolio.pending.step5_buyer.refunded=Refunded security deposit portfolio.pending.step5_buyer.amountTooLow=The amount to transfer is lower than the transaction fee and the min. possible tx value (dust). portfolio.pending.step5_buyer.tradeCompleted.headline=Trade completed -portfolio.pending.step5_buyer.tradeCompleted.msg=Your completed trades are stored under \"Portfolio/History\".\nYou can review all your bitcoin transactions under \"Funds/Transactions\" +portfolio.pending.step5_buyer.tradeCompleted.msg=Your completed trades are stored under \"Portfolio/History\".\nYou can review all your monero transactions under \"Funds/Transactions\" portfolio.pending.step5_buyer.bought=You have bought portfolio.pending.step5_buyer.paid=You have paid @@ -918,13 +942,13 @@ portfolio.pending.mediationResult.popup.info=The mediator has suggested the foll Both traders agreeing to the mediator''s suggestion is the happy path—requesting arbitration is meant for \ exceptional circumstances, such as if a trader is sure the mediator did not make a fair payout suggestion \ (or if the other peer is unresponsive).\n\n\ - More details about the new arbitration model: [HYPERLINK:https://bisq.wiki/Dispute_resolution#Level_3:_Arbitration] + More details about the new arbitration model: [HYPERLINK:https://haveno.exchange/wiki/Dispute_resolution#Level_3:_Arbitration] portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=You have accepted the mediator''s suggested payout \ but it seems that your trading peer has not accepted it.\n\n\ Once the lock time is over on {0} (block {1}), you can open a second-round dispute with an arbitrator who will \ investigate the case again and do a payout based on their findings.\n\n\ You can find more details about the arbitration model at:\ - [HYPERLINK:https://bisq.wiki/Dispute_resolution#Level_3:_Arbitration] + [HYPERLINK:https://haveno.exchange/wiki/Dispute_resolution#Level_3:_Arbitration] portfolio.pending.mediationResult.popup.openArbitration=Reject and request arbitration portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted @@ -1033,11 +1057,13 @@ funds.withdrawal.inputs=Inputs selection funds.withdrawal.useAllInputs=Use all available inputs funds.withdrawal.useCustomInputs=Use custom inputs funds.withdrawal.receiverAmount=Receiver's amount +funds.withdrawal.sendMax=Send max available funds.withdrawal.senderAmount=Sender's amount funds.withdrawal.feeExcluded=Amount excludes mining fee funds.withdrawal.feeIncluded=Amount includes mining fee funds.withdrawal.fromLabel=Withdraw from address funds.withdrawal.toLabel=Withdraw to address +funds.withdrawal.maximum=MAX funds.withdrawal.memoLabel=Withdrawal memo funds.withdrawal.memo=Optionally fill memo funds.withdrawal.withdrawButton=Withdraw selected @@ -1119,9 +1145,7 @@ support.info.submitTxHex=Reserve transaction has been published with the followi support.result.success=Transaction hex has been successfully submitted. support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the \ - mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can \ - check with this tool if the signature of the mediator or arbitrator matches the summary message. +support.sigCheck.popup.info=Paste the summary message of the arbitration process. With this tool, any user can check if the signature of the arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -1171,11 +1195,28 @@ support.chat=Chat support.requested=Requested support.closed=Closed support.open=Open +support.moreButton=MORE... +support.sendLogFiles=Send Log Files +support.uploadTraderChat=Upload Trader Chat support.process=Process support.buyerMaker=XMR Buyer/Maker support.sellerMaker=XMR Seller/Maker support.buyerTaker=XMR Buyer/Taker support.sellerTaker=XMR Seller/Taker +support.sendLogs.title=Send Log Files +support.sendLogs.backgroundInfo=When you experience a bug, arbitrators and support staff will often request copies of the your log files to diagnose the issue.\n\n\ + Upon pressing 'Send', your log files will be compressed and transmitted directly to the arbitrator. +support.sendLogs.step1=Create Zip Archive of Log Files +support.sendLogs.step2=Connection Request to Arbitrator +support.sendLogs.step3=Upload Archived Log Data +support.sendLogs.send=Send +support.sendLogs.cancel=Cancel +support.sendLogs.init=Initializing +support.sendLogs.retry=Retrying send +support.sendLogs.stopped=Transfer stopped +support.sendLogs.progress=Transfer progress: %.0f%% +support.sendLogs.finished=Transfer complete! +support.sendLogs.command=Press 'Send' to retry, or 'Stop' to abort support.txKeyImages=Key Images support.txHash=Transaction Hash support.txHex=Transaction Hex @@ -1239,10 +1280,11 @@ setting.preferences.general=General preferences setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Max. deviation from market price setting.preferences.avoidStandbyMode=Avoid standby mode +setting.preferences.useSoundForNotifications=Play sounds for notifications setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Values higher than {0}% are not allowed. setting.preferences.txFee=BSQ Withdrawal transaction fee (satoshis/vbyte) @@ -1278,11 +1320,13 @@ settings.preferences.editCustomExplorer.name=Name settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=Monero network +settings.net.xmrHeader=Monero network settings.net.p2pHeader=Haveno network settings.net.onionAddressLabel=My onion address settings.net.xmrNodesLabel=Use custom Monero nodes settings.net.moneroPeersLabel=Connected peers +settings.net.connection=Connection +settings.net.connected=Connected settings.net.useTorForXmrJLabel=Use Tor for Monero network settings.net.useTorForXmrAfterSyncRadio=After wallet is synchronized settings.net.useTorForXmrOffRadio=Never @@ -1299,7 +1343,7 @@ settings.net.warn.useCustomNodes.B2XWarning=Please be sure that your Monero node Users who connect to nodes that violate consensus rules are responsible for any resulting damage. \ Any resulting disputes will be decided in favor of the other peer. No technical support will be given \ to users who ignore this warning and protection mechanisms! -settings.net.warn.invalidBtcConfig=Connection to the Monero network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Monero nodes instead. You will need to restart the application. +settings.net.warn.invalidXmrConfig=Connection to the Monero network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Monero nodes instead. You will need to restart the application. settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Monero node when starting. If it is found, Haveno will communicate with the Monero network exclusively through it. settings.net.p2PPeersLabel=Connected peers settings.net.onionAddressColumn=Onion address @@ -1307,7 +1351,7 @@ settings.net.creationDateColumn=Established settings.net.connectionTypeColumn=In/Out settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=Roundtrip settings.net.sentBytesColumn=Sent settings.net.receivedBytesColumn=Received @@ -1323,7 +1367,7 @@ settings.net.notKnownYet=Not known yet... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec settings.net.chainHeight=Monero Peers chain height: {0} -settings.net.ips=[IP address:port | host name:port | onion address:port] (comma separated). Port can be omitted if default is used (8333). +settings.net.ips=[IP address:port | host name:port | onion address:port] (comma separated). Port can be omitted if default is used ({0}). settings.net.seedNode=Seed node settings.net.directPeer=Peer (direct) settings.net.initialDataExchange={0} [Bootstrapping] @@ -1335,7 +1379,7 @@ settings.net.rescanOutputsButton=Rescan Wallet Outputs settings.net.rescanOutputsSuccess=Are you sure you want to rescan your wallet outputs? settings.net.rescanOutputsFailed=Could not rescan wallet outputs.\nError: {0} setting.about.aboutHaveno=About Haveno -setting.about.about=Haveno is open-source software which facilitates the exchange of bitcoin with national currencies (and other cryptocurrencies) through a decentralized peer-to-peer network in a way that strongly protects user privacy. Learn more about Haveno on our project web page. +setting.about.about=Haveno is open-source software which facilitates the exchange of monero with national currencies (and other cryptocurrencies) through a decentralized peer-to-peer network in a way that strongly protects user privacy. Learn more about Haveno on our project web page. setting.about.web=Haveno web page setting.about.code=Source code setting.about.agpl=AGPL License @@ -1372,7 +1416,7 @@ setting.about.shortcuts.openDispute.value=Select pending trade and click: {0} setting.about.shortcuts.walletDetails=Open wallet details window -setting.about.shortcuts.openEmergencyBtcWalletTool=Open emergency wallet tool for XMR wallet +setting.about.shortcuts.openEmergencyXmrWalletTool=Open emergency wallet tool for XMR wallet setting.about.shortcuts.showTorLogs=Toggle log level for Tor messages between DEBUG and WARN @@ -1416,7 +1460,7 @@ account.menu.notifications=Notifications account.menu.walletInfo.balance.headLine=Wallet balances account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\n\ - For BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. + For XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1491,11 +1535,11 @@ If selling XMR, you must be able to provide the following information to a media - the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n\ - the transaction ID (Tx ID or Tx Hash)\n\ - the destination address (recipient's address)\n\n\ -See the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\n\ +See the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\n\ Failure to provide the required transaction data will result in losing disputes.\n\n\ Also note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, \ but you need to enable it in Settings.\n\n\ -See the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +See the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill \ the following requirements:\n\n\ @@ -1644,7 +1688,7 @@ burning ordinary blackcoins (with associated data equal to the destination addre In case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Trading L-XMR on Haveno requires that you understand the following:\n\n\ +account.crypto.popup.liquidmonero.msg=Trading L-XMR on Haveno requires that you understand the following:\n\n\ When receiving L-XMR for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a \ custodial/exchange wallet. You must only receive L-XMR into the Liquid Elements Core wallet, or another \ L-XMR wallet which allows you to obtain the blinding key for your blinded L-XMR address.\n\n\ @@ -1673,18 +1717,9 @@ account.password.removePw.headline=Remove password protection for wallet account.password.setPw.button=Set password account.password.setPw.headline=Set password protection for wallet account.password.info=With password protection enabled, you'll need to enter your password at application startup, when withdrawing monero out of your wallet, and when displaying your seed words. -account.seed.backup.title=Backup your wallets seed words -account.seed.info=Please write down both wallet seed words and the date! \ -You can recover your wallet any time with seed words and the date.\n\ -The same seed words are used for the XMR wallet.\n\n\ -You should write down the seed words on a sheet of paper. Do not save them on your computer.\n\n\ -Please note that the seed words are NOT a replacement for a backup.\n\ -You need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\n\ -Importing seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\n\ -You need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\n\ -Importing seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\n\ -See the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Backup your wallet seed words +account.seed.info=Please write down both the wallet seed words and the date. You can recover your wallet any time with the seed words and date.\n\nYou should write down the seed words on a sheet of paper. Do not save them on the computer.\n\nPlease note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data. +account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data. account.seed.warn.noPw.msg=You have not setup a wallet password which would protect the display of the seed words.\n\n\ Do you want to display the seed words? account.seed.warn.noPw.yes=Yes, and don't ask me again @@ -1777,7 +1812,7 @@ inputControlWindow.balanceLabel=Available balance contractWindow.title=Dispute details contractWindow.dates=Offer date / Trade date -contractWindow.btcAddresses=Monero address XMR buyer / XMR seller +contractWindow.xmrAddresses=Monero address XMR buyer / XMR seller contractWindow.onions=Network address XMR buyer / XMR seller contractWindow.accountAge=Account age XMR buyer / XMR seller contractWindow.numDisputes=No. of disputes XMR buyer / XMR seller @@ -1810,8 +1845,8 @@ disputeSummaryWindow.title=Summary disputeSummaryWindow.openDate=Ticket opening date disputeSummaryWindow.role=Opener's role disputeSummaryWindow.payout=Trade amount payout -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} gets trade amount payout -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} gets trade amount payout +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=Custom payout disputeSummaryWindow.payoutAmount.buyer=Buyer's payout amount disputeSummaryWindow.payoutAmount.seller=Seller's payout amount @@ -1924,11 +1959,11 @@ filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addre filterWindow.disableTradeBelowVersion=Min. version required for trading filterWindow.add=Add filter filterWindow.remove=Remove filter -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Min. XMR amount +offerDetailsWindow.minXmrAmount=Min. XMR amount offerDetailsWindow.min=(min. {0}) offerDetailsWindow.distance=(distance from market price: {0}) offerDetailsWindow.myTradingAccount=My trading account @@ -1937,12 +1972,13 @@ offerDetailsWindow.countryBank=Maker's country of bank offerDetailsWindow.commitment=Commitment offerDetailsWindow.agree=I agree offerDetailsWindow.tac=Terms and conditions -offerDetailsWindow.confirm.maker=Confirm: Place offer to {0} bitcoin +offerDetailsWindow.confirm.maker=Confirm: Place offer to {0} monero offerDetailsWindow.confirm.makerCrypto=Confirm: Place offer to {0} {1} -offerDetailsWindow.confirm.taker=Confirm: Take offer to {0} bitcoin +offerDetailsWindow.confirm.taker=Confirm: Take offer to {0} monero offerDetailsWindow.confirm.takerCrypto=Confirm: Take offer to {0} {1} offerDetailsWindow.creationDate=Creation date offerDetailsWindow.makersOnion=Maker's onion address +offerDetailsWindow.challenge=Offer passphrase qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1979,7 +2015,7 @@ showWalletDataWindow.walletData=Wallet data showWalletDataWindow.includePrivKeys=Include private keys setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1991,7 +2027,7 @@ tacWindow.disagree=I disagree and quit tacWindow.arbitrationSystem=Dispute resolution tradeDetailsWindow.headline=Trade -tradeDetailsWindow.disputedPayoutTxId=Disputed payout transaction ID: +tradeDetailsWindow.disputedPayoutTxId=Disputed payout transaction ID tradeDetailsWindow.tradeDate=Trade date tradeDetailsWindow.txFee=Mining fee tradeDetailsWindow.tradePeersOnion=Trading peers onion address @@ -2002,9 +2038,12 @@ tradeDetailsWindow.agentAddresses=Arbitrator/Mediator tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent XMR. +txDetailsWindow.xmr.noteSent=You have sent XMR. +txDetailsWindow.xmr.noteReceived=You have received XMR. txDetailsWindow.sentTo=Sent to +txDetailsWindow.receivedWith=Received with txDetailsWindow.txId=TxId +txDetailsWindow.txKey=Transaction Key closedTradesSummaryWindow.headline=Trade history summary closedTradesSummaryWindow.totalAmount.title=Total trade amount @@ -2016,6 +2055,9 @@ closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Enter password to unlock +connectionFallback.headline=Connection error +connectionFallback.msg=Error connecting to your custom Monero node(s).\n\nDo you want to try the next best available Monero node? + torNetworkSettingWindow.header=Tor networks settings torNetworkSettingWindow.noBridges=Don't use bridges torNetworkSettingWindow.providedBridges=Connect with provided bridges @@ -2039,10 +2081,10 @@ torNetworkSettingWindow.bridges.info=If Tor is blocked by your internet provider Visit the Tor web page at: https://bridges.torproject.org/bridges to learn more about \ bridges and pluggable transports. -feeOptionWindow.useBTC=Use BTC +feeOptionWindow.useXMR=Use XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -2100,10 +2142,9 @@ popup.warning.noTradingAccountSetup.msg=You need to setup a national currency or popup.warning.noArbitratorsAvailable=There are no arbitrators available. popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=You need to wait until you are fully connected to the network.\nThat might take up to about 2 minutes at startup. -popup.warning.notSufficientConnectionsToBtcNetwork=You need to wait until you have at least {0} connections to the Monero network. +popup.warning.notSufficientConnectionsToXmrNetwork=You need to wait until you have at least {0} connections to the Monero network. popup.warning.downloadNotComplete=You need to wait until the download of missing Monero blocks is complete. -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Monero block has been published.\n\n\ - You can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.walletNotSynced=The Haveno wallet is not synced with the latest blockchain height. Please wait until the wallet syncs or check your connection. popup.warning.removeOffer=Are you sure you want to remove that offer? popup.warning.tooLargePercentageValue=You cannot set a percentage of 100% or larger. popup.warning.examplePercentageValue=Please enter a percentage number like \"5.4\" for 5.4% @@ -2128,8 +2169,8 @@ popup.warning.seed=seed popup.warning.mandatoryUpdate.trading=Please update to the latest Haveno version. \ A mandatory update was released which disables trading for old versions. \ Please check out the Haveno Forum for more information. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=This transaction is not possible, as the mining fees of {0} would exceed the amount to transfer of {1}. \ +popup.warning.noFilter=We did not receive a filter object from the seed nodes. Please inform the network administrators to register a filter object. +popup.warning.burnXMR=This transaction is not possible, as the mining fees of {0} would exceed the amount to transfer of {1}. \ Please wait until the mining fees are low again or until you''ve accumulated more XMR to transfer. popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Monero network.\n\ @@ -2165,7 +2206,7 @@ popup.info.shutDownWithDisputeInit=Haveno is being shut down, but there is a Dis Please wait a minute before shutting down. popup.info.shutDownQuery=Are you sure you want to exit Haveno? popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\n\ - Please make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. + Please make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.info.p2pStatusIndicator.red={0}\n\n\ Your node has no connection to the P2P network. Haveno cannot operate in this state. popup.info.p2pStatusIndicator.yellow={0}\n\n\ @@ -2180,15 +2221,24 @@ popup.warn.daoRequiresRestart=There was a problem with synchronizing the DAO sta popup.privateNotification.headline=Important private notification! -popup.moneroLocalhostNode.msg=Haveno detected a Monero node running on this machine (at localhost).\n\n\Please ensure the node is fully synced before starting Haveno. +popup.xmrLocalNode.msg=Haveno detected a Monero node running on this machine (at localhost).\n\n\Please ensure the node is fully synced before starting Haveno. popup.shutDownInProgress.headline=Shut down in progress popup.shutDownInProgress.msg=Shutting down application can take a few seconds.\nPlease don't interrupt this process. popup.attention.forTradeWithId=Attention required for trade with ID {0} -popup.attention.welcome.test=Welcome to the Haveno test instance!\n\n\ +popup.attention.welcome.stagenet=Welcome to the Haveno test instance!\n\n\ This platform allows you to test Haveno's protocol. Make sure to follow the instructions[HYPERLINK:https://github.com/haveno-dex/haveno/blob/master/docs/installing.md].\n\n\ -If you encounter any problem, please let us know by opening an issue[HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\ +If you encounter any problem, please let us know by opening an issue [HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\ This is a test instance. Do not use real money! +popup.attention.welcome.mainnet=Welcome to Haveno!\n\n\ +This platform allows you to trade Monero for fiat currencies or other cryptocurrencies in a decentralized way.\n\n\ +Get started by creating a new payment account then making or taking an offer.\n\n\ +If you encounter any problem, please let us know by opening an issue [HYPERLINK:https://github.com/haveno-dex/haveno/issues/new]. +popup.attention.welcome.mainnet.test=Welcome to Haveno!\n\n\ +This platform allows you to trade Monero for fiat currencies or other cryptocurrencies in a decentralized way.\n\n\ +Get started by creating a new payment account then making or taking an offer.\n\n\ +If you encounter any problem, please let us know by opening an issue [HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\ +Haveno was recently released for public testing. Please use small amounts! popup.info.multiplePaymentAccounts.headline=Multiple payment accounts available popup.info.multiplePaymentAccounts.msg=You have multiple payment accounts available for this offer. Please make sure you've picked the right one. @@ -2230,6 +2280,12 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=No deposit required from buyer +popup.info.buyerAsTakerWithoutDeposit=\ + Your offer will not require a security deposit or fee from the XMR buyer.\n\n\ + To accept your offer, you must share a passphrase with your trade partner outside Haveno.\n\n\ + The passphrase is automatically generated and shown in the offer details after creation.\ + popup.info.torMigration.msg=Your Haveno node is probably using a deprecated Tor v2 address. \ Please switch your Haveno node to a Tor v3 address. \ Make sure to back up your data directory beforehand. @@ -2262,7 +2318,7 @@ systemTray.show=Show application window systemTray.hide=Hide application window systemTray.info=Info about Haveno systemTray.exit=Exit -systemTray.tooltip=Haveno: A decentralized bitcoin exchange network +systemTray.tooltip=Haveno: A decentralized monero exchange network #################################################################### @@ -2310,6 +2366,7 @@ peerInfoIcon.tooltip.trade.traded={0} onion address: {1}\nYou have already trade peerInfoIcon.tooltip.trade.notTraded={0} onion address: {1}\nYou have not traded with that peer so far.\n{2} peerInfoIcon.tooltip.age=Payment account created {0} ago. peerInfoIcon.tooltip.unknownAge=Payment account age not known. +peerInfoIcon.tooltip.dispute={0}\nNumber of disputes: {1}.\n{2} tooltip.openPopupForDetails=Open popup for details tooltip.invalidTradeState.warning=This trade is in an invalid state. Open the details window for more information @@ -2318,7 +2375,7 @@ tooltip.openBlockchainForTx=Open external blockchain explorer for transaction: { confidence.unknown=Unknown transaction status confidence.seen=Seen by {0} peer(s) / 0 confirmations -confidence.confirmed=Confirmed in {0} block(s) +confidence.confirmed={0} confirmation(s) confidence.invalid=Transaction is invalid peerInfo.title=Peer info @@ -2368,6 +2425,7 @@ navigation.support=\"Support\" formatter.formatVolumeLabel={0} amount{1} formatter.makerTaker=Maker as {0} {1} / Taker as {2} {3} +formatter.makerTakerLocked=Maker as {0} {1} / Taker as {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=You are {0} {1} ({2} {3}) @@ -2415,7 +2473,7 @@ password.deriveKey=Derive key from password password.walletDecrypted=Wallet successfully decrypted and password protection removed. password.wrongPw=You entered the wrong password.\n\nPlease try entering your password again, carefully checking for typos or spelling errors. password.walletEncrypted=Wallet successfully encrypted and password protection enabled. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). +password.walletEncryptionFailed=Password could not be set. password.passwordsDoNotMatch=The 2 passwords you entered don't match. password.forgotPassword=Forgot password? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\n\ @@ -2432,8 +2490,8 @@ seed.creationDate=Creation date seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\n\ You must empty this wallet before attempting to restore an older one, as mixing wallets \ together can lead to invalidated backups.\n\n\ -Please finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\n\ -In case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\n\ +Please finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\n\ +In case you cannot access your monero you can use the emergency tool to empty the wallet.\n\ To open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=I want to restore anyway seed.warn.walletNotEmpty.emptyWallet=I will empty my wallets first @@ -2457,7 +2515,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=Account payment.account.no=Account no. payment.account.name=Account name -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=Account owner full name payment.account.fullName=Full name (first, middle, last) @@ -2478,6 +2536,8 @@ payment.email=Email payment.country=Country payment.extras=Extra requirements payment.email.mobile=Email or mobile no. +payment.email.mobile.cashtag=Cashtag, email, or mobile no. +payment.email.mobile.username=Username, email, or mobile no. payment.crypto.address=Cryptocurrency address payment.crypto.tradeInstantCheckbox=Trade instant (within 1 hour) with this Cryptocurrency payment.crypto.tradeInstant.popup=For instant trading it is required that both trading peers are online to be able \ @@ -2532,7 +2592,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=Username or email or phone no. payment.moneyBeam.accountId=Email or phone no. -payment.venmo.venmoUserName=Venmo username payment.popmoney.accountId=Email or phone no. payment.promptPay.promptPayId=Citizen ID/Tax ID or phone no. payment.supportedCurrencies=Supported currencies @@ -2613,7 +2672,7 @@ payment.limits.info=Please be aware that all bank transfers carry a certain amou \n\ This limit only applies to the size of a single trade—you can place as many trades as you like.\n\ \n\ - See more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. + See more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based \ on the following 2 factors:\n\n\ @@ -2631,18 +2690,22 @@ payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade \n\ These limits only apply to the size of a single trade—you can place as many trades as you like. \n\ \n\ - See more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. + See more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Please confirm your bank allows you to send cash deposits into other peoples' accounts. \ For example, Bank of America and Wells Fargo no longer allow such deposits. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. payment.account.revolut.addUserNameInfo={0}\n\ - Your existing Revolut account ({1}) does not have a ''User name''.\n\ - Please enter your Revolut ''User name'' to update your account data.\n\ + Your existing Revolut account ({1}) does not have a ''Username''.\n\ + Please enter your Revolut ''Username'' to update your account data.\n\ This will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account +payment.cashapp.info=Cash App has higher chargeback risk than most bank transfers. Please be aware of this when trading with Cash App. +payment.venmo.info=Venmo has higher chargeback risk than most bank transfers. Please be aware of this when trading with Venmo. +payment.paypal.info=PayPal has higher chargeback risk than most bank transfers. Please be aware of this when trading with PayPal. + payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\n\ Your existing Amazon Gift Card account ({1}) does not have a Country specified.\n\ @@ -2657,20 +2720,20 @@ payment.swift.info.account=Carefully review the core guidelines for using SWIFT - buyer must use the shared fee model (SHA) \n\ - buyer and seller may incur fees, so they should check their bank's fee schedules beforehand \n\ \n\ -SWIFT is more sophisticated than other payment methods, so please take a moment to review full guidance on the wiki [HYPERLINK:https://bisq.wiki/SWIFT]. +SWIFT is more sophisticated than other payment methods, so please take a moment to review full guidance on the wiki [HYPERLINK:https://haveno.exchange/wiki/SWIFT]. -payment.swift.info.buyer=To buy bitcoin with SWIFT, you must:\n\ +payment.swift.info.buyer=To buy monero with SWIFT, you must:\n\ \n\ - send payment in the currency specified by the offer maker \n\ - use the shared fee model (SHA) to send payment\n\ \n\ -Please review further guidance on the wiki to avoid penalties and ensure smooth trades [HYPERLINK:https://bisq.wiki/SWIFT]. +Please review further guidance on the wiki to avoid penalties and ensure smooth trades [HYPERLINK:https://haveno.exchange/wiki/SWIFT]. payment.swift.info.seller=SWIFT senders are required to use the shared fee model (SHA) to send payments.\n\ \n\ If you receive a SWIFT payment that does not use SHA, open a mediation ticket.\n\ \n\ -Please review further guidance on the wiki to avoid penalties and ensure smooth trades [HYPERLINK:https://bisq.wiki/SWIFT]. +Please review further guidance on the wiki to avoid penalties and ensure smooth trades [HYPERLINK:https://haveno.exchange/wiki/SWIFT]. payment.imps.info.account=Please make sure to include your:\n\n\ ● Account owner full name\n\ @@ -2749,8 +2812,8 @@ CelPay supports multiple stablecoins:\n\n\ ● GBP Stablecoins; TrueGBP\n\ ● HKD Stablecoins; TrueHKD\n\ ● AUD Stablecoins; TrueAUD\n\n\ -BTC Buyers can send any matching currency stablecoin to the BTC Seller. -payment.celpay.info.buyer=Please send payment only to the email address provided by the BTC Seller by sending a payment link.\n\n\ +XMR Buyers can send any matching currency stablecoin to the XMR Seller. +payment.celpay.info.buyer=Please send payment only to the email address provided by the XMR Seller by sending a payment link.\n\n\ CelPay is limited to sending $2,500 (or other currency/crypto equivalent) in 24 hours.\n\n\ Trades above CelPay account limits will likely have to take place over more than one day, or, be cancelled.\n\n\ CelPay supports multiple stablecoins:\n\n\ @@ -2759,9 +2822,9 @@ CelPay supports multiple stablecoins:\n\n\ ● GBP Stablecoins; TrueGBP\n\ ● HKD Stablecoins; TrueHKD\n\ ● AUD Stablecoins; TrueAUD\n\n\ -BTC Buyers can send any matching currency stablecoin to the BTC Seller. -payment.celpay.info.seller=BTC Sellers should expect to receive payment via a secure payment link. \ - Please make sure the email payment link contains the email address provided by the BTC Buyer.\n\n\ +XMR Buyers can send any matching currency stablecoin to the XMR Seller. +payment.celpay.info.seller=XMR Sellers should expect to receive payment via a secure payment link. \ + Please make sure the email payment link contains the email address provided by the XMR Buyer.\n\n\ CelPay users are limited to sending $2,500 (or other currency/crypto equivalent) in 24 hours.\n\n\ Trades above CelPay account limits will likely have to take place over more than one day, or, be cancelled.\n\n\ CelPay supports multiple stablecoins:\n\n\ @@ -2770,7 +2833,7 @@ CelPay supports multiple stablecoins:\n\n\ ● GBP Stablecoins; TrueGBP\n\ ● HKD Stablecoins; TrueHKD\n\ ● AUD Stablecoins; TrueAUD\n\n\ -BTC Sellers should expect to receive any matching currency stablecoin from the BTC Buyer. It is possible for the BTC Buyer to send any matching currency stablecoin. +XMR Sellers should expect to receive any matching currency stablecoin from the XMR Buyer. It is possible for the XMR Buyer to send any matching currency stablecoin. payment.celpay.supportedCurrenciesForReceiver=Supported currencies (please note: all the currencies below are supported stable coins within the Celcius app. Trades are for stable coins, not fiat.) payment.nequi.info.account=Please make sure to include your phone number that is associated with your Nequi account.\n\n\ @@ -2778,12 +2841,12 @@ When users set up a Nequi account payment limits are set to a maximum of ~ 7,000 If you intend to trade amount of over 7,000,000 COP per trade you will need to complete KYC with Bancolombia and pay a fee \ of around 15,000 COP. After this all transactions will incur a 0.4% of tax. Please ensure you are aware of the latest taxes.\n\n\ Users should also be aware of account limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.nequi.info.buyer=Please send payment only to the phone number provided in the BTC Seller's Haveno account.\n\n\ +payment.nequi.info.buyer=Please send payment only to the phone number provided in the XMR Seller's Haveno account.\n\n\ When users set up a Nequi account, payment limits are set to a maximum of ~ 7,000,000 COP that can be sent per month.\n\n\ If you intend to trade amount of over 7,000,000 COP per trade you will need to complete KYC with Bancolombia and pay a fee \ of around 15,000 COP. After this all transactions will incur a 0.4% of tax. Please ensure you are aware of the latest taxes.\n\n\ Users should also be aware of account limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.nequi.info.seller=Please check that the payment received matches the phone number provided in the BTC Buyer's Haveno account.\n\n\ +payment.nequi.info.seller=Please check that the payment received matches the phone number provided in the XMR Buyer's Haveno account.\n\n\ When users set up a Nequi account, payment limits are set to a maximum of ~ 7,000,000 COP that can be sent per month.\n\n\ If you intend to trade amount of over 7,000,000 COP per trade you will need to complete KYC with Bancolombia and pay a fee \ of around 15,000 COP. After this all transactions will incur a 0.4% of tax. Please ensure you are aware of the latest taxes.\n\n\ @@ -2795,10 +2858,10 @@ The maximum amount of transactions you can send/receive using Bizum is €2,000 Bizum users can have a maximum of 150 operations per month.\n\n\ Each bank however may establish its own limits, within the above limits, for its clients.\n\n\ Users should also be aware of account limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.bizum.info.buyer=Please send payment only to the BTC Seller's mobile phone number as provided in Haveno.\n\n\ +payment.bizum.info.buyer=Please send payment only to the XMR Seller's mobile phone number as provided in Haveno.\n\n\ The maximum trade size is €1,000 per payment. The maximum amount of transactions you can send using Bizum is €2,000 Euros per day.\n\n\ If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.bizum.info.seller=Please make sure your payment is received from the BTC Buyer's mobile phone number as provided in Haveno.\n\n\ +payment.bizum.info.seller=Please make sure your payment is received from the XMR Buyer's mobile phone number as provided in Haveno.\n\n\ The maximum trade size is €1,000 per payment. The maximum amount of transactions you can receive using Bizum is €2,000 Euros per day.\n\n\ If you trade over the above limits your trade might be cancelled and there could be a penalty. @@ -2806,10 +2869,10 @@ payment.pix.info.account=Please make sure to include your chosen Pix Key. There CPF (Natural Persons Register) or CNPJ (National Registry of Legal Entities), e-mail address, telephone number or a \ random key generated by the system called a universally unique identifier (UUID). A different key must be used for \ each Pix account you have. Individuals can create up to five keys for each account they own.\n\n\ -When trading on Haveno, BTC Buyers should use their Pix Keys as the payment description so that it is easy for the BTC Sellers to identify the payment as coming from themselves. -payment.pix.info.buyer=Please send payment only the Pix Key provided in the BTC Seller's Haveno account.\n\n\ -Please use your Pix Key as the payment reference so that it is easy for the BTC Seller to identify the payment as coming from yourself. -payment.pix.info.seller=Please check that the payment received description matches the Pix Key provided in the BTC Buyer's Haveno account. +When trading on Haveno, XMR Buyers should use their Pix Keys as the payment description so that it is easy for the XMR Sellers to identify the payment as coming from themselves. +payment.pix.info.buyer=Please send payment only the Pix Key provided in the XMR Seller's Haveno account.\n\n\ +Please use your Pix Key as the payment reference so that it is easy for the XMR Seller to identify the payment as coming from yourself. +payment.pix.info.seller=Please check that the payment received description matches the Pix Key provided in the XMR Buyer's Haveno account. payment.pix.key=Pix Key (CPF, CNPJ, Email, Phone number or UUID) payment.monese.info.account=Monese is a bank app for users of GBP, EUR and RON*. Monese allows users to send money to \ @@ -2818,18 +2881,18 @@ payment.monese.info.account=Monese is a bank app for users of GBP, EUR and RON*. When setting up your Monese account in Haveno please make sure to include your name and phone number that matches your \ Monese account. This will ensure that when you send funds they show from the correct account and when you receive \ funds they will be credited to your account. -payment.monese.info.buyer=Please send payment only to the phone number provided by the BTC Seller in their Haveno account. Please leave the payment description blank. -payment.monese.info.seller=BTC Sellers should expect to receive payment from the phone number / name shown in the BTC Buyer's Haveno account. +payment.monese.info.buyer=Please send payment only to the phone number provided by the XMR Seller in their Haveno account. Please leave the payment description blank. +payment.monese.info.seller=XMR Sellers should expect to receive payment from the phone number / name shown in the XMR Buyer's Haveno account. payment.satispay.info.account=To use Satispay you need a bank account (IBAN) in Italy and to be registered for the service.\n\n\ Satispay account limits are individually set. If you want to trade increased amounts you will need to contact Satispay \ support to increase your limits. Users should also be aware of account limits. If you trade over the above limits \ your trade might be cancelled and there could be a penalty. -payment.satispay.info.buyer=Please send payment only to the BTC Seller's mobile phone number as provided in Haveno.\n\n\ +payment.satispay.info.buyer=Please send payment only to the XMR Seller's mobile phone number as provided in Haveno.\n\n\ Satispay account limits are individually set. If you want to trade increased amounts you will need to contact Satispay \ support to increase your limits. Users should also be aware of account limits. If you trade over the above limits \ your trade might be cancelled and there could be a penalty. -payment.satispay.info.seller=Please make sure your payment is received from the BTC Buyer's mobile phone number / name as provided in Haveno.\n\n\ +payment.satispay.info.seller=Please make sure your payment is received from the XMR Buyer's mobile phone number / name as provided in Haveno.\n\n\ Satispay account limits are individually set. If you want to trade increased amounts you will need to contact Satispay \ support to increase your limits. Users should also be aware of account limits. If you trade over the above limits \ your trade might be cancelled and there could be a penalty. @@ -2839,17 +2902,17 @@ When you send a Tikkie payment request to an individual person you can ask to re request. The maximum amount you can request within 24 hours is €2,500 per Tikkie account.\n\n\ Each bank however may establish its own limits, within these limits, for its clients.\n\n\ Users should also be aware of account limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.tikkie.info.buyer=Please request a payment link from the BTC Seller in trader chat. Once the BTC Seller has \ +payment.tikkie.info.buyer=Please request a payment link from the XMR Seller in trader chat. Once the XMR Seller has \ sent you a payment link that matches the correct amount for the trade please proceed to payment.\n\n\ -When the BTC Seller requests a Tikkie payment the maximum they can ask to receive is €750 per Tikkie request. If the \ - trade is over that amount the BTC Seller will have to sent multiple requests to total the trade amount. The maximum \ +When the XMR Seller requests a Tikkie payment the maximum they can ask to receive is €750 per Tikkie request. If the \ + trade is over that amount the XMR Seller will have to sent multiple requests to total the trade amount. The maximum \ you can request in a day is €2,500.\n\n\ Each bank however may establish its own limits, within these limits, for its clients.\n\n\ Users should also be aware of account limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.tikkie.info.seller=Please send a payment link to the BTC Seller in trader chat. Once the BTC \ +payment.tikkie.info.seller=Please send a payment link to the XMR Seller in trader chat. Once the XMR \ Buyer has sent you payment please check their IBAN detail match the details they have in Haveno.\n\n\ -When the BTC Seller requests a Tikkie payment the maximum they can ask to receive is €750 per Tikkie request. If the \ - trade is over that amount the BTC Seller will have to sent multiple requests to total the trade amount. The maximum \ +When the XMR Seller requests a Tikkie payment the maximum they can ask to receive is €750 per Tikkie request. If the \ + trade is over that amount the XMR Seller will have to sent multiple requests to total the trade amount. The maximum \ you can request in a day is €2,500.\n\n\ Each bank however may establish its own limits, within these limits, for its clients.\n\n\ Users should also be aware of account limits. If you trade over the above limits your trade might be cancelled and there could be a penalty. @@ -2860,27 +2923,27 @@ When setting up your Verse account in Haveno please make sure to include the use funds they will be credited to your account.\n\n\ Verse users are limited to sending or receiving €10,000 per year (or equivalent foreign currency amount) for \ accumulated payments made from or received into their payment account. This can be increased by Verse on request. -payment.verse.info.buyer=Please send payment only to the username provided by the BTC Seller in their Haveno account. \ +payment.verse.info.buyer=Please send payment only to the username provided by the XMR Seller in their Haveno account. \ Please leave the payment description blank.\n\n\ Verse users are limited to sending or receiving €10,000 per year (or equivalent foreign currency amount) for \ accumulated payments made from or received into their payment account. This can be increased by Verse on request. -payment.verse.info.seller=BTC Sellers should expect to receive payment from the username shown in the BTC Buyer's Haveno account.\n\n\ +payment.verse.info.seller=XMR Sellers should expect to receive payment from the username shown in the XMR Buyer's Haveno account.\n\n\ Verse users are limited to sending or receiving €10,000 per year (or equivalent foreign currency amount) for \ accumulated payments made from or received into their payment account. This can be increased by Verse on request. payment.achTransfer.info.account=When adding ACH as a payment method in Haveno users should make sure they are aware what \ it will cost to send and receive an ACH transfer. payment.achTransfer.info.buyer=Please ensure you are aware of what it will cost you to send an ACH transfer.\n\n\ - When paying, send only to the payment details provided in the BTC Seller's account using ACH transfer. + When paying, send only to the payment details provided in the XMR Seller's account using ACH transfer. payment.achTransfer.info.seller=Please ensure you are aware of what it will cost you to receive an ACH transfer.\n\n\ - When receiving payment, please check that it is received from the BTC Buyer's account as an ACH transfer. + When receiving payment, please check that it is received from the XMR Buyer's account as an ACH transfer. payment.domesticWire.info.account=When adding Domestic Wire Transfer as a payment method in Haveno users should make sure \ they are aware what it will cost to send and receive a wire transfer. payment.domesticWire.info.buyer=Please ensure you are aware of what it will cost you to send a wire transfer.\n\n\ - When paying, send only to the payment details provided in the BTC Seller's account. + When paying, send only to the payment details provided in the XMR Seller's account. payment.domesticWire.info.seller=Please ensure you are aware of what it will cost you to receive a wire transfer.\n\n\ - When receiving payment, please check that it is received from the BTC Buyer's account. + When receiving payment, please check that it is received from the XMR Buyer's account. payment.strike.info.account=Please make sure to include your Strike username.\n\n\ In Haveno, Strike is used for fiat to fiat payments only.\n\n\ @@ -2894,10 +2957,10 @@ Users can increase their limits by providing Strike with more information. These ● $1,000 maximum total deposits per week\n\ ● $1,000 maximum per payment\n\n\ If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.strike.info.buyer=Please send payment only to the BTC Seller's Strike username as provided in Haveno.\n\n\ +payment.strike.info.buyer=Please send payment only to the XMR Seller's Strike username as provided in Haveno.\n\n\ The maximum trade size is $1,000 per payment.\n\n\ If you trade over the above limits your trade might be cancelled and there could be a penalty. -payment.strike.info.seller=Please make sure your payment is received from the BTC Buyer's Strike username as provided in Haveno.\n\n\ +payment.strike.info.seller=Please make sure your payment is received from the XMR Buyer's Strike username as provided in Haveno.\n\n\ The maximum trade size is $1,000 per payment.\n\n\ If you trade over the above limits your trade might be cancelled and there could be a penalty. @@ -2905,16 +2968,16 @@ payment.transferwiseUsd.info.account=Due to US banking regulation, sending and r than most other currencies. For this reason USD was not added to Haveno TransferWise payment method.\n\n\ The TransferWise-USD payment method allows Haveno users to trade in USD.\n\n\ Anyone with a Wise, formally TransferWise account, can add TransferWise-USD as a payment method in Haveno. This will \ - allow them to buy and sell BTC with USD.\n\n\ -When trading on Haveno BTC Buyers should not use any reference for reason for payment. If reason for payment is required \ + allow them to buy and sell XMR with USD.\n\n\ +When trading on Haveno XMR Buyers should not use any reference for reason for payment. If reason for payment is required \ they should only use the full name of the TransferWise-USD account owner. -payment.transferwiseUsd.info.buyer=Please send payment only to the email address in the BTC Seller's Haveno TransferWise-USD account. -payment.transferwiseUsd.info.seller=Please check that the payment received matches the BTC Buyer's name of the TransferWise-USD account in Haveno. +payment.transferwiseUsd.info.buyer=Please send payment only to the email address in the XMR Seller's Haveno TransferWise-USD account. +payment.transferwiseUsd.info.seller=Please check that the payment received matches the XMR Buyer's name of the TransferWise-USD account in Haveno. payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\ \n\ -- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n\ -- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\ +- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n\ +- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\ \n\ In the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\n\ Failure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\n\ @@ -2976,7 +3039,7 @@ payment.f2f.info='Face to Face' trades have different rules and come with differ of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to \ an agreement.\n\n\ To be sure you fully understand the differences with 'Face to Face' trades please read the instructions and \ - recommendations at: [HYPERLINK:https://bisq.wiki/Face-to-face_(payment_method)] + recommendations at: [HYPERLINK:https://docs.haveno.exchange/the-project/payment_methods/F2F] payment.f2f.info.openURL=Open web page payment.f2f.offerbook.tooltip.countryAndCity=Country and city: {0} / {1} payment.f2f.offerbook.tooltip.extra=Additional information: {0} @@ -2993,7 +3056,7 @@ payment.payid.info=A PayID like a phone number, email address or an Australian B bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. \ Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\n\ - Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\n\ + Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\n\ Three important notes:\n\ - try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n\ - try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat \ @@ -3137,7 +3200,7 @@ OK_PAY=OKPay CASH_APP=Cash App # suppress inspection "UnusedProperty" VENMO=Venmo - +PAYPAL=PayPal # suppress inspection "UnusedProperty" UPHOLD_SHORT=Uphold @@ -3233,6 +3296,7 @@ OK_PAY_SHORT=OKPay CASH_APP_SHORT=Cash App # suppress inspection "UnusedProperty" VENMO_SHORT=Venmo +PAYPAL_SHORT=PayPal #################################################################### @@ -3246,7 +3310,7 @@ validation.zero=Input of 0 is not allowed. validation.negative=A negative value is not allowed. validation.traditional.tooSmall=Input smaller than minimum possible amount is not allowed. validation.traditional.tooLarge=Input larger than maximum possible amount is not allowed. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=Input larger than {0} is not allowed. validation.xmr.tooSmall=Input smaller than {0} is not allowed. validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -3256,12 +3320,10 @@ validation.sortCodeChars={0} must consist of {1} characters. validation.bankIdNumber={0} must consist of {1} numbers. validation.accountNr=Account number must consist of {0} numbers. validation.accountNrChars=Account number must consist of {0} characters. -validation.btc.invalidAddress=The address is not correct. Please check the address format. +validation.xmr.invalidAddress=The address is not correct. Please check the address format. validation.integerOnly=Please enter integer numbers only. validation.inputError=Your input caused an error:\n{0} -validation.bsq.insufficientBalance=Your available balance is {0}. -validation.btc.exceedsMaxTradeLimit=Your trade limit is {0}. -validation.bsq.amountBelowMinAmount=Min. amount is {0} +validation.xmr.exceedsMaxTradeLimit=Your trade limit is {0}. validation.nationalAccountId={0} must consist of {1} numbers. #new @@ -3282,7 +3344,7 @@ validation.bic.letters=Bank and Country code must be letters validation.bic.invalidLocationCode=BIC contains invalid location code validation.bic.invalidBranchCode=BIC contains invalid branch code validation.bic.sepaRevolutBic=Revolut Sepa accounts are not supported. -validation.btc.invalidFormat=Invalid format for a Monero address. +validation.btc.invalidFormat=Invalid format for a Bitcoin address. validation.email.invalidAddress=Invalid address validation.iban.invalidCountryCode=Country code invalid validation.iban.checkSumNotNumeric=Checksum must be numeric diff --git a/core/src/main/resources/i18n/displayStrings_cs.properties b/core/src/main/resources/i18n/displayStrings_cs.properties index ac8673762a..e2e692c42b 100644 --- a/core/src/main/resources/i18n/displayStrings_cs.properties +++ b/core/src/main/resources/i18n/displayStrings_cs.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Rozumím shared.na=N/A shared.shutDown=Vypnout shared.reportBug=Nahlásit chybu na GitHubu -shared.buyBitcoin=Koupit bitcoin -shared.sellBitcoin=Prodat bitcoin +shared.buyMonero=Koupit monero +shared.sellMonero=Prodat monero shared.buyCurrency=Koupit {0} shared.sellCurrency=Prodat {0} -shared.buyingBTCWith=nakoupit BTC za {0} -shared.sellingBTCFor=prodat BTC za {0} -shared.buyingCurrency=nakoupit {0} (prodat BTC) -shared.sellingCurrency=prodat {0} (nakoupit BTC) +shared.buyCurrencyLocked=Koupit {0} 🔒 +shared.sellCurrencyLocked=Prodat {0} 🔒 +shared.buyingXMRWith=nakoupit XMR za {0} +shared.sellingXMRFor=prodat XMR za {0} +shared.buyingCurrency=nakoupit {0} (prodat XMR) +shared.sellingCurrency=prodat {0} (nakoupit XMR) shared.buy=koupit shared.sell=prodat shared.buying=kupuje @@ -93,7 +95,7 @@ shared.amountMinMax=Množství (min - max) shared.amountHelp=Pokud je v nabídce nastavena minimální a maximální částka, můžete obchodovat s jakoukoli částkou v tomto rozsahu. shared.remove=Odstranit shared.goTo=Přejít na {0} -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Odstranit nabídku shared.dontRemoveOffer=Neodstraňovat nabídku shared.editOffer=Upravit nabídku @@ -103,16 +105,16 @@ shared.faq=Navštívit stránku FAQ shared.yesCancel=Ano, zrušit shared.nextStep=Další krok shared.selectTradingAccount=Vyberte obchodní účet -shared.fundFromSavingsWalletButton=Přesunout finance z Haveno peněženky +shared.fundFromSavingsWalletButton=Použít prostředky z peněženky Haveno shared.fundFromExternalWalletButton=Otevřít vaši externí peněženku pro financování -shared.openDefaultWalletFailed=Nepodařilo se otevřít aplikaci bitcoinové peněženky. Jste si jisti, že máte nějakou nainstalovanou? +shared.openDefaultWalletFailed=Nepodařilo se otevřít aplikaci peněženky Monero. Jste si jisti, že máte nějakou nainstalovanou? shared.belowInPercent=% pod tržní cenou shared.aboveInPercent=% nad tržní cenou shared.enterPercentageValue=Zadejte % hodnotu shared.OR=NEBO shared.notEnoughFunds=Ve své peněžence Haveno nemáte pro tuto transakci dostatek prostředků — je potřeba {0}, ale k dispozici je pouze {1}.\n\nPřidejte prostředky z externí peněženky nebo financujte svou peněženku Haveno v části Prostředky > Přijmout prostředky. shared.waitingForFunds=Čekání na finance... -shared.TheBTCBuyer=BTC kupující +shared.TheXMRBuyer=XMR kupující shared.You=Vy shared.sendingConfirmation=Posílám potvrzení... shared.sendingConfirmationAgain=Prosím pošlete potvrzení znovu @@ -123,9 +125,8 @@ shared.noDateAvailable=Žádné datum není k dispozici shared.noDetailsAvailable=Detaily nejsou k dispozici shared.notUsedYet=Ještě nepoužito shared.date=Datum -shared.sendFundsDetailsWithFee=Odesílání: {0}\nZ adresy: {1}\nNa přijímací adresu: {2}.\nPožadovaný poplatek za těžbu je: {3} ({4} satoshi/vbyte)\nTransakční vsize: {5} vKb\n\nPříjemce obdrží: {6}\n\nOpravdu chcete tuto částku vybrat? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno zjistil, že tato transakce by vytvořila drobné mince, které jsou pod limitem drobných mincí (a není to povoleno pravidly pro bitcoinový konsenzus). Místo toho budou tyto drobné mince ({0} satoshi {1}) přidány k poplatku za těžbu.\n\n\n +shared.sendFundsDetailsDust=Haveno zjistil, že tato transakce by vytvořila drobné mince, které jsou pod limitem drobných mincí (a není to povoleno pravidly pro konsenzus Monero). Místo toho budou tyto drobné mince ({0} satoshi {1}) přidány k poplatku za těžbu.\n\n\n shared.copyToClipboard=Kopírovat do schránky shared.language=Jazyk shared.country=Země @@ -140,6 +141,7 @@ shared.addNewAccount=Přidat nový účet shared.ExportAccounts=Exportovat účty shared.importAccounts=Importovat účty shared.createNewAccount=Vytvořit nový účet +shared.createNewAccountDescription=Vaše údaje o účtu jsou uloženy místně na vašem zařízení a sdíleny pouze s vaším obchodním partnerem a rozhodcem, pokud dojde k otevření sporu. shared.saveNewAccount=Uložit nový účet shared.selectedAccount=Vybraný účet shared.deleteAccount=Smazat účet @@ -169,7 +171,7 @@ shared.payoutTxId=ID platební transakce shared.contractAsJson=Kontakt v JSON formátu shared.viewContractAsJson=Zobrazit kontrakt v JSON formátu shared.contract.title=Kontrakt pro obchod s ID: {0} -shared.paymentDetails=BTC {0} detaily platby +shared.paymentDetails=XMR {0} detaily platby shared.securityDeposit=Kauce shared.yourSecurityDeposit=Vaše kauce shared.contract=Kontrakt @@ -179,19 +181,21 @@ shared.messageSendingFailed=Odeslání zprávy selhalo. Chyba: {0} shared.unlock=Odemknout shared.toReceive=bude přijata shared.toSpend=bude utracena -shared.btcAmount=Částka BTC +shared.xmrAmount=Částka XMR shared.yourLanguage=Vaše jazyky shared.addLanguage=Přidat jazyk shared.total=Celkem shared.totalsNeeded=Potřebné prostředky shared.tradeWalletAddress=Adresa obchodní peněženky shared.tradeWalletBalance=Zůstatek obchodní peněženky +shared.reserveExactAmount=Rezervujte pouze nezbytné prostředky. Vyžaduje poplatek za těžbu a přibližně 20 minut, než vaše nabídka půjde živě. shared.makerTxFee=Tvůrce: {0} shared.takerTxFee=Příjemce: {0} shared.iConfirm=Potvrzuji shared.openURL=Otevřené {0} shared.fiat=Fiat shared.crypto=Krypto +shared.preciousMetals=Drahé kovy shared.all=Vše shared.edit=Upravit shared.advancedOptions=Pokročilé možnosti @@ -226,8 +230,8 @@ shared.enabled=Aktivní #################################################################### mainView.menu.market=Trh -mainView.menu.buyBtc=Koupit BTC -mainView.menu.sellBtc=Prodat BTC +mainView.menu.buyXmr=Koupit XMR +mainView.menu.sellXmr=Prodat XMR mainView.menu.portfolio=Portfolio mainView.menu.funds=Finance mainView.menu.support=Podpora @@ -245,36 +249,39 @@ mainView.balance.reserved.short=Rezervováno mainView.balance.pending.short=Zamčeno mainView.footer.usingTor=(přes Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(přes clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Aktuální poplatek: {0} sat/vB -mainView.footer.xmrInfo.initializing=Připojování do Bitcoinové sítě -mainView.footer.xmrInfo.synchronizingWith=Synchronizace s {0} v bloku: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synchronizováno s {0} v bloku {1} +mainView.footer.xmrFeeRate=/ Aktuální poplatek: {0} sat/vB +mainView.footer.xmrInfo.initializing=Připojování k síti Haveno +mainView.footer.xmrInfo.synchronizingWith=Synchronizace s {0} na bloku: {1} / {2} +mainView.footer.xmrInfo.connectedTo=Připojeno k {0} v bloku {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Synchronizace peněženky s {0} na bloku: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Synchronizováno s {0} na bloku {1} mainView.footer.xmrInfo.connectingTo=Připojování mainView.footer.xmrInfo.connectionFailed=Připojení se nezdařilo -mainView.footer.xmrPeers=Monero síťové nody: {0} -mainView.footer.p2pPeers=Haveno síťové nody: {0} +mainView.footer.xmrPeers=Monero síťové uzly: {0} +mainView.footer.p2pPeers=Haveno síťové uzly: {0} mainView.bootstrapState.connectionToTorNetwork=(1/4) Připojování do sítě Tor... -mainView.bootstrapState.torNodeCreated=(2/4) Tor node vytvořen +mainView.bootstrapState.torNodeCreated=(2/4) Tor uzel vytvořen mainView.bootstrapState.hiddenServicePublished=(3/4) Skrytá služba publikována mainView.bootstrapState.initialDataReceived=(4/4) Iniciační data přijata -mainView.bootstrapWarning.noSeedNodesAvailable=Žádné seed nody nejsou k dispozici -mainView.bootstrapWarning.noNodesAvailable=Žádné seed ani peer nody k dispozici +mainView.bootstrapWarning.noSeedNodesAvailable=Žádné seed uzly nejsou k dispozici +mainView.bootstrapWarning.noNodesAvailable=Žádné seed ani peer uzly k dispozici mainView.bootstrapWarning.bootstrappingToP2PFailed=Zavádění do sítě Haveno se nezdařilo -mainView.p2pNetworkWarnMsg.noNodesAvailable=Pro vyžádání dat nejsou k dispozici žádné seed ani peer nody.\nZkontrolujte připojení k internetu nebo zkuste aplikaci restartovat. +mainView.p2pNetworkWarnMsg.noNodesAvailable=Pro vyžádání dat nejsou k dispozici žádné seed ani peer uzly.\nZkontrolujte připojení k internetu nebo zkuste aplikaci restartovat. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Připojení k síti Haveno selhalo (nahlášená chyba: {0}).\nZkontrolujte připojení k internetu nebo zkuste aplikaci restartovat. -mainView.walletServiceErrorMsg.timeout=Připojení k síti Bitcoin selhalo kvůli vypršení časového limitu. -mainView.walletServiceErrorMsg.connectionError=Připojení k síti Bitcoin selhalo kvůli chybě {0} +mainView.walletServiceErrorMsg.timeout=Připojení k síti Monero selhalo kvůli vypršení časového limitu. +mainView.walletServiceErrorMsg.connectionError=Připojení k síti Monero selhalo kvůli chybě {0} mainView.walletServiceErrorMsg.rejectedTxException=Transakce byla ze sítě zamítnuta.\n\n{0} -mainView.networkWarning.allConnectionsLost=Ztratili jste připojení ke všem {0} síťovým peer nodům.\nMožná jste ztratili připojení k internetu nebo byl váš počítač v pohotovostním režimu. -mainView.networkWarning.localhostBitcoinLost=Ztratili jste připojení k Bitcoinovému localhost nodu.\nRestartujte aplikaci Haveno a připojte se k jiným Bitcoinovým nodům nebo restartujte Bitcoinový localhost node. +mainView.networkWarning.allConnectionsLost=Ztratili jste připojení ke všem {0} síťovým peer uzlům.\nMožná jste ztratili připojení k internetu nebo byl váš počítač v pohotovostním režimu. +mainView.networkWarning.localhostMoneroLost=Ztratili jste připojení k localhost uzlu Monero.\nRestartujte aplikaci Haveno a připojte se k jiným uzlům Monero nebo restartujte localhost Monero uzel. mainView.version.update=(Dostupná aktualizace) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=Koupit {0} market.offerBook.sellWithTraditional=Prodat {0} market.offerBook.sellOffersHeaderLabel=Prodat {0} kupujícímu market.offerBook.buyOffersHeaderLabel=Koupit {0} od prodejce -market.offerBook.buy=Chci koupit bitcoin -market.offerBook.sell=Chci prodat bitcoin +market.offerBook.buy=Chci koupit monero +market.offerBook.sell=Chci prodat monero # SpreadView market.spread.numberOfOffersColumn=Všechny nabídky ({0}) -market.spread.numberOfBuyOffersColumn=Koupit BTC ({0}) -market.spread.numberOfSellOffersColumn=Prodat BTC ({0}) -market.spread.totalAmountColumn=Celkem BTC ({0}) +market.spread.numberOfBuyOffersColumn=Koupit XMR ({0}) +market.spread.numberOfSellOffersColumn=Prodat XMR ({0}) +market.spread.totalAmountColumn=Celkem XMR ({0}) market.spread.spreadColumn=Rozptyl market.spread.expanded=Rozbalit @@ -325,6 +332,7 @@ offerbook.createOffer=Vytvořit nabídku offerbook.takeOffer=Přijmout nabídku offerbook.takeOfferToBuy=Přijmout nabídku na nákup {0} offerbook.takeOfferToSell=Přijmout nabídku k prodeji {0} +offerbook.takeOffer.enterChallenge=Zadejte heslo nabídky offerbook.trader=Obchodník offerbook.offerersBankId=ID banky tvůrce (BIC/SWIFT): {0} offerbook.offerersBankName=Jméno banky tvůrce: {0} @@ -335,6 +343,8 @@ offerbook.availableOffers=Dostupné nabídky offerbook.filterByCurrency=Filtrovat podle měny offerbook.filterByPaymentMethod=Filtrovat podle platební metody offerbook.matchingOffers=Nabídky odpovídající mým účtům +offerbook.filterNoDeposit=Žádný vklad +offerbook.noDepositOffers=Nabídky bez zálohy (vyžaduje se heslo) offerbook.timeSinceSigning=Informace o účtu offerbook.timeSinceSigning.info=Tento účet byl ověřen a {0} offerbook.timeSinceSigning.info.arbitrator=podepsán rozhodcem a může podepisovat účty partnerů @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=účet byl zablokován offerbook.timeSinceSigning.daysSinceSigning={0} dní offerbook.timeSinceSigning.daysSinceSigning.long={0} od podpisu offerbook.xmrAutoConf=Je automatické potvrzení povoleno +offerbook.buyXmrWith=Kupte XMR za: +offerbook.sellXmrFor=Prodat XMR za: offerbook.timeSinceSigning.help=Když úspěšně dokončíte obchod s uživatelem, který má podepsaný platební účet, je váš platební účet podepsán.\n{0} dní později se počáteční limit {1} zruší a váš účet může podepisovat platební účty ostatních uživatelů. offerbook.timeSinceSigning.notSigned=Dosud nepodepsáno @@ -353,12 +365,13 @@ offerbook.timeSinceSigning.notSigned.noNeed=N/A shared.notSigned=Tento účet ještě nebyl podepsán a byl vytvořen před {0} dny shared.notSigned.noNeed=Tento typ účtu nevyžaduje podepisování shared.notSigned.noNeedDays=Tento typ účtu nevyžaduje podepisování a byl vytvořen před {0} dny -shared.notSigned.noNeedAlts=Cryptoové účty neprocházejí kontrolou podpisu a stáří +shared.notSigned.noNeedAlts=Kryptoměnové účty neprocházejí kontrolou podpisu a stáří offerbook.nrOffers=Počet nabídek: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Kauce BTC (%) +offerbook.deposit=Kauce XMR (%) offerbook.deposit.help=Kauce zaplacená každým obchodníkem k zajištění obchodu. Bude vrácena po dokončení obchodu. +offerbook.createNewOffer=Vytvořit nabídku pro {0} {1} offerbook.createOfferToBuy=Vytvořit novou nabídku k nákupu {0} offerbook.createOfferToSell=Vytvořit novou nabídku k prodeji {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=S touto verzí softwaru mohou obchodní popup.warning.tradeLimitDueAccountAgeRestriction.seller=Povolená částka obchodu je omezena na {0} z důvodu bezpečnostních omezení na základě následujících kritérií:\n- Účet kupujícího nebyl podepsán rozhodcem ani obchodním partnerem\n- Doba od podpisu účtu kupujícího není alespoň 30 dní\n- Způsob platby této nabídky je považován za riskantní pro bankovní zpětné zúčtování\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=Povolená částka obchodu je omezena na {0} z důvodu bezpečnostních omezení na základě následujících kritérií:\n- Váš účet nebyl podepsán rozhodcem ani obchodním partnerem\n- Čas od podpisu vašeho účtu není alespoň 30 dní\n- Způsob platby této nabídky je považován za riskantní pro bankovní zpětné zúčtování\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Tento platební metoda je dočasně omezena na {0} do {1}, protože všichni kupující mají nové účty.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Vaše nabídka bude omezena na kupující s podepsanými a starými účty, protože překračuje {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Tato nabídka vyžaduje jinou verzi protokolu než ta, která byla použita ve vaší verzi softwaru.\n\nZkontrolujte, zda máte nainstalovanou nejnovější verzi, jinak uživatel, který nabídku vytvořil, použil starší verzi.\n\nUživatelé nemohou obchodovat s nekompatibilní verzí obchodního protokolu. offerbook.warning.userIgnored=Do seznamu ignorovaných uživatelů jste přidali onion adresu tohoto uživatele. @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=Částka byla zaokrouhlena, aby se zvýšilo so # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Vložte množství v BTC +createOffer.amount.prompt=Vložte množství v XMR createOffer.price.prompt=Zadejte cenu createOffer.volume.prompt=Vložte množství v {0} -createOffer.amountPriceBox.amountDescription=Množství BTC, které chcete {0} +createOffer.amountPriceBox.amountDescription=Množství XMR, které chcete {0} createOffer.amountPriceBox.buy.volumeDescription=Částka v {0}, kterou utratíte createOffer.amountPriceBox.sell.volumeDescription=Částka v {0}, kterou přijmete -createOffer.amountPriceBox.minAmountDescription=Minimální množství BTC +createOffer.amountPriceBox.minAmountDescription=Minimální množství XMR createOffer.securityDeposit.prompt=Kauce createOffer.fundsBox.title=Financujte svou nabídku createOffer.fundsBox.offerFee=Obchodní poplatek @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=Vždy získáte o {0} % více, než je akt createOffer.info.buyBelowMarketPrice=Vždy zaplatíte o {0} % méně, než je aktuální tržní cena, protože cena vaší nabídky bude průběžně aktualizována. createOffer.warning.sellBelowMarketPrice=Vždy získáte o {0} % méně, než je aktuální tržní cena, protože cena vaší nabídky bude průběžně aktualizována. createOffer.warning.buyAboveMarketPrice=Vždy zaplatíte o {0} % více, než je aktuální tržní cena, protože cena vaší nabídky bude průběžně aktualizována. -createOffer.tradeFee.descriptionBTCOnly=Obchodní poplatek +createOffer.tradeFee.descriptionXMROnly=Obchodní poplatek createOffer.tradeFee.descriptionBSQEnabled=Zvolte měnu obchodního poplatku createOffer.triggerPrice.prompt=Nepovinná limitní cena @@ -448,7 +463,12 @@ createOffer.placeOfferButton=Přehled: Umístěte nabídku {0} monero createOffer.createOfferFundWalletInfo.headline=Financujte svou nabídku # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Výše obchodu: {0}\n -createOffer.createOfferFundWalletInfo.msg=Do této nabídky musíte vložit {0}.\n\nTyto prostředky jsou rezervovány ve vaší lokální peněžence a budou uzamčeny na vkladové multisig adrese, jakmile někdo příjme vaši nabídku.\n\nČástka je součtem:\n{1}- Vaše kauce: {2}\n- Obchodní poplatek: {3}\n- Poplatek za těžbu: {4}\n\nPři financování obchodu si můžete vybrat ze dvou možností:\n- Použijte svou peněženku Haveno (pohodlné, ale transakce mohou být propojitelné) NEBO\n- Přenos z externí peněženky (potenciálně více soukromé)\n\nPo uzavření tohoto vyskakovacího okna se zobrazí všechny možnosti a podrobnosti financování. +createOffer.createOfferFundWalletInfo.msg=Potřebujete vložit {0} do této nabídky.\n\n\ + Tyto prostředky jsou rezervovány ve vaší místní peněžence a budou zablokovány v multisig peněžence, jakmile někdo přijme vaši nabídku.\n\n\ + Částka je součtem:\n\ + {1}\ + - Vaše záloha: {2}\n\ + - Poplatek za obchodování: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Při zadávání nabídky došlo k chybě:\n\n{0}\n\nPeněženku ještě neopustily žádné finanční prostředky.\nRestartujte aplikaci a zkontrolujte síťové připojení. @@ -470,30 +490,35 @@ createOffer.setDepositAsBuyer=Nastavit mou kauci jako kupujícího (%) createOffer.setDepositForBothTraders=Nastavit kauci obou obchodníků (%) createOffer.securityDepositInfo=Kauce vašeho kupujícího bude {0} createOffer.securityDepositInfoAsBuyer=Vaše kauce jako kupující bude {0} -createOffer.minSecurityDepositUsed=Je použita min. záloha kupujícího +createOffer.minSecurityDepositUsed=Minimální bezpečnostní záloha je použita +createOffer.buyerAsTakerWithoutDeposit=Žádný vklad od kupujícího (chráněno heslem) +createOffer.myDeposit=Můj bezpečnostní vklad (%) +createOffer.myDepositInfo=Vaše záloha na bezpečnost bude {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Vložte množství v BTC -takeOffer.amountPriceBox.buy.amountDescription=Množství BTC na prodej -takeOffer.amountPriceBox.sell.amountDescription=Množství BTC k nákupu -takeOffer.amountPriceBox.priceDescription=Cena za bitcoin v {0} +takeOffer.amount.prompt=Vložte množství v XMR +takeOffer.amountPriceBox.buy.amountDescription=Množství XMR na prodej +takeOffer.amountPriceBox.sell.amountDescription=Množství XMR k nákupu +takeOffer.amountPriceBox.priceDescription=Cena za monero v {0} takeOffer.amountPriceBox.amountRangeDescription=Možný rozsah množství -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=Částka, kterou jste zadali, přesahuje počet povolených desetinných míst.\nČástka byla upravena na 4 desetinná místa. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=Částka, kterou jste zadali, přesahuje počet povolených desetinných míst.\nČástka byla upravena na 4 desetinná místa. takeOffer.validation.amountSmallerThanMinAmount=Částka nesmí být menší než minimální částka stanovená v nabídce. takeOffer.validation.amountLargerThanOfferAmount=Vstupní částka nesmí být vyšší než částka stanovená v nabídce. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Toto vstupní množství by vytvořilo zanedbatelné drobné pro prodejce BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Toto vstupní množství by vytvořilo zanedbatelné drobné pro prodejce XMR. takeOffer.fundsBox.title=Financujte svůj obchod takeOffer.fundsBox.isOfferAvailable=Kontroluje se, zda je nabídka k dispozici ... takeOffer.fundsBox.tradeAmount=Částka k prodeji takeOffer.fundsBox.offerFee=Obchodní poplatek takeOffer.fundsBox.networkFee=Celkové poplatky za těžbu -takeOffer.fundsBox.takeOfferSpinnerInfo=Probíhá využití nabídky... +takeOffer.fundsBox.takeOfferSpinnerInfo=Přijímám nabídku: {0} takeOffer.fundsBox.paymentLabel=Haveno obchod s ID {0} takeOffer.fundsBox.fundsStructure=(kauce {0}, obchodní poplatek {1}, poplatek za těžbu {2}) +takeOffer.fundsBox.noFundingRequiredTitle=Žádné financování požadováno +takeOffer.fundsBox.noFundingRequiredDescription=Získejte passphrase nabídky od prodávajícího mimo Haveno, abyste tuto nabídku přijali. takeOffer.success.headline=Úspěšně jste přijali nabídku. takeOffer.success.info=Stav vašeho obchodu můžete vidět v \"Portfolio/Otevřené obchody\". takeOffer.error.message=Při převzetí nabídky došlo k chybě.\n\n{0} @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=Vkladová transakce není stále potvrzen # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Váš obchod má alespoň jedno potvrzení blockchainu.\n\n -portfolio.pending.step2_buyer.refTextWarn=Důležité: když vyplňujete platební informace, nechte pole \"důvod platby\" prázdné. NEPOUŽÍVEJTE ID obchodu ani jiné poznámky jako např. 'bitcoin', 'BTC' nebo 'Haveno'. Můžete se se svým obchodním partnerem domluvit pomocí chatu na identifikaci platby, která bude vyhovovat oběma. +portfolio.pending.step2_buyer.refTextWarn=Důležité: když vyplňujete platební informace, nechte pole \"důvod platby\" prázdné. NEPOUŽÍVEJTE ID obchodu ani jiné poznámky jako např. 'monero', 'XMR' nebo 'Haveno'. Můžete se se svým obchodním partnerem domluvit pomocí chatu na identifikaci platby, která bude vyhovovat oběma. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=Pokud vaše banka účtuje poplatky za převod, musíte tyto poplatky uhradit vy. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Převeďte prosím z vaší externí {0} peněženky\n{1} prodejci BTC.\n\n +portfolio.pending.step2_buyer.crypto=Převeďte prosím z vaší externí {0} peněženky\n{1} prodejci XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Přejděte do banky a zaplaťte {0} prodejci BTC.\n\n -portfolio.pending.step2_buyer.cash.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zapište na papírový doklad: NO REFUNDS - bez náhrady.\nPoté ji roztrhněte na 2 části, vytvořte fotografii a odešlete ji na e-mailovou adresu prodejce BTC. +portfolio.pending.step2_buyer.cash=Přejděte do banky a zaplaťte {0} prodejci XMR.\n\n +portfolio.pending.step2_buyer.cash.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zapište na papírový doklad: NO REFUNDS - bez náhrady.\nPoté ji roztrhněte na 2 části, vytvořte fotografii a odešlete ji na e-mailovou adresu prodejce XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Zaplaťte prosím {0} prodejci BTC pomocí MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zašlete autorizační číslo a fotografii s potvrzením e-mailem prodejci BTC.\nPotvrzení musí jasně uvádět celé jméno, zemi, stát a částku prodávajícího. E-mail prodejce je: {0}. +portfolio.pending.step2_buyer.moneyGram=Zaplaťte prosím {0} prodejci XMR pomocí MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zašlete autorizační číslo a fotografii s potvrzením e-mailem prodejci XMR.\nPotvrzení musí jasně uvádět celé jméno, zemi, stát a částku prodávajícího. E-mail prodejce je: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Zaplaťte prosím {0} prodejci BTC pomocí Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zašlete prodejci BTC e-mail s MTCN (sledovací číslo) a fotografii s potvrzením o přijetí.\nPotvrzení musí jasně uvádět celé jméno prodávajícího, město, zemi a částku. E-mail prodejce je: {0}. +portfolio.pending.step2_buyer.westernUnion=Zaplaťte prosím {0} prodejci XMR pomocí Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=DŮLEŽITÉ POŽADAVKY:\nPo provedení platby zašlete prodejci XMR e-mail s MTCN (sledovací číslo) a fotografii s potvrzením o přijetí.\nPotvrzení musí jasně uvádět celé jméno prodávajícího, město, zemi a částku. E-mail prodejce je: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Zašlete prosím {0} prodejci BTC pomocí \"US Postal Money Order\".\n\n +portfolio.pending.step2_buyer.postal=Zašlete prosím {0} prodejci XMR pomocí \"US Postal Money Order\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Zašlete prosím {0} prodejci BTC v poštovní zásilce (\"Pay by Mail\"). Konkrétní instrukce naleznete v obchodní smlouvě. V případě pochybností se můžete zeptat protistrany pomocí obchodního chatu. Více informací naleznete na Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Zašlete prosím {0} prodejci XMR v poštovní zásilce (\"Pay by Mail\"). Konkrétní instrukce naleznete v obchodní smlouvě. V případě pochybností se můžete zeptat protistrany pomocí obchodního chatu. Více informací naleznete na Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Prosím uhraďte {0} pomocí zvolené platební metody prodejci BTC. V dalším kroku naleznete detaily o účtu prodejce.\n\n +portfolio.pending.step2_buyer.pay=Prosím uhraďte {0} pomocí zvolené platební metody prodejci XMR. V dalším kroku naleznete detaily o účtu prodejce.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Kontaktujte prodejce BTC prostřednictvím poskytnutého kontaktu a domluvte si schůzku kde zaplatíte {0}.\n\n +portfolio.pending.step2_buyer.f2f=Kontaktujte prodejce XMR prostřednictvím poskytnutého kontaktu a domluvte si schůzku kde zaplatíte {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Zahajte platbu pomocí {0} portfolio.pending.step2_buyer.recipientsAccountData=Příjemci {0} portfolio.pending.step2_buyer.amountToTransfer=Částka k převodu @@ -628,27 +653,27 @@ portfolio.pending.step2_buyer.buyerAccount=Použijte svůj platební účet portfolio.pending.step2_buyer.paymentSent=Platba zahájena portfolio.pending.step2_buyer.warn=Platbu {0} jste ještě neprovedli!\nVezměte prosím na vědomí, že obchod musí být dokončen do {1}. portfolio.pending.step2_buyer.openForDispute=Neukončili jste platbu!\nMax. doba obchodu uplynula. Obraťte se na mediátora a požádejte o pomoc. -portfolio.pending.step2_buyer.paperReceipt.headline=Odeslali jste papírový doklad prodejci BTC? -portfolio.pending.step2_buyer.paperReceipt.msg=Zapamatujte si:\nMusíte napsat na papírový doklad: NO REFUNDS - bez náhrady.\nPoté ho roztrhněte na 2 části, vytvořte fotografii a odešlete ji na e-mailovou adresu prodejce BTC. +portfolio.pending.step2_buyer.paperReceipt.headline=Odeslali jste papírový doklad prodejci XMR? +portfolio.pending.step2_buyer.paperReceipt.msg=Zapamatujte si:\nMusíte napsat na papírový doklad: NO REFUNDS - bez náhrady.\nPoté ho roztrhněte na 2 části, vytvořte fotografii a odešlete ji na e-mailovou adresu prodejce XMR. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Odeslat autorizační číslo a účtenku -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Musíte zaslat autorizační číslo a fotografii dokladu e-mailem prodejci BTC.\nDoklad musí jasně uvádět celé jméno prodávajícího, zemi, stát a částku. E-mail prodejce je: {0}.\n\nOdeslali jste autorizační číslo a smlouvu prodejci? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Musíte zaslat autorizační číslo a fotografii dokladu e-mailem prodejci XMR.\nDoklad musí jasně uvádět celé jméno prodávajícího, zemi, stát a částku. E-mail prodejce je: {0}.\n\nOdeslali jste autorizační číslo a smlouvu prodejci? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Pošlete MTCN a účtenku -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Musíte odeslat MTCN (sledovací číslo) a fotografii dokladu e-mailem prodejci BTC.\nDoklad musí jasně uvádět celé jméno prodávajícího, město, zemi a částku. E-mail prodejce je: {0}.\n\nOdeslali jste MTCN a smlouvu prodejci? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Musíte odeslat MTCN (sledovací číslo) a fotografii dokladu e-mailem prodejci XMR.\nDoklad musí jasně uvádět celé jméno prodávajícího, město, zemi a částku. E-mail prodejce je: {0}.\n\nOdeslali jste MTCN a smlouvu prodejci? portfolio.pending.step2_buyer.halCashInfo.headline=Pošlete HalCash kód -portfolio.pending.step2_buyer.halCashInfo.msg=Musíte odeslat jak textovou zprávu s kódem HalCash tak i obchodní ID ({0}) prodejci BTC.\nMobilní číslo prodejce je {1}.\n\nPoslali jste kód prodejci? +portfolio.pending.step2_buyer.halCashInfo.msg=Musíte odeslat jak textovou zprávu s kódem HalCash tak i obchodní ID ({0}) prodejci XMR.\nMobilní číslo prodejce je {1}.\n\nPoslali jste kód prodejci? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Některé banky mohou ověřovat jméno příjemce. Účty Faster Payments vytvořené u starých klientů Haveno neposkytují jméno příjemce, proto si jej (v případě potřeby) vyžádejte pomocí obchodního chatu. portfolio.pending.step2_buyer.confirmStart.headline=Potvrďte, že jste zahájili platbu portfolio.pending.step2_buyer.confirmStart.msg=Zahájili jste platbu {0} vašemu obchodnímu partnerovi? portfolio.pending.step2_buyer.confirmStart.yes=Ano, zahájil jsem platbu portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=Neposkytli jste doklad o platbě -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Nezadali jste ID transakce a klíč transakce.\n\nNeposkytnutím těchto údajů nemůže peer použít funkci automatického potvrzení k uvolnění BTC, jakmile bude přijat XMR.\nKromě toho Haveno vyžaduje, aby odesílatel transakce XMR mohl tyto informace poskytnout mediátorovi nebo rozhodci v případě sporu.\nDalší podrobnosti na wiki Haveno: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Nezadali jste ID transakce a klíč transakce.\n\nNeposkytnutím těchto údajů nemůže peer použít funkci automatického potvrzení k uvolnění XMR, jakmile bude přijat XMR.\nKromě toho Haveno vyžaduje, aby odesílatel transakce XMR mohl tyto informace poskytnout mediátorovi nebo rozhodci v případě sporu.\nDalší podrobnosti na wiki Haveno: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Vstup není 32 bajtová hexadecimální hodnota portfolio.pending.step2_buyer.confirmStart.warningButton=Ignorovat a přesto pokračovat portfolio.pending.step2_seller.waitPayment.headline=Počkejte na platbu portfolio.pending.step2_seller.f2fInfo.headline=Kontaktní informace kupujícího -portfolio.pending.step2_seller.waitPayment.msg=Vkladová transakce má alespoň jedno potvrzení na blockchainu.\nMusíte počkat, než kupující BTC zahájí platbu {0}. -portfolio.pending.step2_seller.warn=Kupující BTC dosud neprovedl platbu {0}.\nMusíte počkat, než zahájí platbu.\nPokud obchod nebyl dokončen dne {1}, bude rozhodce vyšetřovat. -portfolio.pending.step2_seller.openForDispute=Kupující BTC ještě nezačal s platbou!\nMax. povolené období pro obchod vypršelo.\nMůžete počkat déle a dát obchodnímu partnerovi více času nebo požádat o pomoc mediátora. +portfolio.pending.step2_seller.waitPayment.msg=Vkladová transakce má alespoň jedno potvrzení na blockchainu.\nMusíte počkat, než kupující XMR zahájí platbu {0}. +portfolio.pending.step2_seller.warn=Kupující XMR dosud neprovedl platbu {0}.\nMusíte počkat, než zahájí platbu.\nPokud obchod nebyl dokončen dne {1}, bude rozhodce vyšetřovat. +portfolio.pending.step2_seller.openForDispute=Kupující XMR ještě nezačal s platbou!\nMax. povolené období pro obchod vypršelo.\nMůžete počkat déle a dát obchodnímu partnerovi více času nebo požádat o pomoc mediátora. tradeChat.chatWindowTitle=Okno chatu pro obchod s ID ''{0}'' tradeChat.openChat=Otevřít chatovací okno tradeChat.rules=Můžete komunikovat se svým obchodním partnerem a vyřešit případné problémy s tímto obchodem.\nOdpovídat v chatu není povinné.\nPokud obchodník poruší některé z níže uvedených pravidel, zahajte spor a nahlaste jej mediátorovi nebo rozhodci.\n\nPravidla chatu:\n\t● Neposílejte žádné odkazy (riziko malwaru). Můžete odeslat ID transakce a jméno block exploreru.\n\t● Neposílejte seed slova, soukromé klíče, hesla nebo jiné citlivé informace!\n\t● Nepodporujte obchodování mimo Haveno (bez zabezpečení).\n\t● Nezapojujte se do žádných forem podvodů v oblasti sociálního inženýrství.\n\t● Pokud partner nereaguje a dává přednost nekomunikovat prostřednictvím chatu, respektujte jeho rozhodnutí.\n\t● Soustřeďte konverzaci pouze na obchod. Tento chat není náhradou messengeru.\n\t● Udržujte konverzaci přátelskou a uctivou. @@ -666,26 +691,26 @@ message.state.ACKNOWLEDGED=Partner potvrdil přijetí zprávy # suppress inspection "UnusedProperty" message.state.FAILED=Odeslání zprávy se nezdařilo -portfolio.pending.step3_buyer.wait.headline=Počkejte na potvrzení platby prodejce BTC -portfolio.pending.step3_buyer.wait.info=Čekání na potvrzení prodejce BTC na přijetí platby {0}. +portfolio.pending.step3_buyer.wait.headline=Počkejte na potvrzení platby prodejce XMR +portfolio.pending.step3_buyer.wait.info=Čekání na potvrzení prodejce XMR na přijetí platby {0}. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Stav zprávy o zahájení platby portfolio.pending.step3_buyer.warn.part1a=na {0} blockchainu portfolio.pending.step3_buyer.warn.part1b=u vašeho poskytovatele plateb (např. banky) -portfolio.pending.step3_buyer.warn.part2=Prodejce BTC vaši platbu stále nepotvrdil. Zkontrolujte {0}, zda bylo odeslání platby úspěšné. -portfolio.pending.step3_buyer.openForDispute=Prodejce BTC nepotvrdil vaši platbu! Max. období pro uskutečnění obchodu uplynulo. Můžete počkat déle a dát obchodnímu partnerovi více času nebo požádat o pomoc mediátora. +portfolio.pending.step3_buyer.warn.part2=Prodejce XMR vaši platbu stále nepotvrdil. Zkontrolujte {0}, zda bylo odeslání platby úspěšné. +portfolio.pending.step3_buyer.openForDispute=Prodejce XMR nepotvrdil vaši platbu! Max. období pro uskutečnění obchodu uplynulo. Můžete počkat déle a dát obchodnímu partnerovi více času nebo požádat o pomoc mediátora. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Váš obchodní partner potvrdil, že zahájil platbu {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=ve vašem oblíbeném {0} blockchain exploreru portfolio.pending.step3_seller.crypto.wallet=na vaší {0} peněžence portfolio.pending.step3_seller.crypto={0}Zkontrolujte prosím {1}, zda transakce na vaši přijímací adresu\n{2}\nmá již dostatečné potvrzení na blockchainu.\nČástka platby musí být {3}\n\nPo zavření vyskakovacího okna můžete zkopírovat a vložit svou {4} adresu z hlavní obrazovky. -portfolio.pending.step3_seller.postal={0}Zkontrolujte, zda jste od kupujícího BTC obdrželi {1} přes \"US Postal Money Order\". +portfolio.pending.step3_seller.postal={0}Zkontrolujte, zda jste od kupujícího XMR obdrželi {1} přes \"US Postal Money Order\". # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Zkontrolujte, zda jste od kupujícího BTC obdrželi {1} přes \"Pay by Mail\". +portfolio.pending.step3_seller.payByMail={0}Zkontrolujte, zda jste od kupujícího XMR obdrželi {1} přes \"Pay by Mail\". # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Váš obchodní partner potvrdil, že zahájil platbu {0}.\n\nPřejděte na webovou stránku online bankovnictví a zkontrolujte, zda jste od kupujícího BTC obdrželi {1}. -portfolio.pending.step3_seller.cash=Vzhledem k tomu, že se platba provádí prostřednictvím hotovostního vkladu, musí kupující BTC napsat na papírový doklad \"NO REFUND\", roztrhat ho na 2 části a odeslat vám e-mailem fotografii.\n\nAbyste se vyhnuli riziku zpětného zúčtování, potvrďte pouze, zda jste obdrželi e-mail a zda si jste jisti, že papírový doklad je platný.\nPokud si nejste jisti, {0} -portfolio.pending.step3_seller.moneyGram=Kupující vám musí zaslat e-mailem autorizační číslo a fotografii s potvrzením.\nPotvrzení musí jasně uvádět vaše celé jméno, zemi, stát a částku. Zkontrolujte si prosím váš e-mail, pokud jste obdrželi autorizační číslo.\n\nPo uzavření tohoto vyskakovacího okna se zobrazí jméno a adresa kupujícího BTC pro vyzvednutí peněz z MoneyGram.\n\nPotvrďte příjem až po úspěšném vyzvednutí peněz! -portfolio.pending.step3_seller.westernUnion=Kupující vám musí zaslat MTCN (sledovací číslo) a fotografii s potvrzením e-mailem.\nPotvrzení musí jasně uvádět vaše celé jméno, město, zemi a částku. Zkontrolujte svůj e-mail, pokud jste obdrželi MTCN.\n\nPo zavření tohoto vyskakovacího okna uvidíte jméno a adresu kupujícího BTC pro vyzvednutí peněz z Western Union.\n\nPotvrďte příjem až po úspěšném vyzvednutí peněz! +portfolio.pending.step3_seller.bank=Váš obchodní partner potvrdil, že zahájil platbu {0}.\n\nPřejděte na webovou stránku online bankovnictví a zkontrolujte, zda jste od kupujícího XMR obdrželi {1}. +portfolio.pending.step3_seller.cash=Vzhledem k tomu, že se platba provádí prostřednictvím hotovostního vkladu, musí kupující XMR napsat na papírový doklad \"NO REFUND\", roztrhat ho na 2 části a odeslat vám e-mailem fotografii.\n\nAbyste se vyhnuli riziku zpětného zúčtování, potvrďte pouze, zda jste obdrželi e-mail a zda si jste jisti, že papírový doklad je platný.\nPokud si nejste jisti, {0} +portfolio.pending.step3_seller.moneyGram=Kupující vám musí zaslat e-mailem autorizační číslo a fotografii s potvrzením.\nPotvrzení musí jasně uvádět vaše celé jméno, zemi, stát a částku. Zkontrolujte si prosím váš e-mail, pokud jste obdrželi autorizační číslo.\n\nPo uzavření tohoto vyskakovacího okna se zobrazí jméno a adresa kupujícího XMR pro vyzvednutí peněz z MoneyGram.\n\nPotvrďte příjem až po úspěšném vyzvednutí peněz! +portfolio.pending.step3_seller.westernUnion=Kupující vám musí zaslat MTCN (sledovací číslo) a fotografii s potvrzením e-mailem.\nPotvrzení musí jasně uvádět vaše celé jméno, město, zemi a částku. Zkontrolujte svůj e-mail, pokud jste obdrželi MTCN.\n\nPo zavření tohoto vyskakovacího okna uvidíte jméno a adresu kupujícího XMR pro vyzvednutí peněz z Western Union.\n\nPotvrďte příjem až po úspěšném vyzvednutí peněz! portfolio.pending.step3_seller.halCash=Kupující vám musí poslat kód HalCash jako textovou zprávu. Kromě toho obdržíte zprávu od HalCash s požadovanými informacemi pro výběr EUR z bankomatu podporujícího HalCash.\n\nPoté, co jste vyzvedli peníze z bankomatu, potvrďte zde přijetí platby! portfolio.pending.step3_seller.amazonGiftCard=Kupující vám poslal e-mailovou kartu Amazon eGift e-mailem nebo textovou zprávou na váš mobilní telefon. Uplatněte nyní kartu Amazon eGift ve svém účtu Amazon a po přijetí potvrďte potvrzení o platbě. @@ -701,7 +726,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID transakce portfolio.pending.step3_seller.xmrTxKey=Transakční klíč portfolio.pending.step3_seller.buyersAccount=Údaje o účtu kupujícího portfolio.pending.step3_seller.confirmReceipt=Potvrďte příjem platby -portfolio.pending.step3_seller.buyerStartedPayment=Kupující BTC zahájil platbu {0}.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=Kupující XMR zahájil platbu {0}.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Podívejte se na potvrzení na blockchainu ve své crypto peněžence nebo v blok exploreru a potvrďte platbu, pokud máte dostatečné potvrzení na blockchainu. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Zkontrolujte na svém obchodním účtu (např. Bankovní účet) a potvrďte, kdy jste platbu obdrželi. portfolio.pending.step3_seller.warn.part1a=na {0} blockchainu @@ -713,7 +738,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Obdrželi jste od svého # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Ověřte také, zda se jméno odesílatele uvedené v obchodní smlouvě shoduje se jménem uvedeným na výpisu z účtu:\nJméno odesílatele podle obchodní smlouvy: {0}\n\nPokud jména nejsou úplně stejná, nepotvrzujte příjem platby. Místo toho otevřete spor stisknutím \"alt + o\" nebo \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Vezměte prosím na vědomí, že jakmile potvrdíte příjem, dosud uzamčený obchodovaný BTC bude uvolněn kupujícímu a kauce bude vrácena.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Vezměte prosím na vědomí, že jakmile potvrdíte příjem, dosud uzamčený obchodovaný XMR bude uvolněn kupujícímu a kauce bude vrácena.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Potvrďte, že jste obdržel(a) platbu portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Ano, obdržel(a) jsem platbu portfolio.pending.step3_seller.onPaymentReceived.signer=DŮLEŽITÉ: Potvrzením přijetí platby ověřujete také účet protistrany a odpovídajícím způsobem jej podepisujete. Protože účet protistrany dosud nebyl podepsán, měli byste odložit potvrzení platby co nejdéle, abyste snížili riziko zpětného zúčtování. @@ -723,7 +748,7 @@ portfolio.pending.step5_buyer.tradeFee=Obchodní poplatek portfolio.pending.step5_buyer.makersMiningFee=Poplatek za těžbu portfolio.pending.step5_buyer.takersMiningFee=Celkové poplatky za těžbu portfolio.pending.step5_buyer.refunded=Vrácená kauce -portfolio.pending.step5_buyer.withdrawBTC=Vyberte své bitcoiny +portfolio.pending.step5_buyer.withdrawXMR=Vyberte své moneroy portfolio.pending.step5_buyer.amount=Částka k výběru portfolio.pending.step5_buyer.withdrawToAddress=Adresa výběru portfolio.pending.step5_buyer.moveToHavenoWallet=Uchovat prostředky v peněžence Haveno @@ -732,7 +757,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Vaše finanční prostředky již portfolio.pending.step5_buyer.confirmWithdrawal=Potvrďte žádost o výběr portfolio.pending.step5_buyer.amountTooLow=Částka k převodu je nižší než transakční poplatek a min. možná hodnota tx (drobné). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Výběr byl dokončen -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Vaše dokončené obchody jsou uloženy na \"Portfolio/Historie\".\nVšechny své bitcoinové transakce si můžete prohlédnout v sekci \"Prostředky/Transakce\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Vaše dokončené obchody jsou uloženy na \"Portfolio/Historie\".\nVšechny své transakce Monero si můžete prohlédnout v sekci \"Finance/Transakce\" portfolio.pending.step5_buyer.bought=Koupili jste portfolio.pending.step5_buyer.paid=Zaplatili jste @@ -794,7 +819,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Už jste přijali portfolio.pending.failedTrade.taker.missingTakerFeeTx=Chybí poplatek příjemce transakce.\n\nBez tohoto tx nelze obchod dokončit. Nebyly uzamčeny žádné prostředky a nebyl zaplacen žádný obchodní poplatek. Tento obchod můžete přesunout do neúspěšných obchodů. portfolio.pending.failedTrade.maker.missingTakerFeeTx=Chybí poplatek příjemce transakce.\n\nBez tohoto tx nelze obchod dokončit. Nebyly uzamčeny žádné prostředky. Vaše nabídka je stále k dispozici dalším obchodníkům, takže jste neztratili poplatek za vytvoření. Tento obchod můžete přesunout do neúspěšných obchodů. portfolio.pending.failedTrade.missingDepositTx=Vkladová transakce (transakce 2-of-2 multisig) chybí.\n\nBez tohoto tx nelze obchod dokončit. Nebyly uzamčeny žádné prostředky, ale byl zaplacen váš obchodní poplatek. Zde můžete požádat o vrácení obchodního poplatku: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nKlidně můžete přesunout tento obchod do neúspěšných obchodů. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Odložená výplatní transakce chybí, ale prostředky byly uzamčeny v vkladové transakci.\n\nNezasílejte prosím fiat nebo crypto platbu prodejci BTC, protože bez odložené platby tx nelze zahájit arbitráž. Místo toho otevřete mediační úkol pomocí Cmd/Ctrl+o. Mediátor by měl navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Tímto způsobem nehrozí žádné bezpečnostní riziko a jsou ztraceny pouze obchodní poplatky.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Odložená výplatní transakce chybí, ale prostředky byly uzamčeny v vkladové transakci.\n\nNezasílejte prosím fiat nebo crypto platbu prodejci XMR, protože bez odložené platby tx nelze zahájit arbitráž. Místo toho otevřete mediační úkol pomocí Cmd/Ctrl+o. Mediátor by měl navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Tímto způsobem nehrozí žádné bezpečnostní riziko a jsou ztraceny pouze obchodní poplatky.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=Odložená výplatní transakce chybí, ale prostředky byly v depozitní transakci uzamčeny.\n\nPokud kupujícímu chybí také odložená výplatní transakce, bude poučen, aby platbu NEPOSLAL a místo toho otevřel mediační úkol. Měli byste také otevřít mediační úkol pomocí Cmd/Ctrl+o.\n\nPokud kupující ještě neposlal platbu, měl by zprostředkovatel navrhnout, aby oba partneři dostali zpět celou částku svých bezpečnostních vkladů (přičemž prodejce také obdrží plnou částku obchodu). Jinak by částka obchodu měla jít kupujícímu.\n\nO vrácení ztracených obchodních poplatků můžete požádat zde: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=Během provádění obchodního protokolu došlo k chybě.\n\nChyba: {0}\n\nJe možné, že tato chyba není kritická a obchod lze dokončit normálně. Pokud si nejste jisti, otevřete si mediační úkol a získejte radu od mediátorů Haveno.\n\nPokud byla chyba kritická a obchod nelze dokončit, možná jste ztratili obchodní poplatek. O vrácení ztracených obchodních poplatků požádejte zde: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=Obchodní kontrakt není stanoven.\n\nObchod nelze dokončit a možná jste ztratili poplatek za obchodování. Pokud ano, můžete požádat o vrácení ztracených obchodních poplatků zde: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +858,7 @@ funds.deposit.fundHavenoWallet=Financovat Haveno peněženku funds.deposit.noAddresses=Dosud nebyly vygenerovány žádné adresy pro vklad funds.deposit.fundWallet=Financujte svou peněženku funds.deposit.withdrawFromWallet=Pošlete peníze z peněženky -funds.deposit.amount=Částka v BTC (volitelná) +funds.deposit.amount=Částka v XMR (volitelná) funds.deposit.generateAddress=Vygenerujte novou adresu funds.deposit.generateAddressSegwit=Nativní formát segwit (Bech32) funds.deposit.selectUnused=Vyberte prosím nepoužívanou adresu z výše uvedené tabulky místo generování nové. @@ -890,7 +915,7 @@ funds.tx.revert=Vrátit funds.tx.txSent=Transakce byla úspěšně odeslána na novou adresu v lokální peněžence Haveno. funds.tx.direction.self=Posláno sobě funds.tx.dustAttackTx=Přijaté drobné -funds.tx.dustAttackTx.popup=Tato transakce odesílá do vaší peněženky velmi malou částku BTC a může se jednat o pokus společností provádějících analýzu blockchainu o špehování vaší peněženky.\n\nPoužijete-li tento transakční výstup ve výdajové transakci, zjistí, že jste pravděpodobně také vlastníkem jiné adresy (sloučení mincí).\n\nKvůli ochraně vašeho soukromí ignoruje peněženka Haveno takové drobné výstupy pro účely utrácení a na obrazovce zůstatku. Můžete nastavit hodnotu "drobnosti", kdy je výstup považován za drobné, v nastavení. +funds.tx.dustAttackTx.popup=Tato transakce odesílá do vaší peněženky velmi malou částku XMR a může se jednat o pokus společností provádějících analýzu blockchainu o špehování vaší peněženky.\n\nPoužijete-li tento transakční výstup ve výdajové transakci, zjistí, že jste pravděpodobně také vlastníkem jiné adresy (sloučení mincí).\n\nKvůli ochraně vašeho soukromí ignoruje peněženka Haveno takové drobné výstupy pro účely utrácení a na obrazovce zůstatku. Můžete nastavit hodnotu "drobnosti", kdy je výstup považován za drobné, v nastavení. #################################################################### # Support @@ -904,7 +929,7 @@ support.filter=Hledat spory support.filter.prompt=Zadejte ID obchodu, datum, onion adresu nebo údaje o účtu support.sigCheck.button=Ověřit podpis -support.sigCheck.popup.info=V případě žádosti o vrácení peněz DAO musíte vložit souhrnnou zprávu procesu zprostředkování a rozhodčího řízení do své žádosti o vrácení peněz na Githubu. Aby bylo toto prohlášení ověřitelné, může každý uživatel pomocí tohoto nástroje zkontrolovat, zda se podpis mediátora nebo rozhodce shoduje se souhrnnou zprávou. +support.sigCheck.popup.info=Vložte souhrnnou zprávu procesu zprostředkování. S tímto nástrojem může každý uživatel zkontrolovat, zda se podpis zprostředkovatele shoduje se souhrnnou zprávou. support.sigCheck.popup.header=Ověřit podpis výsledku sporu support.sigCheck.popup.msg.label=Souhrnná zpráva support.sigCheck.popup.msg.prompt=Zkopírovat a vložit souhrnnou zprávu ze sporu @@ -940,8 +965,8 @@ support.savedInMailbox=Zpráva uložena ve schránce příjemce support.arrived=Zpráva dorazila k příjemci support.acknowledged=Přijetí zprávy potvrzeno příjemcem support.error=Příjemce nemohl zpracovat zprávu. Chyba: {0} -support.buyerAddress=Adresa kupujícího BTC -support.sellerAddress=Adresa prodejce BTC +support.buyerAddress=Adresa kupujícího XMR +support.sellerAddress=Adresa prodejce XMR support.role=Role support.agent=Agent podpory support.state=Stav @@ -949,13 +974,13 @@ support.chat=Chat support.closed=Zavřeno support.open=Otevřené support.process=Rozhodnout -support.buyerMaker=Kupující BTC/Tvůrce -support.sellerMaker=Prodejce BTC/Tvůrce -support.buyerTaker=Kupující BTC/Příjemce -support.sellerTaker=Prodávající BTC/Příjemce +support.buyerMaker=Kupující XMR/Tvůrce +support.sellerMaker=Prodejce XMR/Tvůrce +support.buyerTaker=Kupující XMR/Příjemce +support.sellerTaker=Prodávající XMR/Příjemce -support.backgroundInfo=Haveno není společnost, takže spory řeší jinak.\n\nObchodníci mohou v rámci aplikace komunikovat prostřednictvím zabezpečeného chatu na obrazovce otevřených obchodů a zkusit řešení sporů sami. Pokud to nestačí, může jim pomoci mediátor. Mediátor vyhodnotí situaci a navrhne vyúčtování obchodních prostředků. Pokud oba obchodníci přijmou tento návrh, je výplata dokončena a obchod je uzavřen. Pokud jeden nebo oba obchodníci nesouhlasí s výplatou navrhovanou mediátorem, mohou požádat o rozhodčí řízení. Rozhodce přehodnotí situaci a v odůvodněných případech vrátí osobně prostředky obchodníkovi zpět a požádá o vrácení této platby od Haveno DAO. -support.initialInfo=Do níže uvedeného textového pole zadejte popis problému. Přidejte co nejvíce informací k urychlení doby řešení sporu.\n\nZde je kontrolní seznam informací, které byste měli poskytnout:\n\t● Pokud kupujete BTC: Provedli jste převod Fiat nebo Cryptou? Pokud ano, klikli jste v aplikaci na tlačítko „Platba zahájena“?\n\t● Pokud jste prodejcem BTC: Obdrželi jste platbu Fiat nebo Cryptou? Pokud ano, klikli jste v aplikaci na tlačítko „Platba přijata“?\n\t● Kterou verzi Haveno používáte?\n\t● Jaký operační systém používáte?\n\t● Pokud se vyskytl problém s neúspěšnými transakcemi, zvažte přechod na nový datový adresář.\n\t Někdy dojde k poškození datového adresáře a vede to k podivným chybám.\n\t Viz: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nSeznamte se prosím se základními pravidly procesu sporu:\n\t● Musíte odpovědět na požadavky {0} do 2 dnů.\n\t● Mediátoři reagují do 2 dnů. Rozhodci odpoví do 5 pracovních dnů.\n\t● Maximální doba sporu je 14 dní.\n\t● Musíte spolupracovat s {1} a poskytnout informace, které požaduje, aby jste vyřešili váš případ.\n\t● Při prvním spuštění aplikace jste přijali pravidla uvedena v dokumentu sporu v uživatelské smlouvě.\n\nDalší informace o procesu sporu naleznete na: {2} +support.backgroundInfo=Haveno není společnost, takže spory řeší jinak.\n\nObchodníci mohou v rámci aplikace komunikovat prostřednictvím zabezpečeného chatu na obrazovce otevřených obchodů a pokusit se o řešení sporů sami. Pokud to nestačí, arbitr rozhodne o situaci a určí výplatu obchodních prostředků. +support.initialInfo=Do níže uvedeného textového pole zadejte popis problému. Přidejte co nejvíce informací k urychlení doby řešení sporu.\n\nZde je kontrolní seznam informací, které byste měli poskytnout:\n\t● Pokud kupujete XMR: Provedli jste převod Fiat nebo Cryptou? Pokud ano, klikli jste v aplikaci na tlačítko „Platba zahájena“?\n\t● Pokud jste prodejcem XMR: Obdrželi jste platbu Fiat nebo Cryptou? Pokud ano, klikli jste v aplikaci na tlačítko „Platba přijata“?\n\t● Kterou verzi Haveno používáte?\n\t● Jaký operační systém používáte?\n\t● Pokud se vyskytl problém s neúspěšnými transakcemi, zvažte přechod na nový datový adresář.\n\t Někdy dojde k poškození datového adresáře a vede to k podivným chybám.\n\t Viz: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nSeznamte se prosím se základními pravidly procesu sporu:\n\t● Musíte odpovědět na požadavky {0} do 2 dnů.\n\t● Mediátoři reagují do 2 dnů. Rozhodci odpoví do 5 pracovních dnů.\n\t● Maximální doba sporu je 14 dní.\n\t● Musíte spolupracovat s {1} a poskytnout informace, které požaduje, aby jste vyřešili váš případ.\n\t● Při prvním spuštění aplikace jste přijali pravidla uvedena v dokumentu sporu v uživatelské smlouvě.\n\nDalší informace o procesu sporu naleznete na: {2} support.systemMsg=Systémová zpráva: {0} support.youOpenedTicket=Otevřeli jste žádost o podporu.\n\n{0}\n\nVerze Haveno: {1} support.youOpenedDispute=Otevřeli jste žádost o spor.\n\n{0}\n\nVerze Haveno: {1} @@ -979,13 +1004,14 @@ settings.tab.network=Informace o síti settings.tab.about=O Haveno setting.preferences.general=Základní nastavení -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Max. odchylka od tržní ceny setting.preferences.avoidStandbyMode=Vyhněte se pohotovostnímu režimu +setting.preferences.useSoundForNotifications=Přehrávat zvuky pro upozornění setting.preferences.autoConfirmXMR=Automatické potvrzení XMR setting.preferences.autoConfirmEnabled=Povoleno setting.preferences.autoConfirmRequiredConfirmations=Požadovaná potvrzení -setting.preferences.autoConfirmMaxTradeSize=Max. částka obchodu (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. částka obchodu (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URL (používá Tor, kromě localhost, LAN IP adres a názvů hostitele *.local) setting.preferences.deviationToLarge=Hodnoty vyšší než {0} % nejsou povoleny. setting.preferences.txFee=Poplatek za výběr transakce (satoshi/vbyte) @@ -999,8 +1025,8 @@ setting.preferences.prefCurrency=Preferovaná měna setting.preferences.displayTraditional=Zobrazit národní měny setting.preferences.noTraditional=Nejsou vybrány žádné národní měny setting.preferences.cannotRemovePrefCurrency=Vybranou zobrazovanou měnu nelze odebrat. -setting.preferences.displayCryptos=Zobrazit cryptoy -setting.preferences.noCryptos=Nejsou vybrány žádné cryptoy +setting.preferences.displayCryptos=Zobrazit kryptoměny +setting.preferences.noCryptos=Nejsou vybrány žádné kryptoměny setting.preferences.addTraditional=Přidejte národní měnu setting.preferences.addCrypto=Přidejte crypto setting.preferences.displayOptions=Zobrazit možnosti @@ -1022,29 +1048,31 @@ settings.preferences.editCustomExplorer.name=Jméno settings.preferences.editCustomExplorer.txUrl=Transakční URL settings.preferences.editCustomExplorer.addressUrl=Adresa URL -settings.net.btcHeader=Bitcoinová síť +settings.net.xmrHeader=Síť Monero settings.net.p2pHeader=Síť Haveno settings.net.onionAddressLabel=Moje onion adresa -settings.net.xmrNodesLabel=Použijte vlastní Monero node +settings.net.xmrNodesLabel=Použijte vlastní Monero uzel settings.net.moneroPeersLabel=Připojené peer uzly +settings.net.connection=Připojení +settings.net.connected=Připojeno settings.net.useTorForXmrJLabel=Použít Tor pro Monero síť -settings.net.moneroNodesLabel=Monero nody, pro připojení -settings.net.useProvidedNodesRadio=Použijte nabízené Bitcoin Core nody -settings.net.usePublicNodesRadio=Použít veřejnou Bitcoinovou síť -settings.net.useCustomNodesRadio=Použijte vlastní Bitcoin Core node -settings.net.warn.usePublicNodes=Pokud používáte veřejné Monero nody, jste vystaveni riziku spojenému s používáním nedůvěryhodných vzdálených nodů.\n\nProsím, přečtěte si více podrobností na [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nJste si jistí, že chcete použít veřejné nody? -settings.net.warn.usePublicNodes.useProvided=Ne, použijte nabízené nody +settings.net.moneroNodesLabel=Monero uzly, pro připojení +settings.net.useProvidedNodesRadio=Použijte nabízené Monero Core uzly +settings.net.usePublicNodesRadio=Použít veřejnou síť Monero +settings.net.useCustomNodesRadio=Použijte vlastní Monero Core uzel +settings.net.warn.usePublicNodes=Pokud používáte veřejné Monero uzly, jste vystaveni riziku spojenému s používáním nedůvěryhodných vzdálených uzlů.\n\nProsím, přečtěte si více podrobností na [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nJste si jistí, že chcete použít veřejné uzly? +settings.net.warn.usePublicNodes.useProvided=Ne, použijte nabízené uzly settings.net.warn.usePublicNodes.usePublic=Ano, použít veřejnou síť -settings.net.warn.useCustomNodes.B2XWarning=Ujistěte se, že váš bitcoinový node je důvěryhodný Bitcoin Core node!\n\nPřipojení k nodům, které nedodržují pravidla konsensu Bitcoin Core, může poškodit vaši peněženku a způsobit problémy v obchodním procesu.\n\nUživatelé, kteří se připojují k nodům, které porušují pravidla konsensu, odpovídají za případné škody, které z toho vyplývají. Jakékoli výsledné spory budou rozhodnuty ve prospěch druhého obchodníka. Uživatelům, kteří ignorují tyto varovné a ochranné mechanismy, nebude poskytována technická podpora! -settings.net.warn.invalidBtcConfig=Připojení k bitcoinové síti selhalo, protože je vaše konfigurace neplatná.\n\nVaše konfigurace byla resetována, aby se místo toho použily poskytnuté bitcoinové uzly. Budete muset restartovat aplikaci. -settings.net.localhostXmrNodeInfo=Základní informace: Haveno při spuštění hledá místní Bitcoinový uzel. Pokud je nalezen, Haveno bude komunikovat se sítí Bitcoin výhradně skrze něj. +settings.net.warn.useCustomNodes.B2XWarning=Ujistěte se, že váš Monero uzel je důvěryhodný Monero Core uzel!\n\nPřipojení k uzlům, které nedodržují pravidla konsensu Monero Core, může poškodit vaši peněženku a způsobit problémy v obchodním procesu.\n\nUživatelé, kteří se připojují k uzlům, které porušují pravidla konsensu, odpovídají za případné škody, které z toho vyplývají. Jakékoli výsledné spory budou rozhodnuty ve prospěch druhého obchodníka. Uživatelům, kteří ignorují tyto varovné a ochranné mechanismy, nebude poskytována technická podpora! +settings.net.warn.invalidXmrConfig=Připojení k síti Monero selhalo, protože je vaše konfigurace neplatná.\n\nVaše konfigurace byla resetována, aby byly místo toho použity poskytnuté uzly Monero. Budete muset restartovat aplikaci. +settings.net.localhostXmrNodeInfo=Základní informace: Haveno při spuštění hledá místní Monero uzel. Pokud je nalezen, Haveno bude komunikovat se sítí Monero výhradně skrze něj. settings.net.p2PPeersLabel=Připojené uzly settings.net.onionAddressColumn=Onion adresa settings.net.creationDateColumn=Založeno settings.net.connectionTypeColumn=Příchozí/Odchozí settings.net.sentDataLabel=Statistiky odeslaných dat settings.net.receivedDataLabel=Statistiky přijatých dat -settings.net.chainHeightLabel=Poslední výška bloku BTC +settings.net.chainHeightLabel=Poslední výška bloku XMR settings.net.roundTripTimeColumn=Roundtrip settings.net.sentBytesColumn=Odesláno settings.net.receivedBytesColumn=Přijato @@ -1059,16 +1087,16 @@ settings.net.needRestart=Chcete-li použít tuto změnu, musíte restartovat apl settings.net.notKnownYet=Není dosud známo... settings.net.sentData=Odeslaná data: {0}, {1} zprávy, {2} zprávy/sekundu settings.net.receivedData=Přijatá data: {0}, {1} zprávy, {2} zprávy/sekundu -settings.net.chainHeight=Bitcoin Peers: {0} +settings.net.chainHeight=Monero Peers: {0} settings.net.ips=[IP adresa:port | název hostitele:port | onion adresa:port] (oddělené čárkou). Pokud je použit výchozí port (8333), lze port vynechat. -settings.net.seedNode=Seed node +settings.net.seedNode=Seed uzel settings.net.directPeer=Peer uzel (přímý) settings.net.initialDataExchange={0} [Bootstrapping] settings.net.peer=Peer settings.net.inbound=příchozí settings.net.outbound=odchozí setting.about.aboutHaveno=O projektu Haveno -setting.about.about=Haveno je software s otevřeným zdrojovým kódem, který usnadňuje směnu bitcoinů s národními měnami (a jinými kryptoměnami) prostřednictvím decentralizované sítě typu peer-to-peer způsobem, který silně chrání soukromí uživatelů. Zjistěte více o Haveno na naší webové stránce projektu. +setting.about.about=Haveno je software s otevřeným zdrojovým kódem, který usnadňuje směnu moneroů s národními měnami (a jinými kryptoměnami) prostřednictvím decentralizované sítě typu peer-to-peer způsobem, který silně chrání soukromí uživatelů. Zjistěte více o Haveno na naší webové stránce projektu. setting.about.web=Webová stránka Haveno setting.about.code=Zdrojový kód setting.about.agpl=AGPL Licence @@ -1105,7 +1133,7 @@ setting.about.shortcuts.openDispute.value=Vyberte nevyřízený obchod a klikně setting.about.shortcuts.walletDetails=Otevřít okno s podrobností peněženky -setting.about.shortcuts.openEmergencyBtcWalletTool=Otevřít nástroj nouzové peněženky pro BTC peněženku +setting.about.shortcuts.openEmergencyXmrWalletTool=Otevřít nástroj nouzové peněženky pro XMR peněženku setting.about.shortcuts.showTorLogs=Přepnout úroveň protokolu pro zprávy Tor mezi DEBUG a WARN @@ -1131,7 +1159,7 @@ setting.about.shortcuts.sendPrivateNotification=Odeslat soukromé oznámení par setting.about.shortcuts.sendPrivateNotification.value=Otevřete informace o uživateli kliknutím na avatar a stiskněte: {0} setting.info.headline=Nová funkce automatického potvrzení XMR -setting.info.msg=Při prodeji BTC za XMR můžete pomocí funkce automatického potvrzení ověřit, že do vaší peněženky bylo odesláno správné množství XMR, takže Haveno může automaticky označit obchod jako dokončený, což zrychlí obchodování pro všechny.\n\nAutomatické potvrzení zkontroluje transakci XMR alespoň na 2 uzlech průzkumníka XMR pomocí klíče soukromé transakce poskytnutého odesílatelem XMR. Ve výchozím nastavení používá Haveno uzly průzkumníka spuštěné přispěvateli Haveno, ale pro maximální soukromí a zabezpečení doporučujeme spustit vlastní uzel průzkumníka XMR.\n\nMůžete také nastavit maximální částku BTC na obchod, která se má automaticky potvrdit, a také počet požadovaných potvrzení zde v Nastavení.\n\nZobrazit další podrobnosti (včetně toho, jak nastavit vlastní uzel průzkumníka) na Haveno wiki: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=Při prodeji XMR za XMR můžete pomocí funkce automatického potvrzení ověřit, že do vaší peněženky bylo odesláno správné množství XMR, takže Haveno může automaticky označit obchod jako dokončený, což zrychlí obchodování pro všechny.\n\nAutomatické potvrzení zkontroluje transakci XMR alespoň na 2 uzlech průzkumníka XMR pomocí klíče soukromé transakce poskytnutého odesílatelem XMR. Ve výchozím nastavení používá Haveno uzly průzkumníka spuštěné přispěvateli Haveno, ale pro maximální soukromí a zabezpečení doporučujeme spustit vlastní uzel průzkumníka XMR.\n\nMůžete také nastavit maximální částku XMR na obchod, která se má automaticky potvrdit, a také počet požadovaných potvrzení zde v Nastavení.\n\nZobrazit další podrobnosti (včetně toho, jak nastavit vlastní uzel průzkumníka) na Haveno wiki: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,10 +1168,10 @@ account.tab.mediatorRegistration=Registrace mediátora account.tab.refundAgentRegistration=Registrace rozhodce pro vrácení peněz account.tab.signing=Podepisování account.info.headline=Vítejte ve vašem účtu Haveno -account.info.msg=Zde můžete přidat obchodní účty pro národní měny & cryptoy a vytvořit zálohu dat vaší peněženky a účtu.\n\nPři prvním spuštění Haveno byla vytvořena nová bitcoinová peněženka.\n\nDůrazně doporučujeme zapsat si seed slova bitcoinových peněženek (viz záložka nahoře) a před financováním zvážit přidání hesla. Vklady a výběry bitcoinů jsou spravovány v sekci \ "Finance \".\n\nOchrana osobních údajů a zabezpečení: protože Haveno je decentralizovaná směnárna, všechna data jsou uložena ve vašem počítači. Neexistují žádné servery, takže nemáme přístup k vašim osobním informacím, vašim finančním prostředkům ani vaší IP adrese. Údaje, jako jsou čísla bankovních účtů, adresy cryptoů a bitcoinu atd., jsou sdíleny pouze s obchodním partnerem za účelem uskutečnění obchodů, které zahájíte (v případě sporu uvidí Prostředník nebo Rozhodce stejná data jako váš obchodní partner). +account.info.msg=Zde můžete přidat obchodní účty pro národní měny & kryptoměny a vytvořit zálohu dat vaší peněženky a účtu.\n\nPři prvním spuštění Haveno byla vytvořena nová peněženka Monero.\n\nDůrazně doporučujeme zapsat si seed slova peněženek (viz záložka nahoře) a před financováním zvážit přidání hesla. Vklady a výběry moneroů jsou spravovány v sekci \ "Finance \".\n\nOchrana osobních údajů a zabezpečení: protože Haveno je decentralizovaná směnárna, všechna data jsou uložena ve vašem počítači. Neexistují žádné servery, takže nemáme přístup k vašim osobním informacím, vašim finančním prostředkům ani vaší IP adrese. Údaje, jako jsou čísla bankovních účtů, adresy cryptoů a monerou atd., jsou sdíleny pouze s obchodním partnerem za účelem uskutečnění obchodů, které zahájíte (v případě sporu uvidí Prostředník nebo Rozhodce stejná data jako váš obchodní partner). account.menu.paymentAccount=Účty v národní měně -account.menu.altCoinsAccountView=Cryptoové účty +account.menu.altCoinsAccountView=Kryptoměnové účty account.menu.password=Heslo peněženky account.menu.seedWords=Seed peněženky account.menu.walletInfo=Info o peněžence @@ -1151,7 +1179,7 @@ account.menu.backup=Záloha account.menu.notifications=Oznámení account.menu.walletInfo.balance.headLine=Zůstatky v peněžence -account.menu.walletInfo.balance.info=Zde jsou zobrazeny celkové zůstatky v interní peněžence včetně nepotvrzených transakcí.\nInterní zůstatek BTC uvedený níže by měl odpovídat součtu hodnot 'Dostupný zůstatek' a 'Rezervováno v nabídkách' v pravém horním rohu aplikace. +account.menu.walletInfo.balance.info=Zde jsou zobrazeny celkové zůstatky v interní peněžence včetně nepotvrzených transakcí.\nInterní zůstatek XMR uvedený níže by měl odpovídat součtu hodnot 'Dostupný zůstatek' a 'Rezervováno v nabídkách' v pravém horním rohu aplikace. account.menu.walletInfo.xpub.headLine=Veřejné klíče (xpub) account.menu.walletInfo.walletSelector={0} {1} peněženka account.menu.walletInfo.path.headLine=HD identifikátory klíčů @@ -1172,7 +1200,7 @@ account.arbitratorRegistration.removedFailed=Registraci se nepodařilo odebrat. account.arbitratorRegistration.registerSuccess=Úspěšně jste se zaregistrovali do sítě Haveno. account.arbitratorRegistration.registerFailed=Registraci se nepodařilo dokončit. {0} -account.crypto.yourCryptoAccounts=Vaše cryptoové účty +account.crypto.yourCryptoAccounts=Vaše kryptoměnové účty account.crypto.popup.wallet.msg=Ujistěte se, že dodržujete požadavky na používání peněženek {0}, jak je popsáno na webové stránce {1}.\nPoužití peněženek z centralizovaných směnáren, kde (a) nevlastníte své soukromé klíče nebo (b) které nepoužívají kompatibilní software peněženky, je riskantní: může to vést ke ztrátě obchodovaných prostředků!\nMediátor nebo rozhodce není specialista {2} a v takových případech nemůže pomoci. account.crypto.popup.wallet.confirm=Rozumím a potvrzuji, že vím, jakou peněženku musím použít. # suppress inspection "UnusedProperty" @@ -1180,7 +1208,7 @@ account.crypto.popup.upx.msg=Obchodování s UPX na Haveno vyžaduje, abyste poc # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Obchodování ARQ na Haveno vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání ARQ musíte použít buď oficiální peněženku ArQmA GUI nebo peněženku ArQmA CLI s povoleným příznakem store-tx-info (výchozí hodnota v nových verzích). Ujistěte se, že máte přístup ke klíči tx, který může být vyžadován v případě sporu.\narqma-wallet-cli (použijte příkaz get_tx_key)\narqma-wallet-gui (přejděte na kartu historie a pro potvrzení platby klikněte na tlačítko (P))\n\nV normálním blok exploreru není přenos ověřitelný.\n\nV případě sporu musíte mediátorovi nebo rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresu příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke prohrání sporu. Odesílatel ARQ odpovídá za zajištění ověření převodu ARQ mediátorovi nebo rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, navštivte discord kanál ArQmA (https://discord.gg/s9BQpJT) nebo fórum ArQmA (https://labs.arqma.com). # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Obchodování s XMR na Haveno vyžaduje, abyste pochopili následující požadavek.\n\nPokud prodáváte XMR, musíte být schopni v případě sporu poskytnout mediátorovi nebo rozhodci následující informace:\n- transakční klíč (Tx klíč, Tx tajný klíč nebo Tx soukromý klíč)\n- ID transakce (Tx ID nebo Tx Hash)\n- cílová adresa (adresa příjemce)\n\nNa wiki najdete podrobnosti, kde najdete tyto informace v populárních peněženkách Monero:\n[HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\n\nNeposkytnutí požadovaných údajů o transakci bude mít za následek ztrátu sporů.\n\nVšimněte si také, že Haveno nyní nabízí automatické potvrzení transakcí XMR, aby byly obchody rychlejší, ale musíte to povolit v Nastavení.\n\nDalší informace o funkci automatického potvrzení najdete na wiki:\n[HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Obchodování s XMR na Haveno vyžaduje, abyste pochopili následující požadavek.\n\nPokud prodáváte XMR, musíte být schopni v případě sporu poskytnout mediátorovi nebo rozhodci následující informace:\n- transakční klíč (Tx klíč, Tx tajný klíč nebo Tx soukromý klíč)\n- ID transakce (Tx ID nebo Tx Hash)\n- cílová adresa (adresa příjemce)\n\nNa wiki najdete podrobnosti, kde najdete tyto informace v populárních peněženkách Monero:\n[HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\n\nNeposkytnutí požadovaných údajů o transakci bude mít za následek ztrátu sporů.\n\nVšimněte si také, že Haveno nyní nabízí automatické potvrzení transakcí XMR, aby byly obchody rychlejší, ale musíte to povolit v Nastavení.\n\nDalší informace o funkci automatického potvrzení najdete na wiki:\n[HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Obchodování MSR na Haveno vyžaduje, abyste pochopili a splnili následující požadavky:\n\nK odeslání MSR musíte použít buď oficiální peněženku Masari GUI, peněženku Masari CLI s povoleným příznakem store-tx-info (ve výchozím nastavení povoleno) nebo webovou peněženku Masari (https://wallet.getmasari.org). Ujistěte se, že máte přístup ke klíči tx, který může být vyžadován v případě sporu.\nmasari-wallet-cli (použijte příkaz get_tx_key)\nmasari-wallet-gui (přejděte na kartu historie a klikněte na tlačítko (P) pro potvrzení platby)\n\nWebová peněženka Masari (jděte do Účet -> Historie transakcí a zobrazte podrobností o odeslané transakci)\n\nOvěření lze provést v peněžence.\nmasari-wallet-cli: pomocí příkazu (check_tx_key).\nmasari-wallet-gui: na stránce Pokročilé > Dokázat/Ověřit.\nOvěření lze provést v block exploreru\nOtevřete Block explorer (https://explorer.getmasari.org), použijte vyhledávací lištu k nalezení hash transakce.\nJakmile je transakce nalezena, přejděte dolů do oblasti „Prokázat odesílání“ a podle potřeby vyplňte podrobnosti.\nV případě sporu musíte zprostředkovateli nebo rozhodci poskytnout následující údaje:\n- Soukromý klíč tx\n- Hash transakce\n- Veřejnou adresu příjemce\n\nPokud neposkytnete výše uvedená data nebo použijete nekompatibilní peněženku, dojde ke ztrátě sporu. Odesílatel MSR odpovídá za zajištění ověření přenosu MSR mediátorovi nebo rozhodci v případě sporu.\n\nNení požadováno žádné platební ID, pouze normální veřejná adresa.\nPokud si nejste jisti tímto procesem, požádejte o pomoc oficiální Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1236,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin na Haveno vyžaduje, abyste poch account.crypto.popup.blk-burnt.msg=Chcete-li obchodovat s burnt blackcoiny, musíte znát následující:\n\nBurnt blackcoiny jsou nevyčerpatelné. Aby je bylo možné obchodovat na Haveno, musí mít výstupní skripty podobu: OP_RETURN OP_PUSHDATA, následované přidruženými datovými bajty, které po hexadecimálním zakódování tvoří adresy. Například Burnt blackcoiny s adresou 666f6f („foo“ v UTF-8) budou mít následující skript:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nPro vytvoření Burnt blackcoinů lze použít příkaz „burn“ RPC, který je k dispozici v některých peněženkách.\n\nPro možné případy použití se můžete podívat na https://ibo.laboratorium.ee.\n\nVzhledem k tomu, že Burnt blackcoiny jsou nevyčerpatelné, nelze je znovu prodat. „Prodej“ Burnt blackcoinů znamená vypalování běžných blackcoinů (s přidruženými údaji rovnými cílové adrese).\n\nV případě sporu musí prodejce BLK poskytnout hash transakce. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Obchodování s L-BTC na Haveno vyžaduje, abyste pochopili následující skutečnosti:\n\nKdyž přijímáte L-BTC za obchod na Haveno, nemůžete použít mobilní peněženku Green od Blockstreamu ani jinou custodial peněženku nebo peněženku na burze. L-BTC musíte přijmout pouze do peněženky Liquid Elements Core nebo do jiné L-BTC peněženky, která vám umožní získat slepý klíč pro vaši slepou adresu L-BTC.\n\nV případě, že je nutné zprostředkování, nebo pokud dojde k obchodnímu sporu, musíte zprostředkujícímu mediátorovi Haveno nebo agentovi, který vrací peníze zaslat slepý klíč pro vaši L-BTC adresu, aby mohli ověřit podrobnosti vaší důvěrné transakce na svém vlastním Elements Core full-nodu.\n\nNeposkytnutí požadovaných informací zprostředkovateli nebo agentovi pro vrácení peněz povede ke prohrání sporu. Ve všech sporných případech nese příjemce L-BTC 100% břemeno odpovědnosti za poskytnutí kryptografického důkazu zprostředkovateli nebo agentovi pro vrácení peněz.\n\nPokud těmto požadavkům nerozumíte, neobchodujte s L-BTC na Haveno. +account.crypto.popup.liquidbitcoin.msg=Obchodování s L-XMR na Haveno vyžaduje, abyste pochopili následující skutečnosti:\n\nKdyž přijímáte L-XMR za obchod na Haveno, nemůžete použít mobilní peněženku Green od Blockstreamu ani jinou custodial peněženku nebo peněženku na burze. L-XMR musíte přijmout pouze do peněženky Liquid Elements Core nebo do jiné L-XMR peněženky, která vám umožní získat slepý klíč pro vaši slepou adresu L-XMR.\n\nV případě, že je nutné zprostředkování, nebo pokud dojde k obchodnímu sporu, musíte zprostředkujícímu mediátorovi Haveno nebo agentovi, který vrací peníze zaslat slepý klíč pro vaši L-XMR adresu, aby mohli ověřit podrobnosti vaší důvěrné transakce na svém vlastním Elements Core full-nodu.\n\nNeposkytnutí požadovaných informací zprostředkovateli nebo agentovi pro vrácení peněz povede ke prohrání sporu. Ve všech sporných případech nese příjemce L-XMR 100% břemeno odpovědnosti za poskytnutí kryptografického důkazu zprostředkovateli nebo agentovi pro vrácení peněz.\n\nPokud těmto požadavkům nerozumíte, neobchodujte s L-XMR na Haveno. account.traditional.yourTraditionalAccounts=Vaše účty v národní měně @@ -1226,15 +1254,15 @@ account.password.removePw.button=Odstraňte heslo account.password.removePw.headline=Odstraňte ochranu peněženky pomocí hesla account.password.setPw.button=Nastavit heslo account.password.setPw.headline=Nastavte ochranu peněženky pomocí hesla -account.password.info=S ochranou pomocí hesla budete muset zadat heslo při spuštění aplikace, při výběru monera z vaší peněženky a při zobrazení vašich slov z klíčového základu. +account.password.info=S ochranou pomocí hesla budete muset zadat heslo při spuštění aplikace, při výběru monera z vaší peněženky a při zobrazení slov seedu peněženky. -account.seed.backup.title=Zálohujte si seed slova peněženky -account.seed.info=Napište prosím seed slova peněženky a datum! Peněženku můžete kdykoli obnovit pomocí seed slov a datumu.\nStejná seed slova se používají pro peněženku BTC a BSQ.\n\nMěli byste si zapsat seed slova na list papíru. Neukládejte je do počítače.\n\nUpozorňujeme, že seed slova NEJSOU náhradou za zálohu.\nChcete-li obnovit stav a data aplikace, musíte vytvořit zálohu celého adresáře aplikace z obrazovky \"Účet/Záloha\".\nImport seed slov se doporučuje pouze v naléhavých případech. Aplikace nebude funkční bez řádného zálohování databázových souborů a klíčů! -account.seed.backup.warning=Pamatujte, že seed slova NEJSOU náhradou za zálohu.\nChcete-li obnovit stav a data aplikace, musíte z obrazovky \"Účet/Záloha\" vytvořit zálohu celého adresáře aplikace.\nImport seed slov se doporučuje pouze v naléhavých případech. Bez řádného zálohování databázových souborů a klíčů nebude aplikace funkční!\n\nDalší informace najdete na wiki stránce [HYPERLINK:https://bisq.wiki/Backing_up_application_data]. +account.seed.backup.title=Zálohujte svá klíčová slova peněženky. +account.seed.info=Prosím, zapište si jak klíčová slova peněženky, tak datum. Kdykoliv můžete obnovit svou peněženku pomocí klíčových slov a data.\n\nKlíčová slova byste měli zapsat na kus papíru. Neukládejte je na počítač.\n\nVezměte prosím na vědomí, že klíčová slova NEJSOU náhradou za zálohu.\nMusíte vytvořit zálohu celého adresáře aplikace z obrazovky "Účet/Záloha", abyste mohli obnovit stav a data aplikace. +account.seed.backup.warning=Prosím, poznamenejte si, že klíčová slova nejsou náhradou za zálohu.\nMusíte vytvořit zálohu celého adresáře aplikace z obrazovky "Účet/Záloha", abyste mohli obnovit stav a data aplikace. account.seed.warn.noPw.msg=Nenastavili jste si heslo k peněžence, které by chránilo zobrazení seed slov.\n\nChcete zobrazit seed slova? account.seed.warn.noPw.yes=Ano, a už se mě znovu nezeptat account.seed.enterPw=Chcete-li zobrazit seed slova, zadejte heslo -account.seed.restore.info=Před použitím obnovení ze seed slov si vytvořte zálohu. Uvědomte si, že obnova peněženky je pouze pro naléhavé případy a může způsobit problémy s interní databází peněženky.\nNení to způsob, jak použít zálohu! K obnovení předchozího stavu aplikace použijte zálohu z adresáře dat aplikace.\n\nPo obnovení se aplikace automaticky vypne. Po restartování aplikace se bude znovu synchronizovat s bitcoinovou sítí. To může chvíli trvat a může spotřebovat hodně CPU, zejména pokud byla peněženka starší a měla mnoho transakcí. Vyhněte se přerušování tohoto procesu, jinak budete možná muset znovu odstranit soubor řetězu SPV nebo opakovat proces obnovy. +account.seed.restore.info=Před použitím obnovení ze seed slov si vytvořte zálohu. Uvědomte si, že obnova peněženky je pouze pro naléhavé případy a může způsobit problémy s interní databází peněženky.\nNení to způsob, jak použít zálohu! K obnovení předchozího stavu aplikace použijte zálohu z adresáře dat aplikace.\n\nPo obnovení se aplikace automaticky vypne. Po restartování aplikace se bude znovu synchronizovat se sítí Monero. To může chvíli trvat a může spotřebovat hodně CPU, zejména pokud byla peněženka starší a měla mnoho transakcí. Vyhněte se přerušování tohoto procesu, jinak budete možná muset znovu odstranit soubor řetězu SPV nebo opakovat proces obnovy. account.seed.restore.ok=Dobře, proveďte obnovu a vypněte Haveno @@ -1259,13 +1287,13 @@ account.notifications.trade.label=Dostávat zprávy o obchodu account.notifications.market.label=Dostávat upozornění na nabídky account.notifications.price.label=Dostávat upozornění o cenách account.notifications.priceAlert.title=Cenová upozornění -account.notifications.priceAlert.high.label=Upozorněte, pokud bude cena BTC nad -account.notifications.priceAlert.low.label=Upozorněte, pokud bude cena BTC pod +account.notifications.priceAlert.high.label=Upozorněte, pokud bude cena XMR nad +account.notifications.priceAlert.low.label=Upozorněte, pokud bude cena XMR pod account.notifications.priceAlert.setButton=Nastavit upozornění na cenu account.notifications.priceAlert.removeButton=Odstraňte upozornění na cenu account.notifications.trade.message.title=Obchodní stav se změnil account.notifications.trade.message.msg.conf=Vkladová transakce pro obchod s ID {0} je potvrzena. Otevřete prosím svou aplikaci Haveno a začněte s platbou. -account.notifications.trade.message.msg.started=Kupující BTC zahájil platbu za obchod s ID {0}. +account.notifications.trade.message.msg.started=Kupující XMR zahájil platbu za obchod s ID {0}. account.notifications.trade.message.msg.completed=Obchod s ID {0} je dokončen. account.notifications.offer.message.title=Vaše nabídka byla přijata account.notifications.offer.message.msg=Vaše nabídka s ID {0} byla přijata @@ -1275,10 +1303,10 @@ account.notifications.dispute.message.msg=Obdrželi jste zprávu o sporu pro obc account.notifications.marketAlert.title=Upozornění na nabídku account.notifications.marketAlert.selectPaymentAccount=Nabídky odpovídající platebnímu účtu account.notifications.marketAlert.offerType.label=Typ nabídky, o kterou mám zájem -account.notifications.marketAlert.offerType.buy=Nákupní nabídky (Chci prodat BTC) -account.notifications.marketAlert.offerType.sell=Prodejní nabídky (Chci si koupit BTC) +account.notifications.marketAlert.offerType.buy=Nákupní nabídky (Chci prodat XMR) +account.notifications.marketAlert.offerType.sell=Prodejní nabídky (Chci si koupit XMR) account.notifications.marketAlert.trigger=Nabídková cenová vzdálenost (%) -account.notifications.marketAlert.trigger.info=Když je nastavena cenová vzdálenost, obdržíte upozornění pouze v případě, že je zveřejněna nabídka, která splňuje (nebo překračuje) vaše požadavky. Příklad: chcete prodat BTC, ale budete prodávat pouze s 2% přirážkou k aktuální tržní ceně. Nastavení tohoto pole na 2% zajistí, že budete dostávat upozornění pouze na nabídky s cenami, které jsou o 2% (nebo více) nad aktuální tržní cenou. +account.notifications.marketAlert.trigger.info=Když je nastavena cenová vzdálenost, obdržíte upozornění pouze v případě, že je zveřejněna nabídka, která splňuje (nebo překračuje) vaše požadavky. Příklad: chcete prodat XMR, ale budete prodávat pouze s 2% přirážkou k aktuální tržní ceně. Nastavení tohoto pole na 2% zajistí, že budete dostávat upozornění pouze na nabídky s cenami, které jsou o 2% (nebo více) nad aktuální tržní cenou. account.notifications.marketAlert.trigger.prompt=Procentní vzdálenost od tržní ceny (např. 2,50%, -0,50% atd.) account.notifications.marketAlert.addButton=Přidat upozornění na nabídku account.notifications.marketAlert.manageAlertsButton=Spravovat upozornění na nabídku @@ -1305,10 +1333,10 @@ inputControlWindow.balanceLabel=Dostupný zůstatek contractWindow.title=Podrobnosti o sporu contractWindow.dates=Datum nabídky / Datum obchodu -contractWindow.btcAddresses=Bitcoinová adresa kupujícího BTC / prodávajícího BTC -contractWindow.onions=Síťová adresa kupující BTC / prodávající BTC -contractWindow.accountAge=Stáří účtu BTC kupující / BTC prodejce -contractWindow.numDisputes=Počet sporů BTC kupující / BTC prodejce +contractWindow.xmrAddresses=Monero adresa kupujícího XMR / prodávajícího XMR +contractWindow.onions=Síťová adresa kupující XMR / prodávající XMR +contractWindow.accountAge=Stáří účtu XMR kupující / XMR prodejce +contractWindow.numDisputes=Počet sporů XMR kupující / XMR prodejce contractWindow.contractHash=Hash kontraktu displayAlertMessageWindow.headline=Důležitá informace! @@ -1334,8 +1362,8 @@ disputeSummaryWindow.title=Souhrn disputeSummaryWindow.openDate=Datum otevření úkolu disputeSummaryWindow.role=Role obchodníka disputeSummaryWindow.payout=Výplata částky obchodu -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} dostane výplatu částky obchodu -disputeSummaryWindow.payout.getsAll=BTC {0} dostane maximální výplatu +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} dostane výplatu částky obchodu +disputeSummaryWindow.payout.getsAll=XMR {0} dostane maximální výplatu disputeSummaryWindow.payout.custom=Vlastní výplata disputeSummaryWindow.payoutAmount.buyer=Výše výplaty kupujícího disputeSummaryWindow.payoutAmount.seller=Výše výplaty prodejce @@ -1377,7 +1405,7 @@ disputeSummaryWindow.close.button=Zavřít úkol # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket uzavřen {0}\n{1} adresa uzlu: {2}\n\nSouhrn:\nObchodní ID: {3}\nMěna: {4}\nVýše obchodu: {5}\nVýplatní částka pro kupujícího BTC: {6}\nVýplatní částka pro prodejce BTC: {7}\n\nDůvod sporu: {8}\n\nSouhrnné poznámky:\n{9}\n +disputeSummaryWindow.close.msg=Ticket uzavřen {0}\n{1} adresa uzlu: {2}\n\nSouhrn:\nObchodní ID: {3}\nMěna: {4}\nVýše obchodu: {5}\nVýplatní částka pro kupujícího XMR: {6}\nVýplatní částka pro prodejce XMR: {7}\n\nDůvod sporu: {8}\n\nSouhrnné poznámky:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1418,20 +1446,20 @@ filterWindow.bannedPrivilegedDevPubKeys=Filtrované privilegované klíče pub d filterWindow.arbitrators=Filtrovaní rozhodci (onion adresy oddělené čárkami) filterWindow.mediators=Filtrovaní mediátoři (onion adresy oddělené čárkami) filterWindow.refundAgents=Filtrovaní rozhodci pro vrácení peněz (onion adresy oddělené čárkami) -filterWindow.seedNode=Filtrované seed nody (onion adresy oddělené čárkami) -filterWindow.priceRelayNode=Filtrované cenové relay nody (onion adresy oddělené čárkami) -filterWindow.xmrNode=Filtrované Bitcoinové nody (adresy+porty oddělené čárkami) -filterWindow.preventPublicXmrNetwork=Zabraňte použití veřejné bitcoinové sítě +filterWindow.seedNode=Filtrované seed uzly (onion adresy oddělené čárkami) +filterWindow.priceRelayNode=Filtrované cenové relay uzly (onion adresy oddělené čárkami) +filterWindow.xmrNode=Filtrované uzly Monero (adresy+porty oddělené čárkami) +filterWindow.preventPublicXmrNetwork=Zabraňte použití veřejné sítě Monero filterWindow.disableAutoConf=Zakázat automatické potvrzení filterWindow.autoConfExplorers=Filtrované průzkumníky s automatickým potvrzením (adresy oddělené čárkami) filterWindow.disableTradeBelowVersion=Min. verze nutná pro obchodování filterWindow.add=Přidat filtr filterWindow.remove=Zrušit filtr -filterWindow.xmrFeeReceiverAddresses=Adresy příjemců poplatků BTC +filterWindow.xmrFeeReceiverAddresses=Adresy příjemců poplatků XMR filterWindow.disableApi=Deaktivovat API filterWindow.disableMempoolValidation=Deaktivovat validaci mempoolu -offerDetailsWindow.minBtcAmount=Min. částka BTC +offerDetailsWindow.minXmrAmount=Min. částka XMR offerDetailsWindow.min=(min. {0}) offerDetailsWindow.distance=(vzdálenost od tržní ceny: {0}) offerDetailsWindow.myTradingAccount=Můj obchodní účet @@ -1446,6 +1474,7 @@ offerDetailsWindow.confirm.maker=Potvrďte: Umístit nabídku {0} monero offerDetailsWindow.confirm.taker=Potvrďte: Využít nabídku {0} monero offerDetailsWindow.creationDate=Datum vzniku offerDetailsWindow.makersOnion=Onion adresa tvůrce +offerDetailsWindow.challenge=Passphrase nabídky qRCodeWindow.headline=QR Kód qRCodeWindow.msg=Použijte tento QR kód k financování vaší peněženky Haveno z vaší externí peněženky. @@ -1474,7 +1503,7 @@ showWalletDataWindow.walletData=Data peněženky showWalletDataWindow.includePrivKeys=Zahrnout soukromé klíče setXMRTxKeyWindow.headline=Prokázat odeslání XMR -setXMRTxKeyWindow.note=Přidání tx informací níže umožní automatické potvrzení pro rychlejší obchody. Zobrazit více: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Přidání tx informací níže umožní automatické potvrzení pro rychlejší obchody. Zobrazit více: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=ID transakce (volitelné) setXMRTxKeyWindow.txKey=Transakční klíč (volitelný) @@ -1486,7 +1515,7 @@ tacWindow.disagree=Nesouhlasím a odcházím tacWindow.arbitrationSystem=Řešení sporů tradeDetailsWindow.headline=Obchod -tradeDetailsWindow.disputedPayoutTxId=ID sporné platební transakce: +tradeDetailsWindow.disputedPayoutTxId=ID sporné platební transakce tradeDetailsWindow.tradeDate=Datum obchodu tradeDetailsWindow.txFee=Poplatek za těžbu tradeDetailsWindow.tradePeersOnion=Onion adresa obchodního partnera @@ -1496,8 +1525,10 @@ tradeDetailsWindow.agentAddresses=Rozhodce/Mediátor tradeDetailsWindow.detailData=Detailní data txDetailsWindow.headline=Detaily transakce -txDetailsWindow.xmr.note=Poslali jste BTC. +txDetailsWindow.xmr.noteSent=Poslali jste XMR. +txDetailsWindow.xmr.noteReceived=Obdrželi jste XMR. txDetailsWindow.sentTo=Odesláno na +txDetailsWindow.receivedWith=Přijato s txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Souhrn uzavřených obchodů @@ -1506,7 +1537,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} podle aktuální tržní ce closedTradesSummaryWindow.totalVolume.title=Celkový objem obchodovaný v {0} closedTradesSummaryWindow.totalMinerFee.title=Suma poplatků za těžbu closedTradesSummaryWindow.totalMinerFee.value={0} ({1} z celkového objemu obchodů) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Suma obchodních poplatků v BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Suma obchodních poplatků v XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} z celkového objemu obchodů) walletPasswordWindow.headline=Pro odemknutí zadejte heslo @@ -1532,12 +1563,12 @@ torNetworkSettingWindow.bridges.header=Je Tor blokovaný? torNetworkSettingWindow.bridges.info=Pokud je Tor zablokován vaším internetovým poskytovatelem nebo vaší zemí, můžete zkusit použít Tor mosty (bridges).\nNavštivte webovou stránku Tor na adrese: https://bridges.torproject.org/bridges, kde se dozvíte více o mostech a připojitelných přepravách. feeOptionWindow.headline=Vyberte měnu pro platbu obchodního poplatku -feeOptionWindow.info=Můžete si vybrat, zda chcete zaplatit obchodní poplatek v BSQ nebo v BTC. Pokud zvolíte BSQ, oceníte zlevněný obchodní poplatek. +feeOptionWindow.info=Můžete si vybrat, zda chcete zaplatit obchodní poplatek v BSQ nebo v XMR. Pokud zvolíte BSQ, oceníte zlevněný obchodní poplatek. feeOptionWindow.optionsLabel=Vyberte měnu pro platbu obchodního poplatku -feeOptionWindow.useBTC=Použít BTC +feeOptionWindow.useXMR=Použít XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1575,13 +1606,13 @@ popup.warning.startupFailed.twoInstances=Haveno již běží. Nemůžete spustit popup.warning.tradePeriod.halfReached=Váš obchod s ID {0} dosáhl poloviny max. povoleného obchodního období a stále není dokončen.\n\nObdobí obchodování končí {1}\n\nDalší informace o stavu obchodu naleznete na adrese \"Portfolio/Otevřené obchody\". popup.warning.tradePeriod.ended=Váš obchod s ID {0} dosáhl max. povoleného obchodního období a není dokončen.\n\nObdobí obchodování skončilo {1}\n\nZkontrolujte prosím svůj obchod v sekci "Portfolio/Otevřené obchody\", abyste kontaktovali mediátora. popup.warning.noTradingAccountSetup.headline=Nemáte nastaven obchodní účet -popup.warning.noTradingAccountSetup.msg=Než budete moci vytvořit nabídku, musíte si nastavit národní měnu nebo cryptoový účet.\nChcete si založit účet? +popup.warning.noTradingAccountSetup.msg=Než budete moci vytvořit nabídku, musíte si nastavit národní měnu nebo kryptoměnový účet.\nChcete si založit účet? popup.warning.noArbitratorsAvailable=Nejsou k dispozici žádní rozhodci. popup.warning.noMediatorsAvailable=Nejsou k dispozici žádní mediátoři. popup.warning.notFullyConnected=Musíte počkat, až budete plně připojeni k síti.\nTo může při spuštění trvat až 2 minuty. -popup.warning.notSufficientConnectionsToBtcNetwork=Musíte počkat, až budete mít alespoň {0} připojení k bitcoinové síti. -popup.warning.downloadNotComplete=Musíte počkat, až bude stahování chybějících bitcoinových bloků kompletní. -popup.warning.chainNotSynced=Výška blockchainu peněženky Haveno není správně synchronizována. Pokud jste aplikaci spustili nedávno, počkejte, dokud nebude zveřejněn jeden blok bitcoinů.\n\nVýšku blockchainu můžete zkontrolovat v Nastavení/Informace o síti. Pokud projde více než jeden blok a tento problém přetrvává, asi být zastaven, v takovém případě byste měli provést SPV resynchonizaci. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Musíte počkat, až budete mít alespoň {0} připojení k síti Monero. +popup.warning.downloadNotComplete=Musíte počkat, až bude dokončeno stahování chybějících bloků Monero. +popup.warning.walletNotSynced=Haveno peněženka není synchronizována s nejnovější výškou blockchainu. Počkejte, dokud se peněženka nesynchronizuje, nebo zkontrolujte své připojení. popup.warning.removeOffer=Opravdu chcete tuto nabídku odebrat? popup.warning.tooLargePercentageValue=Nelze nastavit procento 100% nebo větší. popup.warning.examplePercentageValue=Zadejte procento jako číslo \"5.4\" pro 5.4% @@ -1600,14 +1631,13 @@ popup.warning.nodeBanned=Jeden z {0} uzlů byl zabanován. popup.warning.priceRelay=cenové relé popup.warning.seed=seed popup.warning.mandatoryUpdate.trading=Aktualizujte prosím na nejnovější verzi Haveno. Byla vydána povinná aktualizace, která zakazuje obchodování se starými verzemi. Další informace naleznete na fóru Haveno. -popup.warning.noFilter="We did not receive a filter object from the seed nodes." Toto je neočekávaná situace. Prosím upozorněte vývojáře Haveno. -popup.warning.burnBTC=Tato transakce není možná, protože poplatky za těžbu {0} by přesáhly částku převodu {1}. Počkejte prosím, dokud nebudou poplatky za těžbu opět nízké nebo dokud nenahromadíte více BTC k převodu. +popup.warning.burnXMR=Tato transakce není možná, protože poplatky za těžbu {0} by přesáhly částku převodu {1}. Počkejte prosím, dokud nebudou poplatky za těžbu opět nízké nebo dokud nenahromadíte více XMR k převodu. -popup.warning.openOffer.makerFeeTxRejected=Transakční poplatek tvůrce za nabídku s ID {0} byl bitcoinovou sítí odmítnut.\nID transakce = {1}.\nNabídka byla odstraněna, aby se předešlo dalším problémům.\nPřejděte do \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Haveno Keybase týmu. +popup.warning.openOffer.makerFeeTxRejected=Transakční poplatek tvůrce za nabídku s ID {0} byl odmítnut sítí Monero.\nID transakce = {1}.\nNabídka byla odstraněna, aby se předešlo dalším problémům.\nPřejděte do \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Haveno Keybase týmu. popup.warning.trade.txRejected.tradeFee=obchodní poplatek popup.warning.trade.txRejected.deposit=vklad -popup.warning.trade.txRejected=Bitcoinová síť odmítla {0} transakci pro obchod s ID {1}.\nID transakce = {2}\nObchod byl přesunut do neúspěšných obchodů.\nPřejděte do části \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Haveno Keybase týmu. +popup.warning.trade.txRejected=Síť Monero odmítla {0} transakci pro obchod s ID {1}.\nID transakce = {2}\nObchod byl přesunut do neúspěšných obchodů.\nPřejděte do části \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Haveno Keybase týmu. popup.warning.openOfferWithInvalidMakerFeeTx=Transakční poplatek tvůrce za nabídku s ID {0} je neplatný.\nID transakce = {1}.\nPřejděte do \"Nastavení/Informace o síti\" a proveďte synchronizaci SPV.\nPro další pomoc prosím kontaktujte podpůrný kanál v Haveno Keybase týmu. @@ -1616,15 +1646,15 @@ popup.info.securityDepositInfo=Aby oba obchodníci dodržovali obchodní protoko popup.info.cashDepositInfo=Ujistěte se, že ve své oblasti máte pobočku banky, abyste mohli provést hotovostní vklad.\nID banky prodávajícího (BIC/SWIFT) je: {0}. popup.info.cashDepositInfo.confirm=Potvrzuji, že mohu provést vklad popup.info.shutDownWithOpenOffers=Haveno se vypíná, ale existují otevřené nabídky.\n\nTyto nabídky nebudou dostupné v síti P2P, pokud bude Haveno vypnutý, ale budou znovu publikovány do sítě P2P při příštím spuštění Haveno.\n\nChcete-li zachovat své nabídky online, udržujte Haveno spuštěný a ujistěte se, že tento počítač zůstává online (tj. Ujistěte se, že nepřejde do pohotovostního režimu...pohotovostní režim monitoru není problém). -popup.info.qubesOSSetupInfo=Zdá se, že používáte Haveno na Qubes OS.\n\nUjistěte se, že je vaše Haveno qube nastaveno podle našeho průvodce nastavením na [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=Zdá se, že používáte Haveno na Qubes OS.\n\nUjistěte se, že je vaše Haveno qube nastaveno podle našeho průvodce nastavením na [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade z verze {0} na verzi {1} není podporován. Použijte prosím nejnovější verzi Haveno. popup.privateNotification.headline=Důležité soukromé oznámení! popup.securityRecommendation.headline=Důležité bezpečnostní doporučení -popup.securityRecommendation.msg=Chtěli bychom vám připomenout, abyste zvážili použití ochrany heslem pro vaši peněženku, pokud jste ji již neaktivovali.\n\nDůrazně se také doporučuje zapsat seed slova peněženky. Tato seed slova jsou jako hlavní heslo pro obnovení vaší bitcoinové peněženky.\nV sekci "Seed peněženky" naleznete další informace.\n\nDále byste měli zálohovat úplnou složku dat aplikace v sekci \"Záloha\". +popup.securityRecommendation.msg=Chtěli bychom vám připomenout, abyste zvážili použití ochrany heslem pro vaši peněženku, pokud jste ji již neaktivovali.\n\nDůrazně se také doporučuje zapsat seed slova peněženky. Tato seed slova jsou jako hlavní heslo pro obnovení vaší peněženky Monero.\nV sekci "Seed peněženky" naleznete další informace.\n\nDále byste měli zálohovat úplnou složku dat aplikace v sekci \"Záloha\". -popup.moneroLocalhostNode.msg=Haveno zjistil, že na tomto stroji (na localhostu) běží Monero node.\n\nUjistěte se, prosím, že tento node je plně synchronizován před spuštěním Havena. +popup.xmrLocalNode.msg=Haveno zjistil, že na tomto stroji (na localhostu) běží Monero uzel.\n\nUjistěte se, prosím, že tento uzel je plně synchronizován před spuštěním Havena. popup.shutDownInProgress.headline=Probíhá vypínání popup.shutDownInProgress.msg=Vypnutí aplikace může trvat několik sekund.\nProsím, nepřerušujte tento proces. @@ -1670,6 +1700,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys byly podepsány popup.accountSigning.unsignedPubKeys.result.signed=Podepsané pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Nepodařilo se podepsat +popup.info.buyerAsTakerWithoutDeposit.headline=Žádný vklad není od kupujícího požadován +popup.info.buyerAsTakerWithoutDeposit=Vaše nabídka nebude vyžadovat bezpečnostní zálohu ani poplatek od kupujícího XMR.\n\nPro přijetí vaší nabídky musíte sdílet heslo se svým obchodním partnerem mimo Haveno.\n\nHeslo je automaticky vygenerováno a zobrazeno v detailech nabídky po jejím vytvoření. + #################################################################### # Notifications #################################################################### @@ -1677,9 +1710,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Nepodařilo se podepsat notification.trade.headline=Oznámení o obchodu s ID {0} notification.ticket.headline=Úkol na podporu pro obchod s ID {0} notification.trade.completed=Obchod je nyní dokončen a můžete si vybrat své prostředky. -notification.trade.accepted=Vaše nabídka byla přijata BTC {0}. +notification.trade.accepted=Vaše nabídka byla přijata XMR {0}. notification.trade.unlocked=Váš obchod má alespoň jedno potvrzení blockchainu.\nPlatbu můžete začít hned teď. -notification.trade.paymentSent=Kupující BTC zahájil platbu. +notification.trade.paymentSent=Kupující XMR zahájil platbu. notification.trade.selectTrade=Vyberte obchod notification.trade.peerOpenedDispute=Váš obchodní partner otevřel {0}. notification.trade.disputeClosed={0} byl uzavřen. @@ -1698,7 +1731,7 @@ systemTray.show=Otevřít okno aplikace systemTray.hide=Skrýt okno aplikace systemTray.info=Informace o Haveno systemTray.exit=Odejít -systemTray.tooltip=Haveno: Decentralizovaná směnárna bitcoinů +systemTray.tooltip=Haveno: Decentralizovaná směnárna moneroů #################################################################### @@ -1749,7 +1782,7 @@ tooltip.openBlockchainForTx=Otevřete externí blockchain explorer pro transakci confidence.unknown=Neznámý stav transakce confidence.seen=Viděno {0} partnery / 0 potvrzení -confidence.confirmed=Potvrzeno v {0} blocích +confidence.confirmed={0} potvrzení confidence.invalid=Transakce je neplatná peerInfo.title=Info o obchodním partnerovi @@ -1760,10 +1793,10 @@ peerInfo.age.noRisk=Stáří platebního účtu peerInfo.age.chargeBackRisk=Čas od podpisu peerInfo.unknownAge=Stáří není známo -addressTextField.openWallet=Otevřete výchozí bitcoinovou peněženku +addressTextField.openWallet=Otevřete výchozí peněženku Monero addressTextField.copyToClipboard=Zkopírujte adresu do schránky addressTextField.addressCopiedToClipboard=Adresa byla zkopírována do schránky -addressTextField.openWallet.failed=Otevření výchozí bitcoinové peněženky se nezdařilo. Možná nemáte žádnou nainstalovanou? +addressTextField.openWallet.failed=Otevření výchozí peněženky Monero selhalo. Možná nemáte žádnou nainstalovanou? peerInfoIcon.tooltip={0}\nŠtítek: {1} @@ -1795,6 +1828,7 @@ navigation.support=\"Podpora\" formatter.formatVolumeLabel={0} částka{1} formatter.makerTaker=Tvůrce jako {0} {1} / Příjemce jako {2} {3} +formatter.makerTakerLocked=Tvůrce jako {0} {1} / Příjemce jako {2} {3} 🔒 formatter.youAreAsMaker=Jste {1} {0} (jako tvůrce) / Příjemce je {3} {2} formatter.youAreAsTaker=Jste {1} {0} (jako příjemce) / Tvůrce je {3} {2} formatter.youAre={0}te {1} ({2}te {3}) @@ -1840,7 +1874,6 @@ password.deriveKey=Odvozuji klíč z hesla password.walletDecrypted=Peněženka úspěšně dešifrována a ochrana heslem byla odstraněna. password.wrongPw=Zadali jste nesprávné heslo.\n\nZkuste prosím zadat heslo znovu a pečlivě zkontrolujte překlepy nebo pravopisné chyby. password.walletEncrypted=Peněženka úspěšně šifrována a ochrana heslem povolena. -password.walletEncryptionFailed=Heslo peněženky nelze nastavit. Možná jste importovali počáteční slova, která neodpovídají databázi peněženky. Kontaktujte vývojáře na Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=Zadaná 2 hesla se neshodují. password.forgotPassword=Zapomněli jste heslo? password.backupReminder=Pamatujte, že při nastavování hesla do peněženky budou odstraněny všechny automaticky vytvořené zálohy z nezašifrované peněženky.\n\nPřed nastavením hesla se důrazně doporučuje provést zálohu adresáře aplikace a zapsat si počáteční slova! @@ -1854,7 +1887,7 @@ seed.date=Datum peněženky seed.restore.title=Obnovit peněženky z seed slov seed.restore=Obnovit peněženky seed.creationDate=Datum vzniku -seed.warn.walletNotEmpty.msg=Vaše bitcoinová peněženka není prázdná.\n\nTuto peněženku musíte vyprázdnit, než se pokusíte obnovit starší, protože smíchání peněženek může vést ke zneplatnění záloh.\n\nDokončete své obchody, uzavřete všechny otevřené nabídky a přejděte do sekce Prostředky, kde si můžete vybrat své bitcoiny.\nV případě, že nemáte přístup ke svým bitcoinům, můžete použít nouzový nástroj k vyprázdnění peněženky.\nNouzový nástroj otevřete stisknutím kombinace kláves \"Alt+e\" nebo \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Vaše peněženka Monero není prázdná.\n\nTuto peněženku musíte vyprázdnit, než se pokusíte obnovit starší, protože smíchání peněženek může vést ke zneplatnění záloh.\n\nDokončete své obchody, uzavřete všechny otevřené nabídky a přejděte do sekce Prostředky, kde si můžete vybrat své moneroy.\nV případě, že nemáte přístup ke svým moneroům, můžete použít nouzový nástroj k vyprázdnění peněženky.\nNouzový nástroj otevřete stisknutím kombinace kláves \"Alt+e\" nebo \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Chci přesto obnovit seed.warn.walletNotEmpty.emptyWallet=Nejprve vyprázdním své peněženky seed.warn.notEncryptedAnymore=Vaše peněženky jsou šifrovány.\n\nPo obnovení již nebudou peněženky šifrovány a musíte nastavit nové heslo.\n\nChcete pokračovat? @@ -1871,7 +1904,7 @@ seed.restore.openOffers.warn=Máte otevřené nabídky, které budou odstraněny payment.account=Účet payment.account.no=Číslo účtu payment.account.name=Název účtu -payment.account.userName=Uživatelské jméno +payment.account.username=Uživatelské jméno payment.account.phoneNr=Telefonní číslo payment.account.owner=Celé jméno vlastníka účtu payment.account.fullName=Celé jméno (křestní, střední, příjmení) @@ -1903,7 +1936,6 @@ payment.amazon.site=Kupte Amazon eGift zde: payment.ask=Zjistěte pomocí obchodního chatu payment.uphold.accountId=Uživatelské jméno, e-mail nebo číslo telefonu payment.moneyBeam.accountId=E-mail nebo číslo telefonu -payment.venmo.venmoUserName=Uživatelské jméno Venmo payment.popmoney.accountId=E-mail nebo číslo telefonu payment.promptPay.promptPayId=Občanské/daňové identifikační číslo nebo telefonní číslo payment.supportedCurrencies=Podporované měny @@ -1922,7 +1954,7 @@ shared.accountSigningState=Stav podpisu účtu #new payment.crypto.address.dyn={0} adresa -payment.crypto.receiver.address=Cryptoová adresa příjemce +payment.crypto.receiver.address=Kryptoměnová adresa příjemce payment.accountNr=Číslo účtu payment.emailOrMobile=E-mail nebo mobilní číslo payment.useCustomAccountName=Použijte vlastní název účtu @@ -1945,16 +1977,16 @@ payment.checking=Kontrola payment.savings=Úspory payment.personalId=Číslo občanského průkazu payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle je služba převodu peněz, která funguje nejlépe *prostřednictvím* jiné banky.\n\n1. Na této stránce zjistěte, zda (a jak) vaše banka spolupracuje se Zelle:\n[HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Zaznamenejte si zvláštní limity převodů - limity odesílání se liší podle banky a banky často určují samostatné denní, týdenní a měsíční limity.\n\n3. Pokud vaše banka s Zelle nepracuje, můžete ji stále používat prostřednictvím mobilní aplikace Zelle, ale vaše limity převodu budou mnohem nižší.\n\n4. Název uvedený na vašem účtu Haveno MUSÍ odpovídat názvu vašeho účtu Zelle/bankovního účtu.\n\nPokud nemůžete dokončit transakci Zelle, jak je uvedeno ve vaší obchodní smlouvě, můžete ztratit část (nebo vše) ze svého bezpečnostního vkladu.\n\nVzhledem k poněkud vyššímu riziku zpětného zúčtování společnosti Zelle se prodejcům doporučuje kontaktovat nepodepsané kupující prostřednictvím e-mailu nebo SMS, aby ověřili, že kupující skutečně vlastní účet Zelle uvedený v Haveno. payment.fasterPayments.newRequirements.info=Některé banky začaly ověřovat celé jméno příjemce pro převody Faster Payments. Váš současný účet Faster Payments nepožadoval celé jméno.\n\nZvažte prosím znovu vytvoření svého Faster Payments účtu v Havenou, abyste mohli budoucím kupujícím {0} poskytnout celé jméno.\n\nPři opětovném vytvoření účtu nezapomeňte zkopírovat přesný kód řazení, číslo účtu a hodnoty soli (salt) pro ověření věku ze starého účtu do nového účtu. Tím zajistíte zachování stáří a stavu vašeho stávajícího účtu. -payment.moneyGram.info=Při používání MoneyGram musí BTC kupující zaslat autorizační číslo a fotografii potvrzení e-mailem prodejci BTC. Potvrzení musí jasně uvádět celé jméno prodejce, zemi, stát a částku. E-mail prodávajícího se kupujícímu zobrazí během procesu obchodování. -payment.westernUnion.info=Při používání služby Western Union musí kupující BTC zaslat prodejci BTC e-mailem MTCN (sledovací číslo) a fotografii potvrzení. Potvrzení musí jasně uvádět celé jméno prodejce, město, zemi a částku. E-mail prodávajícího se kupujícímu zobrazí během procesu obchodování. -payment.halCash.info=Při používání HalCash musí kupující BTC poslat prodejci BTC kód HalCash prostřednictvím textové zprávy z mobilního telefonu.\n\nUjistěte se, že nepřekračujete maximální částku, kterou vám banka umožňuje odesílat pomocí HalCash. Min. částka za výběr je 10 EUR a max. částka je 600 EUR. Pro opakované výběry je to 3000 EUR za příjemce za den a 6000 EUR za příjemce za měsíc. Zkontrolujte prosím tyto limity u své banky, abyste se ujistili, že používají stejné limity, jaké jsou zde uvedeny.\n\nČástka pro výběr musí být násobkem 10 EUR, protože z bankomatu nemůžete vybrat jiné částky. Uživatelské rozhraní na obrazovce vytvořit-nabídku and přijmout-nabídku upraví částku BTC tak, aby částka EUR byla správná. Nemůžete použít tržní cenu, protože částka v EURECH se mění s měnícími se cenami.\n\nV případě sporu musí kupující BTC poskytnout důkaz, že zaslal EURA. +payment.moneyGram.info=Při používání MoneyGram musí XMR kupující zaslat autorizační číslo a fotografii potvrzení e-mailem prodejci XMR. Potvrzení musí jasně uvádět celé jméno prodejce, zemi, stát a částku. E-mail prodávajícího se kupujícímu zobrazí během procesu obchodování. +payment.westernUnion.info=Při používání služby Western Union musí kupující XMR zaslat prodejci XMR e-mailem MTCN (sledovací číslo) a fotografii potvrzení. Potvrzení musí jasně uvádět celé jméno prodejce, město, zemi a částku. E-mail prodávajícího se kupujícímu zobrazí během procesu obchodování. +payment.halCash.info=Při používání HalCash musí kupující XMR poslat prodejci XMR kód HalCash prostřednictvím textové zprávy z mobilního telefonu.\n\nUjistěte se, že nepřekračujete maximální částku, kterou vám banka umožňuje odesílat pomocí HalCash. Min. částka za výběr je 10 EUR a max. částka je 600 EUR. Pro opakované výběry je to 3000 EUR za příjemce za den a 6000 EUR za příjemce za měsíc. Zkontrolujte prosím tyto limity u své banky, abyste se ujistili, že používají stejné limity, jaké jsou zde uvedeny.\n\nČástka pro výběr musí být násobkem 10 EUR, protože z bankomatu nemůžete vybrat jiné částky. Uživatelské rozhraní na obrazovce vytvořit-nabídku and přijmout-nabídku upraví částku XMR tak, aby částka EUR byla správná. Nemůžete použít tržní cenu, protože částka v EURECH se mění s měnícími se cenami.\n\nV případě sporu musí kupující XMR poskytnout důkaz, že zaslal EURA. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Uvědomte si, že u všech bankovních převodů existuje určité riziko zpětného zúčtování. Aby se toto riziko zmírnilo, stanoví Haveno limity pro jednotlivé obchody na základě odhadované úrovně rizika zpětného zúčtování pro použitou platební metodu.\n\nU této platební metody je váš limit pro jednotlivé obchody pro nákup a prodej {2}.\n\nToto omezení se vztahuje pouze na velikost jednoho obchodu - můžete zadat tolik obchodů, kolik chcete.\n\nDalší podrobnosti najdete na wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Uvědomte si, že u všech bankovních převodů existuje určité riziko zpětného zúčtování. Aby se toto riziko zmírnilo, stanoví Haveno limity pro jednotlivé obchody na základě odhadované úrovně rizika zpětného zúčtování pro použitou platební metodu.\n\nU této platební metody je váš limit pro jednotlivé obchody pro nákup a prodej {2}.\n\nToto omezení se vztahuje pouze na velikost jednoho obchodu - můžete zadat tolik obchodů, kolik chcete.\n\nDalší podrobnosti najdete na wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=Aby se omezilo riziko zpětného zúčtování, Haveno stanoví limity pro jednotlivé obchody pro tento typ platebního účtu na základě následujících 2 faktorů:\n\n1. Obecné riziko zpětného zúčtování pro platební metodu\n2. Stav podepisování účtu\n\nTento platební účet ještě není podepsán, takže je omezen na nákup {0} za obchod. Po podpisu se limity nákupu zvýší následovně:\n\n● Před podpisem a 30 dní po podpisu bude váš limit nákupu podle obchodu {0}\n● 30 dní po podpisu bude váš limit nákupu podle obchodu {1}\n● 60 dní po podpisu bude váš limit nákupu podle obchodu {2}\n\nPodpisy účtu neovlivňují prodejní limity. Můžete okamžitě prodat {2} v jednom obchodu.\n\nTato omezení platí pouze pro objem jednoho obchodu - můžete zadat tolik obchodů, kolik chcete.\n\nDalší podrobnosti najdete na wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=Aby se omezilo riziko zpětného zúčtování, Haveno stanoví limity pro jednotlivé obchody pro tento typ platebního účtu na základě následujících 2 faktorů:\n\n1. Obecné riziko zpětného zúčtování pro platební metodu\n2. Stav podepisování účtu\n\nTento platební účet ještě není podepsán, takže je omezen na nákup {0} za obchod. Po podpisu se limity nákupu zvýší následovně:\n\n● Před podpisem a 30 dní po podpisu bude váš limit nákupu podle obchodu {0}\n● 30 dní po podpisu bude váš limit nákupu podle obchodu {1}\n● 60 dní po podpisu bude váš limit nákupu podle obchodu {2}\n\nPodpisy účtu neovlivňují prodejní limity. Můžete okamžitě prodat {2} v jednom obchodu.\n\nTato omezení platí pouze pro objem jednoho obchodu - můžete zadat tolik obchodů, kolik chcete.\n\nDalší podrobnosti najdete na wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Potvrďte, že vám vaše banka umožňuje odesílat hotovostní vklady na účty jiných lidí. Například Bank of America a Wells Fargo již takové vklady nepovolují. @@ -1966,7 +1998,7 @@ payment.amazonGiftCard.upgrade=Platba kartou Amazon eGift nyní vyžaduje také payment.account.amazonGiftCard.addCountryInfo={0}\nVáš stávající účet pro platbu kartou Amazon eGift ({1}) nemá nastavenou zemi.\nVyberte prosím zemi, ve které je možné vaše karty Amazon eGift uplatnit.\nTato aktualizace vašeho účtu nebude mít vliv na stáří tohoto účtu. payment.amazonGiftCard.upgrade.headLine=Aktualizace účtu pro platbu kartou Amazon eGift -payment.usPostalMoneyOrder.info=Obchodování pomocí amerických poštovních poukázek (USPMO) na Haveno vyžaduje, abyste rozuměli následujícímu:\n\n- Kupující BTC musí před odesláním napsat jméno prodejce BTC do polí plátce i příjemce a pořídit fotografii USPMO a obálku s dokladem o sledování ve vysokém rozlišení.\n- Kupující BTC musí odeslat USPMO prodejci BTC s potvrzením dodávky.\n\nV případě, že je nutná mediace, nebo pokud dojde k obchodnímu sporu, budete povinni poslat fotografie mediátorovi Haveno nebo zástupci pro vrácení peněz spolu s pořadovým číslem USPMO, číslem pošty a částkou dolaru, aby mohli ověřit podrobnosti na webu US Post Office.\n\nNeposkytnutí požadovaných informací mediátorovi nebo arbitrovi bude mít za následek ztrátu případu sporu.\n\nVe všech sporných případech nese odesílatel USPMO 100% břemeno odpovědnosti za poskytnutí důkazů mediátorovi nebo arbitrovi.\n\nPokud těmto požadavkům nerozumíte, neobchodujte pomocí USPMO na Haveno. +payment.usPostalMoneyOrder.info=Obchodování pomocí amerických poštovních poukázek (USPMO) na Haveno vyžaduje, abyste rozuměli následujícímu:\n\n- Kupující XMR musí před odesláním napsat jméno prodejce XMR do polí plátce i příjemce a pořídit fotografii USPMO a obálku s dokladem o sledování ve vysokém rozlišení.\n- Kupující XMR musí odeslat USPMO prodejci XMR s potvrzením dodávky.\n\nV případě, že je nutná mediace, nebo pokud dojde k obchodnímu sporu, budete povinni poslat fotografie mediátorovi Haveno nebo zástupci pro vrácení peněz spolu s pořadovým číslem USPMO, číslem pošty a částkou dolaru, aby mohli ověřit podrobnosti na webu US Post Office.\n\nNeposkytnutí požadovaných informací mediátorovi nebo arbitrovi bude mít za následek ztrátu případu sporu.\n\nVe všech sporných případech nese odesílatel USPMO 100% břemeno odpovědnosti za poskytnutí důkazů mediátorovi nebo arbitrovi.\n\nPokud těmto požadavkům nerozumíte, neobchodujte pomocí USPMO na Haveno. payment.payByMail.contact=Kontaktní informace payment.payByMail.contact.prompt=Obálka se jménem nebo pseudonymem by měla být adresována @@ -1977,7 +2009,7 @@ payment.f2f.city.prompt=Město se zobrazí s nabídkou payment.shared.optionalExtra=Volitelné další informace payment.shared.extraInfo=Dodatečné informace payment.shared.extraInfo.prompt=Uveďte jakékoli speciální požadavky, podmínky a detaily, které chcete zobrazit u vašich nabídek s tímto platebním účtem. (Uživatelé uvidí tyto informace předtím, než akceptují vaši nabídku.) -payment.f2f.info=Obchody „tváří v tvář“ mají různá pravidla a přicházejí s jinými riziky než online transakce.\n\nHlavní rozdíly jsou:\n● Obchodní partneři si musí vyměňovat informace o místě a čase schůzky pomocí poskytnutých kontaktních údajů.\n● Obchodní partneři musí přinést své notebooky a na místě setkání potvrdit „platba odeslána“ a „platba přijata“.\n● Pokud má tvůrce speciální „podmínky“, musí uvést podmínky v textovém poli „Další informace“ na účtu.\n● Přijetím nabídky zadavatel souhlasí s uvedenými „podmínkami a podmínkami“ tvůrce.\n● V případě sporu nemůže být mediátor nebo rozhodce příliš nápomocný, protože je obvykle obtížné získat důkazy o tom, co se na schůzce stalo. V takových případech mohou být prostředky BTC uzamčeny na dobu neurčitou nebo dokud se obchodní partneři nedohodnou.\n\nAbyste si byli jisti, že plně rozumíte rozdílům v obchodech „tváří v tvář“, přečtěte si pokyny a doporučení na adrese: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info=Obchody „tváří v tvář“ mají různá pravidla a přicházejí s jinými riziky než online transakce.\n\nHlavní rozdíly jsou:\n● Obchodní partneři si musí vyměňovat informace o místě a čase schůzky pomocí poskytnutých kontaktních údajů.\n● Obchodní partneři musí přinést své notebooky a na místě setkání potvrdit „platba odeslána“ a „platba přijata“.\n● Pokud má tvůrce speciální „podmínky“, musí uvést podmínky v textovém poli „Další informace“ na účtu.\n● Přijetím nabídky zadavatel souhlasí s uvedenými „podmínkami a podmínkami“ tvůrce.\n● V případě sporu nemůže být mediátor nebo rozhodce příliš nápomocný, protože je obvykle obtížné získat důkazy o tom, co se na schůzce stalo. V takových případech mohou být prostředky XMR uzamčeny na dobu neurčitou nebo dokud se obchodní partneři nedohodnou.\n\nAbyste si byli jisti, že plně rozumíte rozdílům v obchodech „tváří v tvář“, přečtěte si pokyny a doporučení na adrese: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Otevřít webovou stránku payment.f2f.offerbook.tooltip.countryAndCity=Země a město: {0} / {1} payment.f2f.offerbook.tooltip.extra=Další informace: {0} @@ -1989,7 +2021,7 @@ payment.japan.recipient=Jméno payment.australia.payid=PayID payment.payid=PayID spojené s finanční institucí. Jako e-mailová adresa nebo mobilní telefon. payment.payid.info=PayID jako telefonní číslo, e-mailová adresa nebo australské obchodní číslo (ABN), které můžete bezpečně propojit se svou bankou, družstevní záložnou nebo účtem stavební spořitelny. Musíte mít již vytvořený PayID u své australské finanční instituce. Odesílající i přijímající finanční instituce musí podporovat PayID. Další informace najdete na [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=Chcete-li platit dárkovou kartou Amazon eGift, budete muset prodejci BTC poslat kartu Amazon eGift přes svůj účet Amazon.\n\nHaveno zobrazí e-mail nebo mobilní číslo prodejce BTC, kam bude potřeba odeslat tuto dárkovou kartu. Na kartě ve zprávě pro příjemce musí být uvedeno ID obchodu. Pro další detaily a rady viz wiki: [HYPERLINK:https://bisq.wiki/Amazon_eGift_card].\n\nZde jsou tři důležité poznámky:\n- Preferujte dárkové karty v hodnotě do 100 USD, protože Amazon může považovat nákupy karet s vyššími částkami jako podezřelé a zablokovat je.\n- Na kartě do zprávy pro příjemce můžete přidat i vlastní originální text (např. "Happy birthday Susan!") spolu s ID obchodu. (V takovém případě o tom informujte protistranu pomocí obchodovacího chatu, aby mohli s jistotou ověřit, že obdržená dárková karta pochází od vás.)\n- Karty Amazon eGift lze uplatnit pouze na té stránce Amazon, na které byly také koupeny (např. karta koupená na amazon.it může být uplatněna zase jen na amazon.it). +payment.amazonGiftCard.info=Chcete-li platit dárkovou kartou Amazon eGift, budete muset prodejci XMR poslat kartu Amazon eGift přes svůj účet Amazon.\n\nHaveno zobrazí e-mail nebo mobilní číslo prodejce XMR, kam bude potřeba odeslat tuto dárkovou kartu. Na kartě ve zprávě pro příjemce musí být uvedeno ID obchodu. Pro další detaily a rady viz wiki: [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card].\n\nZde jsou tři důležité poznámky:\n- Preferujte dárkové karty v hodnotě do 100 USD, protože Amazon může považovat nákupy karet s vyššími částkami jako podezřelé a zablokovat je.\n- Na kartě do zprávy pro příjemce můžete přidat i vlastní originální text (např. "Happy birthday Susan!") spolu s ID obchodu. (V takovém případě o tom informujte protistranu pomocí obchodovacího chatu, aby mohli s jistotou ověřit, že obdržená dárková karta pochází od vás.)\n- Karty Amazon eGift lze uplatnit pouze na té stránce Amazon, na které byly také koupeny (např. karta koupená na amazon.it může být uplatněna zase jen na amazon.it). # We use constants from the code so we do not use our normal naming convention @@ -2063,7 +2095,7 @@ INTERAC_E_TRANSFER=Interac e-Transfer # suppress inspection "UnusedProperty" HAL_CASH=HalCash # suppress inspection "UnusedProperty" -BLOCK_CHAINS=Cryptoy +BLOCK_CHAINS=Kryptoměny # suppress inspection "UnusedProperty" PROMPT_PAY=PromptPay # suppress inspection "UnusedProperty" @@ -2073,7 +2105,7 @@ TRANSFERWISE=TransferWise # suppress inspection "UnusedProperty" AMAZON_GIFT_CARD=Amazon eGift Card # suppress inspection "UnusedProperty" -BLOCK_CHAINS_INSTANT=Instantní Cryptoy +BLOCK_CHAINS_INSTANT=Instantní kryptoměny # Deprecated: Cannot be deleted as it would break old trade history entries # suppress inspection "UnusedProperty" @@ -2115,7 +2147,7 @@ INTERAC_E_TRANSFER_SHORT=Interac e-Transfer # suppress inspection "UnusedProperty" HAL_CASH_SHORT=HalCash # suppress inspection "UnusedProperty" -BLOCK_CHAINS_SHORT=Cryptoy +BLOCK_CHAINS_SHORT=Kryptoměny # suppress inspection "UnusedProperty" PROMPT_PAY_SHORT=PromptPay # suppress inspection "UnusedProperty" @@ -2125,7 +2157,7 @@ TRANSFERWISE_SHORT=TransferWise # suppress inspection "UnusedProperty" AMAZON_GIFT_CARD_SHORT=Amazon eGift Card # suppress inspection "UnusedProperty" -BLOCK_CHAINS_INSTANT_SHORT=Instantní Cryptoy +BLOCK_CHAINS_INSTANT_SHORT=Instantní kryptoměny # Deprecated: Cannot be deleted as it would break old trade history entries # suppress inspection "UnusedProperty" @@ -2147,7 +2179,7 @@ validation.zero=Vstup 0 není povolen. validation.negative=Záporná hodnota není povolena. validation.traditional.tooSmall=Vstup menší než minimální možné množství není povolen. validation.traditional.tooLarge=Vstup větší než maximální možné množství není povolen. -validation.xmr.fraction=Zadání povede k hodnotě bitcoinu menší než 1 satoshi +validation.xmr.fraction=Zadání povede k hodnotě monerou menší než 1 satoshi validation.xmr.tooLarge=Vstup větší než {0} není povolen. validation.xmr.tooSmall=Vstup menší než {0} není povolen. validation.passwordTooShort=Zadané heslo je příliš krátké. Musí mít min. 8 znaků. @@ -2157,10 +2189,10 @@ validation.sortCodeChars={0} musí obsahovat {1} znaků. validation.bankIdNumber={0} se musí skládat z {1} čísel. validation.accountNr=Číslo účtu se musí skládat z {0} čísel. validation.accountNrChars=Číslo účtu musí obsahovat {0} znaků. -validation.btc.invalidAddress=Adresa není správná. Zkontrolujte formát adresy. +validation.xmr.invalidAddress=Adresa není správná. Zkontrolujte formát adresy. validation.integerOnly=Zadejte pouze celá čísla. validation.inputError=Váš vstup způsobil chybu:\n{0} -validation.btc.exceedsMaxTradeLimit=Váš obchodní limit je {0}. +validation.xmr.exceedsMaxTradeLimit=Váš obchodní limit je {0}. validation.nationalAccountId={0} se musí skládat z {1} čísel. #new @@ -2181,7 +2213,7 @@ validation.bic.letters=Banka a kód země musí být písmena validation.bic.invalidLocationCode=BIC obsahuje neplatný location kód validation.bic.invalidBranchCode=BIC obsahuje neplatný kód pobočky validation.bic.sepaRevolutBic=Účty Revolut Sepa nejsou podporovány. -validation.btc.invalidFormat=Neplatný formát bitcoinové adresy. +validation.btc.invalidFormat=Neplatný formát adresy Bitcoin. validation.email.invalidAddress=Neplatná adresa validation.iban.invalidCountryCode=Kód země je neplatný validation.iban.checkSumNotNumeric=Kontrolní součet musí být číselný diff --git a/core/src/main/resources/i18n/displayStrings_de.properties b/core/src/main/resources/i18n/displayStrings_de.properties index 7f84447cb9..d1bfa9f0b7 100644 --- a/core/src/main/resources/i18n/displayStrings_de.properties +++ b/core/src/main/resources/i18n/displayStrings_de.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Ich verstehe shared.na=N/A shared.shutDown=Herunterfahren shared.reportBug=Fehler auf GitHub melden -shared.buyBitcoin=Bitcoin kaufen -shared.sellBitcoin=Bitcoin verkaufen +shared.buyMonero=Monero kaufen +shared.sellMonero=Monero verkaufen shared.buyCurrency={0} kaufen shared.sellCurrency={0} verkaufen -shared.buyingBTCWith=kaufe BTC mit {0} -shared.sellingBTCFor=verkaufe BTC für {0} -shared.buyingCurrency=kaufe {0} (verkaufe BTC) -shared.sellingCurrency=verkaufe {0} (kaufe BTC) +shared.buyCurrencyLocked={0} kaufen 🔒 +shared.sellCurrencyLocked={0} verkaufen 🔒 +shared.buyingXMRWith=kaufe XMR mit {0} +shared.sellingXMRFor=verkaufe XMR für {0} +shared.buyingCurrency=kaufe {0} (verkaufe XMR) +shared.sellingCurrency=verkaufe {0} (kaufe XMR) shared.buy=kaufen shared.sell=verkaufen shared.buying=kaufe @@ -93,7 +95,7 @@ shared.amountMinMax=Betrag (min - max) shared.amountHelp=Wurde für ein Angebot ein minimaler und maximaler Betrag gesetzt, können Sie jeden Betrag innerhalb dieses Bereiches handeln. shared.remove=Entfernen shared.goTo=Zu {0} gehen -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Angebot entfernen shared.dontRemoveOffer=Angebot nicht entfernen shared.editOffer=Angebot bearbeiten @@ -103,16 +105,16 @@ shared.faq=Zur FAQ Seite shared.yesCancel=Ja, abbrechen shared.nextStep=Nächster Schritt shared.selectTradingAccount=Handelskonto auswählen -shared.fundFromSavingsWalletButton=Gelder aus Haveno-Wallet überweisen +shared.fundFromSavingsWalletButton=Wenden Sie Gelder aus der Haveno-Wallet an shared.fundFromExternalWalletButton=Ihre externe Wallet zum Finanzieren öffnen -shared.openDefaultWalletFailed=Das Öffnen des Standardprogramms für Bitcoin-Wallets ist fehlgeschlagen. Sind Sie sicher, dass Sie eines installiert haben? +shared.openDefaultWalletFailed=Das Öffnen des Standardprogramms für Monero-Wallets ist fehlgeschlagen. Sind Sie sicher, dass Sie eines installiert haben? shared.belowInPercent=% unter dem Marktpreis shared.aboveInPercent=% über dem Marktpreis shared.enterPercentageValue=%-Wert eingeben shared.OR=ODER shared.notEnoughFunds=Für diese Transaktion haben Sie nicht genug Gelder in Ihrem Haveno-Wallet—{0} werden benötigt, aber nur {1} sind verfügbar.\n\nBitte fügen Sie Gelder aus einer externen Wallet hinzu, oder senden Sie Gelder an Ihr Haveno-Wallet unter Gelder > Gelder erhalten. shared.waitingForFunds=Warte auf Gelder... -shared.TheBTCBuyer=Der BTC-Käufer +shared.TheXMRBuyer=Der XMR-Käufer shared.You=Sie shared.sendingConfirmation=Sende Bestätigung... shared.sendingConfirmationAgain=Bitte senden Sie die Bestätigung erneut @@ -123,9 +125,8 @@ shared.noDateAvailable=Kein Datum verfügbar shared.noDetailsAvailable=Keine Details vorhanden shared.notUsedYet=Noch ungenutzt shared.date=Datum -shared.sendFundsDetailsWithFee=Gesendet: {0}\nVon Adresse: {1}\nAn Empfangsadresse: {2}.\nBenötigte Mining-Gebühr ist: {3} ({4} satoshis/vbyte)\nTransaktionsgröße (vsize): {5} vKb\n\nDer Empfänger erhält: {6}\n\nSind Sie sicher, dass Sie diesen Betrag abheben wollen? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Diese Transaktion würde ein Wechselgeld erzeugen das unterhalb des Dust-Grenzwerts liegt (und daher von den Bitcoin-Konsensregeln nicht erlaubt wäre). Stattdessen wird dieser Dust ({0} Satoshi{1}) der Mining-Gebühr hinzugefügt.\n\n\n +shared.sendFundsDetailsDust=Diese Transaktion würde ein Wechselgeld erzeugen das unterhalb des Dust-Grenzwerts liegt (und daher von den Monero-Konsensregeln nicht erlaubt wäre). Stattdessen wird dieser Dust ({0} Satoshi{1}) der Mining-Gebühr hinzugefügt.\n\n\n shared.copyToClipboard=In Zwischenablage kopieren shared.language=Sprache shared.country=Land @@ -140,6 +141,7 @@ shared.addNewAccount=Neues Konto hinzufügen shared.ExportAccounts=Konten exportieren shared.importAccounts=Konten importieren shared.createNewAccount=Neues Konto erstellen +shared.createNewAccountDescription=Ihre Kontodaten werden lokal auf Ihrem Gerät gespeichert und nur mit Ihrem Handelspartner und dem Schiedsrichter geteilt, wenn ein Streitfall eröffnet wird. shared.saveNewAccount=Neues Konto speichern shared.selectedAccount=Konto auswählen shared.deleteAccount=Konto löschen @@ -169,7 +171,7 @@ shared.payoutTxId=Transaktions-ID der Auszahlung shared.contractAsJson=Vertrag im JSON-Format shared.viewContractAsJson=Vertrag im JSON-Format ansehen shared.contract.title=Vertrag für den Handel mit der ID: {0} -shared.paymentDetails=Zahlungsdetails des BTC-{0} +shared.paymentDetails=Zahlungsdetails des XMR-{0} shared.securityDeposit=Kaution shared.yourSecurityDeposit=Ihre Kaution shared.contract=Vertrag @@ -179,19 +181,21 @@ shared.messageSendingFailed=Versenden der Nachricht fehlgeschlagen. Fehler: {0} shared.unlock=Entsperren shared.toReceive=erhalten shared.toSpend=ausgeben -shared.btcAmount=BTC-Betrag +shared.xmrAmount=XMR-Betrag shared.yourLanguage=Ihre Sprachen shared.addLanguage=Sprache hinzufügen shared.total=Insgesamt shared.totalsNeeded=Benötigte Gelder shared.tradeWalletAddress=Adresse der Handels-Wallet shared.tradeWalletBalance=Guthaben der Handels-Wallet +shared.reserveExactAmount=Reserviere nur die notwendigen Mittel. Erfordert eine Mining-Gebühr und ca. 20 Minuten, bevor dein Angebot live geht. shared.makerTxFee=Ersteller: {0} shared.takerTxFee=Abnehmer: {0} shared.iConfirm=Ich bestätige shared.openURL=Öffne {0} shared.fiat=Fiat shared.crypto=Crypto +shared.preciousMetals=Edelmetalle shared.all=Alle shared.edit=Bearbeiten shared.advancedOptions=Erweiterte Optionen @@ -226,8 +230,8 @@ shared.enabled=Aktiviert #################################################################### mainView.menu.market=Markt -mainView.menu.buyBtc=BTC kaufen -mainView.menu.sellBtc=BTC verkaufen +mainView.menu.buyXmr=XMR kaufen +mainView.menu.sellXmr=XMR verkaufen mainView.menu.portfolio=Portfolio mainView.menu.funds=Gelder mainView.menu.support=Support @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Reserviert mainView.balance.pending.short=Gesperrt mainView.footer.usingTor=(über Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(über clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Aktuelle Gebühr: {0} sat/vB -mainView.footer.xmrInfo.initializing=Verbindung mit Bitcoin-Netzwerk wird hergestellt +mainView.footer.xmrFeeRate=/ Aktuelle Gebühr: {0} sat/vB +mainView.footer.xmrInfo.initializing=Verbindung mit Haveno-Netzwerk wird hergestellt mainView.footer.xmrInfo.synchronizingWith=Synchronisierung mit {0} bei Block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synchronisierung mit {0} bei Block {1} +mainView.footer.xmrInfo.connectedTo=Verbunden mit {0} am Block {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Synchronisierung der Brieftasche mit {0} im Block: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Synchronisiert mit {0} bei Block {1} mainView.footer.xmrInfo.connectingTo=Verbinde mit mainView.footer.xmrInfo.connectionFailed=Verbindung fehlgeschlagen zu mainView.footer.xmrPeers=Monero Netzwerk Peers: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=Bootstrapping zum Haveno-Netz mainView.p2pNetworkWarnMsg.noNodesAvailable=Es sind keine Seed-Knoten oder bestehenden Peers verfügbar, um Daten anzufordern.\nÜberprüfen Sie bitte Ihre Internetverbindung oder versuchen Sie die Anwendung neu zu starten. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Verbinden mit Haveno-Netzwerk fehlgeschlagen (gemeldeter Fehler: {0}).\nBitte überprüfen Sie Ihre Internetverbindungen oder versuchen Sie die Anwendung neu zu starten. -mainView.walletServiceErrorMsg.timeout=Verbindung mit Bitcoin-Netzwerk aufgrund einer Zeitüberschreitung fehlgeschlagen. -mainView.walletServiceErrorMsg.connectionError=Verbindung mit Bitcoin-Netzwerk aufgrund eines Fehlers fehlgeschlagen: {0} +mainView.walletServiceErrorMsg.timeout=Verbindung mit Monero-Netzwerk aufgrund einer Zeitüberschreitung fehlgeschlagen. +mainView.walletServiceErrorMsg.connectionError=Verbindung mit Monero-Netzwerk aufgrund eines Fehlers fehlgeschlagen: {0} mainView.walletServiceErrorMsg.rejectedTxException=Eine Transaktion wurde aus dem Netzwerk abgelehnt.\n\n{0} mainView.networkWarning.allConnectionsLost=Sie haben die Verbindung zu allen {0} Netzwerk-Peers verloren.\nMöglicherweise haben Sie Ihre Internetverbindung verloren oder Ihr Computer war im Standbymodus. -mainView.networkWarning.localhostBitcoinLost=Sie haben die Verbindung zum localhost Bitcoinknoten verloren.\nBitte starten Sie die Haveno Anwendung neu, um mit anderen Bitcoinknoten zu verbinden oder starten Sie den localhost Bitcoinknoten neu. +mainView.networkWarning.localhostMoneroLost=Sie haben die Verbindung zum localhost Moneroknoten verloren.\nBitte starten Sie die Haveno Anwendung neu, um mit anderen Moneroknoten zu verbinden oder starten Sie den localhost Moneroknoten neu. mainView.version.update=(Update verfügbar) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional={0} kaufen market.offerBook.sellWithTraditional={0} verkaufen market.offerBook.sellOffersHeaderLabel=Verkaufe {0} an market.offerBook.buyOffersHeaderLabel=Kaufe {0} von -market.offerBook.buy=Ich möchte Bitcoins kaufen -market.offerBook.sell=Ich möchte Bitcoins verkaufen +market.offerBook.buy=Ich möchte Moneros kaufen +market.offerBook.sell=Ich möchte Moneros verkaufen # SpreadView market.spread.numberOfOffersColumn=Alle Angebote ({0}) -market.spread.numberOfBuyOffersColumn=BTC kaufen ({0}) -market.spread.numberOfSellOffersColumn=BTC verkaufen ({0}) -market.spread.totalAmountColumn=BTC insgesamt ({0}) +market.spread.numberOfBuyOffersColumn=XMR kaufen ({0}) +market.spread.numberOfSellOffersColumn=XMR verkaufen ({0}) +market.spread.totalAmountColumn=XMR insgesamt ({0}) market.spread.spreadColumn=Verteilung market.spread.expanded=Erweiterte Ansicht @@ -325,6 +332,7 @@ offerbook.createOffer=Angebot erstellen offerbook.takeOffer=Angebot annehmen offerbook.takeOfferToBuy=Angebot annehmen {0} zu kaufen offerbook.takeOfferToSell=Angebot annehmen {0} zu verkaufen +offerbook.takeOffer.enterChallenge=Geben Sie das Angebots-Passphrase ein offerbook.trader=Händler offerbook.offerersBankId=Bankkennung des Erstellers (BIC/SWIFT): {0} offerbook.offerersBankName=Bankname des Erstellers: {0} @@ -335,6 +343,8 @@ offerbook.availableOffers=Verfügbare Angebote offerbook.filterByCurrency=Nach Währung filtern offerbook.filterByPaymentMethod=Nach Zahlungsmethode filtern offerbook.matchingOffers=Angebote die meinen Zahlungskonten entsprechen +offerbook.filterNoDeposit=Kein Deposit +offerbook.noDepositOffers=Angebote ohne Einzahlung (Passphrase erforderlich) offerbook.timeSinceSigning=Informationen zum Zahlungskonto offerbook.timeSinceSigning.info=Dieses Konto wurde verifiziert und {0} offerbook.timeSinceSigning.info.arbitrator=von einem Vermittler unterzeichnet und kann Partner-Konten unterzeichnen @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=Konto wurde geblockt offerbook.timeSinceSigning.daysSinceSigning={0} Tage offerbook.timeSinceSigning.daysSinceSigning.long={0} seit der Unterzeichnung offerbook.xmrAutoConf=Automatische Bestätigung aktiviert +offerbook.buyXmrWith=XMR kaufen mit: +offerbook.sellXmrFor=XMR verkaufen für: offerbook.timeSinceSigning.help=Wenn Sie einen Trade mit einem Partner erfolgreich abschließen, der ein unterzeichnetes Zahlungskonto hat, wird Ihr Zahlungskonto unterzeichnet.\n{0} Tage später wird das anfängliche Limit von {1} aufgehoben und Ihr Konto kann die Zahlungskonten anderer Partner unterzeichnen. offerbook.timeSinceSigning.notSigned=Noch nicht unterzeichnet @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto Konten haben keine Merkmale wie Unterzeichnun offerbook.nrOffers=Anzahl der Angebote: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Kaution BTC (%) +offerbook.deposit=Kaution XMR (%) offerbook.deposit.help=Kaution die von beiden Handelspartnern bezahlt werden muss, um den Handel abzusichern. Wird zurückgezahlt, wenn der Handel erfolgreich abgeschlossen wurde. +offerbook.createNewOffer=Erstelle Angebot an {0} {1} offerbook.createOfferToBuy=Neues Angebot erstellen, um {0} zu kaufen offerbook.createOfferToSell=Neues Angebot erstellen, um {0} zu verkaufen @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=Mit dieser Version der Software können popup.warning.tradeLimitDueAccountAgeRestriction.seller=Der zulässige Trade-Betrag ist aufgrund von Sicherheitseinschränkungen, die auf den folgenden Kriterien basieren, auf {0} begrenzt:\n- Das Konto des Käufers wurde nicht von einem Vermittler oder einem Partner unterzeichnet\n- Die Zeit seit der Unterzeichnung des Kontos des Käufers beträgt nicht mindestens 30 Tage\n- Die Zahlungsmethode für dieses Angebot gilt als riskant für Bankrückbuchungen\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=Der zulässige Trade-Betrag ist aufgrund von Sicherheitseinschränkungen, die auf den folgenden Kriterien basieren, auf {0} begrenzt:\n- Ihr Konto wurde nicht von einem Vermittler oder einem Partner unterzeichnet\n- Die Zeit seit der Unterzeichnung Ihres Kontos beträgt nicht mindestens 30 Tage\n- Die Zahlungsmethode für dieses Angebot gilt als riskant für Bankrückbuchungen\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Diese Zahlungsmethode ist vorübergehend auf {0} bis {1} begrenzt, da alle Käufer neue Konten haben.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Ihr Angebot wird auf Käufer mit unterzeichneten und alten Konten beschränkt sein, da es {0} übersteigt.\n\n{1} offerbook.warning.wrongTradeProtocol=Dieses Angebot benötigt eine andere Protokollversion, als die Version Ihrer Software.\n\nBitte überprüfen Sie, ob Sie die aktuellste Version installiert haben. Andernfalls hat der Nutzer, der das Angebot erstellt hat, eine ältere Version benutzt.\n\nNutzer können nicht mit inkompatiblen Protokollversionen handeln. offerbook.warning.userIgnored=Sie haben die Onion-Adresse dieses Nutzers zu Ihrer Liste ignorierter Adressen hinzugefügt. @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=Der Betrag wurde gerundet, um die Privatsphäre # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Betrag in BTC eingeben +createOffer.amount.prompt=Betrag in XMR eingeben createOffer.price.prompt=Preis eingeben createOffer.volume.prompt=Betrag in {0} eingeben -createOffer.amountPriceBox.amountDescription=Betrag in BTC zu {0} +createOffer.amountPriceBox.amountDescription=Betrag in XMR zu {0} createOffer.amountPriceBox.buy.volumeDescription=Auszugebender Betrag in {0} createOffer.amountPriceBox.sell.volumeDescription=Zu erhaltender Betrag in {0} -createOffer.amountPriceBox.minAmountDescription=Minimaler Betrag in BTC +createOffer.amountPriceBox.minAmountDescription=Minimaler Betrag in XMR createOffer.securityDeposit.prompt=Kaution createOffer.fundsBox.title=Ihr Angebot finanzieren createOffer.fundsBox.offerFee=Handelsgebühr @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=Sie erhalten immer {0}% mehr als der aktue createOffer.info.buyBelowMarketPrice=Sie zahlen immer {0}% weniger als der aktuelle Marktpreis, da ihr Angebot ständig aktualisiert wird. createOffer.warning.sellBelowMarketPrice=Sie erhalten immer {0}% weniger als der aktuelle Marktpreis, da ihr Angebot ständig aktualisiert wird. createOffer.warning.buyAboveMarketPrice=Sie zahlen immer {0}% mehr als der aktuelle Marktpreis, da ihr Angebot ständig aktualisiert wird. -createOffer.tradeFee.descriptionBTCOnly=Handelsgebühr +createOffer.tradeFee.descriptionXMROnly=Handelsgebühr createOffer.tradeFee.descriptionBSQEnabled=Gebührenwährung festlegen createOffer.triggerPrice.prompt=Auslösepreis (optional) @@ -448,7 +463,12 @@ createOffer.placeOfferButton=Überprüfung: Anbieten moneros zu {0} createOffer.createOfferFundWalletInfo.headline=Ihr Angebot finanzieren # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Handelsbetrag: {0} \n -createOffer.createOfferFundWalletInfo.msg=Sie müssen zum Annehmen dieses Angebots {0} einzahlen.\n\nDiese Gelder werden in Ihrer lokalen Wallet reserviert und in die MultiSig-Kautionsadresse eingesperrt, wenn jemand Ihr Angebot annimmt.\n\nDer Betrag ist die Summe aus:\n{1}- Kaution: {2}\n- Handelsgebühr: {3}\n- Mining-Gebühr: {4}\n\nSie haben zwei Möglichkeiten, Ihren Handel zu finanzieren:\n- Nutzen Sie Ihre Haveno-Wallet (bequem, aber Transaktionen können nachverfolgbar sein) ODER\n- Von einer externen Wallet überweisen (möglicherweise vertraulicher)\n\nSie werden nach dem Schließen dieses Dialogs alle Finanzierungsmöglichkeiten und Details sehen. +createOffer.createOfferFundWalletInfo.msg=Sie müssen {0} in dieses Angebot einzahlen.\n\n\ + Diese Gelder werden in Ihrer lokalen Wallet reserviert und in eine Multisig-Wallet gesperrt, sobald jemand Ihr Angebot annimmt.\n\n\ + Der Betrag ist die Summe aus:\n\ + {1}\ + - Ihre Sicherheitskaution: {2}\n\ + - Handelsgebühr: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Es gab einen Fehler beim Erstellen des Angebots:\n\n{0}\n\nEs haben noch keine Gelder Ihre Wallet verlassen.\nBitte starten Sie Ihre Anwendung neu und überprüfen Sie Ihre Netzwerkverbindung. @@ -470,30 +490,35 @@ createOffer.setDepositAsBuyer=Meine Kaution als Käufer festlegen (%) createOffer.setDepositForBothTraders=Legen Sie die Kaution für beide Handelspartner fest (%) createOffer.securityDepositInfo=Die Kaution ihres Käufers wird {0} createOffer.securityDepositInfoAsBuyer=Ihre Kaution als Käufer wird {0} -createOffer.minSecurityDepositUsed=Min. Kaution des Käufers wird verwendet +createOffer.minSecurityDepositUsed=Der Mindest-Sicherheitsbetrag wird verwendet. +createOffer.buyerAsTakerWithoutDeposit=Kein Deposit erforderlich vom Käufer (Passphrase geschützt) +createOffer.myDeposit=Meine Sicherheitsleistung (%) +createOffer.myDepositInfo=Ihre Sicherheitsleistung beträgt {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Betrag in BTC eingeben -takeOffer.amountPriceBox.buy.amountDescription=Betrag in BTC zu verkaufen -takeOffer.amountPriceBox.sell.amountDescription=Betrag in BTC zu kaufen -takeOffer.amountPriceBox.priceDescription=Preis pro Bitcoin in {0} +takeOffer.amount.prompt=Betrag in XMR eingeben +takeOffer.amountPriceBox.buy.amountDescription=Betrag in XMR zu verkaufen +takeOffer.amountPriceBox.sell.amountDescription=Betrag in XMR zu kaufen +takeOffer.amountPriceBox.priceDescription=Preis pro Monero in {0} takeOffer.amountPriceBox.amountRangeDescription=Mögliche Betragsspanne -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=Der eingegebene Betrag besitzt zu viele Nachkommastellen.\nDer Betrag wurde auf 4 Nachkommastellen angepasst. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=Der eingegebene Betrag besitzt zu viele Nachkommastellen.\nDer Betrag wurde auf 4 Nachkommastellen angepasst. takeOffer.validation.amountSmallerThanMinAmount=Der Betrag kann nicht kleiner als der im Angebot festgelegte minimale Betrag sein. takeOffer.validation.amountLargerThanOfferAmount=Der eingegebene Betrag kann nicht größer als der im Angebot festgelegte Betrag sein. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Der eingegebene Betrag würde Staub als Wechselgeld für den BTC-Verkäufer erzeugen. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Der eingegebene Betrag würde Staub als Wechselgeld für den XMR-Verkäufer erzeugen. takeOffer.fundsBox.title=Ihren Handel finanzieren takeOffer.fundsBox.isOfferAvailable=Verfügbarkeit des Angebots wird überprüft ... takeOffer.fundsBox.tradeAmount=Zu verkaufender Betrag takeOffer.fundsBox.offerFee=Handelsgebühr takeOffer.fundsBox.networkFee=Gesamte Mining-Gebühr -takeOffer.fundsBox.takeOfferSpinnerInfo=Angebot wird angenommen ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Angebot annehmen: {0} takeOffer.fundsBox.paymentLabel=Haveno-Handel mit der ID {0} takeOffer.fundsBox.fundsStructure=({0} Kaution, {1} Handelsgebühr, {2} Mining-Gebühr) +takeOffer.fundsBox.noFundingRequiredTitle=Keine Finanzierung erforderlich +takeOffer.fundsBox.noFundingRequiredDescription=Holen Sie sich das Angebots-Passwort vom Verkäufer außerhalb von Haveno, um dieses Angebot anzunehmen. takeOffer.success.headline=Sie haben erfolgreich ein Angebot angenommen. takeOffer.success.info=Sie können den Status Ihres Trades unter \"Portfolio/Offene Trades\" einsehen. takeOffer.error.message=Bei der Angebotsannahme trat ein Fehler auf.\n\n{0} @@ -504,7 +529,7 @@ takeOffer.noPriceFeedAvailable=Sie können dieses Angebot nicht annehmen, da es takeOffer.takeOfferFundWalletInfo.headline=Ihren Handel finanzieren # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Handelsbetrag: {0}\n -takeOffer.takeOfferFundWalletInfo.msg=Sie müssen zum Annehmen dieses Angebots {0} einzahlen.\n\nDer Betrag ist die Summe aus:\n{1}- Ihre Kaution: {2}\n- Handelsgebühr: {3}\n- Gesamte Mining-Gebühr: {4}\n\nSie haben zwei Möglichkeiten Ihren Handel zu finanzieren:\n- Nutzen Sie Ihre Haveno-Wallet (bequem, aber Transaktionen können nach verfolgbar sein) ODER\n- Von einer externen Wallet überweisen (möglicherweise vertraulicher)\n\nSie werden nach dem Schließen dieses Dialogs alle Finanzierungsmöglichkeiten und Details sehen. +takeOffer.takeOfferFundWalletInfo.msg=Sie müssen zum Annehmen dieses Angebots {0} einzahlen.\n\nDer Betrag ist die Summe aus:\n{1}- Ihre Kaution: {2}\n- Handelsgebühr: {3}\n\nSie haben zwei Möglichkeiten Ihren Handel zu finanzieren:\n- Nutzen Sie Ihre Haveno-Wallet (bequem, aber Transaktionen können nach verfolgbar sein) ODER\n- Von einer externen Wallet überweisen (möglicherweise vertraulicher)\n\nSie werden nach dem Schließen dieses Dialogs alle Finanzierungsmöglichkeiten und Details sehen. takeOffer.alreadyPaidInFunds=Wenn Sie bereits Gelder gezahlt haben, können Sie diese unter \"Gelder/Gelder senden\" abheben. takeOffer.paymentInfo=Zahlungsinformationen takeOffer.setAmountPrice=Betrag festlegen @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=Die Kautionstransaktion ist noch nicht be # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Ihr Handel hat mindestens eine Blockchain-Bestätigung erreicht.\n\n -portfolio.pending.step2_buyer.refTextWarn=Wichtig: Wenn Sie die Zahlung durchführen, lassen Sie das Feld \"Verwendungszweck\" leer. Geben Sie NICHT die Handels-ID oder einen anderen Text wie 'Bitcoin', 'BTC' oder 'Haveno' an. Sie können im Handels-Chat gerne besprechen ob ein alternativer \"Verwendungszweck\" für Sie beide zweckmäßig wäre. +portfolio.pending.step2_buyer.refTextWarn=Wichtig: Wenn Sie die Zahlung durchführen, lassen Sie das Feld \"Verwendungszweck\" leer. Geben Sie NICHT die Handels-ID oder einen anderen Text wie 'Monero', 'XMR' oder 'Haveno' an. Sie können im Handels-Chat gerne besprechen ob ein alternativer \"Verwendungszweck\" für Sie beide zweckmäßig wäre. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=Sollte Ihre Bank irgendwelche Gebühren für die Überweisung erheben, müssen Sie diese Gebühren bezahlen. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Bitte überweisen Sie von Ihrer externen {0}-Wallet\n{1} an den BTC-Verkäufer.\n\n +portfolio.pending.step2_buyer.crypto=Bitte überweisen Sie von Ihrer externen {0}-Wallet\n{1} an den XMR-Verkäufer.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Bitte gehen Sie zu einer Bank und zahlen Sie {0} an den BTC-Verkäufer.\n\n -portfolio.pending.step2_buyer.cash.extra=WICHTIGE VORAUSSETZUNG:\nNachdem Sie die Zahlung getätigt haben, schreiben Sie auf die Quittung: NO REFUNDS.\nReißen Sie diese in zwei Teile und machen Sie ein Foto, das Sie an die E-Mail-Adresse des BTC-Verkäufers senden. +portfolio.pending.step2_buyer.cash=Bitte gehen Sie zu einer Bank und zahlen Sie {0} an den XMR-Verkäufer.\n\n +portfolio.pending.step2_buyer.cash.extra=WICHTIGE VORAUSSETZUNG:\nNachdem Sie die Zahlung getätigt haben, schreiben Sie auf die Quittung: NO REFUNDS.\nReißen Sie diese in zwei Teile und machen Sie ein Foto, das Sie an die E-Mail-Adresse des XMR-Verkäufers senden. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Bitte zahlen Sie {0} an den BTC-Verkäufer mit MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=WICHTIGE VORAUSSETZUNG: \nNachdem Sie die Zahlung getätigt haben, senden Sie die Authorisierungs-Nummer und ein Foto der Quittung per E-Mail an den BTC-Verkäufer.\nDie Quittung muss den vollständigen Namen, das Land, Bundesland des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}. +portfolio.pending.step2_buyer.moneyGram=Bitte zahlen Sie {0} an den XMR-Verkäufer mit MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=WICHTIGE VORAUSSETZUNG: \nNachdem Sie die Zahlung getätigt haben, senden Sie die Authorisierungs-Nummer und ein Foto der Quittung per E-Mail an den XMR-Verkäufer.\nDie Quittung muss den vollständigen Namen, das Land, Bundesland des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Bitte zahlen Sie {0} an den BTC-Verkäufer mit Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=WICHTIGE VORAUSSETZUNG: \nNachdem Sie die Zahlung getätigt haben, senden Sie die MTCN (Tracking-Nummer) und ein Foto der Quittung per E-Mail an den BTC-Verkäufer.\nDie Quittung muss den vollständigen Namen, die Stadt, das Land des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}. +portfolio.pending.step2_buyer.westernUnion=Bitte zahlen Sie {0} an den XMR-Verkäufer mit Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=WICHTIGE VORAUSSETZUNG: \nNachdem Sie die Zahlung getätigt haben, senden Sie die MTCN (Tracking-Nummer) und ein Foto der Quittung per E-Mail an den XMR-Verkäufer.\nDie Quittung muss den vollständigen Namen, die Stadt, das Land des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Bitte senden Sie {0} per \"US Postal Money Order\" an den BTC-Verkäufer.\n\n +portfolio.pending.step2_buyer.postal=Bitte senden Sie {0} per \"US Postal Money Order\" an den XMR-Verkäufer.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Bitte schicken Sie {0} Bargeld per Post an den BTC Verkäufer. Genaue Anweisungen finden Sie im Handelsvertrag, oder Sie stellen über den Handels-Chat Fragen, wenn etwas unklar ist. Weitere Informationen über \"Bargeld per Post\" finden Sie im Haveno-Wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Bitte schicken Sie {0} Bargeld per Post an den XMR Verkäufer. Genaue Anweisungen finden Sie im Handelsvertrag, oder Sie stellen über den Handels-Chat Fragen, wenn etwas unklar ist. Weitere Informationen über \"Bargeld per Post\" finden Sie im Haveno-Wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Bitte zahlen Sie {0} mit der gewählten Zahlungsmethode an den BTC Verkäufer. Sie finden die Konto Details des Verkäufers im nächsten Fenster.\n\n +portfolio.pending.step2_buyer.pay=Bitte zahlen Sie {0} mit der gewählten Zahlungsmethode an den XMR Verkäufer. Sie finden die Konto Details des Verkäufers im nächsten Fenster.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Bitte kontaktieren Sie den BTC-Verkäufer, mit den bereitgestellten Daten und organisieren Sie ein Treffen um {0} zu zahlen.\n\n +portfolio.pending.step2_buyer.f2f=Bitte kontaktieren Sie den XMR-Verkäufer, mit den bereitgestellten Daten und organisieren Sie ein Treffen um {0} zu zahlen.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Zahlung per {0} beginnen portfolio.pending.step2_buyer.recipientsAccountData=Empfänger {0} portfolio.pending.step2_buyer.amountToTransfer=Zu überweisender Betrag @@ -628,27 +653,27 @@ portfolio.pending.step2_buyer.buyerAccount=Ihr zu verwendendes Zahlungskonto portfolio.pending.step2_buyer.paymentSent=Zahlung begonnen portfolio.pending.step2_buyer.warn=Sie haben Ihre {0} Zahlung noch nicht getätigt!\nBeachten Sie bitte, dass der Handel bis {1} abgeschlossen werden muss. portfolio.pending.step2_buyer.openForDispute=Sie haben Ihre Zahlung noch nicht abgeschlossen!\nDie maximale Frist für den Handel ist abgelaufen, bitte wenden Sie sich an den Vermittler, um Hilfe zu erhalten. -portfolio.pending.step2_buyer.paperReceipt.headline=Haben Sie die Quittung an den BTC-Verkäufer gesendet? -portfolio.pending.step2_buyer.paperReceipt.msg=Erinnerung:\nSie müssen folgendes auf die Quittung schreiben: NO REFUNDS.\nZerreißen Sie diese dann in zwei Teile und machen Sie ein Foto, das Sie an die E-Mail-Adresse des BTC-Verkäufers senden. +portfolio.pending.step2_buyer.paperReceipt.headline=Haben Sie die Quittung an den XMR-Verkäufer gesendet? +portfolio.pending.step2_buyer.paperReceipt.msg=Erinnerung:\nSie müssen folgendes auf die Quittung schreiben: NO REFUNDS.\nZerreißen Sie diese dann in zwei Teile und machen Sie ein Foto, das Sie an die E-Mail-Adresse des XMR-Verkäufers senden. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Authorisierungs-Nummer und Quittung senden -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Sie müssen die Authorisierungs-Nummer und ein Foto der Quittung per E-Mail an den BTC-Verkäufer senden.\nDie Quittung muss den vollständigen Namen, das Land, das Bundesland des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}.\n\nHaben Sie die Authorisierungs-Nummer und Vertragt an den Verkäufer gesendet? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Sie müssen die Authorisierungs-Nummer und ein Foto der Quittung per E-Mail an den XMR-Verkäufer senden.\nDie Quittung muss den vollständigen Namen, das Land, das Bundesland des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}.\n\nHaben Sie die Authorisierungs-Nummer und Vertragt an den Verkäufer gesendet? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=MTCN und Quittung senden -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Sie müssen die MTCN (Tracking-Nummer) und ein Foto der Quittung per E-Mail an den BTC-Verkäufer senden.\nDie Quittung muss den vollständigen Namen, die Stadt, das Land des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}.\n\nHaben Sie die MTCN und Vertragt an den Verkäufer gesendet? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Sie müssen die MTCN (Tracking-Nummer) und ein Foto der Quittung per E-Mail an den XMR-Verkäufer senden.\nDie Quittung muss den vollständigen Namen, die Stadt, das Land des Verkäufers und den Betrag deutlich zeigen. Die E-Mail-Adresse des Verkäufers lautet: {0}.\n\nHaben Sie die MTCN und Vertragt an den Verkäufer gesendet? portfolio.pending.step2_buyer.halCashInfo.headline=HalCash Code senden -portfolio.pending.step2_buyer.halCashInfo.msg=Sie müssen eine SMS mit dem HalCash-Code sowie der Trade-ID ({0}) an den BTC-Verkäufer senden.\nDie Handynummer des Verkäufers lautet {1}.\n\nHaben Sie den Code an den Verkäufer gesendet? +portfolio.pending.step2_buyer.halCashInfo.msg=Sie müssen eine SMS mit dem HalCash-Code sowie der Trade-ID ({0}) an den XMR-Verkäufer senden.\nDie Handynummer des Verkäufers lautet {1}.\n\nHaben Sie den Code an den Verkäufer gesendet? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Einige Banken könnten den Namen des Empfängers überprüfen. Faster Payments Konten, die in alten Haveno-Clients angelegt wurden, geben den Namen des Empfängers nicht an, also benutzen Sie bitte den Trade-Chat, um ihn zu erhalten (falls erforderlich). portfolio.pending.step2_buyer.confirmStart.headline=Bestätigen Sie, dass Sie die Zahlung begonnen haben portfolio.pending.step2_buyer.confirmStart.msg=Haben Sie die {0}-Zahlung an Ihren Handelspartner begonnen? portfolio.pending.step2_buyer.confirmStart.yes=Ja, ich habe die Zahlung begonnen portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=Sie haben keinen Zahlungsnachweis eingereicht. -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Sie haben die Transaktions-ID und den Transaktionsschlüssel nicht eingegeben.\n\nWenn Sie diese Informationen nicht zur Verfügung stellen, kann Ihr Handelspartner die automatische Bestätigung nicht nutzen, um die BTC freizugeben sobald die XMR erhalten wurden.\nAußerdem setzt Haveno voraus, dass der Sender der XMR Transaktion diese Informationen im Falle eines Konflikts dem Vermittler oder der Schiedsperson mitteilen kann.\nWeitere Informationen finden Sie im Haveno Wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Sie haben die Transaktions-ID und den Transaktionsschlüssel nicht eingegeben.\n\nWenn Sie diese Informationen nicht zur Verfügung stellen, kann Ihr Handelspartner die automatische Bestätigung nicht nutzen, um die XMR freizugeben sobald die XMR erhalten wurden.\nAußerdem setzt Haveno voraus, dass der Sender der XMR Transaktion diese Informationen im Falle eines Konflikts dem Vermittler oder der Schiedsperson mitteilen kann.\nWeitere Informationen finden Sie im Haveno Wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Die Eingabe ist kein 32 byte Hexadezimalwert portfolio.pending.step2_buyer.confirmStart.warningButton=Ignorieren und fortfahren portfolio.pending.step2_seller.waitPayment.headline=Auf Zahlung warten portfolio.pending.step2_seller.f2fInfo.headline=Kontaktinformation des Käufers -portfolio.pending.step2_seller.waitPayment.msg=Die Kautionstransaktion hat mindestens eine Blockchain-Bestätigung.\nSie müssen warten bis der BTC-Käufer die {0}-Zahlung beginnt. -portfolio.pending.step2_seller.warn=Der BTC-Käufer hat die {0}-Zahlung noch nicht getätigt.\nSie müssen warten bis die Zahlung begonnen wurde.\nWenn der Handel nicht bis {1} abgeschlossen wurde, wird der Vermittler diesen untersuchen. -portfolio.pending.step2_seller.openForDispute=Der BTC-Käufer hat seine Zahlung nicht begonnen!\nDie maximal zulässige Frist für den Handel ist abgelaufen.\nSie können länger warten und dem Handelspartner mehr Zeit geben oder den Vermittler um Hilfe bitten. +portfolio.pending.step2_seller.waitPayment.msg=Die Kautionstransaktion hat mindestens eine Blockchain-Bestätigung.\nSie müssen warten bis der XMR-Käufer die {0}-Zahlung beginnt. +portfolio.pending.step2_seller.warn=Der XMR-Käufer hat die {0}-Zahlung noch nicht getätigt.\nSie müssen warten bis die Zahlung begonnen wurde.\nWenn der Handel nicht bis {1} abgeschlossen wurde, wird der Vermittler diesen untersuchen. +portfolio.pending.step2_seller.openForDispute=Der XMR-Käufer hat seine Zahlung nicht begonnen!\nDie maximal zulässige Frist für den Handel ist abgelaufen.\nSie können länger warten und dem Handelspartner mehr Zeit geben oder den Vermittler um Hilfe bitten. tradeChat.chatWindowTitle=Chat-Fenster für Trade mit ID ''{0}'' tradeChat.openChat=Chat-Fenster öffnen tradeChat.rules=Sie können mit Ihrem Trade-Partner kommunizieren, um mögliche Probleme mit diesem Trade zu lösen.\nEs ist nicht zwingend erforderlich, im Chat zu antworten.\nWenn ein Trader gegen eine der folgenden Regeln verstößt, eröffnen Sie einen Streitfall und melden Sie ihn dem Mediator oder Vermittler.\n\nChat-Regeln:\n\t● Senden Sie keine Links (Risiko von Malware). Sie können die Transaktions-ID und den Namen eines Block-Explorers senden.\n\t● Senden Sie keine Seed-Wörter, Private Keys, Passwörter oder andere sensible Informationen!\n\t● Traden Sie nicht außerhalb von Haveno (keine Sicherheit).\n\t● Beteiligen Sie sich nicht an Betrugsversuchen in Form von Social Engineering.\n\t● Wenn ein Partner nicht antwortet und es vorzieht, nicht über den Chat zu kommunizieren, respektieren Sie seine Entscheidung.\n\t● Beschränken Sie Ihre Kommunikation auf das Traden. Dieser Chat ist kein Messenger-Ersatz oder eine Trollbox.\n\t● Bleiben Sie im Gespräch freundlich und respektvoll. @@ -666,26 +691,26 @@ message.state.ACKNOWLEDGED=Peer hat Nachrichtenerhalt bestätigt # suppress inspection "UnusedProperty" message.state.FAILED=Senden der Nachricht fehlgeschlagen -portfolio.pending.step3_buyer.wait.headline=Auf Zahlungsbestätigung des BTC-Verkäufers warten -portfolio.pending.step3_buyer.wait.info=Auf Bestätigung des BTC-Verkäufers zum Erhalt der {0}-Zahlung warten. +portfolio.pending.step3_buyer.wait.headline=Auf Zahlungsbestätigung des XMR-Verkäufers warten +portfolio.pending.step3_buyer.wait.info=Auf Bestätigung des XMR-Verkäufers zum Erhalt der {0}-Zahlung warten. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Zahlungsbeginn-Nachricht-Status portfolio.pending.step3_buyer.warn.part1a=in der {0}-Blockchain portfolio.pending.step3_buyer.warn.part1b=bei Ihrem Zahlungsanbieter (z.B. Bank) -portfolio.pending.step3_buyer.warn.part2=Der BTC-Verkäufer hat Ihre Zahlung noch nicht bestätigt. Bitte überprüfen Sie {0}, ob der Zahlungsvorgang erfolgreich war. -portfolio.pending.step3_buyer.openForDispute=Der BTC-Verkäufer hat Ihre Zahlung nicht bestätigt! Die maximale Frist für den Handel ist abgelaufen. Sie können länger warten und dem Trading-Partner mehr Zeit geben oder den Vermittler um Hilfe bitten. +portfolio.pending.step3_buyer.warn.part2=Der XMR-Verkäufer hat Ihre Zahlung noch nicht bestätigt. Bitte überprüfen Sie {0}, ob der Zahlungsvorgang erfolgreich war. +portfolio.pending.step3_buyer.openForDispute=Der XMR-Verkäufer hat Ihre Zahlung nicht bestätigt! Die maximale Frist für den Handel ist abgelaufen. Sie können länger warten und dem Trading-Partner mehr Zeit geben oder den Vermittler um Hilfe bitten. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Ihr Handelspartner hat bestätigt, die {0}-Zahlung begonnen zu haben.\n\n portfolio.pending.step3_seller.crypto.explorer=in ihrem bevorzugten {0} Blockchain Explorer portfolio.pending.step3_seller.crypto.wallet=in ihrer {0} Wallet portfolio.pending.step3_seller.crypto={0}Bitte überprüfen Sie mit Ihrem bevorzugten {1}-Blockchain-Explorer, ob die Transaktion zu Ihrer Empfangsadresse\n{2}\nschon genug Blockchain-Bestätigungen hat.\nDer Zahlungsbetrag muss {3} sein\n\nSie können Ihre {4}-Adresse vom Hauptbildschirm kopieren und woanders einfügen, nachdem dieser Dialog geschlossen wurde. -portfolio.pending.step3_seller.postal={0}Bitte überprüfen Sie, ob Sie {1} per \"US Postal Money Order\" vom BTC-Käufer erhalten haben. +portfolio.pending.step3_seller.postal={0}Bitte überprüfen Sie, ob Sie {1} per \"US Postal Money Order\" vom XMR-Käufer erhalten haben. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Bitte überprüfen Sie, ob Sie {1} als \"Bargeld per Post\" vom BTC-Käufer erhalten haben. +portfolio.pending.step3_seller.payByMail={0}Bitte überprüfen Sie, ob Sie {1} als \"Bargeld per Post\" vom XMR-Käufer erhalten haben. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Ihr Handelspartner hat den Beginn der {0}-Zahlung bestätigt.\n\nBitte gehen Sie auf Ihre Online-Banking-Website und überprüfen Sie, ob Sie {1} vom BTC-Käufer erhalten haben. -portfolio.pending.step3_seller.cash=Da die Zahlung per Cash Deposit ausgeführt wurde, muss der BTC-Käufer \"NO REFUND\" auf die Quittung schreiben, diese in 2 Teile reißen und Ihnen ein Foto per E-Mail schicken.\n\nUm die Gefahr einer Rückbuchung zu vermeiden bestätigen Sie nur, wenn Sie die E-Mail erhalten haben und Sie sicher sind, dass die Quittung gültig ist.\nWenn Sie nicht sicher sind, {0} -portfolio.pending.step3_seller.moneyGram=Der Käufer muss Ihnen die Authorisierungs-Nummer und ein Foto der Quittung per E-Mail zusenden.\nDie Quittung muss deutlich Ihren vollständigen Namen, Ihr Land, Ihr Bundesland und den Betrag enthalten. Bitte überprüfen Sie Ihre E-Mail, wenn Sie die Authorisierungs-Nummer erhalten haben.\n\nNach dem Schließen dieses Pop-ups sehen Sie den Namen und die Adresse des BTC-Käufers, um das Geld von MoneyGram abzuholen.\n\nBestätigen Sie den Erhalt erst, nachdem Sie das Geld erfolgreich abgeholt haben! -portfolio.pending.step3_seller.westernUnion=Der Käufer muss Ihnen die MTCN (Sendungsnummer) und ein Foto der Quittung per E-Mail zusenden.\nDie Quittung muss deutlich Ihren vollständigen Namen, Ihre Stadt, Ihr Land und den Betrag enthalten. Bitte überprüfen Sie Ihre E-Mail, wenn Sie die MTCN erhalten haben.\n\nNach dem Schließen dieses Pop-ups sehen Sie den Namen und die Adresse des BTC-Käufers, um das Geld von Western Union abzuholen.\n\nBestätigen Sie den Erhalt erst, nachdem Sie das Geld erfolgreich abgeholt haben! +portfolio.pending.step3_seller.bank=Ihr Handelspartner hat den Beginn der {0}-Zahlung bestätigt.\n\nBitte gehen Sie auf Ihre Online-Banking-Website und überprüfen Sie, ob Sie {1} vom XMR-Käufer erhalten haben. +portfolio.pending.step3_seller.cash=Da die Zahlung per Cash Deposit ausgeführt wurde, muss der XMR-Käufer \"NO REFUND\" auf die Quittung schreiben, diese in 2 Teile reißen und Ihnen ein Foto per E-Mail schicken.\n\nUm die Gefahr einer Rückbuchung zu vermeiden bestätigen Sie nur, wenn Sie die E-Mail erhalten haben und Sie sicher sind, dass die Quittung gültig ist.\nWenn Sie nicht sicher sind, {0} +portfolio.pending.step3_seller.moneyGram=Der Käufer muss Ihnen die Authorisierungs-Nummer und ein Foto der Quittung per E-Mail zusenden.\nDie Quittung muss deutlich Ihren vollständigen Namen, Ihr Land, Ihr Bundesland und den Betrag enthalten. Bitte überprüfen Sie Ihre E-Mail, wenn Sie die Authorisierungs-Nummer erhalten haben.\n\nNach dem Schließen dieses Pop-ups sehen Sie den Namen und die Adresse des XMR-Käufers, um das Geld von MoneyGram abzuholen.\n\nBestätigen Sie den Erhalt erst, nachdem Sie das Geld erfolgreich abgeholt haben! +portfolio.pending.step3_seller.westernUnion=Der Käufer muss Ihnen die MTCN (Sendungsnummer) und ein Foto der Quittung per E-Mail zusenden.\nDie Quittung muss deutlich Ihren vollständigen Namen, Ihre Stadt, Ihr Land und den Betrag enthalten. Bitte überprüfen Sie Ihre E-Mail, wenn Sie die MTCN erhalten haben.\n\nNach dem Schließen dieses Pop-ups sehen Sie den Namen und die Adresse des XMR-Käufers, um das Geld von Western Union abzuholen.\n\nBestätigen Sie den Erhalt erst, nachdem Sie das Geld erfolgreich abgeholt haben! portfolio.pending.step3_seller.halCash=Der Käufer muss Ihnen den HalCash-Code als SMS zusenden. Außerdem erhalten Sie eine Nachricht von HalCash mit den erforderlichen Informationen, um EUR an einem HalCash-fähigen Geldautomaten abzuheben.\n\nNachdem Sie das Geld am Geldautomaten abgeholt haben, bestätigen Sie bitte hier den Zahlungseingang! portfolio.pending.step3_seller.amazonGiftCard=Der Käufer hat Ihnen eine Amazon eGift Geschenkkarte per E-Mail oder per Textnachricht auf Ihr Handy geschickt. Bitte lösen Sie die Amazon eGift Geschenkkarte jetzt in Ihrem Amazon-Konto ein und bestätigen Sie nach der erfolgreichen Annahme den Zahlungseingang. @@ -701,7 +726,7 @@ portfolio.pending.step3_seller.xmrTxHash=Transaktions-ID portfolio.pending.step3_seller.xmrTxKey=Transaktions-Schlüssel portfolio.pending.step3_seller.buyersAccount=Käufer Konto-Informationen portfolio.pending.step3_seller.confirmReceipt=Zahlungserhalt bestätigen -portfolio.pending.step3_seller.buyerStartedPayment=Der BTC-Käufer hat die {0}-Zahlung begonnen.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=Der XMR-Käufer hat die {0}-Zahlung begonnen.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Überprüfen Sie Ihre Crypto-Wallet oder Ihren Block-Explorer auf Blockchain-Bestätigungen und bestätigen Sie die Zahlung, wenn ausreichend viele Blockchain-Bestätigungen angezeigt werden. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Prüfen Sie Ihr Handelskonto (z.B. Bankkonto) und bestätigen Sie, wenn Sie die Zahlung erhalten haben. portfolio.pending.step3_seller.warn.part1a=in der {0}-Blockchain @@ -713,7 +738,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Ist die {0}-Zahlung Ihres # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Bitte überprüfen Sie auch, ob der Name des im Trade-Vertrag angegebenen Absenders mit dem Namen auf Ihrem Kontoauszug übereinstimmt:\nName des Absenders, pro Trade-Vertrag: {0}\n\nWenn die Namen nicht genau gleich sind, bestätigen Sie den Zahlungseingang nicht. Eröffnen Sie stattdessen einen Konflikt, indem Sie \"alt + o\" oder \"option + o\" drücken.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Bitte beachten Sie, dass, sobald Sie den Erhalt bestätigt haben, der gesperrte Trade-Betrag an den BTC-Käufer freigegeben wird und die Kaution zurückerstattet wird.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Bitte beachten Sie, dass, sobald Sie den Erhalt bestätigt haben, der gesperrte Trade-Betrag an den XMR-Käufer freigegeben wird und die Kaution zurückerstattet wird.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Bestätigen Sie, die Zahlung erhalten zu haben portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Ja, ich habe die Zahlung erhalten portfolio.pending.step3_seller.onPaymentReceived.signer=WICHTIG: Mit der Bestätigung des Zahlungseingangs verifizieren Sie auch das Konto der Gegenpartei und unterzeichnen es entsprechend. Da das Konto der Gegenpartei noch nicht unterzeichnet ist, sollten Sie die Bestätigung der Zahlung so lange wie möglich hinauszögern, um das Risiko einer Rückbelastung zu reduzieren. @@ -723,7 +748,7 @@ portfolio.pending.step5_buyer.tradeFee=Handelsgebühr portfolio.pending.step5_buyer.makersMiningFee=Mining-Gebühr portfolio.pending.step5_buyer.takersMiningFee=Gesamte Mining-Gebühr portfolio.pending.step5_buyer.refunded=Rückerstattete Kaution -portfolio.pending.step5_buyer.withdrawBTC=Ihre Bitcoins abheben +portfolio.pending.step5_buyer.withdrawXMR=Ihre Moneros abheben portfolio.pending.step5_buyer.amount=Abzuhebender Betrag portfolio.pending.step5_buyer.withdrawToAddress=An diese Adresse abheben portfolio.pending.step5_buyer.moveToHavenoWallet=Gelder in der Haveno Wallet aufbewahren @@ -732,7 +757,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Ihre Gelder wurden bereits abgeho portfolio.pending.step5_buyer.confirmWithdrawal=Anfrage zum Abheben bestätigen portfolio.pending.step5_buyer.amountTooLow=Der zu überweisende Betrag ist kleiner als die Transaktionsgebühr und der minimale Tx-Wert (Staub). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Abheben abgeschlossen -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Ihre abgeschlossenen Trades sind unter \"Portfolio/Verlauf\" gespeichert.\nSie können all Ihre Bitcoin-Transaktionen unter \"Gelder/Transaktionen\" einsehen +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Ihre abgeschlossenen Trades sind unter \"Portfolio/Verlauf\" gespeichert.\nSie können all Ihre Monero-Transaktionen unter \"Gelder/Transaktionen\" einsehen portfolio.pending.step5_buyer.bought=Sie haben gekauft portfolio.pending.step5_buyer.paid=Sie haben gezahlt @@ -794,7 +819,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Sie haben bereits akzept portfolio.pending.failedTrade.taker.missingTakerFeeTx=Die Transaktion der Abnehmer-Gebühr fehlt.\n\nOhne diese tx kann der Handel nicht abgeschlossen werden. Keine Gelder wurden gesperrt und keine Handelsgebühr wurde bezahlt. Sie können diesen Handel zu den fehlgeschlagenen Händeln verschieben. portfolio.pending.failedTrade.maker.missingTakerFeeTx=Die Transaktion der Abnehmer-Gebühr fehlt.\n\nOhne diese tx kann der Handel nicht abgeschlossen werden. Keine Gelder wurden gesperrt. Ihr Angebot ist für andere Händler weiterhin verfügbar. Sie haben die Ersteller-Gebühr also nicht verloren. Sie können diesen Handel zu den fehlgeschlagenen Händeln verschieben. portfolio.pending.failedTrade.missingDepositTx=Die Einzahlungstransaktion (die 2-of-2 Multisig-Transaktion) fehlt.\n\nOhne diese tx kann der Handel nicht abgeschlossen werden. Keine Gelder wurden gesperrt aber die Handels-Gebühr wurde bezahlt. Sie können eine Anfrage für eine Rückerstattung der Handels-Gebühr hier einreichen: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nSie können diesen Handel gerne zu den fehlgeschlagenen Händeln verschieben. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Die verzögerte Auszahlungstransaktion fehlt, aber die Gelder wurden in der Einzahlungstransaktion gesperrt.\n\nBitte schicken Sie KEINE Geld-(Traditional-) oder Crypto-Zahlungen an den BTC Verkäufer, weil ohne die verzögerte Auszahlungstransaktion später kein Schlichtungsverfahren eröffnet werden kann. Stattdessen öffnen Sie ein Vermittlungs-Ticket mit Cmd/Strg+o. Der Vermittler sollte vorschlagen, dass beide Handelspartner ihre vollständige Sicherheitskaution zurückerstattet bekommen (und der Verkäufer auch seinen Handels-Betrag). Durch diese Vorgehensweise entsteht kein Sicherheitsrisiko und es geht ausschließlich die Handelsgebühr verloren.\n\nSie können eine Rückerstattung der verlorenen gegangenen Handelsgebühren hier erbitten: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Die verzögerte Auszahlungstransaktion fehlt, aber die Gelder wurden in der Einzahlungstransaktion gesperrt.\n\nBitte schicken Sie KEINE Geld-(Traditional-) oder Crypto-Zahlungen an den XMR Verkäufer, weil ohne die verzögerte Auszahlungstransaktion später kein Schlichtungsverfahren eröffnet werden kann. Stattdessen öffnen Sie ein Vermittlungs-Ticket mit Cmd/Strg+o. Der Vermittler sollte vorschlagen, dass beide Handelspartner ihre vollständige Sicherheitskaution zurückerstattet bekommen (und der Verkäufer auch seinen Handels-Betrag). Durch diese Vorgehensweise entsteht kein Sicherheitsrisiko und es geht ausschließlich die Handelsgebühr verloren.\n\nSie können eine Rückerstattung der verlorenen gegangenen Handelsgebühren hier erbitten: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=Die verzögerte Auszahlungstransaktion fehlt, aber die Gelder wurden in der Einzahlungstransaktion gesperrt.\n\nWenn dem Käufer die verzögerte Auszahlungstransaktion auch fehlt, wird er dazu aufgefordert die Bezahlung NICHT zu schicken und stattdessen ein Vermittlungs-Ticket zu eröffnen. Sie sollten auch ein Vermittlungs-Ticket mit Cmd/Strg+o öffnen.\n\nWenn der Käufer die Zahlung noch nicht geschickt hat, sollte der Vermittler vorschlagen, dass beide Handelspartner ihre Sicherheitskaution vollständig zurückerhalten (und der Verkäufer auch den Handels-Betrag). Anderenfalls sollte der Handels-Betrag an den Käufer gehen.\n\nSie können eine Rückerstattung der verlorenen gegangenen Handelsgebühren hier erbitten: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=Während der Ausführung des Handel-Protokolls ist ein Fehler aufgetreten.\n\nFehler: {0}\n\nEs kann sein, dass dieser Fehler nicht gravierend ist und der Handel ganz normal abgeschlossen werden kann. Wenn Sie sich unsicher sind, öffnen Sie ein Vermittlungs-Ticket um den Rat eines Haveno Vermittlers zu erhalten.\n\nWenn der Fehler gravierend war, kann der Handel nicht abgeschlossen werden und Sie haben vielleicht die Handelsgebühr verloren. Sie können eine Rückerstattung der verlorenen gegangenen Handelsgebühren hier erbitten: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=Der Handelsvertrag ist nicht festgelegt.\n\nDer Handel kann nicht abgeschlossen werden und Sie haben möglicherweise die Handelsgebühr verloren. Sollte das der Fall sein, können Sie eine Rückerstattung der verlorenen gegangenen Handelsgebühren hier beantragen: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +858,7 @@ funds.deposit.fundHavenoWallet=Haveno-Wallet finanzieren funds.deposit.noAddresses=Es wurden noch keine Kautionsadressen generiert funds.deposit.fundWallet=Ihre Wallet finanzieren funds.deposit.withdrawFromWallet=Gelder aus Wallet übertragen -funds.deposit.amount=Betrag in BTC (optional) +funds.deposit.amount=Betrag in XMR (optional) funds.deposit.generateAddress=Neue Adresse generieren funds.deposit.generateAddressSegwit=Native segwit Format (Bech32) funds.deposit.selectUnused=Bitte wählen Sie eine ungenutzte Adresse aus der Tabelle oben, anstatt eine neue zu generieren. @@ -890,7 +915,7 @@ funds.tx.revert=Umkehren funds.tx.txSent=Transaktion erfolgreich zu einer neuen Adresse in der lokalen Haveno-Wallet gesendet. funds.tx.direction.self=An Sie selbst senden funds.tx.dustAttackTx=Staub erhalten -funds.tx.dustAttackTx.popup=Diese Transaktion sendet einen sehr kleinen BTC Betrag an Ihre Wallet und kann von Chainanalyse Unternehmen genutzt werden um ihre Wallet zu spionieren.\n\nWenn Sie den Transaktionsausgabe in einer Ausgabe nutzen, wird es lernen, dass Sie wahrscheinlich auch Besitzer der anderen Adressen sind (coin merge),\n\nUm Ihre Privatsphäre zu schützen, wir die Havenowallet Staubausgaben für Ausgaben und bei der Anzeige der Guthabens ignorieren. Sie können den Grenzwert, ab wann ein Wert als Staub angesehen wird in den Einstellungen ändern. +funds.tx.dustAttackTx.popup=Diese Transaktion sendet einen sehr kleinen XMR Betrag an Ihre Wallet und kann von Chainanalyse Unternehmen genutzt werden um ihre Wallet zu spionieren.\n\nWenn Sie den Transaktionsausgabe in einer Ausgabe nutzen, wird es lernen, dass Sie wahrscheinlich auch Besitzer der anderen Adressen sind (coin merge),\n\nUm Ihre Privatsphäre zu schützen, wir die Havenowallet Staubausgaben für Ausgaben und bei der Anzeige der Guthabens ignorieren. Sie können den Grenzwert, ab wann ein Wert als Staub angesehen wird in den Einstellungen ändern. #################################################################### # Support @@ -904,7 +929,7 @@ support.filter=Konflikte durchsuchen support.filter.prompt=Tragen sie Handel ID, Datum, Onion Adresse oder Kontodaten support.sigCheck.button=Signatur überprüfen -support.sigCheck.popup.info=Im Falle eines Vergütungsantrags an die DAO müssen Sie eine Zusammenfassung des Vermittlungs- und Schiedsverfahrens in Ihren Vergütungsantrags auf Github einfügen. Um diese Angabe überprüfbar zu machen, kann jeder Nutzer mit diesem Tool überprüfen, ob die Signatur des Vermittlers oder der Schiedsperson mit der Zusammenfassung übereinstimmt. +support.sigCheck.popup.info=Fügen Sie die Zusammenfassungsnachricht des Schiedsverfahrens ein. Mit diesem Tool kann jeder Benutzer überprüfen, ob die Unterschrift des Schiedsrichters mit der Zusammenfassungsnachricht übereinstimmt. support.sigCheck.popup.header=Signatur des Konfliktergebnisses überprüfen support.sigCheck.popup.msg.label=Zusammenfassende Nachricht support.sigCheck.popup.msg.prompt=Zusammenfassende Angaben aus dem Konflikt kopieren und einfügen @@ -940,8 +965,8 @@ support.savedInMailbox=Die Nachricht wurde im Postfach des Empfängers gespeiche support.arrived=Die Nachricht ist beim Empfänger angekommen support.acknowledged=Nachrichtenankunft vom Empfänger bestätigt support.error=Empfänger konnte die Nachricht nicht verarbeiten. Fehler: {0} -support.buyerAddress=BTC-Adresse des Käufers -support.sellerAddress=BTC-Adresse des Verkäufers +support.buyerAddress=XMR-Adresse des Käufers +support.sellerAddress=XMR-Adresse des Verkäufers support.role=Rolle support.agent=Support-Mitarbeiter support.state=Status @@ -949,13 +974,13 @@ support.chat=Chat support.closed=Geschlossen support.open=Offen support.process=Process -support.buyerMaker=BTC-Käufer/Ersteller -support.sellerMaker=BTC-Verkäufer/Ersteller -support.buyerTaker=BTC-Käufer/Abnehmer -support.sellerTaker=BTC-Verkäufer/Abnehmer +support.buyerMaker=XMR-Käufer/Ersteller +support.sellerMaker=XMR-Verkäufer/Ersteller +support.buyerTaker=XMR-Käufer/Abnehmer +support.sellerTaker=XMR-Verkäufer/Abnehmer -support.backgroundInfo=Haveno ist kein Unternehmen, daher behandelt es Konflikte unterschiedlich.\n\nTrader können innerhalb der Anwendung über einen sicheren Chat auf dem Bildschirm für offene Trades kommunizieren, um zu versuchen, Konflikte selbst zu lösen. Wenn das nicht ausreicht, kann ein Mediator einschreiten und helfen. Der Mediator wird die Situation bewerten und eine Auszahlung von Trade Funds vorschlagen. Wenn beide Trader diesen Vorschlag annehmen, ist die Auszahlungstransaktion abgeschlossen und der Trade geschlossen. Wenn ein oder beide Trader mit der vom Mediator vorgeschlagenen Auszahlung nicht einverstanden sind, können sie ein Vermittlungsverfahren beantragen, bei dem der Vermittler die Situation neu bewertet und, falls gerechtfertigt, dem Trader persönlich eine Rückerstattung leistet und die Rückerstattung dieser Zahlung vom Haveno DAO verlangt. -support.initialInfo=Bitte geben Sie eine Beschreibung Ihres Problems in das untenstehende Textfeld ein. Fügen Sie so viele Informationen wie möglich hinzu, um die Zeit für die Konfliktlösung zu verkürzen.\n\nHier ist eine Checkliste für Informationen, die Sie angeben sollten:\n\t● Wenn Sie der BTC-Käufer sind: Haben Sie die Traditional- oder Crypto-Überweisung gemacht? Wenn ja, haben Sie in der Anwendung auf die Schaltfläche "Zahlung gestartet" geklickt?\n\t● Wenn Sie der BTC-Verkäufer sind: Haben Sie die Traditional- oder Crypto-Zahlung erhalten? Wenn ja, haben Sie in der Anwendung auf die Schaltfläche "Zahlung erhalten" geklickt?\n\t● Welche Version von Haveno verwenden Sie?\n\t● Welches Betriebssystem verwenden Sie?\n\t● Wenn Sie ein Problem mit fehlgeschlagenen Transaktionen hatten, überlegen Sie bitte, in ein neues Datenverzeichnis zu wechseln.\n\t Manchmal wird das Datenverzeichnis beschädigt und führt zu seltsamen Fehlern. \n\t Siehe: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nBitte machen Sie sich mit den Grundregeln für den Konfliktprozess vertraut:\n\t● Sie müssen auf die Anfragen der {0}'' innerhalb von 2 Tagen antworten.\n\t● Mediatoren antworten innerhalb von 2 Tagen. Die Vermittler antworten innerhalb von 5 Werktagen.\n\t● Die maximale Frist für einen Konflikt beträgt 14 Tage.\n\t● Sie müssen mit den {1} zusammenarbeiten und die Informationen zur Verfügung stellen, die sie anfordern, um Ihren Fall zu bearbeiten.\n\t● Mit dem ersten Start der Anwendung haben Sie die Regeln des Konfliktdokuments in der Nutzervereinbarung akzeptiert.\n\nSie können mehr über den Konfliktprozess erfahren unter: {2} +support.backgroundInfo=Haveno ist kein Unternehmen, daher behandelt es Konflikte unterschiedlich.\n\nTrader können innerhalb der Anwendung über einen sicheren Chat auf dem Bildschirm für offene Trades kommunizieren, um zu versuchen, Konflikte selbst zu lösen. Wenn das nicht ausreicht, kann ein Mediator einschreiten und helfen. Der Mediator wird die Situation bewerten und eine Auszahlung von Trade Funds vorschlagen. +support.initialInfo=Bitte geben Sie eine Beschreibung Ihres Problems in das untenstehende Textfeld ein. Fügen Sie so viele Informationen wie möglich hinzu, um die Zeit für die Konfliktlösung zu verkürzen.\n\nHier ist eine Checkliste für Informationen, die Sie angeben sollten:\n\t● Wenn Sie der XMR-Käufer sind: Haben Sie die Traditional- oder Crypto-Überweisung gemacht? Wenn ja, haben Sie in der Anwendung auf die Schaltfläche "Zahlung gestartet" geklickt?\n\t● Wenn Sie der XMR-Verkäufer sind: Haben Sie die Traditional- oder Crypto-Zahlung erhalten? Wenn ja, haben Sie in der Anwendung auf die Schaltfläche "Zahlung erhalten" geklickt?\n\t● Welche Version von Haveno verwenden Sie?\n\t● Welches Betriebssystem verwenden Sie?\n\t● Wenn Sie ein Problem mit fehlgeschlagenen Transaktionen hatten, überlegen Sie bitte, in ein neues Datenverzeichnis zu wechseln.\n\t Manchmal wird das Datenverzeichnis beschädigt und führt zu seltsamen Fehlern. \n\t Siehe: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nBitte machen Sie sich mit den Grundregeln für den Konfliktprozess vertraut:\n\t● Sie müssen auf die Anfragen der {0}'' innerhalb von 2 Tagen antworten.\n\t● Mediatoren antworten innerhalb von 2 Tagen. Die Vermittler antworten innerhalb von 5 Werktagen.\n\t● Die maximale Frist für einen Konflikt beträgt 14 Tage.\n\t● Sie müssen mit den {1} zusammenarbeiten und die Informationen zur Verfügung stellen, die sie anfordern, um Ihren Fall zu bearbeiten.\n\t● Mit dem ersten Start der Anwendung haben Sie die Regeln des Konfliktdokuments in der Nutzervereinbarung akzeptiert.\n\nSie können mehr über den Konfliktprozess erfahren unter: {2} support.systemMsg=Systemnachricht: {0} support.youOpenedTicket=Sie haben eine Anfrage auf Support geöffnet.\n\n{0}\n\nHaveno-Version: {1} support.youOpenedDispute=Sie haben eine Anfrage für einen Konflikt geöffnet.\n\n{0}\n\nHaveno-version: {1} @@ -979,13 +1004,14 @@ settings.tab.network=Netzwerk-Info settings.tab.about=Über setting.preferences.general=Allgemeine Voreinstellungen -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Max. Abweichung vom Marktpreis setting.preferences.avoidStandbyMode=Standby Modus verhindern +setting.preferences.useSoundForNotifications=Spiele Geräusche für Benachrichtigungen setting.preferences.autoConfirmXMR=XMR automatische Bestätigung setting.preferences.autoConfirmEnabled=Aktiviert setting.preferences.autoConfirmRequiredConfirmations=Benötigte Bestätigungen -setting.preferences.autoConfirmMaxTradeSize=Max. Trade-Höhe (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. Trade-Höhe (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (verwendet Tor, außer localhost, LAN IP Adresse und *.local hostnames) setting.preferences.deviationToLarge=Werte größer als {0}% sind nicht erlaubt. setting.preferences.txFee=Auszahlungstransaktionsgebühr (satoshis/vbyte) @@ -1022,29 +1048,31 @@ settings.preferences.editCustomExplorer.name=Name settings.preferences.editCustomExplorer.txUrl=Transaktions-URL settings.preferences.editCustomExplorer.addressUrl=Adress-URL -settings.net.btcHeader=Bitcoin-Netzwerk +settings.net.xmrHeader=Monero-Netzwerk settings.net.p2pHeader=Haveno-Netzwerk settings.net.onionAddressLabel=Meine Onion-Adresse settings.net.xmrNodesLabel=Spezifische Monero-Knoten verwenden settings.net.moneroPeersLabel=Verbundene Peers +settings.net.connection=Verbindung +settings.net.connected=Verbunden settings.net.useTorForXmrJLabel=Tor für das Monero-Netzwerk verwenden settings.net.moneroNodesLabel=Mit Monero-Knoten verbinden -settings.net.useProvidedNodesRadio=Bereitgestellte Bitcoin-Core-Knoten verwenden -settings.net.usePublicNodesRadio=Öffentliches Bitcoin-Netzwerk benutzen -settings.net.useCustomNodesRadio=Spezifische Bitcoin-Core-Knoten verwenden +settings.net.useProvidedNodesRadio=Bereitgestellte Monero-Core-Knoten verwenden +settings.net.usePublicNodesRadio=Öffentliches Monero-Netzwerk benutzen +settings.net.useCustomNodesRadio=Spezifische Monero-Core-Knoten verwenden settings.net.warn.usePublicNodes=Wenn Sie öffentliche Monero-Nodes verwenden, sind Sie den Risiken ausgesetzt, die mit der Verwendung unvertrauenswürdiger Remote-Nodes verbunden sind.\n\nBitte lesen Sie weitere Details unter [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nSind Sie sich sicher, dass Sie öffentliche Nodes verwenden möchten? settings.net.warn.usePublicNodes.useProvided=Nein, bereitgestellte Knoten verwenden settings.net.warn.usePublicNodes.usePublic=Ja, öffentliches Netzwerk verwenden -settings.net.warn.useCustomNodes.B2XWarning=Bitte stellen Sie sicher, dass Sie sich mit einem vertrauenswürdigen Bitcoin-Core-Knoten verbinden!\n\nWenn Sie sich mit Knoten verbinden, die gegen die Bitcoin Core Konsensus-Regeln verstoßen, kann es zu Problemen in Ihrer Wallet und im Verlauf des Handelsprozesses kommen.\n\nBenutzer die sich zu oben genannten Knoten verbinden, sind für den verursachten Schaden verantwortlich. Dadurch entstandene Konflikte werden zugunsten des anderen Teilnehmers entschieden. Benutzer die unsere Warnungen und Sicherheitsmechanismen ignorieren wird keine technische Unterstützung geleistet! -settings.net.warn.invalidBtcConfig=Die Verbindung zum Bitcoin-Netzwerk ist fehlgeschlagen, weil Ihre Konfiguration ungültig ist.\n\nIhre Konfiguration wurde zurückgesetzt, um stattdessen die bereitgestellten Bitcoin-Nodes zu verwenden. Sie müssen die Anwendung neu starten. -settings.net.localhostXmrNodeInfo=Hintergrundinformationen: Haveno sucht beim Start nach einem lokalen Bitcoin-Node. Wird dieser gefunden, kommuniziert Haveno ausschließlich über diesen mit dem Bitcoin-Netzwerk. +settings.net.warn.useCustomNodes.B2XWarning=Bitte stellen Sie sicher, dass Sie sich mit einem vertrauenswürdigen Monero-Core-Knoten verbinden!\n\nWenn Sie sich mit Knoten verbinden, die gegen die Monero Core Konsensus-Regeln verstoßen, kann es zu Problemen in Ihrer Wallet und im Verlauf des Handelsprozesses kommen.\n\nBenutzer die sich zu oben genannten Knoten verbinden, sind für den verursachten Schaden verantwortlich. Dadurch entstandene Konflikte werden zugunsten des anderen Teilnehmers entschieden. Benutzer die unsere Warnungen und Sicherheitsmechanismen ignorieren wird keine technische Unterstützung geleistet! +settings.net.warn.invalidXmrConfig=Die Verbindung zum Monero-Netzwerk ist fehlgeschlagen, weil Ihre Konfiguration ungültig ist.\n\nIhre Konfiguration wurde zurückgesetzt, um stattdessen die bereitgestellten Monero-Nodes zu verwenden. Sie müssen die Anwendung neu starten. +settings.net.localhostXmrNodeInfo=Hintergrundinformationen: Haveno sucht beim Start nach einem lokalen Monero-Node. Wird dieser gefunden, kommuniziert Haveno ausschließlich über diesen mit dem Monero-Netzwerk. settings.net.p2PPeersLabel=Verbundene Peers settings.net.onionAddressColumn=Onion-Adresse settings.net.creationDateColumn=Eingerichtet settings.net.connectionTypeColumn=Ein/Aus settings.net.sentDataLabel=Daten-Statistiken senden settings.net.receivedDataLabel=Daten-Statistiken empfangen -settings.net.chainHeightLabel=Letzte BTC Blockzeit +settings.net.chainHeightLabel=Letzte XMR Blockzeit settings.net.roundTripTimeColumn=Umlaufzeit settings.net.sentBytesColumn=Gesendet settings.net.receivedBytesColumn=Erhalten @@ -1059,7 +1087,7 @@ settings.net.needRestart=Sie müssen die Anwendung neustarten, um die Änderunge settings.net.notKnownYet=Noch nicht bekannt... settings.net.sentData=Gesendete Daten: {0}, {1} Nachrichten, {2} Nachrichten/Sekunde settings.net.receivedData=Empfangene Daten: {0}, {1} Nachrichten, {2} Nachrichten/Sekunde -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[IP Adresse:Port | Hostname:Port | Onion-Adresse:Port] (Komma getrennt). Port kann weggelassen werden, wenn Standard genutzt wird (8333). settings.net.seedNode=Seed-Knoten settings.net.directPeer=Peer (direkt) @@ -1068,7 +1096,7 @@ settings.net.peer=Peer settings.net.inbound=eingehend settings.net.outbound=ausgehend setting.about.aboutHaveno=Über Haveno -setting.about.about=Haveno ist Open-Source Software, die den Tausch von Bitcoin mit nationaler Währung (und anderen Kryptowährungen), durch ein dezentralisiertes Peer-zu-Peer Netzwerk auf eine Weise ermöglicht, die Ihre Privatsphäre stark beschützt. Lernen Sie auf unserer Projektwebseite mehr über Haveno. +setting.about.about=Haveno ist Open-Source Software, die den Tausch von Monero mit nationaler Währung (und anderen Kryptowährungen), durch ein dezentralisiertes Peer-zu-Peer Netzwerk auf eine Weise ermöglicht, die Ihre Privatsphäre stark beschützt. Lernen Sie auf unserer Projektwebseite mehr über Haveno. setting.about.web=Haveno-Website setting.about.code=Quellcode setting.about.agpl=AGPL-Lizenz @@ -1105,7 +1133,7 @@ setting.about.shortcuts.openDispute.value=Wählen Sie den ausstehenden Trade und setting.about.shortcuts.walletDetails=Öffnen Sie das Fenster für Wallet-Details -setting.about.shortcuts.openEmergencyBtcWalletTool=Öffnen Sie das Notfallwerkzeug für die BTC-Wallet +setting.about.shortcuts.openEmergencyXmrWalletTool=Öffnen Sie das Notfallwerkzeug für die XMR-Wallet setting.about.shortcuts.showTorLogs=Umschalten des Log-Levels für Tor-Meldungen zwischen DEBUG und WARN @@ -1131,7 +1159,7 @@ setting.about.shortcuts.sendPrivateNotification=Private Benachrichtigung an Peer setting.about.shortcuts.sendPrivateNotification.value=Öffnen Sie die Partner-Infos am Avatar und klicken Sie: {0} setting.info.headline=Neues automatisches Bestätigungs-Feature für XMR -setting.info.msg=Wenn Sie BTC für XMR verkaufen, können Sie die automatische Bestätigung aktivieren um nachzuprüfen ob die korrekte Menge an Ihr Wallet gesendet wurde. So kann Haveno den Trade automatisch abschließen und Trades dadurch für alle schneller machen.\n\nDie automatische Bestätigung überprüft die XMR Transaktion über mindestens 2 XMR Explorer Nodes mit dem privaten Transaktionsschlüssel den der Sender zur Verfügung gestellt hat. Haveno verwendet standardmäßig Explorer Nodes die von Haveno Contributors betrieben werden aber wir empfehlen, dass Sie für ein Maximum an Sicherheit und Privatsphäre Ihre eigene XMR Explorer Node betreiben.\n\nFür automatische Bestätigungen, können Sie die max. Höhe an BTC pro Trade und die Anzahl der benötigten Bestätigungen in den Einstellungen festlegen.\n\nFinden Sie weitere Informationen (und eine Anleitung wie Sie Ihre eigene Explorer Node aufsetzen) im Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=Wenn Sie XMR für XMR verkaufen, können Sie die automatische Bestätigung aktivieren um nachzuprüfen ob die korrekte Menge an Ihr Wallet gesendet wurde. So kann Haveno den Trade automatisch abschließen und Trades dadurch für alle schneller machen.\n\nDie automatische Bestätigung überprüft die XMR Transaktion über mindestens 2 XMR Explorer Nodes mit dem privaten Transaktionsschlüssel den der Sender zur Verfügung gestellt hat. Haveno verwendet standardmäßig Explorer Nodes die von Haveno Contributors betrieben werden aber wir empfehlen, dass Sie für ein Maximum an Sicherheit und Privatsphäre Ihre eigene XMR Explorer Node betreiben.\n\nFür automatische Bestätigungen, können Sie die max. Höhe an XMR pro Trade und die Anzahl der benötigten Bestätigungen in den Einstellungen festlegen.\n\nFinden Sie weitere Informationen (und eine Anleitung wie Sie Ihre eigene Explorer Node aufsetzen) im Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1168,7 @@ account.tab.mediatorRegistration=Mediator-Registrierung account.tab.refundAgentRegistration=Registrierung des Rückerstattungsbeauftragten account.tab.signing=Unterzeichnung account.info.headline=Willkommen in Ihrem Haveno-Konto -account.info.msg=Hier können Sie Trading-Konten für nationale Währungen und Cryptos hinzufügen und Backups für Ihre Wallets & Kontodaten erstellen.\n\nEine leere Bitcoin-Wallet wurde erstellt, als Sie das erste Mal Haveno gestartet haben.\n\nWir empfehlen, dass Sie Ihre Bitcoin-Wallet-Seed-Wörter aufschreiben (siehe Tab oben) und sich überlegen ein Passwort hinzuzufügen, bevor Sie einzahlen. Bitcoin-Einzahlungen und Auszahlungen werden unter \"Gelder\" verwaltet.\n\nHinweis zu Privatsphäre & Sicherheit: da Haveno eine dezentralisierte Börse ist, bedeutet dies, dass all Ihre Daten auf ihrem Computer bleiben. Es gibt keine Server und wir haben keinen Zugriff auf Ihre persönlichen Informationen, Ihre Gelder oder selbst Ihre IP-Adresse. Daten wie Bankkontonummern, Crypto- & Bitcoinadressen, etc werden nur mit Ihrem Trading-Partner geteilt, um Trades abzuschließen, die Sie initiiert haben (im Falle eines Konflikts wird der Vermittler die selben Daten sehen wie Ihr Trading-Partner). +account.info.msg=Hier können Sie Trading-Konten für nationale Währungen und Cryptos hinzufügen und Backups für Ihre Wallets & Kontodaten erstellen.\n\nEine leere Monero-Wallet wurde erstellt, als Sie das erste Mal Haveno gestartet haben.\n\nWir empfehlen, dass Sie Ihre Monero-Wallet-Seed-Wörter aufschreiben (siehe Tab oben) und sich überlegen ein Passwort hinzuzufügen, bevor Sie einzahlen. Monero-Einzahlungen und Auszahlungen werden unter \"Gelder\" verwaltet.\n\nHinweis zu Privatsphäre & Sicherheit: da Haveno eine dezentralisierte Börse ist, bedeutet dies, dass all Ihre Daten auf ihrem Computer bleiben. Es gibt keine Server und wir haben keinen Zugriff auf Ihre persönlichen Informationen, Ihre Gelder oder selbst Ihre IP-Adresse. Daten wie Bankkontonummern, Crypto- & Moneroadressen, etc werden nur mit Ihrem Trading-Partner geteilt, um Trades abzuschließen, die Sie initiiert haben (im Falle eines Konflikts wird der Vermittler die selben Daten sehen wie Ihr Trading-Partner). account.menu.paymentAccount=Nationale Währungskonten account.menu.altCoinsAccountView=Crypto-Konten @@ -1151,7 +1179,7 @@ account.menu.backup=Backup account.menu.notifications=Benachrichtigungen account.menu.walletInfo.balance.headLine=Wallet-Guthaben -account.menu.walletInfo.balance.info=Hier wird das Wallet-Guthaben einschließlich unbestätigter Transaktionen angezeigt.\nFür BTC sollte das unten angezeigte Wallet-Guthaben mit der Summe der oben rechts in diesem Fenster angezeigten "Verfügbaren" und "Reservierten" Guthaben übereinstimmen. +account.menu.walletInfo.balance.info=Hier wird das Wallet-Guthaben einschließlich unbestätigter Transaktionen angezeigt.\nFür XMR sollte das unten angezeigte Wallet-Guthaben mit der Summe der oben rechts in diesem Fenster angezeigten "Verfügbaren" und "Reservierten" Guthaben übereinstimmen. account.menu.walletInfo.xpub.headLine=Watch Keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} Wallet account.menu.walletInfo.path.headLine=HD Keychain Pfade @@ -1180,7 +1208,7 @@ account.crypto.popup.upx.msg=Der Handel mit UPX auf Haveno setzt voraus, dass Si # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Der Handel mit ARQ auf Haveno setzt voraus, dass Sie die folgenden Anforderungen verstehen und erfüllen:\n\nFür den Versand von ARQ müssen Sie entweder das offizielle ArQmA GUI-Wallet oder das ArQmA CLI-Wallet mit aktiviertem store-tx-info Flag verwenden (Standard in neuen Versionen). Bitte stellen Sie sicher, dass Sie auf den tx Key zugreifen können, da dies im Falle eines Konfliktes erforderlich wäre.\narqma-wallet-cli (verwenden Sie den Befehl get_tx_key)\narqma-wallet-gui (gehen Sie zur History Tab und klicken Sie auf (P) für den Zahlungsnachweis)\n\nBei normalen Blockexplorern ist der Transfer nicht verifizierbar.\n\nSie müssen dem Mediator oder Vermittler im Konfliktfall die folgenden Daten zur Verfügung stellen:\n- Der tx Private Key\n- Der Transaktionshash\n- Die öffentliche Adresse des Empfängers\n\nWenn Sie die oben genannten Daten nicht angeben oder wenn Sie eine inkompatible Wallet verwendet haben, verlieren Sie den Konfliktfall. Der ARQ-Sender ist im Fall eines Konflikts dafür verantwortlich, die Verifizierung des ARQ-Transfers dem Mediator oder Vermittler nachzuweisen.\n\nEs ist keine Zahlungs-ID erforderlich, sondern nur die normale öffentliche Adresse.\nWenn Sie sich über diesen Prozess nicht sicher sind, besuchen Sie den ArQmA Discord Channel (https://discord.gg/s9BQpJT) oder das ArQmA Forum (https://labs.arqma.com), um weitere Informationen zu erhalten. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Der Handel mit XMR auf Haveno setzt voraus, dass Sie die folgende Anforderung verstehen.\n\nWenn Sie XMR verkaufen, müssen Sie in der Lage sein, einem Vermittler oder einer Schiedsperson im Falle eines Konflikts die folgenden Informationen zur Verfügung zu stellen:\n- den Transaktionsschlüssel (Tx Key, Tx Secret Key oder Tx Private Key)\n- die Transaktions-ID (Tx ID oder Tx Hash)\n- die Zieladresse (Empfängeradresse)\n\nIm Wiki finden Sie Einzelheiten darüber wo Sie diese Informationen in den populärsten Monero-Wallets finden [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nWerden die erforderlichen Transaktionsdaten nicht zur Verfügung gestellt, führt dies dazu, dass der Konflikt zu Ihrem Nachteil entschieden wird.\n\nBeachten Sie auch, dass Haveno jetzt eine automatische Bestätigung für XMR-Transaktionen anbietet, um Transaktionen schneller zu machen, aber Sie müssen dies in den Einstellungen aktivieren.\n\nWeitere Informationen über die automatische Bestätigungsfunktion finden Sie im Wiki: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Der Handel mit XMR auf Haveno setzt voraus, dass Sie die folgende Anforderung verstehen.\n\nWenn Sie XMR verkaufen, müssen Sie in der Lage sein, einem Vermittler oder einer Schiedsperson im Falle eines Konflikts die folgenden Informationen zur Verfügung zu stellen:\n- den Transaktionsschlüssel (Tx Key, Tx Secret Key oder Tx Private Key)\n- die Transaktions-ID (Tx ID oder Tx Hash)\n- die Zieladresse (Empfängeradresse)\n\nIm Wiki finden Sie Einzelheiten darüber wo Sie diese Informationen in den populärsten Monero-Wallets finden [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nWerden die erforderlichen Transaktionsdaten nicht zur Verfügung gestellt, führt dies dazu, dass der Konflikt zu Ihrem Nachteil entschieden wird.\n\nBeachten Sie auch, dass Haveno jetzt eine automatische Bestätigung für XMR-Transaktionen anbietet, um Transaktionen schneller zu machen, aber Sie müssen dies in den Einstellungen aktivieren.\n\nWeitere Informationen über die automatische Bestätigungsfunktion finden Sie im Wiki: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Der Handel mit MSR auf Haveno setzt voraus, dass Sie die folgenden Anforderungen verstehen und erfüllen:\n\nFür den Versand von MSR müssen Sie entweder das offizielle Masari GUI Wallet, das Masari CLI Wallet mit dem aktivierten store-tx-info Flag (standardmäßig aktiviert) oder das Masari Web Wallet (https://wallet.getmasari.org) verwenden. Bitte stellen Sie sicher, dass Sie auf den tx Key zugreifen können, da dies im Falle eines Konfliktes erforderlich wäre.\nmasari-wallet-cli (verwenden Sie den Befehl get_tx_key)\nmasari-wallet-gui (gehen Sie zur History Tab und klicken Sie auf (P) für den Zahlungsnachweis).\n\nMasari Web Wallet (gehen Sie zum Konto -> Transaktionshistorie und lassen Sie Details zu Ihrer gesendeten Transaktion anzeigen)\n\nDie Verifizierung kann im Wallet durchgeführt werden.\nmasari-wallet-cli : mit dem Befehl (check_tx_key).\nmasari-wallet-gui : auf der Seite Advanced > Prove/Check.\nDie Verifizierung kann im Block-Explorer durchgeführt werden. \nÖffnen Sie den Block-Explorer (https://explorer.getmasari.org), verwenden Sie die Suchleiste, um Ihren Transaktionshash zu finden.\nSobald die Transaktion gefunden wurde, scrollen Sie nach unten zum Bereich 'Prove Sending' und geben Sie bei Bedarf Details ein.\nSie müssen dem Mediator oder Vermittler im Konfliktfall die folgenden Daten zur Verfügung stellen:\n- Den tx Private Key\n- Den Transaktionshash\n- Die öffentliche Adresse des Empfängers\n\nWenn Sie die oben genannten Daten nicht angeben oder wenn Sie eine inkompatible Wallet verwendet haben, verlieren Sie den Konfliktfall. Der MSR-Sender ist im Fall eines Konflikts dafür verantwortlich, die Verifizierung des MSR-Transfers dem Mediator oder Vermittler nachzuweisen.\n\nEs ist keine Zahlungs-ID erforderlich, sondern nur die normale öffentliche Adresse.\nWenn Sie sich über diesen Prozess nicht sicher sind, fragen Sie um Hilfe auf der offiziellen Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1236,7 @@ account.crypto.popup.pars.msg=Der Handel mit ParsiCoin auf Haveno setzt voraus, account.crypto.popup.blk-burnt.msg=Um "Burnt Blackcoins" zu handeln, müssen Sie folgendes wissen:\n\nBurnt Blackcoins können nicht ausgegeben werden. Um sie auf Haveno zu handeln, müssen die Ausgabeskripte in der Form vorliegen: OP_RETURN OP_PUSHDATA, gefolgt von zugehörigen Datenbytes, die nach der Hex-Codierung Adressen darstellen. Beispielsweise haben Burnt Blackcoins mit der Adresse 666f6f ("foo" in UTF-8) das folgende Skript:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nUm Burnt Blackcoins zu erstellen, kann man den in einigen Wallets verfügbaren RPC-Befehl "burn" verwenden.\n\nFür mögliche Anwendungsfälle kann man einen Blick auf https://ibo.laboratorium.ee werfen.\n\nDa Burnt Blackcoins nicht ausgegeben werden können, können sie nicht wieder verkauft werden. "Verkaufen" von Burnt Blackcoins bedeutet, gewöhnliche Blackcoins zu verbrennen (mit zugehörigen Daten entsprechend der Zieladresse).\n\nIm Konfliktfall hat der BLK-Verkäufer den Transaktionshash zur Verfügung zu stellen. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Das Trading mit L-BTC auf Haveno setzt voraus, dass Sie Folgendes verstehen:\n\nWenn Sie L-BTC für einen Trade auf Haveno erhalten, können Sie nicht die mobile Blockstream Green Wallet App oder eine Custodial/Exchange Wallet verwenden. Sie dürfen L-BTC nur in der Liquid Elements Core Wallet oder eine andere L-BTC-Wallet erhalten, die es Ihnen ermöglicht, den Blinding Key für Ihre verdeckte L-BTC-Adresse zu erhalten.\n\nFalls eine Mediation erforderlich ist oder ein Trade-Konflikt entsteht, müssen Sie den Blinding Key für Ihre L-BTC-Empfangsadresse dem Haveno-Mediator oder dem Refund Agent mitteilen, damit dieser die Details Ihrer vertraulichen Transaktion auf seinem eigenen Elements Core Full Node überprüfen kann.\n\nWenn Sie dem Mediator oder Refund Agent die erforderlichen Informationen nicht zur Verfügung stellen, führt dies dazu, dass Sie den Streitfall verlieren. In allen Streitfällen trägt der L-BTC-Empfänger 100 % der Verantwortung für die Bereitstellung kryptographischer Beweise an den Mediator oder den Refund Agent.\n\nWenn Sie diese Anforderungen nicht verstehen, sollten Sie nicht mit L-BTC auf Haveno traden. +account.crypto.popup.liquidmonero.msg=Das Trading mit L-XMR auf Haveno setzt voraus, dass Sie Folgendes verstehen:\n\nWenn Sie L-XMR für einen Trade auf Haveno erhalten, können Sie nicht die mobile Blockstream Green Wallet App oder eine Custodial/Exchange Wallet verwenden. Sie dürfen L-XMR nur in der Liquid Elements Core Wallet oder eine andere L-XMR-Wallet erhalten, die es Ihnen ermöglicht, den Blinding Key für Ihre verdeckte L-XMR-Adresse zu erhalten.\n\nFalls eine Mediation erforderlich ist oder ein Trade-Konflikt entsteht, müssen Sie den Blinding Key für Ihre L-XMR-Empfangsadresse dem Haveno-Mediator oder dem Refund Agent mitteilen, damit dieser die Details Ihrer vertraulichen Transaktion auf seinem eigenen Elements Core Full Node überprüfen kann.\n\nWenn Sie dem Mediator oder Refund Agent die erforderlichen Informationen nicht zur Verfügung stellen, führt dies dazu, dass Sie den Streitfall verlieren. In allen Streitfällen trägt der L-XMR-Empfänger 100 % der Verantwortung für die Bereitstellung kryptographischer Beweise an den Mediator oder den Refund Agent.\n\nWenn Sie diese Anforderungen nicht verstehen, sollten Sie nicht mit L-XMR auf Haveno traden. account.traditional.yourTraditionalAccounts=Ihre Nationalen Währungskonten @@ -1228,13 +1256,13 @@ account.password.setPw.button=Passwort festlegen account.password.setPw.headline=Passwortschutz Ihrer Wallet einrichten account.password.info=Mit aktiviertem Passwortschutz müssen Sie Ihr Passwort eingeben, wenn Sie Monero aus Ihrer Brieftasche abheben, wenn Sie Ihre Seed-Wörter anzeigen oder Ihre Brieftasche wiederherstellen möchten sowie beim Start der Anwendung. -account.seed.backup.title=Backup der Seed-Wörter Ihrer Wallet erstellen -account.seed.info=Bitte schreiben Sie die sowohl Seed-Wörter als auch das Datum auf! Mit diesen Seed-Wörtern und dem Datum können Sie Ihre Wallet jederzeit wiederherstellen.\nDie Seed-Wörter werden für die BTC- und BSQ-Wallet genutzt.\n\nSchreiben Sie die Seed-Wörter auf ein Blatt Papier schreiben und speichern Sie sie nicht auf Ihrem Computer.\n\nBitte beachten Sie, dass die Seed-Wörter KEIN Ersatz für ein Backup sind.\nSie müssen ein Backup des gesamten Anwendungsverzeichnisses unter \"Konto/Backup\" erstellen, um den ursprünglichen Zustand der Anwendung wiederherstellen zu können.\nDas Importieren der Seed-Wörter wird nur für Notfälle empfohlen. Die Anwendung wird ohne richtiges Backup der Datenbankdateien und Schlüssel nicht funktionieren! -account.seed.backup.warning=Bitte beachten Sie, dass die Seed Wörter kein Ersatz für ein Backup sind.\nSie müssen ein Backup vom gesamten Anwendungs-Verzeichnis vom \"Account/Backup\" Pfad machen um den Status und die Dateien der Anwendung wiederherzustellen. \nDie Seed Wörter zu importieren wird nur für Notfälle empfohlen. Die Anwendung wird ohne ordnungsgemäßes Backup der Dateien und Schlüssel nicht funktionieren!\n\nWeitere Informationen finden Sie auf der Wiki-Seite [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Erstelle eine Sicherungskopie deiner Wallet-Schlüsselwörter. +account.seed.info=Bitte notiere sowohl die Schlüsselwörter deiner Geldbörse als auch das Datum. Du kannst deine Geldbörse jederzeit mit den Schlüsselwörtern und dem Datum wiederherstellen.\n\nDu solltest die Schlüsselwörter auf ein Blatt Papier schreiben. Speichere sie nicht auf dem Computer.\n\nBitte beachte, dass die Schlüsselwörter KEIN Ersatz für ein Backup sind.\nDu musst eine Sicherungskopie des gesamten Anwendungsverzeichnisses von der "Konto/Sicherung" Seite erstellen, um den Anwendungsstatus und die Daten wiederherzustellen. +account.seed.backup.warning=Bitte beachte, dass die Seed-Wörter KEIN Ersatz für ein Backup sind.\nDu musst eine Sicherungskopie des gesamten Anwendungsverzeichnisses von der "Konto/Sicherung" Seite erstellen, um den Anwendungsstatus und die Daten wiederherzustellen. account.seed.warn.noPw.msg=Sie haben kein Wallet-Passwort festgelegt, was das Anzeigen der Seed-Wörter schützen würde.\n\nMöchten Sie die Seed-Wörter jetzt anzeigen? account.seed.warn.noPw.yes=Ja, und nicht erneut fragen account.seed.enterPw=Geben Sie Ihr Passwort ein um die Seed-Wörter zu sehen -account.seed.restore.info=Bitte erstellen Sie vor dem Wiederherstellen durch Keimwörter ein Backup. Beachten Sie auch, dass Wallet-Wiederherstellung nur für Notfälle ist und Probleme mit der internen Wallet-Datenbank verursachen kann.\nEs ist kein Weg ein Backup anzuwenden! Bitte nutzen Sie ein Backup des Anwendungsdatenordner um eine vorherigen Zustand wiederherzustellen. \n\nNach der Wiederherstellung wird die Anwendung herunterfahren. Nachdem Sie die Anwendung wieder gestartet haben, wird sie wieder mit dem Bitcoin-Netzwerk synchronisieren. Dies kann lange dauern und die CPU stark beanspruchen, vor allem, wenn die Wallet alt und viele Transaktionen hatte. Bitte unterbreche Sie diesen Prozess nicht, sonst müssen Sie vielleicht die SPV Kettendatei löschen und den Wiederherstellungsprozess wiederholen. +account.seed.restore.info=Bitte erstellen Sie vor dem Wiederherstellen durch Keimwörter ein Backup. Beachten Sie auch, dass Wallet-Wiederherstellung nur für Notfälle ist und Probleme mit der internen Wallet-Datenbank verursachen kann.\nEs ist kein Weg ein Backup anzuwenden! Bitte nutzen Sie ein Backup des Anwendungsdatenordner um eine vorherigen Zustand wiederherzustellen. \n\nNach der Wiederherstellung wird die Anwendung herunterfahren. Nachdem Sie die Anwendung wieder gestartet haben, wird sie wieder mit dem Monero-Netzwerk synchronisieren. Dies kann lange dauern und die CPU stark beanspruchen, vor allem, wenn die Wallet alt und viele Transaktionen hatte. Bitte unterbreche Sie diesen Prozess nicht, sonst müssen Sie vielleicht die SPV Kettendatei löschen und den Wiederherstellungsprozess wiederholen. account.seed.restore.ok=Ok, mache die Wiederherstellung und fahre Haveno herunter @@ -1259,13 +1287,13 @@ account.notifications.trade.label=Erhalte Nachrichten zu Händel account.notifications.market.label=Erhalte Benachrichtigungen zu Angeboten account.notifications.price.label=Erhalte Preisbenachrichtigungen account.notifications.priceAlert.title=Preisalarme: -account.notifications.priceAlert.high.label=Benachrichtigen, wenn BTC-Preis über -account.notifications.priceAlert.low.label=Benachrichtigen, wenn BTC-Preis unter +account.notifications.priceAlert.high.label=Benachrichtigen, wenn XMR-Preis über +account.notifications.priceAlert.low.label=Benachrichtigen, wenn XMR-Preis unter account.notifications.priceAlert.setButton=Preisalarm setzen account.notifications.priceAlert.removeButton=Preisalarm entfernen account.notifications.trade.message.title=Handelsstatus verändert account.notifications.trade.message.msg.conf=Die Kaution-Transaktion für den Handel mit ID {0} wurde bestätigt. Bitte öffnen Sie Ihre Haveno Anwendung und starten die Zahlung. -account.notifications.trade.message.msg.started=Der BTC-Käufer hat die Zahlung für den Handel mit ID {0} begonnen. +account.notifications.trade.message.msg.started=Der XMR-Käufer hat die Zahlung für den Handel mit ID {0} begonnen. account.notifications.trade.message.msg.completed=Der Handel mit ID {0} ist abgeschlossen. account.notifications.offer.message.title=Ihr Angebot wurde angenommen account.notifications.offer.message.msg=Ihr Angebot mit ID {0} wurde angenommen @@ -1275,10 +1303,10 @@ account.notifications.dispute.message.msg=Sie haben eine Konflikt-Nachricht für account.notifications.marketAlert.title=Angebotsalarme account.notifications.marketAlert.selectPaymentAccount=Angebote, die dem Zahlungskonto entsprechen account.notifications.marketAlert.offerType.label=Angebotstyp, an dem ich interessiert bin -account.notifications.marketAlert.offerType.buy=Kauf-Angebote (Ich möchte BTC verkaufen) -account.notifications.marketAlert.offerType.sell=Verkauf-Angebote (Ich möchte BTC kaufen) +account.notifications.marketAlert.offerType.buy=Kauf-Angebote (Ich möchte XMR verkaufen) +account.notifications.marketAlert.offerType.sell=Verkauf-Angebote (Ich möchte XMR kaufen) account.notifications.marketAlert.trigger=Angebot Preisdistanz (%) -account.notifications.marketAlert.trigger.info=Mit gesetzter Preisdistanz, werden Sie nur einen Alarm erhalten, wenn ein Angebot veröffentlicht wird, das die Bedingungen erfüllt (oder übertrifft). Beispiel: Sie möchten BTC verkaufen, aber Sie werden nur 2% über dem momentanen Marktpreis verkaufen. Dieses Feld auf 2% setzen stellt sicher, dass Sie nur nur Alarme für Angebote erhalten, die 2% (oder mehr) über dem momentanen Marktpreis liegen. +account.notifications.marketAlert.trigger.info=Mit gesetzter Preisdistanz, werden Sie nur einen Alarm erhalten, wenn ein Angebot veröffentlicht wird, das die Bedingungen erfüllt (oder übertrifft). Beispiel: Sie möchten XMR verkaufen, aber Sie werden nur 2% über dem momentanen Marktpreis verkaufen. Dieses Feld auf 2% setzen stellt sicher, dass Sie nur nur Alarme für Angebote erhalten, die 2% (oder mehr) über dem momentanen Marktpreis liegen. account.notifications.marketAlert.trigger.prompt=Prozentualer Abstand zum Marktpreis (z.B. 2.50%, -0.50%, etc) account.notifications.marketAlert.addButton=Angebotsalarme hinzufügen account.notifications.marketAlert.manageAlertsButton=Angebotsalarme verwalten @@ -1305,10 +1333,10 @@ inputControlWindow.balanceLabel=Verfügbarer Betrag contractWindow.title=Konfliktdetails contractWindow.dates=Angebotsdatum / Handelsdatum -contractWindow.btcAddresses=Bitcoinadresse BTC-Käufer / BTC-Verkäufer -contractWindow.onions=Netzwerkadresse BTC-Käufer / BTC-Verkäufer -contractWindow.accountAge=Kontoalter BTC Käufer / BTC Verkäufer -contractWindow.numDisputes=Anzahl Konflikte BTC-Käufer / BTC-Verkäufer +contractWindow.xmrAddresses=Moneroadresse XMR-Käufer / XMR-Verkäufer +contractWindow.onions=Netzwerkadresse XMR-Käufer / XMR-Verkäufer +contractWindow.accountAge=Kontoalter XMR Käufer / XMR Verkäufer +contractWindow.numDisputes=Anzahl Konflikte XMR-Käufer / XMR-Verkäufer contractWindow.contractHash=Vertrags-Hash displayAlertMessageWindow.headline=Wichtige Informationen! @@ -1334,8 +1362,8 @@ disputeSummaryWindow.title=Zusammenfassung disputeSummaryWindow.openDate=Erstellungsdatum des Tickets disputeSummaryWindow.role=Rolle des Händlers disputeSummaryWindow.payout=Auszahlung des Handelsbetrags -disputeSummaryWindow.payout.getsTradeAmount=Der BTC-{0} erhält die Auszahlung des Handelsbetrags -disputeSummaryWindow.payout.getsAll=Menge in BTC zu {0} +disputeSummaryWindow.payout.getsTradeAmount=Der XMR-{0} erhält die Auszahlung des Handelsbetrags +disputeSummaryWindow.payout.getsAll=Menge in XMR zu {0} disputeSummaryWindow.payout.custom=Spezifische Auszahlung disputeSummaryWindow.payoutAmount.buyer=Auszahlungsbetrag des Käufers disputeSummaryWindow.payoutAmount.seller=Auszahlungsbetrag des Verkäufers @@ -1377,7 +1405,7 @@ disputeSummaryWindow.close.button=Ticket schließen # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket geschlossen am {0}\n{1}Node Adresse: {2}\n\nZusammenfassung:\nTrade ID: {3}\nWährung: {4}\nTrade-Betrag: {5}\nAuszahlungsbetrag für den BTC Käufer: {6}\nAuszahlungsbetrag für den BTC Verkäufer: {7}\n\nGrund für den Konflikt: {8}\n\nWeitere Hinweise:\n{9}\n +disputeSummaryWindow.close.msg=Ticket geschlossen am {0}\n{1}Node Adresse: {2}\n\nZusammenfassung:\nTrade ID: {3}\nWährung: {4}\nTrade-Betrag: {5}\nAuszahlungsbetrag für den XMR Käufer: {6}\nAuszahlungsbetrag für den XMR Verkäufer: {7}\n\nGrund für den Konflikt: {8}\n\nWeitere Hinweise:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1420,18 +1448,18 @@ filterWindow.mediators=Gefilterte Mediatoren (mit Komma getr. Onion-Adressen) filterWindow.refundAgents=Gefilterte Rückerstattungsagenten (mit Komma getr. Onion-Adressen) filterWindow.seedNode=Gefilterte Seed-Knoten (Komma getr. Onion-Adressen) filterWindow.priceRelayNode=Gefilterte Preisrelais Knoten (Komma getr. Onion-Adressen) -filterWindow.xmrNode=Gefilterte Bitcoinknoten (Komma getr. Adresse + Port) -filterWindow.preventPublicXmrNetwork=Nutzung des öffentlichen Bitcoin-Netzwerks verhindern +filterWindow.xmrNode=Gefilterte Moneroknoten (Komma getr. Adresse + Port) +filterWindow.preventPublicXmrNetwork=Nutzung des öffentlichen Monero-Netzwerks verhindern filterWindow.disableAutoConf=Automatische Bestätigung deaktivieren filterWindow.autoConfExplorers=Gefilterter Explorer mit Auto-Bestätigung (Adressen mit Komma separiert) filterWindow.disableTradeBelowVersion=Min. zum Handeln erforderliche Version filterWindow.add=Filter hinzufügen filterWindow.remove=Filter entfernen -filterWindow.xmrFeeReceiverAddresses=BTC Gebühr Empfänger-Adressen +filterWindow.xmrFeeReceiverAddresses=XMR Gebühr Empfänger-Adressen filterWindow.disableApi=API deaktivieren filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Min. BTC-Betrag +offerDetailsWindow.minXmrAmount=Min. XMR-Betrag offerDetailsWindow.min=(min. {0}) offerDetailsWindow.distance=(Abstand zum Marktpreis: {0}) offerDetailsWindow.myTradingAccount=Mein Handelskonto @@ -1446,6 +1474,7 @@ offerDetailsWindow.confirm.maker=Bestätigen: Anbieten monero zu {0} offerDetailsWindow.confirm.taker=Bestätigen: Angebot annehmen monero zu {0} offerDetailsWindow.creationDate=Erstellungsdatum offerDetailsWindow.makersOnion=Onion-Adresse des Erstellers +offerDetailsWindow.challenge=Angebots-Passphrase qRCodeWindow.headline=QR Code qRCodeWindow.msg=Bitte nutzen Sie diesen QR Code um Ihr Haveno Wallet von Ihrem externen Wallet aufzuladen. @@ -1474,7 +1503,7 @@ showWalletDataWindow.walletData=Wallet-Daten showWalletDataWindow.includePrivKeys=Private Schlüssel einbeziehen setXMRTxKeyWindow.headline=Senden der XMR beweisen -setXMRTxKeyWindow.note=Hinzufügen der Transaktionsinfo unten aktiviert die automatische Bestätigung für schneller Trades. Mehr lesen: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Hinzufügen der Transaktionsinfo unten aktiviert die automatische Bestätigung für schneller Trades. Mehr lesen: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=ID der Transaktion (optional) setXMRTxKeyWindow.txKey=Transaktionsschlüssel (optional) @@ -1486,7 +1515,7 @@ tacWindow.disagree=Ich stimme nicht zu und beende tacWindow.arbitrationSystem=Streitbeilegung tradeDetailsWindow.headline=Handel -tradeDetailsWindow.disputedPayoutTxId=Transaktions-ID der strittigen Auszahlung: +tradeDetailsWindow.disputedPayoutTxId=Transaktions-ID der strittigen Auszahlung tradeDetailsWindow.tradeDate=Handelsdatum tradeDetailsWindow.txFee=Mining-Gebühr tradeDetailsWindow.tradePeersOnion=Onion-Adresse des Handelspartners @@ -1496,8 +1525,10 @@ tradeDetailsWindow.agentAddresses=Vermittler/Mediator tradeDetailsWindow.detailData=Detaillierte Daten txDetailsWindow.headline=Transaktionsdetails -txDetailsWindow.xmr.note=Sie haben BTC gesendet. +txDetailsWindow.xmr.noteSent=Sie haben XMR gesendet. +txDetailsWindow.xmr.noteReceived=Sie haben XMR erhalten. txDetailsWindow.sentTo=Gesendet an +txDetailsWindow.receivedWith=Erhalten mit txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1506,7 +1537,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Passwort zum Entsperren eingeben @@ -1532,12 +1563,12 @@ torNetworkSettingWindow.bridges.header=Ist Tor blockiert? torNetworkSettingWindow.bridges.info=Falls Tor von Ihrem Provider oder in Ihrem Land blockiert wird, können Sie versuchen Tor-Bridges zu nutzen.\nBesuchen Sie die Tor-Webseite unter: https://bridges.torproject.org/bridges um mehr über Bridges und pluggable transposrts zu lernen. feeOptionWindow.headline=Währung für Handelsgebührzahlung auswählen -feeOptionWindow.info=Sie können wählen, die Gebühr in BSQ oder BTC zu zahlen. Wählen Sie BSQ, erhalten Sie eine vergünstigte Handelsgebühr. +feeOptionWindow.info=Sie können wählen, die Gebühr in BSQ oder XMR zu zahlen. Wählen Sie BSQ, erhalten Sie eine vergünstigte Handelsgebühr. feeOptionWindow.optionsLabel=Währung für Handelsgebührzahlung auswählen -feeOptionWindow.useBTC=BTC nutzen +feeOptionWindow.useXMR=XMR nutzen feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1610,9 @@ popup.warning.noTradingAccountSetup.msg=Sie müssen ein nationales Währung- ode popup.warning.noArbitratorsAvailable=Momentan sind keine Vermittler verfügbar. popup.warning.noMediatorsAvailable=Es sind keine Mediatoren verfügbar. popup.warning.notFullyConnected=Sie müssen warten, bis Sie vollständig mit dem Netzwerk verbunden sind.\nDas kann bis ungefähr 2 Minuten nach dem Start dauern. -popup.warning.notSufficientConnectionsToBtcNetwork=Sie müssen warten, bis Sie wenigstens {0} Verbindungen zum Bitcoinnetzwerk haben. -popup.warning.downloadNotComplete=Sie müssen warten bis der Download der fehlenden Bitcoinblöcke abgeschlossen ist. -popup.warning.chainNotSynced=Die Blockchain Größe der Haveno Wallet ist nicht korrekt synchronisiert. Wenn Sie kürzlich die Applikation geöffnet haben, warten Sie bitte bis ein Bitcoin Block veröffentlicht wurde.\n\nSie können die Blockchain Größe unter Einstellungen/Netzwerkinformationen finden. Wenn mehr als ein Block veröffentlicht wird und das Problem weiterhin bestehen sollte, wird es eventuell abgewürgt werden. Dann sollten Sie einen SPV Resync durchführen. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Sie müssen warten, bis Sie wenigstens {0} Verbindungen zum Moneronetzwerk haben. +popup.warning.downloadNotComplete=Sie müssen warten bis der Download der fehlenden Moneroblöcke abgeschlossen ist. +popup.warning.walletNotSynced=Die Haveno-Brieftasche ist nicht mit der neuesten Höhe der Blockchain synchronisiert. Bitte warten Sie, bis die Brieftasche synchronisiert ist, oder überprüfen Sie Ihre Verbindung. popup.warning.removeOffer=Sind Sie sicher, dass Sie das Angebot entfernen wollen? popup.warning.tooLargePercentageValue=Es kann kein Prozentsatz von 100% oder mehr verwendet werden. popup.warning.examplePercentageValue=Bitte geben sei einen Prozentsatz wie folgt ein \"5.4\" für 5.4% @@ -1601,13 +1632,13 @@ popup.warning.priceRelay=Preisrelais popup.warning.seed=Seed popup.warning.mandatoryUpdate.trading=Bitte aktualisieren Sie auf die neueste Haveno-Version. Es wurde ein obligatorisches Update veröffentlicht, das den Handel mit alten Versionen deaktiviert. Bitte besuchen Sie das Haveno-Forum für weitere Informationen. popup.warning.noFilter=Wir haben kein Filterobjekt von den Seed Nodes erhalten. Diese Situation ist unerwartet. Bitte informieren Sie die Haveno Entwickler. -popup.warning.burnBTC=Die Transaktion ist nicht möglich, da die Mininggebühren von {0} den übertragenen Betrag von {1} überschreiten würden. Bitte warten Sie, bis die Gebühren wieder niedrig sind, oder Sie mehr BTC zum übertragen angesammelt haben. +popup.warning.burnXMR=Die Transaktion ist nicht möglich, da die Mininggebühren von {0} den übertragenen Betrag von {1} überschreiten würden. Bitte warten Sie, bis die Gebühren wieder niedrig sind, oder Sie mehr XMR zum übertragen angesammelt haben. -popup.warning.openOffer.makerFeeTxRejected=Die Verkäufergebühren-Transaktion für das Angebot mit der ID {0} wurde vom Bitcoin-Netzwerk abgelehnt.\nTransaktions-ID={1}.\nDas Angebot wurde entfernt, um weitere Probleme zu vermeiden.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie eine SPV-Resynchronisierung durch.\nFür weitere Hilfe wenden Sie sich bitte an den Haveno-Support-Kanal des Haveno Keybase Teams. +popup.warning.openOffer.makerFeeTxRejected=Die Verkäufergebühren-Transaktion für das Angebot mit der ID {0} wurde vom Monero-Netzwerk abgelehnt.\nTransaktions-ID={1}.\nDas Angebot wurde entfernt, um weitere Probleme zu vermeiden.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie eine SPV-Resynchronisierung durch.\nFür weitere Hilfe wenden Sie sich bitte an den Haveno-Support-Kanal des Haveno Keybase Teams. popup.warning.trade.txRejected.tradeFee=Trade-Gebühr popup.warning.trade.txRejected.deposit=Kaution -popup.warning.trade.txRejected=Die {0} Transaktion für den Trade mit der ID {1} wurde vom Bitcoin-Netzwerk abgelehnt.\nTransaktions-ID={2}}\nDer Trade wurde in gescheiterte Trades verschoben.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie einen SPV Resync durch.\nFür weitere Hilfe wenden Sie sich bitte an den Haveno-Support-Kanal des Haveno Keybase Teams. +popup.warning.trade.txRejected=Die {0} Transaktion für den Trade mit der ID {1} wurde vom Monero-Netzwerk abgelehnt.\nTransaktions-ID={2}}\nDer Trade wurde in gescheiterte Trades verschoben.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie einen SPV Resync durch.\nFür weitere Hilfe wenden Sie sich bitte an den Haveno-Support-Kanal des Haveno Keybase Teams. popup.warning.openOfferWithInvalidMakerFeeTx=Die Verkäufergebühren-Transaktion für das Angebot mit der ID {0} ist ungültig.\nTransaktions-ID={1}.\nBitte gehen Sie zu \"Einstellungen/Netzwerkinformationen\" und führen Sie eine SPV-Resynchronisierung durch.\nFür weitere Hilfe wenden Sie sich bitte an den Haveno-Support-Kanal des Haveno Keybase Teams. @@ -1616,15 +1647,15 @@ popup.info.securityDepositInfo=Um sicherzustellen, dass beide Händler dem Hande popup.info.cashDepositInfo=Stellen Sie sicher, dass eine Bank-Filiale in Ihrer Nähe befindet, um die Bargeld Kaution zu zahlen.\nDie Bankkennung (BIC/SWIFT) der Bank des Verkäufers ist: {0}. popup.info.cashDepositInfo.confirm=Ich bestätige, dass ich die Kaution zahlen kann popup.info.shutDownWithOpenOffers=Haveno wird heruntergefahren, aber Sie haben offene Angebote verfügbar.\n\nDiese Angebote sind nach dem Herunterfahren nicht mehr verfügbar und werden erneut im P2P-Netzwerk veröffentlicht wenn Sie das nächste Mal Haveno starten.\n\nLassen Sie Haveno weiter laufen und stellen Sie sicher, dass Ihr Computer online bleibt, um Ihre Angebote verfügbar zu halten (z.B.: verhindern Sie den Standby-Modus... der Standby-Modus des Monitors stellt kein Problem dar). -popup.info.qubesOSSetupInfo=Es scheint so als ob Sie Haveno auf Qubes OS laufen haben.\n\nBitte stellen Sie sicher, dass Haveno qube nach unserem Setup Guide eingerichtet wurde: [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=Es scheint so als ob Sie Haveno auf Qubes OS laufen haben.\n\nBitte stellen Sie sicher, dass Haveno qube nach unserem Setup Guide eingerichtet wurde: [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade von Version {0} auf Version {1} wird nicht unterstützt. Bitte nutzen Sie die aktuelle Haveno Version. popup.privateNotification.headline=Wichtige private Benachrichtigung! popup.securityRecommendation.headline=Wichtige Sicherheitsempfehlung -popup.securityRecommendation.msg=Wir würden Sie gerne daran erinnern, sich zu überlegen, den Passwortschutz Ihrer Wallet zu verwenden, falls Sie diesen noch nicht aktiviert haben.\n\nEs wird außerdem dringend empfohlen, dass Sie die Wallet-Seed-Wörter aufschreiben. Diese Seed-Wörter sind wie ein Master-Passwort zum Wiederherstellen ihrer Bitcoin-Wallet.\nIm \"Wallet-Seed\"-Abschnitt finden Sie weitere Informationen.\n\nZusätzlich sollten Sie ein Backup des ganzen Anwendungsdatenordners im \"Backup\"-Abschnitt erstellen. +popup.securityRecommendation.msg=Wir würden Sie gerne daran erinnern, sich zu überlegen, den Passwortschutz Ihrer Wallet zu verwenden, falls Sie diesen noch nicht aktiviert haben.\n\nEs wird außerdem dringend empfohlen, dass Sie die Wallet-Seed-Wörter aufschreiben. Diese Seed-Wörter sind wie ein Master-Passwort zum Wiederherstellen ihrer Monero-Wallet.\nIm \"Wallet-Seed\"-Abschnitt finden Sie weitere Informationen.\n\nZusätzlich sollten Sie ein Backup des ganzen Anwendungsdatenordners im \"Backup\"-Abschnitt erstellen. -popup.moneroLocalhostNode.msg=Haveno hat einen Monero-Knoten entdeckt, der auf diesem Rechner (auf localhost) läuft.\n\nBitte stellen Sie sicher, dass der Knoten vollständig synchronisiert ist, bevor Sie Haveno starten. +popup.xmrLocalNode.msg=Haveno hat einen Monero-Knoten entdeckt, der auf diesem Rechner (auf localhost) läuft.\n\nBitte stellen Sie sicher, dass der Knoten vollständig synchronisiert ist, bevor Sie Haveno starten. popup.shutDownInProgress.headline=Anwendung wird heruntergefahren popup.shutDownInProgress.msg=Das Herunterfahren der Anwendung kann einige Sekunden dauern.\nBitte unterbrechen Sie diesen Vorgang nicht. @@ -1670,6 +1701,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys wurden unterzeichnet popup.accountSigning.unsignedPubKeys.result.signed=Unterzeichnete Pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Unterzeichnung fehlgeschlagen +popup.info.buyerAsTakerWithoutDeposit.headline=Kein Depositum vom Käufer erforderlich +popup.info.buyerAsTakerWithoutDeposit=Ihr Angebot erfordert keine Sicherheitsleistung oder Gebühr vom XMR-Käufer.\n\nUm Ihr Angebot anzunehmen, müssen Sie ein Passwort mit Ihrem Handelspartner außerhalb von Haveno teilen.\n\nDas Passwort wird automatisch generiert und nach der Erstellung in den Angebotsdetails angezeigt. + #################################################################### # Notifications #################################################################### @@ -1677,9 +1711,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Unterzeichnung fehlgeschlagen notification.trade.headline=Benachrichtigung zum Handel mit der ID {0} notification.ticket.headline=Support-Ticket für den Handel mit der ID {0} notification.trade.completed=Ihr Handel ist jetzt abgeschlossen und Sie können Ihre Gelder abheben. -notification.trade.accepted=Ihr Angebot wurde von einem BTC-{0} angenommen. +notification.trade.accepted=Ihr Angebot wurde von einem XMR-{0} angenommen. notification.trade.unlocked=Ihr Handel hat wenigstens eine Blockchain-Bestätigung.\nSie können die Zahlung nun beginnen. -notification.trade.paymentSent=Der BTC-Käufer hat die Zahlung begonnen. +notification.trade.paymentSent=Der XMR-Käufer hat die Zahlung begonnen. notification.trade.selectTrade=Handel wählen notification.trade.peerOpenedDispute=Ihr Handelspartner hat ein/einen {0} geöffnet. notification.trade.disputeClosed=Der/Das {0} wurde geschlossen. @@ -1698,7 +1732,7 @@ systemTray.show=Anwendungsfenster anzeigen systemTray.hide=Anwendungsfenster verstecken systemTray.info=Informationen zu Haveno systemTray.exit=Beenden -systemTray.tooltip=Haveno: Ein dezentrales Bitcoin-Tauschbörsen-Netzwerk +systemTray.tooltip=Haveno: Ein dezentrales Monero-Tauschbörsen-Netzwerk #################################################################### @@ -1749,7 +1783,7 @@ tooltip.openBlockchainForTx=Externen Blockchain-Explorer für Transaktion öffne confidence.unknown=Unbekannter Transaktionsstatus confidence.seen=Von {0} Peer(s) gesehen / 0 Bestätigungen -confidence.confirmed=In {0} Blöcken(Block) bestätigt +confidence.confirmed={0} Bestätigung(en) confidence.invalid=Die Transaktion ist ungültig peerInfo.title=Peer-Infos @@ -1760,10 +1794,10 @@ peerInfo.age.noRisk=Alter des Zahlungskontos peerInfo.age.chargeBackRisk=Zeit seit der Unterzeichnung peerInfo.unknownAge=Alter unbekannt -addressTextField.openWallet=Ihre Standard-Bitcoin-Wallet öffnen +addressTextField.openWallet=Ihre Standard-Monero-Wallet öffnen addressTextField.copyToClipboard=Adresse in Zwischenablage kopieren addressTextField.addressCopiedToClipboard=Die Adresse wurde in die Zwischenablage kopiert -addressTextField.openWallet.failed=Öffnen einer Bitcoin-Wallet-Standardanwendung ist fehlgeschlagen. Haben Sie möglicherweise keine installiert? +addressTextField.openWallet.failed=Öffnen einer Monero-Wallet-Standardanwendung ist fehlgeschlagen. Haben Sie möglicherweise keine installiert? peerInfoIcon.tooltip={0}\nMarkierung: {1} @@ -1795,6 +1829,7 @@ navigation.support=\"Support\" formatter.formatVolumeLabel={0} Betrag{1} formatter.makerTaker=Ersteller als {0} {1} / Abnehmer als {2} {3} +formatter.makerTakerLocked=Ersteller als {0} {1} / Abnehmer als {2} {3} 🔒 formatter.youAreAsMaker=Sie sind: {1} {0} (Ersteller) / Abnehmer ist: {3} {2} formatter.youAreAsTaker=Sie sind: {1} {0} (Abnehmer) / Ersteller ist: {3} {2} formatter.youAre=Sie {0} {1} ({2} {3}) @@ -1811,11 +1846,11 @@ formatter.asTaker={0} {1} als Abnehmer # we use enum values here # dynamic values are not recognized by IntelliJ # suppress inspection "UnusedProperty" -XMR_MAINNET=Bitcoin-Hauptnetzwerk +XMR_MAINNET=Monero-Hauptnetzwerk # suppress inspection "UnusedProperty" -XMR_LOCAL=Bitcoin-Testnetzwerk +XMR_LOCAL=Monero-Testnetzwerk # suppress inspection "UnusedProperty" -XMR_STAGENET=Bitcoin-Regtest +XMR_STAGENET=Monero-Regtest time.year=Jahr time.month=Monat @@ -1840,7 +1875,6 @@ password.deriveKey=Schlüssel aus Passwort ableiten password.walletDecrypted=Die Wallet wurde erfolgreich entschlüsselt und der Passwortschutz entfernt. password.wrongPw=Sie haben das falsche Passwort eingegeben.\n\nVersuchen Sie bitte Ihr Passwort erneut einzugeben, wobei Sie dies vorsichtig auf Tipp- und Rechtschreibfehler überprüfen sollten. password.walletEncrypted=Die Wallet wurde erfolgreich verschlüsselt und der Passwortschutz aktiviert. -password.walletEncryptionFailed=Wallet Passwort konnte nicht eingerichtet werden. Sie haben vielleicht Seed-Wörter importiert, die nicht mit der Wallet-Datenbank übereinstimmen. Bitte kontaktieren Sie die Entwickler auf Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=Die 2 eingegebenen Passwörter stimmen nicht überein. password.forgotPassword=Passwort vergessen? password.backupReminder=Beachten Sie, dass wenn Sie ein Passwort setzen, alle automatisch erstellten Backups der unverschlüsselten Wallet gelöscht werden.\n\nEs wird dringend empfohlen ein Backup des Anwendungsverzeichnisses zu erstellen und die Seed-Wörter aufzuschreiben, bevor Sie ein Passwort erstellen! @@ -1854,7 +1888,7 @@ seed.date=Wallets-Datum seed.restore.title=Wallets aus Seed-Wörtern wiederherstellen seed.restore=Wallets wiederherstellen seed.creationDate=Erstellungsdatum -seed.warn.walletNotEmpty.msg=Ihre Bitcoin-Wallet ist nicht leer.\n\nSie müssen diese Wallet leeren, bevor Sie versuchen, eine ältere Wallet wiederherzustellen, da das Verwechseln von Wallets zu ungültigen Backups führen kann.\n\nBitte schließen Sie Ihre laufenden Trades ab, schließen Sie Ihre offenen Angebote und gehen Sie auf \"Gelder\", um Ihre Bitcoins zu versenden.\nSollten Sie nicht auf Ihre Bitcoins zugreifen können, können Sie das Notfallwerkzeug nutzen, um Ihre Wallet zu leeren.\nUm das Notfallwerkzeug zu öffnen, drücken Sie \"alt + e\" oder \"cmd/Strg + e\". +seed.warn.walletNotEmpty.msg=Ihre Monero-Wallet ist nicht leer.\n\nSie müssen diese Wallet leeren, bevor Sie versuchen, eine ältere Wallet wiederherzustellen, da das Verwechseln von Wallets zu ungültigen Backups führen kann.\n\nBitte schließen Sie Ihre laufenden Trades ab, schließen Sie Ihre offenen Angebote und gehen Sie auf \"Gelder\", um Ihre Moneros zu versenden.\nSollten Sie nicht auf Ihre Moneros zugreifen können, können Sie das Notfallwerkzeug nutzen, um Ihre Wallet zu leeren.\nUm das Notfallwerkzeug zu öffnen, drücken Sie \"alt + e\" oder \"cmd/Strg + e\". seed.warn.walletNotEmpty.restore=Ich möchte trotzdem wiederherstellen seed.warn.walletNotEmpty.emptyWallet=Ich werde meine Wallets erst leeren seed.warn.notEncryptedAnymore=Ihre Wallets sind verschlüsselt.\n\nNach einer Wiederherstellung werden die Wallets nicht mehr verschlüsselt sein und Sie werden ein neues Passwort festlegen müssen.\n\nMöchten Sie fortfahren? @@ -1871,7 +1905,7 @@ seed.restore.openOffers.warn=Sie haben noch offene Angebote die entfernt werden payment.account=Konto payment.account.no=Kontonummer payment.account.name=Kontoname -payment.account.userName=Benutzername +payment.account.username=Benutzername payment.account.phoneNr=Telefonnummer payment.account.owner=Vollständiger Name des Kontoinhabers payment.account.fullName=Vollständiger Name (vor, zweit, nach) @@ -1903,7 +1937,6 @@ payment.amazon.site=Kaufe Geschenkkarte auf payment.ask=Im Trader Chat fragen payment.uphold.accountId=Nutzername oder Email oder Telefonnr. payment.moneyBeam.accountId=E-Mail oder Telefonnummer -payment.venmo.venmoUserName=Venmo Nutzername payment.popmoney.accountId=E-Mail oder Telefonnummer payment.promptPay.promptPayId=Personalausweis/Steuernummer oder Telefonnr. payment.supportedCurrencies=Unterstützte Währungen @@ -1945,16 +1978,16 @@ payment.checking=Überprüfe payment.savings=Ersparnisse payment.personalId=Personalausweis payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle ist ein Geldtransferdienst, der am besten *durch* eine andere Bank funktioniert.\n\n1. Sehen Sie auf dieser Seite nach, ob (und wie) Ihre Bank mit Zelle zusammenarbeitet:\nhttps://www.zellepay.com/get-started\n\n2. Achten Sie besonders auf Ihre Überweisungslimits - die Sendelimits variieren je nach Bank, und die Banken geben oft separate Tages-, Wochen- und Monatslimits an.\n\n3. Wenn Ihre Bank nicht mit Zelle zusammenarbeitet, können Sie die Zahlungsmethode trotzdem über die Zelle Mobile App benutzen, aber Ihre Überweisungslimits werden viel niedriger sein.\n\n4. Der auf Ihrem Haveno-Konto angegebene Name MUSS mit dem Namen auf Ihrem Zelle/Bankkonto übereinstimmen. \n\nWenn Sie eine Zelle Transaktion nicht wie in Ihrem Handelsvertrag angegeben durchführen können, verlieren Sie möglicherweise einen Teil (oder die gesamte) Sicherheitskaution.\n\nWegen des etwas höheren Chargeback-Risikos von Zelle wird Verkäufern empfohlen, nicht unterzeichnete Käufer per E-Mail oder SMS zu kontaktieren, um zu überprüfen, ob der Käufer wirklich das in Haveno angegebene Zelle-Konto besitzt. payment.fasterPayments.newRequirements.info=Einige Banken haben damit begonnen, den vollständigen Namen des Empfängers für Faster Payments Überweisungen zu überprüfen. Ihr aktuelles Faster Payments-Konto gibt keinen vollständigen Namen an.\n\nBitte erwägen Sie, Ihr Faster Payments-Konto in Haveno neu einzurichten, um zukünftigen {0} Käufern einen vollständigen Namen zu geben.\n\nWenn Sie das Konto neu erstellen, stellen Sie sicher, dass Sie die genaue Bankleitzahl, Kontonummer und die "Salt"-Werte für die Altersverifikation von Ihrem alten Konto auf Ihr neues Konto kopieren. Dadurch wird sichergestellt, dass das Alter und der Unterschriftsstatus Ihres bestehenden Kontos erhalten bleiben. -payment.moneyGram.info=Bei der Nutzung von MoneyGram, muss der BTC Käufer die MoneyGram Zulassungsnummer und ein Foto der Quittung per E-Mail an den BTC-Verkäufer senden. Die Quittung muss den vollständigen Namen, das Land, das Bundesland des Verkäufers und den Betrag deutlich zeigen. Der Käufer bekommt die E-Mail-Adresse des Verkäufers im Handelsprozess angezeigt. -payment.westernUnion.info=Bei der Nutzung von Western Union, muss der BTC Käufer die MTCN (Tracking-Nummer) Foto der Quittung per E-Mail an den BTC-Verkäufer senden. Die Quittung muss den vollständigen Namen, das Land, die Stadt des Verkäufers und den Betrag deutlich zeigen. Der Käufer bekommt die E-Mail-Adresse des Verkäufers im Handelsprozess angezeigt. -payment.halCash.info=Bei Verwendung von HalCash muss der BTC-Käufer dem BTC-Verkäufer den HalCash-Code per SMS vom Mobiltelefon senden.\n\nBitte achten Sie darauf, dass Sie den maximalen Betrag, den Sie bei Ihrer Bank mit HalCash versenden dürfen, nicht überschreiten. Der Mindestbetrag pro Auszahlung beträgt 10 EUR und der Höchstbetrag 600 EUR. Bei wiederholten Abhebungen sind es 3000 EUR pro Empfänger pro Tag und 6000 EUR pro Empfänger pro Monat. Bitte überprüfen Sie diese Limits bei Ihrer Bank, um sicherzustellen, dass sie die gleichen Limits wie hier angegeben verwenden.\n\nDer Auszahlungsbetrag muss ein Vielfaches von 10 EUR betragen, da Sie keine anderen Beträge an einem Geldautomaten abheben können. Die Benutzeroberfläche beim Erstellen und Annehmen eines Angebots passt den BTC-Betrag so an, dass der EUR-Betrag korrekt ist. Sie können keinen marktbasierten Preis verwenden, da sich der EUR-Betrag bei sich ändernden Preisen ändern würde.\n\nIm Streitfall muss der BTC-Käufer den Nachweis erbringen, dass er die EUR geschickt hat. +payment.moneyGram.info=Bei der Nutzung von MoneyGram, muss der XMR Käufer die MoneyGram Zulassungsnummer und ein Foto der Quittung per E-Mail an den XMR-Verkäufer senden. Die Quittung muss den vollständigen Namen, das Land, das Bundesland des Verkäufers und den Betrag deutlich zeigen. Der Käufer bekommt die E-Mail-Adresse des Verkäufers im Handelsprozess angezeigt. +payment.westernUnion.info=Bei der Nutzung von Western Union, muss der XMR Käufer die MTCN (Tracking-Nummer) Foto der Quittung per E-Mail an den XMR-Verkäufer senden. Die Quittung muss den vollständigen Namen, das Land, die Stadt des Verkäufers und den Betrag deutlich zeigen. Der Käufer bekommt die E-Mail-Adresse des Verkäufers im Handelsprozess angezeigt. +payment.halCash.info=Bei Verwendung von HalCash muss der XMR-Käufer dem XMR-Verkäufer den HalCash-Code per SMS vom Mobiltelefon senden.\n\nBitte achten Sie darauf, dass Sie den maximalen Betrag, den Sie bei Ihrer Bank mit HalCash versenden dürfen, nicht überschreiten. Der Mindestbetrag pro Auszahlung beträgt 10 EUR und der Höchstbetrag 600 EUR. Bei wiederholten Abhebungen sind es 3000 EUR pro Empfänger pro Tag und 6000 EUR pro Empfänger pro Monat. Bitte überprüfen Sie diese Limits bei Ihrer Bank, um sicherzustellen, dass sie die gleichen Limits wie hier angegeben verwenden.\n\nDer Auszahlungsbetrag muss ein Vielfaches von 10 EUR betragen, da Sie keine anderen Beträge an einem Geldautomaten abheben können. Die Benutzeroberfläche beim Erstellen und Annehmen eines Angebots passt den XMR-Betrag so an, dass der EUR-Betrag korrekt ist. Sie können keinen marktbasierten Preis verwenden, da sich der EUR-Betrag bei sich ändernden Preisen ändern würde.\n\nIm Streitfall muss der XMR-Käufer den Nachweis erbringen, dass er die EUR geschickt hat. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Bitte beachten Sie, dass alle Banküberweisungen mit einem gewissen Rückbuchungsrisiko verbunden sind. Um dieses Risiko zu mindern, setzt Haveno Limits pro Trade fest, je nachdem wie hoch das Rückbuchungsrisiko der Zahlungsmethode ist. \n\nFür diese Zahlungsmethode beträgt Ihr Pro-Trade-Limit zum Kaufen oder Verkaufen {2}.\nDieses Limit gilt nur für die Größe eines einzelnen Trades - Sie können soviele Trades platzieren wie Sie möchten.\n\nFinden Sie mehr Informationen im Wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Bitte beachten Sie, dass alle Banküberweisungen mit einem gewissen Rückbuchungsrisiko verbunden sind. Um dieses Risiko zu mindern, setzt Haveno Limits pro Trade fest, je nachdem wie hoch das Rückbuchungsrisiko der Zahlungsmethode ist. \n\nFür diese Zahlungsmethode beträgt Ihr Pro-Trade-Limit zum Kaufen oder Verkaufen {2}.\nDieses Limit gilt nur für die Größe eines einzelnen Trades - Sie können soviele Trades platzieren wie Sie möchten.\n\nFinden Sie mehr Informationen im Wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=Um das Risiko einer Rückbuchung zu minimieren, setzt Haveno für diese Zahlungsmethode Limits pro Trade auf der Grundlage der folgenden 2 Faktoren fest:\n\n1. Allgemeines Rückbuchungsrisiko für die Zahlungsmethode\n2. Status der Kontounterzeichnung\n\nDieses Zahlungskonto ist noch nicht unterzeichnet. Es ist daher auf den Kauf von {0} pro Trade beschränkt ist. Nach der Unterzeichnung werden die Kauflimits wie folgt erhöht:\n\n● Vor der Unterzeichnung und für 30 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {0}\n● 30 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {1}\n● 60 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {2}\n\nVerkaufslimits sind von der Kontounterzeichnung nicht betroffen. Sie können {2} in einem einzigen Trade sofort verkaufen.\n\nDieses Limit gilt nur für die Größe eines einzelnen Trades - Sie können soviele Trades platzieren wie sie möchten.\n\nWeitere Informationen gibt es im Wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=Um das Risiko einer Rückbuchung zu minimieren, setzt Haveno für diese Zahlungsmethode Limits pro Trade auf der Grundlage der folgenden 2 Faktoren fest:\n\n1. Allgemeines Rückbuchungsrisiko für die Zahlungsmethode\n2. Status der Kontounterzeichnung\n\nDieses Zahlungskonto ist noch nicht unterzeichnet. Es ist daher auf den Kauf von {0} pro Trade beschränkt ist. Nach der Unterzeichnung werden die Kauflimits wie folgt erhöht:\n\n● Vor der Unterzeichnung und für 30 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {0}\n● 30 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {1}\n● 60 Tage nach der Unterzeichnung beträgt Ihr Kauflimit pro Trade {2}\n\nVerkaufslimits sind von der Kontounterzeichnung nicht betroffen. Sie können {2} in einem einzigen Trade sofort verkaufen.\n\nDieses Limit gilt nur für die Größe eines einzelnen Trades - Sie können soviele Trades platzieren wie sie möchten.\n\nWeitere Informationen gibt es im Wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Bitte bestätigen Sie, dass Ihre Bank Bareinzahlungen in Konten von anderen Personen erlaubt. Zum Beispiel werden diese Einzahlungen bei der Bank of America und Wells Fargo nicht mehr erlaubt. @@ -1966,7 +1999,7 @@ payment.amazonGiftCard.upgrade=Bei der Zahlungsmethode Amazon Geschenkkarten mus payment.account.amazonGiftCard.addCountryInfo={0}\nDein bestehendes Amazon Geschenkkarten Konto ({1}) wurde keinem Land zugeteilt.\nBitte geben Sie das Amazon Geschenkkarten Land ein um Ihre Kontodaten zu aktualisieren.\nDas wird ihr Kontoalter nicht beeinflussen. payment.amazonGiftCard.upgrade.headLine=Amazon Geschenkkarte Konto updaten -payment.usPostalMoneyOrder.info=Der Handel auf Haveno unter Verwendung von US Postal Money Orders (USPMO) setzt voraus, dass Sie Folgendes verstehen:\n\n- Der BTC-Käufer muss den Namen des BTC-Verkäufers sowohl in das Feld des Zahlers als auch in das Feld des Zahlungsempfängers eintragen und vor dem Versand ein hochauflösendes Foto des USPMO und des Umschlags mit dem Tracking-Nachweis machen.\n- BTC-Käufer müssen den USPMO mit Zustellbenachrichtigung an den BTC-Verkäufer schicken.\n\nFür den Fall, dass eine Mediation erforderlich ist oder es zu einem Handelskonflikt kommt, müssen Sie die Fotos zusammen mit der USPMO-Seriennummer, der Nummer des Postamtes und dem Dollarbetrag an den Haveno-Vermittler oder Rückerstattungsbeauftragten schicken, damit dieser die Angaben auf der Website der US-Post überprüfen kann.\n\nWenn Sie dem Vermittler oder der Schiedsperson die erforderlichen Informationen nicht zur Verfügung stellen, führt dies dazu, dass der Konflikt zu Ihrem Nachteil entschieden wird.\n\nIn allen Konfliktfällen trägt der USPMO-Absender 100% der Verantwortung für die Bereitstellung von Beweisen/Nachweisen für den Vermittler oder die Schiedsperson.\n\nWenn Sie diese Anforderungen nicht verstehen, handeln Sie bitte nicht auf Haveno unter Verwendung von USPMO. +payment.usPostalMoneyOrder.info=Der Handel auf Haveno unter Verwendung von US Postal Money Orders (USPMO) setzt voraus, dass Sie Folgendes verstehen:\n\n- Der XMR-Käufer muss den Namen des XMR-Verkäufers sowohl in das Feld des Zahlers als auch in das Feld des Zahlungsempfängers eintragen und vor dem Versand ein hochauflösendes Foto des USPMO und des Umschlags mit dem Tracking-Nachweis machen.\n- XMR-Käufer müssen den USPMO mit Zustellbenachrichtigung an den XMR-Verkäufer schicken.\n\nFür den Fall, dass eine Mediation erforderlich ist oder es zu einem Handelskonflikt kommt, müssen Sie die Fotos zusammen mit der USPMO-Seriennummer, der Nummer des Postamtes und dem Dollarbetrag an den Haveno-Vermittler oder Rückerstattungsbeauftragten schicken, damit dieser die Angaben auf der Website der US-Post überprüfen kann.\n\nWenn Sie dem Vermittler oder der Schiedsperson die erforderlichen Informationen nicht zur Verfügung stellen, führt dies dazu, dass der Konflikt zu Ihrem Nachteil entschieden wird.\n\nIn allen Konfliktfällen trägt der USPMO-Absender 100% der Verantwortung für die Bereitstellung von Beweisen/Nachweisen für den Vermittler oder die Schiedsperson.\n\nWenn Sie diese Anforderungen nicht verstehen, handeln Sie bitte nicht auf Haveno unter Verwendung von USPMO. payment.payByMail.info=Der Handel über Pay by Mail auf Haveno erfordert, dass Sie Folgendes verstehen:\n\ \n\ @@ -1996,7 +2029,7 @@ payment.f2f.city.prompt=Die Stadt wird mit dem Angebot angezeigt payment.shared.optionalExtra=Freiwillige zusätzliche Informationen payment.shared.extraInfo=Zusätzliche Informationen payment.shared.extraInfo.prompt=Gib spezielle Bedingungen, Abmachungen oder Details die bei ihren Angeboten unter diesem Zahlungskonto angezeigt werden sollen an. Nutzer werden diese Informationen vor der Annahme des Angebots sehen. -payment.f2f.info=Persönliche 'Face to Face' Trades haben unterschiedliche Regeln und sind mit anderen Risiken verbunden als gewöhnliche Online-Trades.\n\nDie Hauptunterschiede sind:\n● Die Trading Partner müssen die Kontaktdaten und Informationen über den Ort und die Uhrzeit des Treffens austauschen.\n● Die Trading Partner müssen ihre Laptops mitbringen und die Bestätigung der "gesendeten Zahlung" und der "erhaltenen Zahlung" am Treffpunkt vornehmen.\n● Wenn ein Ersteller eines Angebots spezielle "Allgemeine Geschäftsbedingungen" hat, muss er diese im Textfeld "Zusatzinformationen" des Kontos angeben.\n● Mit der Annahme eines Angebots erklärt sich der Käufer mit den vom Anbieter angegebenen "Allgemeinen Geschäftsbedingungen" einverstanden.\n● Im Konfliktfall kann der Mediator oder Arbitrator nicht viel tun, da es in der Regel schwierig ist zu bestimmen, was beim Treffen passiert ist. In solchen Fällen können die Bitcoin auf unbestimmte Zeit oder bis zu einer Einigung der Trading Peers gesperrt werden.\n\nUm sicherzustellen, dass Sie die Besonderheiten der persönlichen 'Face to Face' Trades vollständig verstehen, lesen Sie bitte die Anweisungen und Empfehlungen unter: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info=Persönliche 'Face to Face' Trades haben unterschiedliche Regeln und sind mit anderen Risiken verbunden als gewöhnliche Online-Trades.\n\nDie Hauptunterschiede sind:\n● Die Trading Partner müssen die Kontaktdaten und Informationen über den Ort und die Uhrzeit des Treffens austauschen.\n● Die Trading Partner müssen ihre Laptops mitbringen und die Bestätigung der "gesendeten Zahlung" und der "erhaltenen Zahlung" am Treffpunkt vornehmen.\n● Wenn ein Ersteller eines Angebots spezielle "Allgemeine Geschäftsbedingungen" hat, muss er diese im Textfeld "Zusatzinformationen" des Kontos angeben.\n● Mit der Annahme eines Angebots erklärt sich der Käufer mit den vom Anbieter angegebenen "Allgemeinen Geschäftsbedingungen" einverstanden.\n● Im Konfliktfall kann der Mediator oder Arbitrator nicht viel tun, da es in der Regel schwierig ist zu bestimmen, was beim Treffen passiert ist. In solchen Fällen können die Monero auf unbestimmte Zeit oder bis zu einer Einigung der Trading Peers gesperrt werden.\n\nUm sicherzustellen, dass Sie die Besonderheiten der persönlichen 'Face to Face' Trades vollständig verstehen, lesen Sie bitte die Anweisungen und Empfehlungen unter: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Webseite öffnen payment.f2f.offerbook.tooltip.countryAndCity=Land und Stadt: {0} / {1} payment.f2f.offerbook.tooltip.extra=Zusätzliche Informationen: {0} @@ -2008,7 +2041,7 @@ payment.japan.recipient=Name payment.australia.payid=PayID payment.payid=PayIDs wie E-Mail Adressen oder Telefonnummern die mit Finanzinstitutionen verbunden sind. payment.payid.info=Eine PayID wie eine Telefonnummer, E-Mail Adresse oder Australische Business Number (ABN) mit der Sie sicher Ihre Bank, Kreditgenossenschaft oder Bausparkassenkonto verlinken können. Sie müssen bereits eine PayID mit Ihrer Australischen Finanzinstitution erstellt haben. Beide Institutionen, die die sendet und die die empfängt, müssen PayID unterstützen. Weitere informationen finden Sie unter [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=Um mit einer Amazon eGift Geschenkkarte zu bezahlen, müssen Sie eine Amazon eGift Geschenkkarte über Ihr Amazon-Konto an den BTC-Verkäufer senden. \n\nHaveno zeigt die E-Mail-Adresse oder Telefonnummer des BTC-Verkäufers an, an die die Geschenkkarte gesendet werden soll, und Sie müssen die Handels-ID in das Nachrichtenfeld der Geschenkkarte eintragen. Bitte lesen Sie das Wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] für weitere Details und empfohlene Vorgehensweisen. \n\nDrei wichtige Hinweise:\n- Versuchen Sie Geschenkkarten mit Beträgen von 100 USD oder weniger zu versenden, weil Amazon größere Geschenkkarten gerne als betrügerisch kennzeichnet\n- Versuchen Sie einen kreativen, glaubwürdigen Text für die Nachricht der Geschenkkarten zu verwenden (z.B. "Alles Gute zum Geburtstag Susi!"), zusammen mit der Handels-ID (und verwenden Sie den Handels-Chat, um Ihrem Handelspartner den von Ihnen gewählten Referenztext mitzuteilen, damit er Ihre Zahlung überprüfen kann)\n- Amazon Geschenkkarten können nur auf der Amazon-Website eingelöst werden, auf der sie gekauft wurden (z. B. kann eine auf amazon.it gekaufte Geschenkkarte nur auf amazon.it eingelöst werden) +payment.amazonGiftCard.info=Um mit einer Amazon eGift Geschenkkarte zu bezahlen, müssen Sie eine Amazon eGift Geschenkkarte über Ihr Amazon-Konto an den XMR-Verkäufer senden. \n\nHaveno zeigt die E-Mail-Adresse oder Telefonnummer des XMR-Verkäufers an, an die die Geschenkkarte gesendet werden soll, und Sie müssen die Handels-ID in das Nachrichtenfeld der Geschenkkarte eintragen. Bitte lesen Sie das Wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] für weitere Details und empfohlene Vorgehensweisen. \n\nDrei wichtige Hinweise:\n- Versuchen Sie Geschenkkarten mit Beträgen von 100 USD oder weniger zu versenden, weil Amazon größere Geschenkkarten gerne als betrügerisch kennzeichnet\n- Versuchen Sie einen kreativen, glaubwürdigen Text für die Nachricht der Geschenkkarten zu verwenden (z.B. "Alles Gute zum Geburtstag Susi!"), zusammen mit der Handels-ID (und verwenden Sie den Handels-Chat, um Ihrem Handelspartner den von Ihnen gewählten Referenztext mitzuteilen, damit er Ihre Zahlung überprüfen kann)\n- Amazon Geschenkkarten können nur auf der Amazon-Website eingelöst werden, auf der sie gekauft wurden (z. B. kann eine auf amazon.it gekaufte Geschenkkarte nur auf amazon.it eingelöst werden) # We use constants from the code so we do not use our normal naming convention @@ -2166,7 +2199,7 @@ validation.zero=Die Eingabe von 0 ist nicht erlaubt. validation.negative=Ein negativer Wert ist nicht erlaubt. validation.traditional.tooSmall=Eingaben kleiner als der minimal mögliche Betrag sind nicht erlaubt. validation.traditional.tooLarge=Eingaben größer als der maximal mögliche Betrag sind nicht erlaubt. -validation.xmr.fraction=Input wird einem Bitcoin Wert von weniger als 1 satoshi entsprechen +validation.xmr.fraction=Input wird einem Monero Wert von weniger als 1 satoshi entsprechen validation.xmr.tooLarge=Eingaben größer als {0} sind nicht erlaubt. validation.xmr.tooSmall=Eingabe kleiner als {0} ist nicht erlaubt. validation.passwordTooShort=Das Passwort das Sie eingegeben haben ist zu kurz. Es muss mindestens 8 Zeichen enthalten. @@ -2176,10 +2209,10 @@ validation.sortCodeChars={0} muss aus {1} Zeichen bestehen. validation.bankIdNumber={0} muss aus {1} Zahlen bestehen. validation.accountNr=Die Kontonummer muss aus {0} Zahlen bestehen. validation.accountNrChars=Die Kontonummer muss aus {0} Zeichen bestehen. -validation.btc.invalidAddress=Die Adresse ist nicht korrekt. Bitte überprüfen Sie das Adressformat. +validation.xmr.invalidAddress=Die Adresse ist nicht korrekt. Bitte überprüfen Sie das Adressformat. validation.integerOnly=Bitte nur ganze Zahlen eingeben. validation.inputError=Ihre Eingabe hat einen Fehler verursacht:\n{0} -validation.btc.exceedsMaxTradeLimit=Ihr Handelslimit ist {0}. +validation.xmr.exceedsMaxTradeLimit=Ihr Handelslimit ist {0}. validation.nationalAccountId={0} muss aus {1} Zahlen bestehen. #new diff --git a/core/src/main/resources/i18n/displayStrings_es.properties b/core/src/main/resources/i18n/displayStrings_es.properties index 25003e4d5f..af7539e7fd 100644 --- a/core/src/main/resources/i18n/displayStrings_es.properties +++ b/core/src/main/resources/i18n/displayStrings_es.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Entendido shared.na=No disponible shared.shutDown=Apagar shared.reportBug=Reportar error de software en Github -shared.buyBitcoin=Comprar bitcoin -shared.sellBitcoin=Vender bitcoin +shared.buyMonero=Comprar monero +shared.sellMonero=Vender monero shared.buyCurrency=Comprar {0} shared.sellCurrency=Vender {0} -shared.buyingBTCWith=Comprando BTC con {0} -shared.sellingBTCFor=Vendiendo BTC por {0} -shared.buyingCurrency=comprando {0} (Vendiendo BTC) -shared.sellingCurrency=Vendiendo {0} (comprando BTC) +shared.buyCurrencyLocked=Comprar {0} 🔒 +shared.sellCurrencyLocked=Vender {0} 🔒 +shared.buyingXMRWith=Comprando XMR con {0} +shared.sellingXMRFor=Vendiendo XMR por {0} +shared.buyingCurrency=comprando {0} (Vendiendo XMR) +shared.sellingCurrency=Vendiendo {0} (comprando XMR) shared.buy=comprar shared.sell=vender shared.buying=comprando @@ -93,7 +95,7 @@ shared.amountMinMax=Cantidad (min-max) shared.amountHelp=Si una oferta tiene una cantidad mínima y máxima establecida, entonces puede intercambiar cualquier cantidad dentro de este rango. shared.remove=Eliminar shared.goTo=Ir a {0} -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Eliminar oferta shared.dontRemoveOffer=No eliminar oferta shared.editOffer=Editar oferta @@ -103,7 +105,7 @@ shared.faq=Visitar web preguntas frecuentes shared.yesCancel=Sí, cancelar shared.nextStep=Siguiente paso shared.selectTradingAccount=Selecionar cuenta de intercambio -shared.fundFromSavingsWalletButton=Transferir fondos desde la cartera Haveno +shared.fundFromSavingsWalletButton=Aplicar fondos desde la billetera de Haveno shared.fundFromExternalWalletButton=Abrir su monedero externo para agregar fondos shared.openDefaultWalletFailed=Fallo al abrir la aplicación de cartera predeterminada. ¿Tal vez no tenga una instalada? shared.belowInPercent=% por debajo del precio de mercado @@ -112,7 +114,7 @@ shared.enterPercentageValue=Introduzca valor % shared.OR=ó shared.notEnoughFunds=No tiene suficientes fondos en su monedero haveno para esta transacción. Necesita {0} pero solo tiene {1} disponibles.\n\nPor favor deposite desde un monedero externo o agregue fondos a su monedero Haveno en Fondos > Recibir Fondos. shared.waitingForFunds=Esperando fondos... -shared.TheBTCBuyer=El comprador de BTC +shared.TheXMRBuyer=El comprador de XMR shared.You=Usted shared.sendingConfirmation=Enviando confirmación... shared.sendingConfirmationAgain=Por favor envíe confirmación de nuevo @@ -123,9 +125,8 @@ shared.noDateAvailable=Sin fecha disponible shared.noDetailsAvailable=Sin detalles disponibles shared.notUsedYet=Sin usar aún shared.date=Fecha -shared.sendFundsDetailsWithFee=Enviando: {0}\nDesde la dirección: {1}\nA la dirección receptora: {2}.\nLa comisión requerida de transacción es: {3} ({4} Satoshis/vbyte)\nTamaño de la transacción: {5} vKb\n\nEl receptor recibirá: {6}\n\nSeguro que quiere retirar esta cantidad? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detectó que esta transacción crearía una salida que está por debajo del umbral mínimo considerada polvo (y no está permitida por las reglas de consenso en Bitcoin). En cambio, esta transacción polvo ({0} satoshi {1}) se agregará a la tarifa de minería.\n\n\n +shared.sendFundsDetailsDust=Haveno detectó que esta transacción crearía una salida que está por debajo del umbral mínimo considerada polvo (y no está permitida por las reglas de consenso en Monero). En cambio, esta transacción polvo ({0} satoshi {1}) se agregará a la tarifa de minería.\n\n\n shared.copyToClipboard=Copiar al portapapeles shared.language=Idioma shared.country=País @@ -140,6 +141,7 @@ shared.addNewAccount=Añadir una nueva cuenta shared.ExportAccounts=Exportar cuentas shared.importAccounts=Importar cuentas shared.createNewAccount=Crear nueva cuenta +shared.createNewAccountDescription=Los detalles de su cuenta se almacenan localmente en su dispositivo y se comparten solo con su contraparte comercial y el árbitro si se abre una disputa. shared.saveNewAccount=Guardar nueva cuenta shared.selectedAccount=Cuenta seleccionada shared.deleteAccount=Borrar cuenta @@ -169,7 +171,7 @@ shared.payoutTxId=ID de transacción de pago shared.contractAsJson=Contrato en formato JSON shared.viewContractAsJson=Ver contrato en formato JSON shared.contract.title=Contrato de intercambio con ID: {0} -shared.paymentDetails=Detalles de pago BTC {0} +shared.paymentDetails=Detalles de pago XMR {0} shared.securityDeposit=Depósito de seguridad shared.yourSecurityDeposit=Su depósito de seguridad shared.contract=Contrato @@ -179,19 +181,21 @@ shared.messageSendingFailed=Envío de mensaje fallido. Error: {0} shared.unlock=Desbloquear shared.toReceive=a recibir shared.toSpend=a gastar -shared.btcAmount=Cantidad BTC +shared.xmrAmount=Cantidad XMR shared.yourLanguage=Sus idiomas shared.addLanguage=Añadir idioma shared.total=Total shared.totalsNeeded=Fondos necesarios shared.tradeWalletAddress=Dirección de la cartera para intercambio shared.tradeWalletBalance=Saldo de la cartera de intercambio +shared.reserveExactAmount=Reserve solo los fondos necesarios. Requiere una tarifa de minería y aproximadamente 20 minutos antes de que tu oferta se haga pública. shared.makerTxFee=Creador: {0} shared.takerTxFee=Tomador: {0} shared.iConfirm=Confirmo shared.openURL=Abrir {0} shared.fiat=Fiat shared.crypto=Cripto +shared.preciousMetals=Metales Preciosos shared.all=Todos shared.edit=Editar shared.advancedOptions=Opciones avanzadas @@ -226,8 +230,8 @@ shared.enabled=Habilitado #################################################################### mainView.menu.market=Mercado -mainView.menu.buyBtc=Comprar BTC -mainView.menu.sellBtc=Vender BTC +mainView.menu.buyXmr=Comprar XMR +mainView.menu.sellXmr=Vender XMR mainView.menu.portfolio=Portafolio mainView.menu.funds=Fondos mainView.menu.support=Soporte @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Reservado mainView.balance.pending.short=Bloqueado mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/Tasas actuales: {0} sat/vB -mainView.footer.xmrInfo.initializing=Conectando a la red Bitcoin +mainView.footer.xmrFeeRate=/Tasas actuales: {0} sat/vB +mainView.footer.xmrInfo.initializing=Conectando a la red Haveno mainView.footer.xmrInfo.synchronizingWith=Sincronizando con {0} en el bloque: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Sincronizado con {0} en el bloque {1} +mainView.footer.xmrInfo.connectedTo=Conectado a {0} en el bloque {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Sincronizando la billetera con {0} en el bloque: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Sincronizado con {0} en el bloque {1} mainView.footer.xmrInfo.connectingTo=Conectando a mainView.footer.xmrInfo.connectionFailed=Conexión fallida a mainView.footer.xmrPeers=Pares de Monero: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=Fallo al conectarse a la red mainView.p2pNetworkWarnMsg.noNodesAvailable=No hay nodos de sembrado o puntos de red persistentes para los datos requeridos.\nPor favor, compruebe su conexión a Internet o intente reiniciar la aplicación. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Fallo conectándose a la red Haveno (error reportado: {0}).\nPor favor, compruebe su conexión a internet o pruebe reiniciando la aplicación. -mainView.walletServiceErrorMsg.timeout=Error al conectar a la red Bitcoin en el límite de tiempo establecido. -mainView.walletServiceErrorMsg.connectionError=La conexión a la red Bitcoin falló por un error: {0} +mainView.walletServiceErrorMsg.timeout=Error al conectar a la red Monero en el límite de tiempo establecido. +mainView.walletServiceErrorMsg.connectionError=La conexión a la red Monero falló por un error: {0} mainView.walletServiceErrorMsg.rejectedTxException=Se rechazó una transacción desde la red.\n\n{0} mainView.networkWarning.allConnectionsLost=Perdió la conexión a todos los {0} usuarios de red.\nTal vez se ha interrumpido su conexión a Internet o su computadora estaba en modo suspendido. -mainView.networkWarning.localhostBitcoinLost=Perdió la conexión al nodo Bitcoin localhost.\nPor favor reinicie la aplicación Haveno para conectarse a otros nodos Bitcoin o reinice el nodo Bitcoin localhost. +mainView.networkWarning.localhostMoneroLost=Perdió la conexión al nodo Monero localhost.\nPor favor reinicie la aplicación Haveno para conectarse a otros nodos Monero o reinice el nodo Monero localhost. mainView.version.update=(Actualización disponible) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=Comprar {0} market.offerBook.sellWithTraditional=Vender {0} market.offerBook.sellOffersHeaderLabel=Vender {0} a market.offerBook.buyOffersHeaderLabel=Comprar {0} de -market.offerBook.buy=Quiero comprar bitcoin -market.offerBook.sell=Quiero vender bitcoin +market.offerBook.buy=Quiero comprar monero +market.offerBook.sell=Quiero vender monero # SpreadView market.spread.numberOfOffersColumn=Todas las ofertas ({0}) -market.spread.numberOfBuyOffersColumn=Comprar BTC ({0}) -market.spread.numberOfSellOffersColumn=Vender BTC ({0}) -market.spread.totalAmountColumn=Total BTC ({0}) +market.spread.numberOfBuyOffersColumn=Comprar XMR ({0}) +market.spread.numberOfSellOffersColumn=Vender XMR ({0}) +market.spread.totalAmountColumn=Total XMR ({0}) market.spread.spreadColumn=Diferencial market.spread.expanded=Vista expandida @@ -325,6 +332,7 @@ offerbook.createOffer=Crear oferta offerbook.takeOffer=Tomar oferta offerbook.takeOfferToBuy=Tomar oferta de compra de {0} offerbook.takeOfferToSell=Tomar oferta de venta de {0} +offerbook.takeOffer.enterChallenge=Introduzca la frase secreta de la oferta offerbook.trader=Trader offerbook.offerersBankId=ID del banco del creador (BIC/SWIFT): {0} offerbook.offerersBankName=Nombre del banco del creador: {0} @@ -335,6 +343,8 @@ offerbook.availableOffers=Ofertas disponibles offerbook.filterByCurrency=Filtrar por moneda offerbook.filterByPaymentMethod=Filtrar por método de pago offerbook.matchingOffers=Ofertas que concuerden con mis cuentas +offerbook.filterNoDeposit=Sin depósito +offerbook.noDepositOffers=Ofertas sin depósito (se requiere frase de paso) offerbook.timeSinceSigning=Información de la cuenta offerbook.timeSinceSigning.info=Esta cuenta fue verificada y {0} offerbook.timeSinceSigning.info.arbitrator=firmada por un árbitro y puede firmar cuentas de pares @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=La cuenta fue bloqueada offerbook.timeSinceSigning.daysSinceSigning={0} días offerbook.timeSinceSigning.daysSinceSigning.long={0} desde el firmado offerbook.xmrAutoConf=¿Está habilitada la confirmación automática? +offerbook.buyXmrWith=Compra XMR con: +offerbook.sellXmrFor=Vender XMR por: offerbook.timeSinceSigning.help=Cuando complete con éxito un intercambio con un par que tenga una cuenta de pago firmada, su cuenta de pago es firmada.\n{0} días después, el límite inicial de {1} se eleva y su cuenta puede firmar tras cuentas de pago. offerbook.timeSinceSigning.notSigned=No firmada aún @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Las cuentas de crypto no necesitan firmado o edad offerbook.nrOffers=Número de ofertas: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Depósito en BTC (%) +offerbook.deposit=Depósito en XMR (%) offerbook.deposit.help=Depósito pagado por cada comerciante para garantizar el intercambio. Será devuelto al acabar el intercambio. +offerbook.createNewOffer=Crear oferta a {0} {1} offerbook.createOfferToBuy=Crear nueva oferta para comprar {0} offerbook.createOfferToSell=Crear nueva oferta para vender {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=Con esta versión de software, los pare popup.warning.tradeLimitDueAccountAgeRestriction.seller=El monto de intercambio permitido está limitado a {0} debido a restricciones de seguridad basadas en los siguientes criterios:\n- La cuenta del comprador no ha sido firmada por un árbitro o par\n- El tiempo desde el firmado de la cuenta del comprador no es de al menos 30 días.\n- el método de pago para esta oferta se considera riesgoso para devoluciones de cargo\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=El monto de intercambio permitido está limitado a {0} debido a restricciones de seguridad basadas en los siguientes criterios:\n- Su cuenta de pago no ha sido firmada por un árbitro o par\n- El tiempo desde el firmado de su cuenta no es de al menos 30 días\n- El método de pago para esta oferta se considera riesgoso para devoluciones de cargo\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Este método de pago está temporalmente limitado a {0} hasta {1} porque todos los compradores tienen cuentas nuevas.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Tu oferta estará limitada a compradores con cuentas firmadas y antiguas porque excede {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Esta oferta requiere un protocolo de intercambio diferente al utilizado en su versión del software.\n\nPor favor, compruebe que tiene instalada la última versión del software, o de otra forma el usuario que creó la oferta ha utilizado una versión más antigua que la suya.\n\nLos usuarios no pueden realizar transacciones con una versión de protocolo de intercambio incompatible. offerbook.warning.userIgnored=Ha añadido esta dirección onion a la lista de ignorados. @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=La cantidad se redondeó para incrementar la pr # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Introducir cantidad en BTC +createOffer.amount.prompt=Introducir cantidad en XMR createOffer.price.prompt=Introducir precio createOffer.volume.prompt=Introducir cantidad en {0} -createOffer.amountPriceBox.amountDescription=Cantidad de BTC a {0} +createOffer.amountPriceBox.amountDescription=Cantidad de XMR a {0} createOffer.amountPriceBox.buy.volumeDescription=Cantidad a gastar en {0} createOffer.amountPriceBox.sell.volumeDescription=Cantidad a recibir en {0}. -createOffer.amountPriceBox.minAmountDescription=Cantidad mínima de BTC +createOffer.amountPriceBox.minAmountDescription=Cantidad mínima de XMR createOffer.securityDeposit.prompt=Depósito de seguridad createOffer.fundsBox.title=Dote de fondos su oferta. createOffer.fundsBox.offerFee=Comisión de transacción @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=Siempre tendrá {0}% más que el precio de createOffer.info.buyBelowMarketPrice=Siempre pagará {0}% menos que el precio de mercado ya que el precio de su oferta será actualizado continuamente. createOffer.warning.sellBelowMarketPrice=Siempre tendrá {0}% menos que el precio de mercado ya que el precio de su oferta será actualizado continuamente. createOffer.warning.buyAboveMarketPrice=Siempre pagará {0}% más que el precio de mercado ya que el precio de su oferta será actualizado continuamente. -createOffer.tradeFee.descriptionBTCOnly=Comisión de transacción +createOffer.tradeFee.descriptionXMROnly=Comisión de transacción createOffer.tradeFee.descriptionBSQEnabled=Seleccionar moneda de comisión de intercambio createOffer.triggerPrice.prompt=Establecer precio de ejecución opcional @@ -448,7 +463,12 @@ createOffer.placeOfferButton=Revisar: Poner oferta para {0} monero createOffer.createOfferFundWalletInfo.headline=Dote de fondos su trato. # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Cantidad a intercambiar: {0}\n -createOffer.createOfferFundWalletInfo.msg=Necesita depositar {0} para completar esta oferta.\n\nEsos fondos son reservados en su cartera local y se bloquearán en la dirección de depósito multifirma una vez que alguien tome su oferta.\nLa cantidad es la suma de:\n{1}- Su depósito de seguridad: {2}\n- Comisión de intercambio: {3}\n- Comisión de minado: {4}\n\nPuede elegir entre dos opciones a la hora de depositar fondos para realizar su intercambio:\n- Usar su cartera Haveno (conveniente, pero las transacciones pueden ser trazables) O también\n- Transferir desde una cartera externa (potencialmente con mayor privacidad)\n\nConocerá todos los detalles y opciones para depositar fondos al cerrar esta ventana. +createOffer.createOfferFundWalletInfo.msg=Necesitas depositar {0} para esta oferta.\n\n\ + Estos fondos están reservados en tu billetera local y se bloquearán en una billetera multisig una vez que alguien acepte tu oferta.\n\n\ + El monto es la suma de:\n\ + {1}\ + - Tu depósito de seguridad: {2}\n\ + - Comisión de comercio: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Ocurrió un error al colocar la oferta:\n\n{0}\n\nNingún importe de su cartera ha sido deducido aún.\nPor favor, reinicie su aplicación y compruebe su conexión a la red. @@ -470,30 +490,35 @@ createOffer.setDepositAsBuyer=Establecer mi depósito de seguridad como comprado createOffer.setDepositForBothTraders=Establecer el depósito de seguridad para los comerciantes (%) createOffer.securityDepositInfo=Su depósito de seguridad como comprador será {0} createOffer.securityDepositInfoAsBuyer=Su depósito de seguridad como comprador será {0} -createOffer.minSecurityDepositUsed=En uso el depósito de seguridad mínimo +createOffer.minSecurityDepositUsed=Se utiliza un depósito de seguridad mínimo +createOffer.buyerAsTakerWithoutDeposit=No se requiere depósito del comprador (protegido por passphrase) +createOffer.myDeposit=Mi depósito de seguridad (%) +createOffer.myDepositInfo=Tu depósito de seguridad será {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Introducir la cantidad en BTC -takeOffer.amountPriceBox.buy.amountDescription=Cantidad de BTC a vender -takeOffer.amountPriceBox.sell.amountDescription=Cantidad de BTC a comprar -takeOffer.amountPriceBox.priceDescription=Precio por bitcoin en {0} +takeOffer.amount.prompt=Introducir la cantidad en XMR +takeOffer.amountPriceBox.buy.amountDescription=Cantidad de XMR a vender +takeOffer.amountPriceBox.sell.amountDescription=Cantidad de XMR a comprar +takeOffer.amountPriceBox.priceDescription=Precio por monero en {0} takeOffer.amountPriceBox.amountRangeDescription=Rango de cantidad posible. -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=La cantidad introducida excede el número de decimales permitidos.\nLa cantidad ha sido ajustada a 4 decimales. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=La cantidad introducida excede el número de decimales permitidos.\nLa cantidad ha sido ajustada a 4 decimales. takeOffer.validation.amountSmallerThanMinAmount=La cantidad no puede ser menor que el mínimo definido en la oferta. takeOffer.validation.amountLargerThanOfferAmount=La cantidad introducida no puede ser mayor que el máximo definido en la oferta. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=La cantidad introducida crearía polvo (dust change) para el vendedor de bitcoin. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=La cantidad introducida crearía polvo (dust change) para el vendedor de monero. takeOffer.fundsBox.title=Dote de fondos su intercambio. takeOffer.fundsBox.isOfferAvailable=Comprobar si la oferta está disponible... takeOffer.fundsBox.tradeAmount=Cantidad a vender takeOffer.fundsBox.offerFee=Comisión de transacción takeOffer.fundsBox.networkFee=Comisiones de minado totales -takeOffer.fundsBox.takeOfferSpinnerInfo=Aceptación de oferta en espera... +takeOffer.fundsBox.takeOfferSpinnerInfo=Aceptando oferta: {0} takeOffer.fundsBox.paymentLabel=Intercambio Haveno con ID {0} takeOffer.fundsBox.fundsStructure=({0} depósito de seguridad {1} tasa de intercambio, {2} tarifa de minado) +takeOffer.fundsBox.noFundingRequiredTitle=No se requiere financiamiento +takeOffer.fundsBox.noFundingRequiredDescription=Obtén la frase de acceso de la oferta del vendedor fuera de Haveno para aceptar esta oferta. takeOffer.success.headline=Ha aceptado la oferta con éxito. takeOffer.success.info=Puede ver el estado de su intercambio en \"Portafolio/Intercambios abiertos\". takeOffer.error.message=Un error ocurrió al tomar la oferta.\n\n{0} @@ -504,7 +529,7 @@ takeOffer.noPriceFeedAvailable=No puede tomar esta oferta porque utiliza un prec takeOffer.takeOfferFundWalletInfo.headline=Dotar de fondos su intercambio # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Cantidad a intercambiar: {0}\n -takeOffer.takeOfferFundWalletInfo.msg=Necesita depositar {0} para tomar esta oferta.\n\nLa cantidad es la suma de:\n{1} - Su depósito de seguridad: {2}\n- Comisión de intercambio: {3}\n- Comisiones de minado totales: {4}\n\nPuede elegir entre dos opciones al depositar fondos para realizar su intercambio:\n- Usar su cartera Haveno (conveniente, pero las transacciones pueden ser trazables) O también\n- Transferir desde una cartera externa (potencialmente con mayor privacidad)\n\nVerá todos los detalles y opciones para depositar fondos al cerrar esta ventana. +takeOffer.takeOfferFundWalletInfo.msg=Necesitas depositar {0} para aceptar esta oferta.\n\nLa cantidad es la suma de:\n{1}- Tu depósito de seguridad: {2}\n- Tarifa de transacción: {3} takeOffer.alreadyPaidInFunds=Si ya ha depositado puede retirarlo en la pantalla \"Fondos/Disponible para retirar\". takeOffer.paymentInfo=Información de pago takeOffer.setAmountPrice=Establecer cantidad @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=La transacción de depósito aún no ha s # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Su intercambio tiene al menos una confirmación en la cadena de bloques.\n\n -portfolio.pending.step2_buyer.refTextWarn=Importante: al hacer un pago, deje el campo \"motivo de pago\" vacío. NO PONGA la ID de intercambio o algún otro texto como 'bitcoin', 'BTC', o 'Haveno'. Los comerciantes pueden convenir en el chat de intercambio un \"motivo de pago\" alternativo. +portfolio.pending.step2_buyer.refTextWarn=Importante: al hacer un pago, deje el campo \"motivo de pago\" vacío. NO PONGA la ID de intercambio o algún otro texto como 'monero', 'XMR', o 'Haveno'. Los comerciantes pueden convenir en el chat de intercambio un \"motivo de pago\" alternativo. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=Si su banco carga alguna tasa por hacer la transferencia, es responsable de pagar esas tasas. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Por favor transfiera fondos desde su cartera externa {0}\n{1} al vendedor de BTC.\n\n +portfolio.pending.step2_buyer.crypto=Por favor transfiera fondos desde su cartera externa {0}\n{1} al vendedor de XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Por favor vaya al banco y pague {0} al vendedor de BTC.\n\n -portfolio.pending.step2_buyer.cash.extra=REQUERIMIENTO IMPORTANTE:\nDespués de haber hecho el pago escribe en el recibo de papel: NO REFUNDS\nLuego divídalo en 2 partes, haga una foto y envíela a la dirección de correo electrónico del vendedor de BTC. +portfolio.pending.step2_buyer.cash=Por favor vaya al banco y pague {0} al vendedor de XMR.\n\n +portfolio.pending.step2_buyer.cash.extra=REQUERIMIENTO IMPORTANTE:\nDespués de haber hecho el pago escribe en el recibo de papel: NO REFUNDS\nLuego divídalo en 2 partes, haga una foto y envíela a la dirección de correo electrónico del vendedor de XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Por favor pague {0} al vendedor de BTC utilizando MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=REQUERIMIENTO IMPORTANTE:\nDespués que usted haya realizado el pago, envíe el número de autorización y una foto del recibo al vendedor de BTC por correo electrónico.\nEl recibo debe mostrar claramente el monto, asi como el nombre completo, país y demarcación (departamento,estado, etc.) del vendedor. El correo electrónico del vendedor es: {0}. +portfolio.pending.step2_buyer.moneyGram=Por favor pague {0} al vendedor de XMR utilizando MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=REQUERIMIENTO IMPORTANTE:\nDespués que usted haya realizado el pago, envíe el número de autorización y una foto del recibo al vendedor de XMR por correo electrónico.\nEl recibo debe mostrar claramente el monto, asi como el nombre completo, país y demarcación (departamento,estado, etc.) del vendedor. El correo electrónico del vendedor es: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Por favor pague {0} al vendedor de BTC usando Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=REQUERIMIENTO IMPORTANTE:\nDespués de haber realizado el pago envíe el MTCN (número de seguimiento) y una foto de el recibo por email a el vendedor de BTC.\nEl recibo debe mostrar claramente el nombre completo del emisor, la ciudad, país y la cantidad. El email del vendedor es: {0}. +portfolio.pending.step2_buyer.westernUnion=Por favor pague {0} al vendedor de XMR usando Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=REQUERIMIENTO IMPORTANTE:\nDespués de haber realizado el pago envíe el MTCN (número de seguimiento) y una foto de el recibo por email a el vendedor de XMR.\nEl recibo debe mostrar claramente el nombre completo del emisor, la ciudad, país y la cantidad. El email del vendedor es: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Por favor envíe {0} mediante \"US Postal Money Order\" a el vendedor de BTC.\n\n +portfolio.pending.step2_buyer.postal=Por favor envíe {0} mediante \"US Postal Money Order\" a el vendedor de XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Por favor envíe {0} usando \"Efectivo por Correo\" al vendedor. Las instrucciones específicas están en el contrato de intercambio, y si no queda claro, pregunte a través del chat de intercambio.\nVea más detalles acerca de Efectivo por Correo en la wiki de Haveno [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Por favor envíe {0} usando \"Efectivo por Correo\" al vendedor. Las instrucciones específicas están en el contrato de intercambio, y si no queda claro, pregunte a través del chat de intercambio.\nVea más detalles acerca de Efectivo por Correo en la wiki de Haveno [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Por favor pague {0} a través del método de pago especificado al vendedor BTC. Encontrará los detalles de la cuenta del vendedor en la siguiente pantalla.\n\n +portfolio.pending.step2_buyer.pay=Por favor pague {0} a través del método de pago especificado al vendedor XMR. Encontrará los detalles de la cuenta del vendedor en la siguiente pantalla.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Por favor contacte al vendedor de BTC con el contacto proporcionado y acuerden un encuentro para pagar {0}.\n\n +portfolio.pending.step2_buyer.f2f=Por favor contacte al vendedor de XMR con el contacto proporcionado y acuerden un encuentro para pagar {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Comenzar pago utilizando {0} portfolio.pending.step2_buyer.recipientsAccountData=Receptores {0} portfolio.pending.step2_buyer.amountToTransfer=Cantidad a transferir @@ -628,12 +653,12 @@ portfolio.pending.step2_buyer.buyerAccount=Su cuenta de pago para ser usada portfolio.pending.step2_buyer.paymentSent=Pago iniciado portfolio.pending.step2_buyer.warn=¡Todavía no ha realizado su pago {0}!\nPor favor, tenga en cuenta que el pago tiene que completarse antes de {1}. portfolio.pending.step2_buyer.openForDispute=¡No ha completado su pago!\nEl periodo máximo para el intercambio ha concluido. Por favor, contacte con el mediador para abrir una disputa. -portfolio.pending.step2_buyer.paperReceipt.headline=¿Ha enviado el recibo a el vendedor de BTC? -portfolio.pending.step2_buyer.paperReceipt.msg=Recuerde:\nTiene que escribir en el recibo de papel: NO REFUNDS.\nLuego divídalo en 2 partes, haga una foto y envíela a la dirección de e-mail del vendedor de BTC. +portfolio.pending.step2_buyer.paperReceipt.headline=¿Ha enviado el recibo a el vendedor de XMR? +portfolio.pending.step2_buyer.paperReceipt.msg=Recuerde:\nTiene que escribir en el recibo de papel: NO REFUNDS.\nLuego divídalo en 2 partes, haga una foto y envíela a la dirección de e-mail del vendedor de XMR. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Enviar número de autorización y recibo -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Debe enviar el número de autorización y una foto del recibo por correo electrónico al vendedor de BTC.\nEl recibo debe mostrar claramente el monto, así como el nombre completo, país y demarcación (departamento,estado, etc.) del vendedor. El correo electrónico del vendedor es: {0}.\n\n¿Envió usted el número de autorización y el contrato al vendedor? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Debe enviar el número de autorización y una foto del recibo por correo electrónico al vendedor de XMR.\nEl recibo debe mostrar claramente el monto, así como el nombre completo, país y demarcación (departamento,estado, etc.) del vendedor. El correo electrónico del vendedor es: {0}.\n\n¿Envió usted el número de autorización y el contrato al vendedor? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Enviar MTCN y recibo -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Necesita enviar el MTCN (número de seguimiento) y una foto de el recibo por email a el vendedor de BTC\nEl recibo debe mostrar claramente el nombre completo del emisor, la ciudad, el país y la cantidad. El email del vendedor es: {0}\n\n¿Envió el MTCN y el contrato al vendedor? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Necesita enviar el MTCN (número de seguimiento) y una foto de el recibo por email a el vendedor de XMR\nEl recibo debe mostrar claramente el nombre completo del emisor, la ciudad, el país y la cantidad. El email del vendedor es: {0}\n\n¿Envió el MTCN y el contrato al vendedor? portfolio.pending.step2_buyer.halCashInfo.headline=Enviar código HalCash portfolio.pending.step2_buyer.halCashInfo.msg=Necesita enviar un mensaje de texto con el código HalCash\nEl móvil del vendedor es {1}.\n\n¿Envió el código al vendedor? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Algunos bancos pueden verificar el nombre del receptor. Las cuentas Faster Payments creadas en antiguos clientes de Haveno no proporcionan el nombre completo del receptor, así que por favor, utilice el chat del intercambio para obtenerlo (si es necesario). @@ -641,14 +666,14 @@ portfolio.pending.step2_buyer.confirmStart.headline=Confirme que ha comenzado el portfolio.pending.step2_buyer.confirmStart.msg=¿Ha iniciado el pago de {0} a su par de intercambio? portfolio.pending.step2_buyer.confirmStart.yes=Sí, lo he iniciado. portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=No ha entregado una prueba de pago válida. -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=No ha introducido la transacción de ID y la clave de transacción.\n\nAl no proveer esta información el par no puede usar la autoconfirmación para liberar los BTC en cuanto los XMR se han recibido.\nAdemás de esto, Haveno requiere que el emisor de la transacción XMR sea capaz de entregar esta información al mediador o árbitro en caso de disputa.\nVea más detalles en la wiki de Haveno: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=No ha introducido la transacción de ID y la clave de transacción.\n\nAl no proveer esta información el par no puede usar la autoconfirmación para liberar los XMR en cuanto los XMR se han recibido.\nAdemás de esto, Haveno requiere que el emisor de la transacción XMR sea capaz de entregar esta información al mediador o árbitro en caso de disputa.\nVea más detalles en la wiki de Haveno: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=El valor introducido no es un valor hexadecimal de 32 bytes portfolio.pending.step2_buyer.confirmStart.warningButton=Ignorar y continuar de todos modos portfolio.pending.step2_seller.waitPayment.headline=Esperar al pago. portfolio.pending.step2_seller.f2fInfo.headline=Información de contacto del comprador -portfolio.pending.step2_seller.waitPayment.msg=La transacción del depósito tiene al menos una confirmación en la cadena de bloques.\nTiene que esperar hasta que el comprador de BTC comience el pago de {0}. -portfolio.pending.step2_seller.warn=El comprador de BTC aún no ha realizado el pago de {0}.\nNecesita esperar hasta que el pago comience.\nSi el intercambio aún no se ha completado el {1} el árbitro procederá a investigar. -portfolio.pending.step2_seller.openForDispute=El comprador de BTC no ha comenzado su pago!\nEl periodo máximo permitido ha finalizado.\nPuede esperar más y dar más tiempo a la otra parte o contactar con el mediador para abrir una disputa. +portfolio.pending.step2_seller.waitPayment.msg=La transacción del depósito tiene al menos una confirmación en la cadena de bloques.\nTiene que esperar hasta que el comprador de XMR comience el pago de {0}. +portfolio.pending.step2_seller.warn=El comprador de XMR aún no ha realizado el pago de {0}.\nNecesita esperar hasta que el pago comience.\nSi el intercambio aún no se ha completado el {1} el árbitro procederá a investigar. +portfolio.pending.step2_seller.openForDispute=El comprador de XMR no ha comenzado su pago!\nEl periodo máximo permitido ha finalizado.\nPuede esperar más y dar más tiempo a la otra parte o contactar con el mediador para abrir una disputa. tradeChat.chatWindowTitle=Ventana de chat para intercambio con ID "{0}" tradeChat.openChat=Abrir ventana de chat tradeChat.rules=Puede comunicarse con su par de intercambio para resolver posibles problemas con este intercambio.\nNo es obligatorio responder en el chat.\nSi un comerciante viola alguna de las reglas de abajo, abra una disputa y repórtelo al mediador o árbitro.\n\nReglas del chat:\n\t● No enviar ningún enlace (riesgo de malware). Puedes enviar el ID de la transacción y el nombre de un explorador de bloques.\n\t● ¡No enviar las palabras semilla, llaves privadas, contraseñas u otra información sensible!\n\t● No alentar a intercambiar fuera de Haveno (sin seguridad).\n\t● No se enfrente a ningún intento de estafa de ingeniería social.\n\t● Si un par no responde y prefiere no comunicarse, respete su decisión.\n\t● Limite el tema de conversación al intercambio. Este chat no es un sustituto del messenger o troll-box.\n\t● Mantenga la conversación amigable y respetuosa. @@ -666,26 +691,26 @@ message.state.ACKNOWLEDGED=El usuario de red confirmó la recepción del mensaje # suppress inspection "UnusedProperty" message.state.FAILED=El envío del mensaje falló -portfolio.pending.step3_buyer.wait.headline=Espere a la confirmación de pago del vendedor de BTC. -portfolio.pending.step3_buyer.wait.info=Esperando a la confirmación del recibo de pago de {0} por parte del vendedor de BTC. +portfolio.pending.step3_buyer.wait.headline=Espere a la confirmación de pago del vendedor de XMR. +portfolio.pending.step3_buyer.wait.info=Esperando a la confirmación del recibo de pago de {0} por parte del vendedor de XMR. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Estado del mensaje de pago iniciado portfolio.pending.step3_buyer.warn.part1a=en la cadena de bloques {0} portfolio.pending.step3_buyer.warn.part1b=en su proveedor de pago (v.g. banco) -portfolio.pending.step3_buyer.warn.part2=El vendedor de BTC aún no ha confirmado su pago. Por favor, compruebe {0} si el envío del pago fue correcto. -portfolio.pending.step3_buyer.openForDispute=¡El vendedor de BTC aún no ha confirmado su pago! El periodo máximo para el intercambio ha concluido. Puede esperar y dar más tiempo a la otra parte o solicitar asistencia del mediador. +portfolio.pending.step3_buyer.warn.part2=El vendedor de XMR aún no ha confirmado su pago. Por favor, compruebe {0} si el envío del pago fue correcto. +portfolio.pending.step3_buyer.openForDispute=¡El vendedor de XMR aún no ha confirmado su pago! El periodo máximo para el intercambio ha concluido. Puede esperar y dar más tiempo a la otra parte o solicitar asistencia del mediador. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=La otra parte del intercambio confirma haber iniciado el pago de {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=en su explorador de cadena de bloques {0} favorito portfolio.pending.step3_seller.crypto.wallet=en su cartera {0} portfolio.pending.step3_seller.crypto={0}Por favor compruebe {1} si la transacción a su dirección de recepción\n{2}\ntiene suficientes confirmaciones en la cadena de bloques.\nLa cantidad a pagar tiene que ser {3}\n\nPuede copiar y pegar su dirección {4} desde la pantalla principal después de cerrar este popup. -portfolio.pending.step3_seller.postal={0}Por favor compruebe si ha recibido {1} con \"US Postal Money Order\" enviados por el comprador BTC. +portfolio.pending.step3_seller.postal={0}Por favor compruebe si ha recibido {1} con \"US Postal Money Order\" enviados por el comprador XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Por favor compruebe si ha recibido {1} con \"Efectivo por Correo\" enviados por el comprador BTC. +portfolio.pending.step3_seller.payByMail={0}Por favor compruebe si ha recibido {1} con \"Efectivo por Correo\" enviados por el comprador XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Su par de intercambio confirma que ha iniciado el pago de {0}.\n\nPor favor vaya a la página web de su banco y compruebe si ha recibido {1} del comprador de BTC. -portfolio.pending.step3_seller.cash=Debido a que el pago se hecho vía depósito en efectivo el comprador de BTC tiene que escribir \"SIN REEMBOLSO\" en el recibo de papel, dividirlo en 2 partes y enviarte una foto por e-mail.\n\nPara impedir el riesgo de reembolso, solo confirme si ha recibido el e-mail y si está seguro de que el recibo es válido.\nSi no está seguro, {0} -portfolio.pending.step3_seller.moneyGram=El comprador tiene que enviarle el número de autorización y una foto del recibo por correo electrónico.\n\nEl recibo debe mostrar claramente el monto, asi como su nombre completo, país y demarcación (departamento,estado, etc.). Por favor revise su correo electrónico si recibió el número de autorización.\n\nDespués de cerrar esa ventana emergente (popup), verá el nombre y la dirección del comprador de BTC para retirar el dinero de MoneyGram.\n\n¡Solo confirme el recibo de transacción después de haber obtenido el dinero con éxito! -portfolio.pending.step3_seller.westernUnion=El comprador tiene que enviarle el MTCN (número de seguimiento) y una foto de el recibo por email.\nEl recibo debe mostrar claramente su nombre completo, ciudad, país y la cantidad. Por favor compruebe su email si ha recibido el MTCN.\n\nDespués de cerrar ese popup verá el nombre del comprador de BTC y la dirección para recoger el dinero de Western Union.\n\nSolo confirme el recibo después de haber recogido satisfactoriamente el dinero! +portfolio.pending.step3_seller.bank=Su par de intercambio confirma que ha iniciado el pago de {0}.\n\nPor favor vaya a la página web de su banco y compruebe si ha recibido {1} del comprador de XMR. +portfolio.pending.step3_seller.cash=Debido a que el pago se hecho vía depósito en efectivo el comprador de XMR tiene que escribir \"SIN REEMBOLSO\" en el recibo de papel, dividirlo en 2 partes y enviarte una foto por e-mail.\n\nPara impedir el riesgo de reembolso, solo confirme si ha recibido el e-mail y si está seguro de que el recibo es válido.\nSi no está seguro, {0} +portfolio.pending.step3_seller.moneyGram=El comprador tiene que enviarle el número de autorización y una foto del recibo por correo electrónico.\n\nEl recibo debe mostrar claramente el monto, asi como su nombre completo, país y demarcación (departamento,estado, etc.). Por favor revise su correo electrónico si recibió el número de autorización.\n\nDespués de cerrar esa ventana emergente (popup), verá el nombre y la dirección del comprador de XMR para retirar el dinero de MoneyGram.\n\n¡Solo confirme el recibo de transacción después de haber obtenido el dinero con éxito! +portfolio.pending.step3_seller.westernUnion=El comprador tiene que enviarle el MTCN (número de seguimiento) y una foto de el recibo por email.\nEl recibo debe mostrar claramente su nombre completo, ciudad, país y la cantidad. Por favor compruebe su email si ha recibido el MTCN.\n\nDespués de cerrar ese popup verá el nombre del comprador de XMR y la dirección para recoger el dinero de Western Union.\n\nSolo confirme el recibo después de haber recogido satisfactoriamente el dinero! portfolio.pending.step3_seller.halCash=El comprador tiene que enviarle el código HalCash como un mensaje de texto. Junto a esto recibirá un mensaje desde HalCash con la información requerida para retirar los EUR de un cajero que soporte HalCash.\n\nDespués de retirar el dinero del cajero confirme aquí la recepción del pago! portfolio.pending.step3_seller.amazonGiftCard=El comprador le ha enviado una Tarjeta Amazon eGift por email o mensaje de texto al teléfono móvil. Por favor canjee ahora la Tarjeta Amazon eGift en su cuenta Amazon y una vez aceptado confirme el recibo del pago. @@ -701,7 +726,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID de la transacción portfolio.pending.step3_seller.xmrTxKey=Clave de transacción portfolio.pending.step3_seller.buyersAccount=Datos de cuenta del comprador portfolio.pending.step3_seller.confirmReceipt=Confirmar recibo de pago -portfolio.pending.step3_seller.buyerStartedPayment=El comprador de BTC ha iniciado el pago de {0}.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=El comprador de XMR ha iniciado el pago de {0}.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Compruebe las confirmaciones en la cadena de bloques en su monedero de crypto o explorador de bloques y confirme el pago cuando tenga suficientes confirmaciones. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Compruebe su cuenta de intercambio (v.g. cuenta bancaria) y confirme cuando haya recibido el pago. portfolio.pending.step3_seller.warn.part1a=en la cadena de bloques {0} @@ -713,7 +738,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=¿Ha recibido el pago de # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Por favor verifique también que el nombre del emisor especificado en el contrato de intercambio concuerda con el nombre que aparece en su declaración bancaria:\nNombre del emisor, para el contrato de intercambio: {0}\n\nSi los nombres no son exactamente los mismos, no confirme el recibo de pago. En su lugar, abra una disputa pulsando \"alt + o\" o \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Por favor tenga en cuenta, que tan pronto como haya confirmado el recibo, la cantidad de intercambio bloqueada será librerada al comprador de BTC y el depósito de seguridad será devuelto. +portfolio.pending.step3_seller.onPaymentReceived.note=Por favor tenga en cuenta, que tan pronto como haya confirmado el recibo, la cantidad de intercambio bloqueada será librerada al comprador de XMR y el depósito de seguridad será devuelto. portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Confirme que ha recibido el pago portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Sí, he recibido el pago portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANTE: Confirmando el recibo de pago, está también verificando la cuenta de la contraparte y firmándola en consecuencia. Como la cuenta de la contraparte no ha sido firmada aún, debería retrasar la confirmación de pago tanto como sea posible para reducir el riesgo de devolución de cargo. @@ -723,7 +748,7 @@ portfolio.pending.step5_buyer.tradeFee=Comisión de transacción portfolio.pending.step5_buyer.makersMiningFee=Comisión de minado portfolio.pending.step5_buyer.takersMiningFee=Comisiones de minado totales portfolio.pending.step5_buyer.refunded=Depósito de seguridad devuelto -portfolio.pending.step5_buyer.withdrawBTC=Retirar bitcoins +portfolio.pending.step5_buyer.withdrawXMR=Retirar moneros portfolio.pending.step5_buyer.amount=Cantidad a retirar portfolio.pending.step5_buyer.withdrawToAddress=Retirar a la dirección portfolio.pending.step5_buyer.moveToHavenoWallet=Mantener fondos en el monedero de Haveno @@ -732,7 +757,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Sus fondos ya han sido retirados. portfolio.pending.step5_buyer.confirmWithdrawal=Confirme la petición de retiro portfolio.pending.step5_buyer.amountTooLow=La cantidad a transferir es inferior a la tasa de transacción y el mínimo valor de transacción posible (polvo - dust). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Retiro completado -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Sus intercambios completados están almacenados en \"Portfolio/Historial\".\nPuede revisar todas las transacciones de bitcoin en \"Fondos/Transacciones\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Sus intercambios completados están almacenados en \"Portfolio/Historial\".\nPuede revisar todas las transacciones de monero en \"Fondos/Transacciones\" portfolio.pending.step5_buyer.bought=Ha comprado portfolio.pending.step5_buyer.paid=Ha pagado @@ -794,7 +819,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Ya ha aceptado portfolio.pending.failedTrade.taker.missingTakerFeeTx=Falta la transacción de tasa de tomador\n\nSin esta tx, el intercambio no se puede completar. No se han bloqueado fondos y no se ha pagado ninguna tasa de intercambio. Puede mover esta operación a intercambios fallidos. portfolio.pending.failedTrade.maker.missingTakerFeeTx=Falta la transacción de tasa de tomador de su par.\n\nSin esta tx, el intercambio no se puede completar. No se han bloqueado fondos. Su oferta aún está disponible para otros comerciantes, por lo que no ha perdido la tasa de tomador. Puede mover este intercambio a intercambios fallidos. portfolio.pending.failedTrade.missingDepositTx=Falta la transacción de depósito (la transacción multifirma 2 de 2).\n\nSin esta tx, el intercambio no se puede completar. No se han bloqueado fondos, pero se ha pagado su tarifa comercial. Puede hacer una solicitud para que se le reembolse la tarifa comercial aquí: [HYPERLINK:https://github.com/bisq-network/support/issues].\n\nSiéntase libre de mover esta operación a operaciones fallidas. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Falta la transacción de pago demorado, pero los fondos se han bloqueado en la transacción de depósito.\n\nNO envíe el pago traditional o crypto al vendedor de BTC, porque sin el tx de pago demorado, no se puede abrir el arbitraje. En su lugar, abra un ticket de mediación con Cmd / Ctrl + o. El mediador debe sugerir que ambos pares recuperen el monto total de sus depósitos de seguridad (y el vendedor también recibirá el monto total de la operación). De esta manera, no hay riesgo en la seguridad y solo se pierden las tarifas comerciales.\n\nPuede solicitar un reembolso por las tarifas comerciales perdidas aquí: [HYPERLINK:https://github.com/bisq-network/support/issues]. +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Falta la transacción de pago demorado, pero los fondos se han bloqueado en la transacción de depósito.\n\nNO envíe el pago traditional o crypto al vendedor de XMR, porque sin el tx de pago demorado, no se puede abrir el arbitraje. En su lugar, abra un ticket de mediación con Cmd / Ctrl + o. El mediador debe sugerir que ambos pares recuperen el monto total de sus depósitos de seguridad (y el vendedor también recibirá el monto total de la operación). De esta manera, no hay riesgo en la seguridad y solo se pierden las tarifas comerciales.\n\nPuede solicitar un reembolso por las tarifas comerciales perdidas aquí: [HYPERLINK:https://github.com/bisq-network/support/issues]. portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=Falta la transacción del pago demorado, pero los fondos se han bloqueado en la transacción de depósito.\n\nSi al comprador también le falta la transacción de pago demorado, se le indicará que NO envíe el pago y abra un ticket de mediación. También debe abrir un ticket de mediación con Cmd / Ctrl + o.\n\nSi el comprador aún no ha enviado el pago, el mediador debe sugerir que ambos pares recuperen el monto total de sus depósitos de seguridad (y el vendedor también recibirá el monto total de la operación). De lo contrario, el monto comercial debe ir al comprador.\n\nPuede solicitar un reembolso por las tarifas comerciales perdidas aquí: [HYPERLINK:https://github.com/bisq-network/support/issues]. portfolio.pending.failedTrade.errorMsgSet=Hubo un error durante la ejecución del protocolo de intercambio.\n\nError: {0}\n\nPuede ser que este error no sea crítico y que el intercambio se pueda completar normalmente. Si no está seguro, abra un ticket de mediación para obtener consejos de los mediadores de Haveno.\n\nSi el error fue crítico y la operación no se puede completar, es posible que haya perdido su tarifa de operación. Solicite un reembolso por las tarifas comerciales perdidas aquí: [HYPERLINK:ttps://github.com/bisq-network/support/issues]. portfolio.pending.failedTrade.missingContract=El contrato del intercambio no está establecido.\n\nLa operación no se puede completar y es posible que haya perdido su tarifa de operación. Si es así, puede solicitar un reembolso por las tarifas comerciales perdidas aquí: [HYPERLINK:https://github.com/bisq-network/support/issues]. @@ -833,7 +858,7 @@ funds.deposit.fundHavenoWallet=Fondear monedero Haveno funds.deposit.noAddresses=Aún no se ha generado la dirección de depósito funds.deposit.fundWallet=Dotar de fondos su monedero funds.deposit.withdrawFromWallet=Enviar fondos desde monedero -funds.deposit.amount=Cantidad en BTC (opcional) +funds.deposit.amount=Cantidad en XMR (opcional) funds.deposit.generateAddress=Generar una nueva dirección funds.deposit.generateAddressSegwit=Formato de segwit nativo (Bech32) funds.deposit.selectUnused=Por favor seleccione una dirección no utilizada de la tabla de arriba en vez de generar una nueva. @@ -843,6 +868,7 @@ funds.withdrawal.inputs=Selección de entradas funds.withdrawal.useAllInputs=Usar todos los entradas disponibles funds.withdrawal.useCustomInputs=Usar entradas personalizados funds.withdrawal.receiverAmount=Cantidad del receptor +funds.withdrawal.sendMax=Enviar máximo disponible funds.withdrawal.senderAmount=Cantidad del emisor funds.withdrawal.feeExcluded=La cantidad no incluye comisión de minado funds.withdrawal.feeIncluded=La cantidad incluye comisión de minado @@ -890,7 +916,7 @@ funds.tx.revert=Revertir funds.tx.txSent=Transacción enviada exitosamente a una nueva dirección en la billetera Haveno local. funds.tx.direction.self=Enviado a usted mismo funds.tx.dustAttackTx=Dust recibido -funds.tx.dustAttackTx.popup=Esta transacción está enviando una cantidad de BTC muy pequeña a su monedero y puede ser un intento de compañías de análisis de cadenas para espiar su monedero.\n\nSi usa este output para gastar en una transacción, conocerán que probablemente usted sea el propietario de sus otras direcciones (fusión de monedas).\n\nPara proteger su privacidad el monedero Haveno ignora estos outputs para propósitos de gasto y en el balance mostrado. Puede establecer el umbral en el que un output es considerado dust en ajustes. +funds.tx.dustAttackTx.popup=Esta transacción está enviando una cantidad de XMR muy pequeña a su monedero y puede ser un intento de compañías de análisis de cadenas para espiar su monedero.\n\nSi usa este output para gastar en una transacción, conocerán que probablemente usted sea el propietario de sus otras direcciones (fusión de monedas).\n\nPara proteger su privacidad el monedero Haveno ignora estos outputs para propósitos de gasto y en el balance mostrado. Puede establecer el umbral en el que un output es considerado dust en ajustes. #################################################################### # Support @@ -904,7 +930,7 @@ support.filter=Buscar disputas support.filter.prompt=Introduzca ID de transacción, fecha, dirección onion o datos de cuenta. support.sigCheck.button=Comprobar firma -support.sigCheck.popup.info=En caso de una solicitud de reembolso a la DAO, debe pegar el mensaje de resumen del proceso de mediación y arbitraje en su solicitud de reembolso en Github. Para que esta declaración sea verificable, cualquier usuario puede verificar con esta herramienta si la firma del mediador o árbitro coincide con el resumen del mensaje. +support.sigCheck.popup.info=Pegue el mensaje resumido del proceso de arbitraje. Con esta herramienta, cualquier usuario puede verificar si la firma del árbitro coincide con el mensaje resumido. support.sigCheck.popup.header=Verificar firma del resultado de la disputa support.sigCheck.popup.msg.label=Mensaje de resumen support.sigCheck.popup.msg.prompt=Copie y pegue el mensaje de resumen de la disputa @@ -940,8 +966,8 @@ support.savedInMailbox=Mensaje guardado en la bandeja de entrada del receptor support.arrived=El mensaje ha llegado al receptor support.acknowledged=El arribo del mensaje fue confirmado por el receptor support.error=El receptor no pudo procesar el mensaje. Error: {0} -support.buyerAddress=Dirección del comprador de BTC -support.sellerAddress=Dirección del vendedor de BTC +support.buyerAddress=Dirección del comprador de XMR +support.sellerAddress=Dirección del vendedor de XMR support.role=Rol support.agent=Agente de soporte support.state=Estado @@ -949,13 +975,13 @@ support.chat=Chat support.closed=Cerrado support.open=Abierto support.process=Proceso -support.buyerMaker=comprador/creador BTC -support.sellerMaker=vendedor/creador BTC -support.buyerTaker=comprador/Tomador BTC -support.sellerTaker=vendedor/Tomador BTC +support.buyerMaker=comprador/creador XMR +support.sellerMaker=vendedor/creador XMR +support.buyerTaker=comprador/Tomador XMR +support.sellerTaker=vendedor/Tomador XMR -support.backgroundInfo=Haveno no es una compañía, por ello maneja las disputas de una forma diferente.\n\nLos compradores y vendedores pueden comunicarse a través de la aplicación por un chat seguro en la pantalla de intercambios abiertos para intentar resolver una disputa por su cuenta. Si eso no es suficiente, un mediador puede intervenir para ayudar. El mediador evaluará la situación y dará una recomendación para el pago de los fondos de la transacción. Si ambos aceptan esta sugerencia, la transacción del pago se completa y el intercambio se cierra. Si uno o ambos no están de acuerdo con el pago recomendado por el mediador, pueden solicitar arbitraje. El árbitro re-evaluará la situación y, si es necesario, hará el pago personalmente y solicitará un reembolso de este pago a la DAO de Haveno. -support.initialInfo=Por favor, introduzca una descripción de su problema en el campo de texto de abajo. Añada tanta información como sea posible para agilizar la resolución de la disputa.\n\nEsta es una lista de la información que usted debe proveer:\n\t● Si es el comprador de BTC: ¿Hizo la transferencia Traditional o Cryptocurrency? Si es así, ¿Pulsó el botón 'pago iniciado' en la aplicación?\n\t● Si es el vendedor de BTC: ¿Recibió el pago Traditional o Cryptocurrency? Si es así, ¿Pulsó el botón 'pago recibido' en la aplicación?\n\t● ¿Qué versión de Haveno está usando?\n\t● ¿Qué sistema operativo está usando?\n\t● Si tiene problemas con transacciones fallidas, por favor considere cambiar a un nuevo directorio de datos.\n\tA veces el directorio de datos se corrompe y causa errores extraños.\n\tVer: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPor favor, familiarícese con las reglas básicas del proceso de disputa:\n\t● Tiene que responder a los requerimientos de {0} en 2 días.\n\t● Los mediadores responden en 2 días. Los árbitros responden en 5 días laborables.\n\t● El periodo máximo para una disputa es de 14 días.\n\t● Tiene que cooperar con {1} y proveer la información necesaria que soliciten.\n\t● Aceptó la reglas esbozadas en el documento de disputa en el acuerdo de usuario cuando inició por primera ver la aplicación.\n\nPuede leer más sobre el proceso de disputa en: {2} +support.backgroundInfo=Haveno no es una compañía, por lo que maneja las disputas de manera diferente.\n\nLos comerciantes pueden comunicarse dentro de la aplicación a través de un chat seguro en la pantalla de operaciones abiertas para intentar resolver las disputas por sí mismos. Si eso no es suficiente, un mediador evaluará la situación y decidirá un pago de los fondos de la operación. +support.initialInfo=Por favor, introduzca una descripción de su problema en el campo de texto de abajo. Añada tanta información como sea posible para agilizar la resolución de la disputa.\n\nEsta es una lista de la información que usted debe proveer:\n\t● Si es el comprador de XMR: ¿Hizo la transferencia Traditional o Cryptocurrency? Si es así, ¿Pulsó el botón 'pago iniciado' en la aplicación?\n\t● Si es el vendedor de XMR: ¿Recibió el pago Traditional o Cryptocurrency? Si es así, ¿Pulsó el botón 'pago recibido' en la aplicación?\n\t● ¿Qué versión de Haveno está usando?\n\t● ¿Qué sistema operativo está usando?\n\t● Si tiene problemas con transacciones fallidas, por favor considere cambiar a un nuevo directorio de datos.\n\tA veces el directorio de datos se corrompe y causa errores extraños.\n\tVer: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPor favor, familiarícese con las reglas básicas del proceso de disputa:\n\t● Tiene que responder a los requerimientos de {0} en 2 días.\n\t● Los mediadores responden en 2 días. Los árbitros responden en 5 días laborables.\n\t● El periodo máximo para una disputa es de 14 días.\n\t● Tiene que cooperar con {1} y proveer la información necesaria que soliciten.\n\t● Aceptó la reglas esbozadas en el documento de disputa en el acuerdo de usuario cuando inició por primera ver la aplicación.\n\nPuede leer más sobre el proceso de disputa en: {2} support.systemMsg=Mensaje de sistema: {0} support.youOpenedTicket=Ha abierto una solicitud de soporte.\n\n{0}\n\nVersión Haveno: {1} support.youOpenedDispute=Ha abierto una solicitud de disputa.\n\n{0}\n\nVersión Haveno: {1} @@ -979,13 +1005,14 @@ settings.tab.network=Información de red settings.tab.about=Acerca de setting.preferences.general=Preferencias generales -setting.preferences.explorer=Explorador Bitcoin +setting.preferences.explorer=Explorador Monero setting.preferences.deviation=Desviación máxima del precio de mercado setting.preferences.setting.preferences.avoidStandbyMode=Evitar modo en espera +setting.preferences.useSoundForNotifications=Reproducir sonidos para notificaciones setting.preferences.autoConfirmXMR=Autoconfirmación XMR setting.preferences.autoConfirmEnabled=Habilitado setting.preferences.autoConfirmRequiredConfirmations=Confirmaciones requeridas -setting.preferences.autoConfirmMaxTradeSize=Cantidad máxima de intecambio (BTC) +setting.preferences.autoConfirmMaxTradeSize=Cantidad máxima de intecambio (XMR) setting.preferences.autoConfirmServiceAddresses=Explorador de URLs Monero (usa Tor, excepto para localhost, direcciones LAN IP, y hostnames *.local) setting.preferences.deviationToLarge=No se permiten valores superiores a {0}% setting.preferences.txFee=Tasa de transacción de retiro (satoshis/vbyte) @@ -1022,29 +1049,31 @@ settings.preferences.editCustomExplorer.name=Nombre settings.preferences.editCustomExplorer.txUrl=URL de transacción settings.preferences.editCustomExplorer.addressUrl=URL de la dirección -settings.net.btcHeader=Red Bitcoin +settings.net.xmrHeader=Red Monero settings.net.p2pHeader=Red Haveno settings.net.onionAddressLabel=Mi dirección onion settings.net.xmrNodesLabel=Utilizar nodos Monero personalizados settings.net.moneroPeersLabel=Pares conectados +settings.net.connection=Conexión +settings.net.connected=Conectado settings.net.useTorForXmrJLabel=Usar Tor para la red Monero settings.net.moneroNodesLabel=Nodos Monero para conectarse -settings.net.useProvidedNodesRadio=Utilizar nodos Bitcoin Core proporcionados -settings.net.usePublicNodesRadio=Utilizar red pública Bitcoin -settings.net.useCustomNodesRadio=Utilizar nodos Bitcoin Core personalizados +settings.net.useProvidedNodesRadio=Utilizar nodos Monero Core proporcionados +settings.net.usePublicNodesRadio=Utilizar red pública Monero +settings.net.useCustomNodesRadio=Utilizar nodos Monero Core personalizados settings.net.warn.usePublicNodes=Si utiliza nodos públicos de Monero, está sujeto a cualquier riesgo asociado con el uso de nodos remotos no confiables.\n\nPor favor, lea más detalles en [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\n¿Está seguro de que desea utilizar nodos públicos? settings.net.warn.usePublicNodes.useProvided=No, utilizar nodos proporcionados settings.net.warn.usePublicNodes.usePublic=Sí, utilizar la red pública -settings.net.warn.useCustomNodes.B2XWarning=¡Por favor, asegúrese de que su nodo Bitcoin es un nodo de confianza Bitcoin Core!\n\nConectar a nodos que no siguen las reglas de consenso puede causar perjuicios a su cartera y causar problemas en el proceso de intercambio.\n\nLos usuarios que se conecten a los nodos que violan las reglas de consenso son responsables de cualquier daño que estos creen. Las disputas causadas por ello se decidirán en favor del otro participante. No se dará soporte técnico a usuarios que ignoren esta advertencia y los mecanismos de protección! -settings.net.warn.invalidBtcConfig=La conexión a la red Bitcoin falló debido a que su configuración es inválida.\n\nSu configuración se ha reestablecido para usar los nodos Bitcoin proporcionados. Necesitará reiniciar la aplicación. -settings.net.localhostXmrNodeInfo=Información complementaria: Haveno busca un nodo local Bitcoin al inicio. Si lo encuentra, Haveno se comunicará a la red Bitcoin exclusivamente a través de él. +settings.net.warn.useCustomNodes.B2XWarning=¡Por favor, asegúrese de que su nodo Monero es un nodo de confianza Monero Core!\n\nConectar a nodos que no siguen las reglas de consenso puede causar perjuicios a su cartera y causar problemas en el proceso de intercambio.\n\nLos usuarios que se conecten a los nodos que violan las reglas de consenso son responsables de cualquier daño que estos creen. Las disputas causadas por ello se decidirán en favor del otro participante. No se dará soporte técnico a usuarios que ignoren esta advertencia y los mecanismos de protección! +settings.net.warn.invalidXmrConfig=La conexión a la red Monero falló debido a que su configuración es inválida.\n\nSu configuración se ha reestablecido para usar los nodos Monero proporcionados. Necesitará reiniciar la aplicación. +settings.net.localhostXmrNodeInfo=Información complementaria: Haveno busca un nodo local Monero al inicio. Si lo encuentra, Haveno se comunicará a la red Monero exclusivamente a través de él. settings.net.p2PPeersLabel=Pares conectados settings.net.onionAddressColumn=Dirección onion settings.net.creationDateColumn=Establecido settings.net.connectionTypeColumn=Dentro/Fuera settings.net.sentDataLabel=Estadísticas de datos enviados settings.net.receivedDataLabel=Estadísticas de datos recibidos -settings.net.chainHeightLabel=Altura del último bloque BTC +settings.net.chainHeightLabel=Altura del último bloque XMR settings.net.roundTripTimeColumn=Tiempo de ida y vuelta settings.net.sentBytesColumn=Enviado settings.net.receivedBytesColumn=Recibido @@ -1059,7 +1088,7 @@ settings.net.needRestart=Necesita reiniciar la aplicación para aplicar ese camb settings.net.notKnownYet=Aún no conocido... settings.net.sentData=Datos enviados: {0}, mensajes {1}, mensajes {2} mensajes por segundo settings.net.receivedData=Datos recibidos: {0}, mensajes {1}, mensajes por segundo {2} -settings.net.chainHeight=Altura de la cadena de pares Bitcoin: {0} +settings.net.chainHeight=Altura de la cadena de pares Monero: {0} settings.net.ips=[Dirección IP:puerto | host:puerto | dirección onion:puerto] (separado por coma). El puerto puede ser omitido si se utiliza el predeterminado (8333). settings.net.seedNode=Nodo semilla settings.net.directPeer=Par (directo) @@ -1068,7 +1097,7 @@ settings.net.peer=Par settings.net.inbound=entrante settings.net.outbound=saliente setting.about.aboutHaveno=Acerca de Haveno -setting.about.about=Haveno es un software de código abierto que facilita el intercambio de bitcoin por monedas nacionales (y otras criptomonedas) a través de una red descentralizada peer-to-peer de modo que se proteja fuertemente la privacidad del usuario. Aprenda más acerca de Haveno en la página web del proyecto. +setting.about.about=Haveno es un software de código abierto que facilita el intercambio de monero por monedas nacionales (y otras criptomonedas) a través de una red descentralizada peer-to-peer de modo que se proteja fuertemente la privacidad del usuario. Aprenda más acerca de Haveno en la página web del proyecto. setting.about.web=Página web de Haveno setting.about.code=código fuente setting.about.agpl=Licencia AGPL @@ -1105,7 +1134,7 @@ setting.about.shortcuts.openDispute.value=Seleccionar intercambios pendientes y setting.about.shortcuts.walletDetails=Abrir ventana de detalles de monedero -setting.about.shortcuts.openEmergencyBtcWalletTool=Abrir herramienta de monedero de emergencia para el monedero BTC +setting.about.shortcuts.openEmergencyXmrWalletTool=Abrir herramienta de monedero de emergencia para el monedero XMR setting.about.shortcuts.showTorLogs=Cambiar nivel de registro para mensajes Tor entre DEBUG y WARN @@ -1131,7 +1160,7 @@ setting.about.shortcuts.sendPrivateNotification=Enviar notificación privada a l setting.about.shortcuts.sendPrivateNotification.value=Abrir información de par en el avatar o disputa y pulsar: {0} setting.info.headline=Nueva función de autoconfirmación XMR -setting.info.msg=Al vender XMR por XMR puede usar la función de autoconfirmación para verificar que la cantidad correcta de XMR se envió al monedero con lo que Haveno pueda marcar el intercambio como completo, haciendo los intercambios más rápidos para todos.\n\nLa autoconfirmación comprueba que la transacción de XMR en al menos 2 nodos exploradores XMR usando la clave de transacción entregada por el emisor XMR. Por defecto, Haveno usa nodos exploradores ejecutados por contribuyentes Haveno, pero recomendamos usar sus propios nodos exploradores para un máximo de privacidad y seguridad.\n\nTambién puede configurar la cantidad máxima de BTC por intercambio para la autoconfirmación, así como el número de confirmaciones en Configuración.\n\nVea más detalles (incluído cómo configurar su propio nodo explorador) en la wiki Haveno: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=Al vender XMR por XMR puede usar la función de autoconfirmación para verificar que la cantidad correcta de XMR se envió al monedero con lo que Haveno pueda marcar el intercambio como completo, haciendo los intercambios más rápidos para todos.\n\nLa autoconfirmación comprueba que la transacción de XMR en al menos 2 nodos exploradores XMR usando la clave de transacción entregada por el emisor XMR. Por defecto, Haveno usa nodos exploradores ejecutados por contribuyentes Haveno, pero recomendamos usar sus propios nodos exploradores para un máximo de privacidad y seguridad.\n\nTambién puede configurar la cantidad máxima de XMR por intercambio para la autoconfirmación, así como el número de confirmaciones en Configuración.\n\nVea más detalles (incluído cómo configurar su propio nodo explorador) en la wiki Haveno: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1169,7 @@ account.tab.mediatorRegistration=Registro de mediador account.tab.refundAgentRegistration=Registro de agente de devolución de fondos account.tab.signing=Firmado account.info.headline=Bienvenido a su cuenta Haveno -account.info.msg=Aquí puede añadir cuentas de intercambio para monedas nacionales y cryptos y crear una copia de su cartera y datos de cuenta.\n\nUna nueva cartera Bitcoin fue creada la primera vez que inició Haveno.\n\nRecomendamos encarecidamente que escriba sus palabras de la semilla de la cartera Bitcoin (mire pestaña arriba) y considere añadir una contraseña antes de enviar fondos. Los ingresos y retiros de Bitcoin se administran en la sección \"Fondos\".\n\nNota de privacidad y seguridad: Debido a que Haveno es un exchange descentralizado, todos sus datos se guardan en su ordenador. No hay servidores, así que no tenemos acceso a su información personal, sus saldos, o incluso su dirección IP. Datos como número de cuenta bancaria, direcciones crypto y Bitcoin, etc son solo compartidos con su par de intercambio para completar intercambios iniciados (en caso de una disputa el mediador o árbitro verá los mismos datos que el par de intercambio). +account.info.msg=Aquí puede añadir cuentas de intercambio para monedas nacionales y cryptos y crear una copia de su cartera y datos de cuenta.\n\nUna nueva cartera Monero fue creada la primera vez que inició Haveno.\n\nRecomendamos encarecidamente que escriba sus palabras de la semilla de la cartera Monero (mire pestaña arriba) y considere añadir una contraseña antes de enviar fondos. Los ingresos y retiros de Monero se administran en la sección \"Fondos\".\n\nNota de privacidad y seguridad: Debido a que Haveno es un exchange descentralizado, todos sus datos se guardan en su ordenador. No hay servidores, así que no tenemos acceso a su información personal, sus saldos, o incluso su dirección IP. Datos como número de cuenta bancaria, direcciones crypto y Monero, etc son solo compartidos con su par de intercambio para completar intercambios iniciados (en caso de una disputa el mediador o árbitro verá los mismos datos que el par de intercambio). account.menu.paymentAccount=Cuentas de moneda nacional account.menu.altCoinsAccountView=Cuentas de crypto @@ -1151,7 +1180,7 @@ account.menu.backup=Copia de seguridad account.menu.notifications=Notificaciones account.menu.walletInfo.balance.headLine=Balances de monedero -account.menu.walletInfo.balance.info=Esto muestrta el balance interno del monedero, incluyendo transacciones no confirmadas.\nPara BTC, el balance interno de monedero mostrado abajo debe cuadrar con la suma de balances 'Disponible' y 'Reservado' mostrado arriba a la derecha de esta ventana. +account.menu.walletInfo.balance.info=Esto muestrta el balance interno del monedero, incluyendo transacciones no confirmadas.\nPara XMR, el balance interno de monedero mostrado abajo debe cuadrar con la suma de balances 'Disponible' y 'Reservado' mostrado arriba a la derecha de esta ventana. account.menu.walletInfo.xpub.headLine=Claves centinela (xpub keys) account.menu.walletInfo.walletSelector={0} {1} monedero account.menu.walletInfo.path.headLine=ruta HD keychain @@ -1180,7 +1209,7 @@ account.crypto.popup.upx.msg=Para intercambiar UPX en haveno es preciso que uste # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=El ARQ de intercambio de Haveno requiere que entienda y cumpla los siguientes requerimientos:\n\nPara el ARQ de envío, necesita utilizar la cartera oficial ArQmA GUI o una cartera ArQmA CLI con la opción store-tx-info habilitada (predeterminada en nuevas versiones). Por favor asegúrese de poder acceder a la llave tx ya que podría ser requerido en caso de disputa.\narqma-wallet-cli (utilice el comando get_tx_key)\narqma-wallet-gui (vaya a la pestaña historial y pulse el botón (P) para prueba de pago)\n\nEn los exploradores de bloques normales la transferencia no es verificable.\n\nNecesita proveer al mediador o al árbitro los siguientes datos en caso de disputa:\n- El tx de la llave privada\n- El hash de transacción\n- La dirección publica de recepción\n\nNo proveer los datos arriba señalados, o si utilizó una cartera incompatible, resultará en perder la disputa. La parte ARQ que envía es responsable de proveer verificación de la transferencia ARQ al mediador o al árbitro en caso de disputa.\n\nNo se requiere ID de pago, solo la dirección pública normal.\nSi no está seguro sobre el proceso visite el canal ArQmA en discord (https://discord.gg/s9BQpJT) o el foro de ArQmA (https://labs.arqma.com) para encontrar más información. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Intercambiar XMR en Haveno requiere entender y cumplir los siguientes requisitos\n\nPruebas de pago:\n\n\nSi está vendiendo XMR, debe ser capaz de entregar la siguiente información en caso de disputa:\n\n- La clave de transacción (Tx key, Tx Secret Key o Tx Private Key)\n- La ID de transacción (Tx ID o Tx Hash)\n- La dirección de destino (recipient's address)\n\nVea la wiki para detalles sobre dónde encontrar esta información en los principales monederos XMR:\nhttps://bisq.wiki/Trading_Monero#Proving_payments\n\n\nNo entregar estos datos de transacción resultará en pérdida de la disputa.\n\nTenga en cuenta que Haveno ahora ofrece confirmación automática de transacciones XMR para realizar intercambios más rápido, pero necesita habilitarlo en Configuración. \n\nVea la wiki para más información sobre la función de autoconfirmación.\n[HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +account.crypto.popup.xmr.msg=Intercambiar XMR en Haveno requiere entender y cumplir los siguientes requisitos\n\nPruebas de pago:\n\n\nSi está vendiendo XMR, debe ser capaz de entregar la siguiente información en caso de disputa:\n\n- La clave de transacción (Tx key, Tx Secret Key o Tx Private Key)\n- La ID de transacción (Tx ID o Tx Hash)\n- La dirección de destino (recipient's address)\n\nVea la wiki para detalles sobre dónde encontrar esta información en los principales monederos XMR:\nhttps://haveno.exchange/wiki/Trading_Monero#Proving_payments\n\n\nNo entregar estos datos de transacción resultará en pérdida de la disputa.\n\nTenga en cuenta que Haveno ahora ofrece confirmación automática de transacciones XMR para realizar intercambios más rápido, pero necesita habilitarlo en Configuración. \n\nVea la wiki para más información sobre la función de autoconfirmación.\n[HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Para intercambiar MSR en Haveno es necesario que usted entienda y cumpla los siguientes requisitos:\n\nPara enviar MSR es necesario que use el monedero oficial de Masari monedero GUI o Masari monedero CLI con la opción "store-tx-info" habilitada (predeterminada en las nuevas versiones) o el monedero oficial Masari Web (https://wallet.getmasari.org). Por favor, asegúrese de poder acceder a las llaves tx, ya que podrían requerirse en caso de alguna disputa. \nmasari-wallet-cli (utilice el comando get_tx_key)\nmasari-wallet-gui (vaya a la pestaña historial y haga clic en el botón (P) para prueba de pago). \n\nMonedero Masari Web (vaya a Cuenta -> historial transacción y vea los detalles de su transacción enviada.)\n\nPuede lograr verificación de la transacción dentro del monedero:\nmasari-wallet-cli : usando el comando (check_tx_key).\nmasari-wallet-gui: vaya a la pestaña Avanzado > Comprobar/Revisar.\nVerificación de transacción también se puede lograr desde el explorador de bloques\nAbrir explorador de bloques (https://explorer.getmasari.org), use la barra de búsqueda para buscar el hash de transacción. \nCuando encuentre su transacción, navegue hacia el final donde dice "Comprobar Envío" y rellene los detalles necesarios. \nUsted necesita compartir esta información con el mediador o árbitro en caso de disputa:\n- La clave privada tx\n- El hash de transacción\n- La dirección pública del que recibe\n\nSi no proporciona los datos arriba señalados, o si utilizó una cartera incompatible, perderá la disputa. El que envía MSR es responsable de entregar la verificación de transferencia al mediador o árbitro en caso de disputa.\n\nNo se requiere el ID de pago, sólo la dirección pública normal.\nSi no está seguro sobre el proceso, pida ayuda visitando el canal oficial de Masari en Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1237,7 @@ account.crypto.popup.pars.msg=Intercambiar ParsiCoin en Haveno requiere que uste account.crypto.popup.blk-burnt.msg=Para intercambiar blackcoins quemados. usted necesita saber lo siguiente:\n\nBlackcoins quemados son indestructibles. Para intercambiarlos en Haveno, los guiones de output tienen que estar en la forma: OP_RETURN OP_PUSHDATA, seguidos por bytes de datos asociados que, después de codificarlos en hexadecimal, construyen direcciones. Por ejemplo, blackcoins quemados con una dirección 666f6f ("foo" en UTF-8) tendrán el siguiente guion:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nPara crear blackcoins quemados, uno puede usar el comando RPC "quemar" disponible en algunas carteras.\n\nPara posibles casos de uso, uno puede mirar en https://ibo.laboratorium.ee .\n\nComo los blackcoins quemados son undestructibles, no pueden ser revendidos. "Vender" blackcoins quemados significa quemar blackcoins comunes (con datos asociados igual a la dirección de destino).\n\nEn caso de una disputa, el vendedor BLK necesita proveer el hash de transacción. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Comerciar L-BTC en Haveno requiere que entienda lo siguiente:\n\nAl recibir L-BTC de un intercambio en Haveno, no puede usar la app de monedero móvil Blockstream Green Wallet o un exchange/monedero que custodie sus fondos. Solo debe recibir L-BTC en el monedero Liquid Elements Core, u otro monedero L-BTC que le permita obtener la clave cegadora para su dirección L-BTC cegada.\n\nEn caso de ser necesaria mediación, o si se lleva a cabo una disputa, debe entregar la clave cegadora para su dirección receptora de L-BTC al mediador o agente de devolución de fondos Haveno para que verifique los detalles de su Transacción Confidencial en su nodo completo Elements Core.\n\nSi no entrega la información requerida al mediador o al agente de devolución de fondos se resolverá en una pérdida del caso en disputa. En todos los casos de disputa, el receptor de L-BTC es responsable del 100% de la carga de aportar la prueba criptográfica al mediador o agente de devolución de fondos.\n\nSi no entiende estos requerimientos, no intercambio L-BTC en Haveno. +account.crypto.popup.liquidmonero.msg=Comerciar L-XMR en Haveno requiere que entienda lo siguiente:\n\nAl recibir L-XMR de un intercambio en Haveno, no puede usar la app de monedero móvil Blockstream Green Wallet o un exchange/monedero que custodie sus fondos. Solo debe recibir L-XMR en el monedero Liquid Elements Core, u otro monedero L-XMR que le permita obtener la clave cegadora para su dirección L-XMR cegada.\n\nEn caso de ser necesaria mediación, o si se lleva a cabo una disputa, debe entregar la clave cegadora para su dirección receptora de L-XMR al mediador o agente de devolución de fondos Haveno para que verifique los detalles de su Transacción Confidencial en su nodo completo Elements Core.\n\nSi no entrega la información requerida al mediador o al agente de devolución de fondos se resolverá en una pérdida del caso en disputa. En todos los casos de disputa, el receptor de L-XMR es responsable del 100% de la carga de aportar la prueba criptográfica al mediador o agente de devolución de fondos.\n\nSi no entiende estos requerimientos, no intercambio L-XMR en Haveno. account.traditional.yourTraditionalAccounts=Sus cuentas de moneda nacional: @@ -1228,13 +1257,13 @@ account.password.setPw.button=Establecer contraseña account.password.setPw.headline=Establecer protección por contraseña del monedero account.password.info=Con la protección de contraseña habilitada, deberá ingresar su contraseña al iniciar la aplicación, al retirar monero de su billetera y al mostrar sus palabras de semilla. -account.seed.backup.title=Copia de seguridad de palabras semilla del monedero -account.seed.info=Por favor apunte en un papel tanto las palabras semilla del monedero como la fecha! Puede recuperar su monedero en cualquier momento con las palabras semilla y la fecha.\nLas mismas palabras semilla se usan para el monedero BTC como BSQ\n\nDebe apuntar las palabras semillas en una hoja de papel. No la guarde en su computadora.\n\nPor favor, tenga en cuenta que las palabras semilla no son un sustituto de la copia de seguridad.\nNecesita hacer la copia de seguridad de todo el directorio de aplicación en la pantalla \"Cuenta/Copia de Seguridad\" para recuperar un estado de aplicación válido y los datos.\nImportar las palabras semilla solo se recomienda para casos de emergencia. La aplicación no será funcional sin una buena copia de seguridad de los archivos de la base de datos y las claves! -account.seed.backup.warning=Por favor tenga en cuenta que las palabras semilla NO SON un sustituto de la copia de seguridad.\nTiene que crear una copia de todo el directorio de aplicación desde la pantalla \"Cuenta/Copia de seguridad\ para recuperar el estado y datos de la aplicación.\nImportar las palabras semilla solo se recomienda para casos de emergencia. La aplicación no funcionará sin una copia de seguridad adecuada de las llaves y archivos de sistema!\n\nVea la página wiki [HYPERLINK:https://bisq.wiki/Backing_up_application_data] para más información. +account.seed.backup.title=Haz una copia de seguridad de las palabras clave de tu billetera. +account.seed.info=Por favor, anota tanto las palabras clave de tu billetera como la fecha. Puedes recuperar tu billetera en cualquier momento con las palabras clave y la fecha.\n\nDeberías anotar las palabras clave en una hoja de papel. No las guardes en la computadora.\n\nPor favor, ten en cuenta que las palabras clave NO son un reemplazo para una copia de seguridad.\nNecesitas crear una copia de seguridad de todo el directorio de la aplicación desde la pantalla "Cuenta/Copia de seguridad" para recuperar el estado y los datos de la aplicación. +account.seed.backup.warning=Por favor, ten en cuenta que las palabras clave no son un reemplazo para una copia de seguridad.\nNecesitas crear una copia de seguridad de todo el directorio de la aplicación desde la pantalla "Cuenta/Copia de seguridad" para recuperar el estado y los datos de la aplicación. account.seed.warn.noPw.msg=No ha establecido una contraseña de cartera que proteja la visualización de las palabras semilla.\n\n¿Quiere que se muestren las palabras semilla? account.seed.warn.noPw.yes=Sí, y no preguntar de nuevo account.seed.enterPw=Introducir contraseña para ver las palabras semilla -account.seed.restore.info=Por favor haga una copia de seguridad antes de aplicar la restauración desde las palabras semilla. Tenga en cuenta que la restauración de cartera solo es para casos de emergencia y puede causar problemas con la base de datos interna del monedero.\nNo es el modo de aplicar una restauración de copia de seguridad! Por favor use una copia de seguridad desde el archivo de directorio de la aplicación para restaurar un estado de aplicación anterior.\n\nDespués de restaurar la aplicación se cerrará automáticamente. Después de reiniciar la aplicacion se resincronizará con la red Bitcoin. Esto puede llevar un tiempo y consumir mucha CPU, especialemente si la cartera es antigua y tiene muchas transacciones. Por favor evite interrumpir este proceso, o podría tener que borrar el archivo de la cadena SPV de nuevo o repetir el proceso de restauración. +account.seed.restore.info=Por favor haga una copia de seguridad antes de aplicar la restauración desde las palabras semilla. Tenga en cuenta que la restauración de cartera solo es para casos de emergencia y puede causar problemas con la base de datos interna del monedero.\nNo es el modo de aplicar una restauración de copia de seguridad! Por favor use una copia de seguridad desde el archivo de directorio de la aplicación para restaurar un estado de aplicación anterior.\n\nDespués de restaurar la aplicación se cerrará automáticamente. Después de reiniciar la aplicacion se resincronizará con la red Monero. Esto puede llevar un tiempo y consumir mucha CPU, especialemente si la cartera es antigua y tiene muchas transacciones. Por favor evite interrumpir este proceso, o podría tener que borrar el archivo de la cadena SPV de nuevo o repetir el proceso de restauración. account.seed.restore.ok=Ok, adelante con la restauración y el apagado de Haveno. @@ -1259,13 +1288,13 @@ account.notifications.trade.label=Recibir mensajes de intercambio account.notifications.market.label=Recibir alertas de oferta account.notifications.price.label=Recibir alertas de precio account.notifications.priceAlert.title=Alertas de precio -account.notifications.priceAlert.high.label=Notificar si el precio de BTC está por encima -account.notifications.priceAlert.low.label=Notificar si el precio de BTC está por debajo +account.notifications.priceAlert.high.label=Notificar si el precio de XMR está por encima +account.notifications.priceAlert.low.label=Notificar si el precio de XMR está por debajo account.notifications.priceAlert.setButton=Establecer alerta de precio account.notifications.priceAlert.removeButton=Eliminar alerta de precio account.notifications.trade.message.title=Estado de intercambio cambiado account.notifications.trade.message.msg.conf=La transacción de depósito para el intercambio con ID {0} está confirmado. Por favor abra su aplicación Haveno e inicie el pago. -account.notifications.trade.message.msg.started=El comprador de BTC ha iniciado el pago para el intercambio con ID {0} +account.notifications.trade.message.msg.started=El comprador de XMR ha iniciado el pago para el intercambio con ID {0} account.notifications.trade.message.msg.completed=El intercambio con ID {0} se ha completado. account.notifications.offer.message.title=Su oferta fue tomada. account.notifications.offer.message.msg=Su oferta con ID {0} se ha tomado. @@ -1275,10 +1304,10 @@ account.notifications.dispute.message.msg=Ha recibido un mensaje de disputa para account.notifications.marketAlert.title=Altertas de oferta account.notifications.marketAlert.selectPaymentAccount=Ofertas que concuerden con la cuenta de pago account.notifications.marketAlert.offerType.label=Tipo de oferta en la que estoy interesado -account.notifications.marketAlert.offerType.buy=Ofertas de compra (quiero vender BTC) -account.notifications.marketAlert.offerType.sell=Ofertas de venta (quiero comprar BTC) +account.notifications.marketAlert.offerType.buy=Ofertas de compra (quiero vender XMR) +account.notifications.marketAlert.offerType.sell=Ofertas de venta (quiero comprar XMR) account.notifications.marketAlert.trigger=Distancia de precio en la oferta (%) -account.notifications.marketAlert.trigger.info=Con distancia de precio establecida, solamente recibirá una alerta cuando se publique una oferta que satisfaga (o exceda) sus requerimientos. Por ejemplo: quiere vender BTC, pero solo venderá con un 2% de premium sobre el precio de mercado actual. Configurando este campo a 2% le asegurará que solo recibirá alertas de ofertas con precios que estén al 2% (o más) sobre el precio de mercado actual. +account.notifications.marketAlert.trigger.info=Con distancia de precio establecida, solamente recibirá una alerta cuando se publique una oferta que satisfaga (o exceda) sus requerimientos. Por ejemplo: quiere vender XMR, pero solo venderá con un 2% de premium sobre el precio de mercado actual. Configurando este campo a 2% le asegurará que solo recibirá alertas de ofertas con precios que estén al 2% (o más) sobre el precio de mercado actual. account.notifications.marketAlert.trigger.prompt=Porcentaje de distancia desde el precio de mercado (e.g. 2.50%, -0.50%, etc) account.notifications.marketAlert.addButton=Añadir alerta de oferta account.notifications.marketAlert.manageAlertsButton=Gestionar alertas de oferta @@ -1305,10 +1334,10 @@ inputControlWindow.balanceLabel=Saldo disponible contractWindow.title=Detalles de la disputa contractWindow.dates=Fecha oferta / Fecha intercambio -contractWindow.btcAddresses=Dirección Bitcoin comprador BTC / vendedor BTC -contractWindow.onions=Dirección de red de comprador BTC / Vendedor BTC -contractWindow.accountAge=Edad de cuenta del comprador BTC / vendedor BTC -contractWindow.numDisputes=No. de disputas del comprador BTC / Vendedor BTC +contractWindow.xmrAddresses=Dirección Monero comprador XMR / vendedor XMR +contractWindow.onions=Dirección de red de comprador XMR / Vendedor XMR +contractWindow.accountAge=Edad de cuenta del comprador XMR / vendedor XMR +contractWindow.numDisputes=No. de disputas del comprador XMR / Vendedor XMR contractWindow.contractHash=Hash del contrato displayAlertMessageWindow.headline=Información importante! @@ -1334,8 +1363,8 @@ disputeSummaryWindow.title=Resumen disputeSummaryWindow.openDate=Fecha de apertura de ticket disputeSummaryWindow.role=Rol del trader disputeSummaryWindow.payout=Pago de la cantidad de intercambio -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} obtiene la cantidad de pago de intercambio -disputeSummaryWindow.payout.getsAll=Cantidad máxima de pago BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} obtiene la cantidad de pago de intercambio +disputeSummaryWindow.payout.getsAll=Cantidad máxima de pago XMR {0} disputeSummaryWindow.payout.custom=Pago personalizado disputeSummaryWindow.payoutAmount.buyer=Cantidad de pago del comprador disputeSummaryWindow.payoutAmount.seller=Cantidad de pago del vendedor @@ -1377,7 +1406,7 @@ disputeSummaryWindow.close.button=Cerrar ticket # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket cerrado el {0}\n{1} dirección de nodo: {2}\n\nResumen:\nID de intercambio: {3}\nMoneda: {4}\nCantidad del intercambio: {5}\nCantidad de pago para el comprador de BTC: {6}\nCantidad de pago para el vendedor de BTC: {7}\n\nMotivo de la disputa: {8}\n\nNotas resumidas:\n{9}\n +disputeSummaryWindow.close.msg=Ticket cerrado el {0}\n{1} dirección de nodo: {2}\n\nResumen:\nID de intercambio: {3}\nMoneda: {4}\nCantidad del intercambio: {5}\nCantidad de pago para el comprador de XMR: {6}\nCantidad de pago para el vendedor de XMR: {7}\n\nMotivo de la disputa: {8}\n\nNotas resumidas:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1420,18 +1449,18 @@ filterWindow.mediators=Mediadores filtrados (direcciones onion separadas por com filterWindow.refundAgents=Agentes de devolución de fondos filtrados (direcciones onion separadas por coma) filterWindow.seedNode=Nodos semilla filtrados (direcciones onion separadas por coma) filterWindow.priceRelayNode=nodos de retransmisión de precio filtrados (direcciones onion separadas por coma) -filterWindow.xmrNode=Nodos Bitcoin filtrados (direcciones + puerto separadas por coma) -filterWindow.preventPublicXmrNetwork=Prevenir uso de la red Bitcoin pública +filterWindow.xmrNode=Nodos Monero filtrados (direcciones + puerto separadas por coma) +filterWindow.preventPublicXmrNetwork=Prevenir uso de la red Monero pública filterWindow.disableAutoConf=Deshabilitar autoconfirmación filterWindow.autoConfExplorers=Exploradores de autoconfirmación filtrados (direcciones separadas por coma) filterWindow.disableTradeBelowVersion=Versión mínima requerida para intercambios. filterWindow.add=Añadir filtro filterWindow.remove=Eliminar filtro -filterWindow.xmrFeeReceiverAddresses=Direcciones de recepción de la tasa BTC +filterWindow.xmrFeeReceiverAddresses=Direcciones de recepción de la tasa XMR filterWindow.disableApi=Deshabilitar API filterWindow.disableMempoolValidation=Deshabilitar validación de Mempool -offerDetailsWindow.minBtcAmount=Cantidad mínima BTC +offerDetailsWindow.minXmrAmount=Cantidad mínima XMR offerDetailsWindow.min=(mínimo {0}) offerDetailsWindow.distance=(distancia del precio de mercado: {0}) offerDetailsWindow.myTradingAccount=MI cuenta de intercambio @@ -1446,6 +1475,7 @@ offerDetailsWindow.confirm.maker=Confirmar: Poner oferta para {0} monero offerDetailsWindow.confirm.taker=Confirmar: Tomar oferta {0} monero offerDetailsWindow.creationDate=Fecha de creación offerDetailsWindow.makersOnion=Dirección onion del creador +offerDetailsWindow.challenge=Frase de contraseña de la oferta qRCodeWindow.headline=Código QR qRCodeWindow.msg=Por favor, utilice este código QR para fondear su billetera Haveno desde su billetera externa. @@ -1474,7 +1504,7 @@ showWalletDataWindow.walletData=Datos del monedero showWalletDataWindow.includePrivKeys=Incluir claves privadas: setXMRTxKeyWindow.headline=Prueba de envío de XMR -setXMRTxKeyWindow.note=Añadiendo la información de transacción a continuación, se habilita la autoconfirmación para intercambios más rápidos. Ver más: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Añadiendo la información de transacción a continuación, se habilita la autoconfirmación para intercambios más rápidos. Ver más: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=ID de transacción (opcional) setXMRTxKeyWindow.txKey=Clave de transacción (opcional) @@ -1496,8 +1526,10 @@ tradeDetailsWindow.agentAddresses=Árbitro/Mediador tradeDetailsWindow.detailData=Detalle de datos txDetailsWindow.headline=Detalles de transacción -txDetailsWindow.xmr.note=Ha enviado BTC +txDetailsWindow.xmr.noteSent=Ha enviado XMR +txDetailsWindow.xmr.noteReceived=Has recibido XMR. txDetailsWindow.sentTo=Enviado a +txDetailsWindow.receivedWith=Recibido con txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Resume de historia de intercambio @@ -1506,7 +1538,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} con el precio de mercado ac closedTradesSummaryWindow.totalVolume.title=Cantidad total intercambiada en {0} closedTradesSummaryWindow.totalMinerFee.title=Suma de todas las trasas de minado closedTradesSummaryWindow.totalMinerFee.value={0} ({1} de la cantidad total intercambiada) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Suma de todas las tasas de intercambio pagadas en BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Suma de todas las tasas de intercambio pagadas en XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} de la cantidad total intercambiada) walletPasswordWindow.headline=Introducir contraseña para desbloquear @@ -1532,12 +1564,12 @@ torNetworkSettingWindow.bridges.header=¿Está Tor bloqueado? torNetworkSettingWindow.bridges.info=Si Tor está bloqueado por su proveedor de internet o por su país puede intentar usar puentes Tor.\nVisite la página web Tor en https://bridges.torproject.org/bridges para saber más acerca de los puentes y transportes conectables. feeOptionWindow.headline=Elija la moneda para el pago de la comisiones de intercambio -feeOptionWindow.info=Puede elegir pagar la tasa de intercambio en BSQ o BTC. Si elige BSQ apreciará la comisión de intercambio descontada. +feeOptionWindow.info=Puede elegir pagar la tasa de intercambio en BSQ o XMR. Si elige BSQ apreciará la comisión de intercambio descontada. feeOptionWindow.optionsLabel=Elija moneda para el pago de comisiones de intercambio -feeOptionWindow.useBTC=Usar BTC +feeOptionWindow.useXMR=Usar XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1611,9 @@ popup.warning.noTradingAccountSetup.msg=Necesita configurar una moneda nacional popup.warning.noArbitratorsAvailable=No hay árbitros disponibles. popup.warning.noMediatorsAvailable=No hay mediadores disponibles. popup.warning.notFullyConnected=Necesita esperar hasta que esté completamente conectado a la red.\nPuede llevar hasta 2 minutos al inicio. -popup.warning.notSufficientConnectionsToBtcNetwork=Necesita esperar hasta que tenga al menos {0} conexiones a la red Bitcoin. -popup.warning.downloadNotComplete=Tiene que esperar hasta que finalice la descarga de los bloques Bitcoin que faltan. -popup.warning.chainNotSynced=La cadena de bloques del monedero Haveno no está sincronizada correctamente. Si ha iniciado la aplicación recientemente, espere a que se haya publicado al menos un bloque Bitcoin.\n\nPuede comprobar la altura de la cadena de bloques en Configuración/Información de red. Si se encuentra más de un bloque y el problema persiste podría estar estancado, en cuyo caso deberá hacer una resincronización SPV.\n[HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Necesita esperar hasta que tenga al menos {0} conexiones a la red Monero. +popup.warning.downloadNotComplete=Tiene que esperar hasta que finalice la descarga de los bloques Monero que faltan. +popup.warning.walletNotSynced=La billetera Haveno no está sincronizada con la última altura de la cadena de bloques. Por favor, espere hasta que la billetera se sincronice o verifique su conexión. popup.warning.removeOffer=¿Está seguro que quiere eliminar la oferta? popup.warning.tooLargePercentageValue=No puede establecer un porcentaje del 100% o superior. popup.warning.examplePercentageValue=Por favor, introduzca un número de porcentaje como \"5.4\" para 5.4% @@ -1601,13 +1633,13 @@ popup.warning.priceRelay=retransmisión de precio popup.warning.seed=semilla popup.warning.mandatoryUpdate.trading=Por favor, actualice a la última versión de Haveno. Se lanzó una actualización obligatoria que inhabilita intercambios con versiones anteriores. Por favor, lea el Foro de Haveno para más información\n popup.warning.noFilter=No hemos recibido un objeto de filtro desde los nodos semilla. Esta situación no se esperaba. Por favor, informe a los desarrolladores Haveno. -popup.warning.burnBTC=Esta transacción no es posible, ya que las comisiones de minado de {0} excederían la cantidad a transferir de {1}. Por favor, espere a que las comisiones de minado bajen o hasta que haya acumulado más BTC para transferir. +popup.warning.burnXMR=Esta transacción no es posible, ya que las comisiones de minado de {0} excederían la cantidad a transferir de {1}. Por favor, espere a que las comisiones de minado bajen o hasta que haya acumulado más XMR para transferir. -popup.warning.openOffer.makerFeeTxRejected=La tasa de transacción para la oferta con ID {0} se rechazó por la red Bitcoin.\nID de transacción={1}\nLa oferta se ha eliminado para evitar futuros problemas.\nPor favor vaya a \"Configuración/Información de red\" y haga una resincronización SPV.\nPara más ayuda por favor contacte con el equipo de soporte de Haveno en el canal de Haveno en Keybase. +popup.warning.openOffer.makerFeeTxRejected=La tasa de transacción para la oferta con ID {0} se rechazó por la red Monero.\nID de transacción={1}\nLa oferta se ha eliminado para evitar futuros problemas.\nPor favor vaya a \"Configuración/Información de red\" y haga una resincronización SPV.\nPara más ayuda por favor contacte con el equipo de soporte de Haveno en el canal de Haveno en Keybase. popup.warning.trade.txRejected.tradeFee=tasa de intercambio popup.warning.trade.txRejected.deposit=depósito -popup.warning.trade.txRejected=La transacción {0} para el intercambio con ID {1} se rechazó por la red Bitcoin.\nID de transacción={2}\nEl intercambio se movió a intercambios fallidos.\nPor favor vaya a \"Configuración/Información de red\" y haga una resincronización SPV.\nPara más ayuda por favor contacte con el equipo de soporte de Haveno en el canal de Haveno en Keybase. +popup.warning.trade.txRejected=La transacción {0} para el intercambio con ID {1} se rechazó por la red Monero.\nID de transacción={2}\nEl intercambio se movió a intercambios fallidos.\nPor favor vaya a \"Configuración/Información de red\" y haga una resincronización SPV.\nPara más ayuda por favor contacte con el equipo de soporte de Haveno en el canal de Haveno en Keybase. popup.warning.openOfferWithInvalidMakerFeeTx=La transacción de tasa de creador para la oferta con ID {0} es inválida.\nID de transacción={1}.\nPor favor vaya a \"Configuración/Información de red\" y haga una resincronización SPV.\nPara más ayuda por favor contacte con el equipo de soporte de Haveno en el canal de Haveno de Keybase. @@ -1616,15 +1648,15 @@ popup.info.securityDepositInfo=Para asegurarse de que ambos comerciantes siguen popup.info.cashDepositInfo=Por favor asegúrese de que tiene una oficina bancaria donde pueda hacer el depósito de efectivo.\nEl ID del banco (BIC/SWIFT) de del vendedor es: {0} popup.info.cashDepositInfo.confirm=Confirmo que puedo hacer el depósito popup.info.shutDownWithOpenOffers=Haveno se está cerrando, pero hay ofertas abiertas.\n\nEstas ofertas no estarán disponibles en la red P2P mientras Haveno esté cerrado, pero serán re-publicadas a la red P2P la próxima vez que inicie Haveno.\n\nPara mantener sus ofertas en línea, mantenga Haveno ejecutándose y asegúrese de que la computadora permanece en línea también (Ej. asegúrese de que no se pone en modo standby... el monitor en espera no es un problema). -popup.info.qubesOSSetupInfo=Parece que está ejecutando Haveno en Qubes OS\n\nAsegúrese de que su Haveno qube esté configurado de acuerdo con nuestra Guía de configuración en [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes] +popup.info.qubesOSSetupInfo=Parece que está ejecutando Haveno en Qubes OS\n\nAsegúrese de que su Haveno qube esté configurado de acuerdo con nuestra Guía de configuración en [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes] popup.warn.downGradePrevention=Degradar desde la versión {0} a la versión {1} no está soportado. Por favor use la última versión de Haveno. popup.privateNotification.headline=Notificación privada importante! popup.securityRecommendation.headline=Recomendación de seguridad importante -popup.securityRecommendation.msg=Nos gustaría recordarle que considere usar protección por contraseña para su cartera, si no la ha activado ya.\n\nTambién es muy recomendable que escriba en un papel las palabras semilla del monedero. Esas palabras semilla son como una contraseña maestra para recuperar su cartera Bitcoin.\nEn la sección \"Semilla de cartera\" encontrará más información.\n\nAdicionalmente, debería hacer una copia de seguridad completa del directorio de aplicación en la sección \"Copia de seguridad\" +popup.securityRecommendation.msg=Nos gustaría recordarle que considere usar protección por contraseña para su cartera, si no la ha activado ya.\n\nTambién es muy recomendable que escriba en un papel las palabras semilla del monedero. Esas palabras semilla son como una contraseña maestra para recuperar su cartera Monero.\nEn la sección \"Semilla de cartera\" encontrará más información.\n\nAdicionalmente, debería hacer una copia de seguridad completa del directorio de aplicación en la sección \"Copia de seguridad\" -popup.moneroLocalhostNode.msg=Haveno ha detectado un nodo de Monero ejecutándose en esta máquina (en el localhost).\n\nPor favor, asegúrese de que el nodo esté completamente sincronizado antes de iniciar Haveno. +popup.xmrLocalNode.msg=Haveno ha detectado un nodo de Monero ejecutándose en esta máquina (en el localhost).\n\nPor favor, asegúrese de que el nodo esté completamente sincronizado antes de iniciar Haveno. popup.shutDownInProgress.headline=Cerrando aplicación... popup.shutDownInProgress.msg=Cerrar la aplicación puede llevar unos segundos.\nPor favor no interrumpa el proceso. @@ -1670,6 +1702,9 @@ popup.accountSigning.unsignedPubKeys.signed=Las claves públicas se firmaron popup.accountSigning.unsignedPubKeys.result.signed=Claves públicas firmadas popup.accountSigning.unsignedPubKeys.result.failed=Error al firmar +popup.info.buyerAsTakerWithoutDeposit.headline=No se requiere depósito del comprador +popup.info.buyerAsTakerWithoutDeposit=Tu oferta no requerirá un depósito de seguridad ni una tarifa del comprador de XMR.\n\nPara aceptar tu oferta, debes compartir una frase de acceso con tu compañero de comercio fuera de Haveno.\n\nLa frase de acceso se genera automáticamente y se muestra en los detalles de la oferta después de la creación. + #################################################################### # Notifications #################################################################### @@ -1677,9 +1712,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Error al firmar notification.trade.headline=Notificación de intercambio con ID {0} notification.ticket.headline=Ticket de soporte de intercambio con ID {0} notification.trade.completed=El intercambio se ha completado y puede retirar sus fondos. -notification.trade.accepted=Su oferta ha sido aceptada por un {0} BTC +notification.trade.accepted=Su oferta ha sido aceptada por un {0} XMR notification.trade.unlocked=Su intercambio tiene al menos una confirmación en la cadena de bloques.\nPuede comenzar el pago ahora. -notification.trade.paymentSent=El comprador de BTC ha comenzado el pago. +notification.trade.paymentSent=El comprador de XMR ha comenzado el pago. notification.trade.selectTrade=Seleccionar intercambio notification.trade.peerOpenedDispute=Su pareja de intercambio ha abierto un {0}. notification.trade.disputeClosed={0} se ha cerrado. @@ -1698,7 +1733,7 @@ systemTray.show=Mostrar ventana de aplicación systemTray.hide=Esconder ventana de aplicación systemTray.info=Información sobre Haveno systemTray.exit=Salir -systemTray.tooltip=Haveno: Una red de intercambio de bitcoin descentralizada +systemTray.tooltip=Haveno: Una red de intercambio de monero descentralizada #################################################################### @@ -1749,7 +1784,7 @@ tooltip.openBlockchainForTx=Abrir explorador de cadena de bloques externo para l confidence.unknown=Estado de transacción desconocido confidence.seen=Visto por {0} par/es / 0 confirmaciones -confidence.confirmed=Confirmado en {0} bloque/s +confidence.confirmed={0} confirmaciones confidence.invalid=La transacción es inválida peerInfo.title=Información del par @@ -1760,10 +1795,10 @@ peerInfo.age.noRisk=Antigüedad de la cuenta de pago peerInfo.age.chargeBackRisk=Tiempo desde el firmado peerInfo.unknownAge=Edad desconocida -addressTextField.openWallet=Abrir su cartera Bitcoin predeterminada +addressTextField.openWallet=Abrir su cartera Monero predeterminada addressTextField.copyToClipboard=Copiar dirección al portapapeles addressTextField.addressCopiedToClipboard=La dirección se ha copiado al portapapeles -addressTextField.openWallet.failed=Fallo al abrir la cartera Bitcoin predeterminada. ¿Tal vez no tenga una instalada? +addressTextField.openWallet.failed=Fallo al abrir la cartera Monero predeterminada. ¿Tal vez no tenga una instalada? peerInfoIcon.tooltip={0}\nEtiqueta: {1} @@ -1795,6 +1830,7 @@ navigation.support=\"Soporte\" formatter.formatVolumeLabel={0} cantidad{1} formatter.makerTaker=Creador como {0} {1} / Tomador como {2} {3} +formatter.makerTakerLocked=Creador como {0} {1} / Tomador como {2} {3} 🔒 formatter.youAreAsMaker=Usted es: {1} {0} (creador) / El tomador es: {3} {2} formatter.youAreAsTaker=Usted es: {1} {0} (tomador) / Creador es: {3} {2} formatter.youAre=Usted es {0} {1} ({2} {3}) @@ -1840,7 +1876,6 @@ password.deriveKey=Derivar clave desde contraseña password.walletDecrypted=El monedero se desencriptó con éxito y se eliminó la protección por contraseña. password.wrongPw=Ha introducido la contraseña incorrecta.\n\nPor favor, introduzca nuevamente la contraseña, evitando errores. password.walletEncrypted=El monedero se encriptó con éxito y se activó la protección por contraseña. -password.walletEncryptionFailed=No se pudo establecer la contraseña de de la cartera. Puede haber importado palabras semilla que no corresponden a la base de datos del monedero. Por favor contacte con los desarrolladores en Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=Las 2 contraseñas introducidas no coinciden. password.forgotPassword=¿Ha olvidado la contraseña? password.backupReminder=Por favor, al establecer una contraseña para la cartera, tenga en cuenta que todas las copias de seguridad creadas de la cartera no encriptada serán borradas automáticamente @@ -1854,7 +1889,7 @@ seed.date=Fecha de la cartera seed.restore.title=Restaurar monederos desde las palabras semilla seed.restore=Restaurar monederos seed.creationDate=Fecha de creación -seed.warn.walletNotEmpty.msg=Su cartera de Bitcoin no está vacía.\n\nDebe vaciar esta cartera antes de intentar restaurar a otra más antigua, ya que mezclar monederos puede llevar a copias de seguridad inválidas.\n\nPor favor, finalice sus intercambios, cierre todas las ofertas abiertas y vaya a la sección Fondos para retirar sus bitcoins.\nEn caso de que no pueda acceder a sus bitcoins puede utilizar la herramienta de emergencia para vaciar el monedero.\nPara abrir la herramienta de emergencia pulse \"alt + e\" o \"Cmd/Ctrl + e\". +seed.warn.walletNotEmpty.msg=Su cartera de Monero no está vacía.\n\nDebe vaciar esta cartera antes de intentar restaurar a otra más antigua, ya que mezclar monederos puede llevar a copias de seguridad inválidas.\n\nPor favor, finalice sus intercambios, cierre todas las ofertas abiertas y vaya a la sección Fondos para retirar sus moneros.\nEn caso de que no pueda acceder a sus moneros puede utilizar la herramienta de emergencia para vaciar el monedero.\nPara abrir la herramienta de emergencia pulse \"alt + e\" o \"Cmd/Ctrl + e\". seed.warn.walletNotEmpty.restore=Quiero restaurar de todos modos seed.warn.walletNotEmpty.emptyWallet=Vaciaré mi monedero antes seed.warn.notEncryptedAnymore=Sus carteras están cifradas.\n\nDespués de restaurarlas, las carteras no estarán cifradas y tendrá que introducir una nueva contraseña.\n\n¿Quiere continuar? @@ -1871,7 +1906,7 @@ seed.restore.openOffers.warn=Tiene ofertas abiertas que serán eliminadas si res payment.account=Cuenta payment.account.no=Número de cuenta payment.account.name=Nombre de cuenta -payment.account.userName=Nombre de usuario +payment.account.username=Nombre de usuario payment.account.phoneNr=Número de teléfono payment.account.owner=Nombre completo del propietario de la cuenta payment.account.fullName=Nombre completo @@ -1903,7 +1938,6 @@ payment.amazon.site=Compre una tarjeta regalo en payment.ask=Pregunte en el Chat de Intercambio payment.uphold.accountId=Nombre de usuario, correo electrónico o núm de teléfono payment.moneyBeam.accountId=Correo electrónico o núm. de telefóno -payment.venmo.venmoUserName=Nombre de usuario Venmo payment.popmoney.accountId=Correo electrónico o núm. de telefóno payment.promptPay.promptPayId=Citizen ID/Tax ID o número de teléfono payment.supportedCurrencies=Monedas soportadas @@ -1945,16 +1979,16 @@ payment.checking=Comprobando payment.savings=Ahorros payment.personalId=ID personal: payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle es un servicio de transmisión de dinero que funciona mejor *a través* de otro banco..\n\n1. Compruebe esta página para ver si (y cómo) trabaja su banco con Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Preste atención a los límites de transferencia -límites de envío- que varían entre bancos, y que los bancos especifican a menudo diferentes límites diarios, semanales y mensuales..\n\n3. Si su banco no trabaja con Zelle, aún puede usarlo a través de la app móvil de Zelle, pero sus límites de transferencia serán mucho menores.\n\n4. El nombre especificado en su cuenta Haveno DEBE ser igual que el nombre en su cuenta de Zelle/bancaria. \n\nSi no puede completar una transacción Zelle tal como se especifica en el contrato, puede perder algo (o todo) el depósito de seguridad!\n\nDebido a que Zelle tiene cierto riesgo de reversión de pago, se aconseja que los vendedores contacten con los compradores no firmados a través de email o SMS para verificar que el comprador realmente tiene la cuenta de Zelle especificada en Haveno. payment.fasterPayments.newRequirements.info=Algunos bancos han comenzado a verificar el nombre completo del receptor para las transferencias Faster Payments. Su cuenta actual Faster Payments no especifica un nombre completo.\n\nConsidere recrear su cuenta Faster Payments en Haveno para proporcionarle a los futuros compradores {0} un nombre completo.\n\nCuando vuelva a crear la cuenta, asegúrese de copiar el UK Short Code de forma precisa , el número de cuenta y los valores salt de la cuenta anterior a su cuenta nueva para la verificación de edad. Esto asegurará que la edad de su cuenta existente y el estado de la firma se conserven. -payment.moneyGram.info=Al utilizar MoneyGram, el comprador de BTC tiene que enviar el número de autorización y una foto del recibo al vendedor de BTC por correo electrónico. El recibo debe mostrar claramente el nobre completo del vendedor, país, estado y cantidad. El email del vendedor se mostrará al comprador durante el proceso de intercambio. -payment.westernUnion.info=Al utilizar Western Union, el comprador de BTC tiene que enviar el número de seguimiento (MTCN) y una foto del recibo al vendedor de BTC por correo electrónico. El recibo debe mostrar claramente el como el nombre completo del vendedor, país, ciudad y cantidad. Al comprador se le mostrará el correo electrónico del vendedor en el proceso de intercambio. -payment.halCash.info=Al usar HalCash el comprador de BTC necesita enviar al vendedor de BTC el código HalCash a través de un mensaje de texto desde el teléfono móvil.\n\nPor favor asegúrese de que no excede la cantidad máxima que su banco le permite enviar con HalCash. La cantidad mínima por retirada es de 10 EUR y el máximo son 600 EUR. Para retiros frecuentes es 3000 por receptor al día y 6000 por receptor al mes. Por favor compruebe estos límites con su banco y asegúrese que son los mismos aquí expuestos.\n\nLa cantidad de retiro debe ser un múltiplo de 10 EUR ya que no se puede retirar otras cantidades desde el cajero automático. La Interfaz de Usuario en la pantalla crear oferta y tomar oferta ajustará la cantidad de BTC para que la cantidad de EUR sea correcta. No puede usar precios basados en el mercado ya que la cantidad de EUR cambiaría con el cambio de precios.\n\nEn caso de disputa el comprador de BTC necesita proveer la prueba de que ha enviado EUR. +payment.moneyGram.info=Al utilizar MoneyGram, el comprador de XMR tiene que enviar el número de autorización y una foto del recibo al vendedor de XMR por correo electrónico. El recibo debe mostrar claramente el nobre completo del vendedor, país, estado y cantidad. El email del vendedor se mostrará al comprador durante el proceso de intercambio. +payment.westernUnion.info=Al utilizar Western Union, el comprador de XMR tiene que enviar el número de seguimiento (MTCN) y una foto del recibo al vendedor de XMR por correo electrónico. El recibo debe mostrar claramente el como el nombre completo del vendedor, país, ciudad y cantidad. Al comprador se le mostrará el correo electrónico del vendedor en el proceso de intercambio. +payment.halCash.info=Al usar HalCash el comprador de XMR necesita enviar al vendedor de XMR el código HalCash a través de un mensaje de texto desde el teléfono móvil.\n\nPor favor asegúrese de que no excede la cantidad máxima que su banco le permite enviar con HalCash. La cantidad mínima por retirada es de 10 EUR y el máximo son 600 EUR. Para retiros frecuentes es 3000 por receptor al día y 6000 por receptor al mes. Por favor compruebe estos límites con su banco y asegúrese que son los mismos aquí expuestos.\n\nLa cantidad de retiro debe ser un múltiplo de 10 EUR ya que no se puede retirar otras cantidades desde el cajero automático. La Interfaz de Usuario en la pantalla crear oferta y tomar oferta ajustará la cantidad de XMR para que la cantidad de EUR sea correcta. No puede usar precios basados en el mercado ya que la cantidad de EUR cambiaría con el cambio de precios.\n\nEn caso de disputa el comprador de XMR necesita proveer la prueba de que ha enviado EUR. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Por favor, tenga en cuenta que todas las transferencias bancarias tienen cierto riesgo de reversión de pago.\n\nPara disminuir este riesgo, Haveno establece límites por intercambio en función del nivel estimado de riesgo de reversión de pago para el método usado.\n\nPara este método de pago, su límite por intercambio para comprar y vender es {2}.\n\nEste límite solo aplica al tamaño de un intercambio: puede poner tantos intercambios como quira.\n\nConsulte detalles en la wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Por favor, tenga en cuenta que todas las transferencias bancarias tienen cierto riesgo de reversión de pago.\n\nPara disminuir este riesgo, Haveno establece límites por intercambio en función del nivel estimado de riesgo de reversión de pago para el método usado.\n\nPara este método de pago, su límite por intercambio para comprar y vender es {2}.\n\nEste límite solo aplica al tamaño de un intercambio: puede poner tantos intercambios como quira.\n\nConsulte detalles en la wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=Para limitar el riesgo de devolución de cargo, Haveno establece límites por compra basados en los 2 siguientes factores:\n\n1. Riesgo general de devolución de cargo para el método de pago\n2. Estado de firmado de cuenta\n\nEsta cuenta de pago aún no ha sido firmada, con lo que ha sido limitada para comprar {0} por intercambio. Después de firmarse, los límites de compra se incrementarán de esta manera:\n\n● Antes de ser firmada, y hasta 30 días después de la firma, su límite por intercambio de compra será {0}\n● 30 días después de la firma, su límite de compra por intercambio será de {1}\n● 60 días después de la firma, su límite de compra por intercambio será de {2}\n\nLos límites de venta no se ven afectados por el firmado de cuentas. Puede vender {2} en un solo \nintercambio inmediatamente.\n\nEstos límites solo aplican al tamaño de un intercambio. Puede hacer tantos intercambios como quiera.\n\n Consulte detalles en la wiki [HYPERLINK:https://bisq.wiki/Account_limits].\n\n +payment.limits.info.withSigning=Para limitar el riesgo de devolución de cargo, Haveno establece límites por compra basados en los 2 siguientes factores:\n\n1. Riesgo general de devolución de cargo para el método de pago\n2. Estado de firmado de cuenta\n\nEsta cuenta de pago aún no ha sido firmada, con lo que ha sido limitada para comprar {0} por intercambio. Después de firmarse, los límites de compra se incrementarán de esta manera:\n\n● Antes de ser firmada, y hasta 30 días después de la firma, su límite por intercambio de compra será {0}\n● 30 días después de la firma, su límite de compra por intercambio será de {1}\n● 60 días después de la firma, su límite de compra por intercambio será de {2}\n\nLos límites de venta no se ven afectados por el firmado de cuentas. Puede vender {2} en un solo \nintercambio inmediatamente.\n\nEstos límites solo aplican al tamaño de un intercambio. Puede hacer tantos intercambios como quiera.\n\n Consulte detalles en la wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits].\n\n payment.cashDeposit.info=Por favor confirme que su banco permite enviar depósitos de efectivo a cuentas de otras personas. Por ejemplo, Bank of America y Wells Fargo ya no permiten estos depósitos. @@ -1966,7 +2000,7 @@ payment.amazonGiftCard.upgrade=El método de pago Tarjetas regalo Amazon requier payment.account.amazonGiftCard.addCountryInfo={0}\nSu cuenta actual de Tarjeta regalo Amazon ({1}) no tiene un País especificado.\nPor favor introduzca el país de su Tarjeta regalo Amazon para actualizar sus datos de cuenta.\nEsto no afectará el estatus de edad de su cuenta. payment.amazonGiftCard.upgrade.headLine=Actualizar cuenta Tarjeta regalo Amazon -payment.usPostalMoneyOrder.info=Los intercambios usando US Postal Money Orders (USPMO) en Haveno requiere que entienda lo siguiente:\n\n- Los compradores de BTC deben escribir la dirección del vendedor en los campos de "Payer" y "Payee" y tomar una foto en alta resolución de la USPMO y del sobre con la prueba de seguimiento antes de enviar.\n- Los compradores de BTC deben enviar la USPMO con confirmación de entrega.\n\nEn caso de que sea necesaria la mediación, se requerirá al comprador que entregue las fotos al mediador o agente de devolución de fondos, junto con el número de serie de la USPMO, número de oficina postal, y la cantidad de USD, para que puedan verificar los detalles en la web de US Post Office.\n\nNo entregar la información requerida al Mediador o Árbitro resultará en pérdida del caso de disputa. \n\nEn todos los casos de disputa, el emisor de la USPMO tiene el 100% de responsabilidad en aportar la evidencia al Mediador o Árbitro.\n\nSi no entiende estos requerimientos, no comercie usando USPMO en Haveno. +payment.usPostalMoneyOrder.info=Los intercambios usando US Postal Money Orders (USPMO) en Haveno requiere que entienda lo siguiente:\n\n- Los compradores de XMR deben escribir la dirección del vendedor en los campos de "Payer" y "Payee" y tomar una foto en alta resolución de la USPMO y del sobre con la prueba de seguimiento antes de enviar.\n- Los compradores de XMR deben enviar la USPMO con confirmación de entrega.\n\nEn caso de que sea necesaria la mediación, se requerirá al comprador que entregue las fotos al mediador o agente de devolución de fondos, junto con el número de serie de la USPMO, número de oficina postal, y la cantidad de USD, para que puedan verificar los detalles en la web de US Post Office.\n\nNo entregar la información requerida al Mediador o Árbitro resultará en pérdida del caso de disputa. \n\nEn todos los casos de disputa, el emisor de la USPMO tiene el 100% de responsabilidad en aportar la evidencia al Mediador o Árbitro.\n\nSi no entiende estos requerimientos, no comercie usando USPMO en Haveno. payment.payByMail.info=Comerciar utilizando Pay by Mail en Haveno requiere que comprendas lo siguiente:\n\ \n\ @@ -1996,7 +2030,7 @@ payment.f2f.city.prompt=La ciudad se mostrará con la oferta payment.shared.optionalExtra=Información adicional opcional payment.shared.extraInfo=Información adicional payment.shared.extraInfo.prompt=Defina cualquier término especial, condiciones o detalles que quiera mostrar junto a sus ofertas para esta cuenta de pago (otros usuarios podrán ver esta información antes de aceptar las ofertas). -payment.f2f.info=Los intercambios 'Cara a Cara' tienen diferentes reglas y riesgos que las transacciones en línea.\n\nLas principales diferencias son:\n● Los pares de intercambio necesitan intercambiar información acerca del punto de reunión y la hora usando los detalles de contacto proporcionados.\n● Los pares de intercambio tienen que traer sus portátiles y hacer la confirmación de 'pago enviado' y 'pago recibido' en el lugar de reunión.\n● Si un creador tiene 'términos y condiciones' especiales necesita declararlos en el campo de texto 'información adicional' en la cuenta.\n● Tomando una oferta el tomador está de acuerdo con los 'términos y condiciones' declarados por el creador.\n● En caso de disputa el árbitro no puede ayudar mucho ya que normalmente es complicado obtener evidencias no manipulables de lo que ha pasado en una reunión. En estos casos los fondos BTC pueden bloquearse indefinidamente o hasta que los pares lleguen a un acuerdo.\n\nPara asegurarse de que comprende las diferencias con los intercambios 'Cara a Cara' por favor lea las instrucciones y recomendaciones en: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info=Los intercambios 'Cara a Cara' tienen diferentes reglas y riesgos que las transacciones en línea.\n\nLas principales diferencias son:\n● Los pares de intercambio necesitan intercambiar información acerca del punto de reunión y la hora usando los detalles de contacto proporcionados.\n● Los pares de intercambio tienen que traer sus portátiles y hacer la confirmación de 'pago enviado' y 'pago recibido' en el lugar de reunión.\n● Si un creador tiene 'términos y condiciones' especiales necesita declararlos en el campo de texto 'información adicional' en la cuenta.\n● Tomando una oferta el tomador está de acuerdo con los 'términos y condiciones' declarados por el creador.\n● En caso de disputa el árbitro no puede ayudar mucho ya que normalmente es complicado obtener evidencias no manipulables de lo que ha pasado en una reunión. En estos casos los fondos XMR pueden bloquearse indefinidamente o hasta que los pares lleguen a un acuerdo.\n\nPara asegurarse de que comprende las diferencias con los intercambios 'Cara a Cara' por favor lea las instrucciones y recomendaciones en: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Abrir paǵina web payment.f2f.offerbook.tooltip.countryAndCity=País y ciudad: {0} / {1} payment.f2f.offerbook.tooltip.extra=Información adicional: {0} @@ -2008,7 +2042,7 @@ payment.japan.recipient=Nombre payment.australia.payid=PayID payment.payid=PayID conectado a una institución financiera. Como la dirección email o el número de móvil. payment.payid.info=Un PayID como un número de teléfono, dirección email o Australian Business Number (ABN), que puede conectar con seguridad a su banco, unión de crédito o cuenta de construcción de sociedad. Necesita haber creado una PayID con su institución financiera australiana. Tanto para enviar y recibir las instituciones financieras deben soportar PayID. Para más información por favor compruebe [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=Para pagar con Tarjeta eGift Amazon. necesitará enviar una Tarjeta eGift Amazon al vendedor BTC a través de su cuenta Amazon.\n\nHaveno mostrará la dirección e-mail del vendedor de BTC o el número de teléfono donde la tarjeta de regalo deberá enviarse. Por favor vea la wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] para más detalles y mejores prácticas.\n\nNotas importantes:\n- Pruebe a enviar las tarjetas regalo en cantidades de 100USD o menores, ya que Amazon está señalando tarjetas regalo mayores como fraudulentas.\n- Intente usar textos para el mensaje de la tarjeta regalo creíbles y creativos ("Feliz cumpleaños!").\n- Las tarjetas Amazon eGift pueden ser redimidas únicamente en la web de Amazon en la que se compraron (por ejemplo, una tarjeta comprada en amazon.it solo puede ser redimida en amazon.it) +payment.amazonGiftCard.info=Para pagar con Tarjeta eGift Amazon. necesitará enviar una Tarjeta eGift Amazon al vendedor XMR a través de su cuenta Amazon.\n\nHaveno mostrará la dirección e-mail del vendedor de XMR o el número de teléfono donde la tarjeta de regalo deberá enviarse. Por favor vea la wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] para más detalles y mejores prácticas.\n\nNotas importantes:\n- Pruebe a enviar las tarjetas regalo en cantidades de 100USD o menores, ya que Amazon está señalando tarjetas regalo mayores como fraudulentas.\n- Intente usar textos para el mensaje de la tarjeta regalo creíbles y creativos ("Feliz cumpleaños!").\n- Las tarjetas Amazon eGift pueden ser redimidas únicamente en la web de Amazon en la que se compraron (por ejemplo, una tarjeta comprada en amazon.it solo puede ser redimida en amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2166,7 +2200,7 @@ validation.zero=El 0 no es un valor permitido. validation.negative=No se permiten entradas negativas. validation.traditional.tooSmall=No se permite introducir un valor menor que el mínimo posible validation.traditional.tooLarge=No se permiten entradas más grandes que la mayor posible. -validation.xmr.fraction=El valor introducido resulta en un valor de bitcoin menor a 1 satoshi +validation.xmr.fraction=El valor introducido resulta en un valor de monero menor a 1 satoshi validation.xmr.tooLarge=No se permiten valores mayores que {0}. validation.xmr.tooSmall=Valores menores que {0} no se permiten. validation.passwordTooShort=El password introducido es muy corto. Necesita tener al menos 8 caracteres. @@ -2176,10 +2210,10 @@ validation.sortCodeChars={0} debe consistir en {1} caracteres validation.bankIdNumber={0} debe consistir en {1} números. validation.accountNr=El número de cuenta debe consistir en {0} números. validation.accountNrChars=El número de cuenta debe consistir en {0} caracteres. -validation.btc.invalidAddress=La dirección no es correcta. Por favor compruebe el formato de la dirección. +validation.xmr.invalidAddress=La dirección no es correcta. Por favor compruebe el formato de la dirección. validation.integerOnly=Por favor, introduzca sólo números enteros. validation.inputError=Su entrada causó un error:\n{0} -validation.btc.exceedsMaxTradeLimit=Su límite de intercambio es {0}. +validation.xmr.exceedsMaxTradeLimit=Su límite de intercambio es {0}. validation.nationalAccountId={0} debe consistir de {1} número(s). #new diff --git a/core/src/main/resources/i18n/displayStrings_fa.properties b/core/src/main/resources/i18n/displayStrings_fa.properties index 1d851c3466..6c5286402f 100644 --- a/core/src/main/resources/i18n/displayStrings_fa.properties +++ b/core/src/main/resources/i18n/displayStrings_fa.properties @@ -36,12 +36,14 @@ shared.iUnderstand=فهمیدم shared.na=بدون پاسخ shared.shutDown=خاموش shared.reportBug=Report bug on GitHub -shared.buyBitcoin=خرید بیتکوین -shared.sellBitcoin=بیتکوین بفروشید +shared.buyMonero=خرید بیتکوین +shared.sellMonero=بیتکوین بفروشید shared.buyCurrency=خرید {0} shared.sellCurrency=فروش {0} -shared.buyingBTCWith=خرید بیتکوین با {0} -shared.sellingBTCFor=فروش بیتکوین با {0} +shared.buyCurrencyLocked=بخر {0} 🔒 +shared.sellCurrencyLocked=فروش {0} 🔒 +shared.buyingXMRWith=خرید بیتکوین با {0} +shared.sellingXMRFor=فروش بیتکوین با {0} shared.buyingCurrency=خرید {0} ( فروش بیتکوین) shared.sellingCurrency=فروش {0} (خرید بیتکوین) shared.buy=خرید @@ -93,7 +95,7 @@ shared.amountMinMax=مقدار (حداقل - حداکثر) shared.amountHelp=اگر پیشنهادی دستهی حداقل و حداکثر مقدار دارد، شما می توانید هر مقداری در محدوده پیشنهاد را معامله کنید. shared.remove=حذف shared.goTo=به {0} بروید -shared.BTCMinMax=بیتکوین (حداقل - حداکثر) +shared.XMRMinMax=بیتکوین (حداقل - حداکثر) shared.removeOffer=حذف پیشنهاد shared.dontRemoveOffer=پیشنهاد را حذف نکنید shared.editOffer=ویرایش پیشنهاد @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=بله، لغو شود shared.nextStep=گام بعدی shared.selectTradingAccount=حساب معاملات را انتخاب کنید -shared.fundFromSavingsWalletButton=انتقال وجه از کیف Haveno +shared.fundFromSavingsWalletButton=اعمال وجه از کیف پول هاونو shared.fundFromExternalWalletButton=برای تهیه پول، کیف پول بیرونی خود را باز کنید -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent= ٪ زیر قیمت بازار shared.aboveInPercent= ٪ بالای قیمت بازار shared.enterPercentageValue=ارزش ٪ را وارد کنید shared.OR=یا shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=در انتظار دریافت وجه... -shared.TheBTCBuyer=خریدار بیتکوین +shared.TheXMRBuyer=خریدار بیتکوین shared.You=شما shared.sendingConfirmation=در حال ارسال تاییدیه... shared.sendingConfirmationAgain=لطفاً تاییدیه را دوباره ارسال نمایید @@ -123,9 +125,8 @@ shared.noDateAvailable=تاریخ موجود نیست shared.noDetailsAvailable=جزئیاتی در دسترس نیست shared.notUsedYet=هنوز مورد استفاده قرار نگرفته shared.date=تاریخ -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=کپی در کلیپبورد shared.language=زبان shared.country=کشور @@ -140,6 +141,7 @@ shared.addNewAccount=افزودن حساب جدید shared.ExportAccounts=صادر کردن حسابها shared.importAccounts=وارد کردن حسابها shared.createNewAccount=ایجاد حساب جدید +shared.createNewAccountDescription=جزئیات حساب شما بهطور محلی بر روی دستگاه شما ذخیره شده و تنها با همتجارت شما و داور در صورت باز شدن یک اختلاف به اشتراک گذاشته میشود. shared.saveNewAccount=ذخیرهی حساب جدید shared.selectedAccount=حساب انتخاب شده shared.deleteAccount=حذف حساب @@ -169,7 +171,7 @@ shared.payoutTxId=شناسه تراکنش پرداخت shared.contractAsJson=قرارداد در قالب JSON shared.viewContractAsJson=مشاهدهی قرارداد در قالب JSON: shared.contract.title=قرارداد برای معامله با شناسه ی {0} -shared.paymentDetails=جزئیات پرداخت BTC {0} +shared.paymentDetails=جزئیات پرداخت XMR {0} shared.securityDeposit=سپردهی اطمینان shared.yourSecurityDeposit=سپرده ی اطمینان شما shared.contract=قرارداد @@ -179,19 +181,21 @@ shared.messageSendingFailed=ارسال پیام ناموفق بود. خطا: {0} shared.unlock=باز کردن shared.toReceive=قابل دریافت shared.toSpend=قابل خرج کردن -shared.btcAmount=مقدار بیتکوین +shared.xmrAmount=مقدار بیتکوین shared.yourLanguage=زبانهای شما shared.addLanguage=افزودن زبان shared.total=مجموع shared.totalsNeeded=وجه مورد نیاز shared.tradeWalletAddress=آدرس کیفپول معاملات shared.tradeWalletBalance=موجودی کیفپول معاملات +shared.reserveExactAmount=فقط وجوه مورد نیاز را رزرو کنید. نیاز به هزینه استخراج و حدود ۲۰ دقیقه زمان قبل از فعال شدن پیشنهاد شما دارد. shared.makerTxFee=سفارش گذار: {0} shared.takerTxFee=پذیرنده سفارش: {0} shared.iConfirm=تایید میکنم shared.openURL=باز {0} shared.fiat=فیات shared.crypto=کریپتو +shared.preciousMetals=فلزات گرانبها shared.all=همه shared.edit=ویرایش shared.advancedOptions=گزینههای پیشرفته @@ -226,8 +230,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=بازار -mainView.menu.buyBtc=خرید بیتکوین -mainView.menu.sellBtc=فروش بیتکوین +mainView.menu.buyXmr=خرید بیتکوین +mainView.menu.sellXmr=فروش بیتکوین mainView.menu.portfolio=سبد سرمایه mainView.menu.funds=وجوه mainView.menu.support=پشتیبانی @@ -245,12 +249,15 @@ mainView.balance.reserved.short=اندوخته mainView.balance.pending.short=قفل شده mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(لوکال هاست) +mainView.footer.localhostMoneroNode=(لوکال هاست) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=در حال ارتباط با شبکه بیتکوین -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=اتصال به شبکه Haveno +mainView.footer.xmrInfo.synchronizingWith=همگامسازی با {0} در بلوک: {1} / {2} +mainView.footer.xmrInfo.connectedTo=متصل شده به {0} در بلوک {1} +mainView.footer.xmrInfo.synchronizingWalletWith=همگامسازی کیفپول با {0} در بلوک: {1} / {2} +mainView.footer.xmrInfo.syncedWith=همگامسازی با {0} در بلوک {1} انجام شده است mainView.footer.xmrInfo.connectingTo=در حال ایجاد ارتباط با mainView.footer.xmrInfo.connectionFailed=Connection failed to mainView.footer.xmrPeers=Monero network peers: {0} @@ -274,7 +281,7 @@ mainView.walletServiceErrorMsg.connectionError=ارتباط با شبکهی mainView.walletServiceErrorMsg.rejectedTxException=A transaction was rejected from the network.\n\n{0} mainView.networkWarning.allConnectionsLost=اتصال شما به تمام {0} همتایان شبکه قطع شد.\nشاید ارتباط کامپیوتر شما قطع شده است یا کامپیوتر در حالت Standby است. -mainView.networkWarning.localhostBitcoinLost=اتصال شما به Node لوکال هاست بیتکوین قطع شد.\nلطفاً به منظور اتصال به سایر Nodeهای بیتکوین، برنامهی Haveno یا Node لوکال هاست بیتکوین را مجددا راه اندازی کنید. +mainView.networkWarning.localhostMoneroLost=اتصال شما به Node لوکال هاست بیتکوین قطع شد.\nلطفاً به منظور اتصال به سایر Nodeهای بیتکوین، برنامهی Haveno یا Node لوکال هاست بیتکوین را مجددا راه اندازی کنید. mainView.version.update=(به روز رسانی موجود است) @@ -325,6 +332,7 @@ offerbook.createOffer=ایجاد پیشنهاد offerbook.takeOffer=برداشتن پیشنهاد offerbook.takeOfferToBuy=پیشنهاد خرید {0} را بردار offerbook.takeOfferToSell=پیشنهاد فروش {0} را بردار +offerbook.takeOffer.enterChallenge=عبارت عبور پیشنهاد را وارد کنید offerbook.trader=معاملهگر offerbook.offerersBankId=شناسه بانک سفارشگذار (BIC/SWIFT): {0} offerbook.offerersBankName= نام بانک سفارشگذار : {0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=بانکهای کشورهای پذیرف offerbook.availableOffers=پیشنهادهای موجود offerbook.filterByCurrency=فیلتر بر اساس ارز offerbook.filterByPaymentMethod=فیلتر بر اساس روش پرداخت -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=پیشنهادات متناسب با حسابهای من +offerbook.filterNoDeposit=هیچ سپردهای +offerbook.noDepositOffers=پیشنهادهایی بدون ودیعه (نیاز به عبارت عبور) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=account was banned offerbook.timeSinceSigning.daysSinceSigning={0} روز offerbook.timeSinceSigning.daysSinceSigning.long={0} since signing offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=با XMR خرید کنید: +offerbook.sellXmrFor=فروش XMR برای: offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=تعداد پیشنهادها: {0} offerbook.volume={0} (حداقل - حداکثر) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=پیشنهاد ایجاد کنید به {0} {1} offerbook.createOfferToBuy=پیشنهاد جدید برای خرید {0} ایجاد کن offerbook.createOfferToSell=پیشنهاد جدید برای فروش {0} ایجاد کن @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- The buyer''s account has not been signed by an arbitrator or a peer\n- The time since signing of the buyer''s account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- Your account has not been signed by an arbitrator or a peer\n- The time since signing of your account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=این روش پرداخت موقتاً تا {1} به {0} محدود شده است زیرا همه خریداران حسابهای جدیدی دارند.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=پیشنهاد شما تنها مختص خریدارانی خواهد بود که حسابهایی با امضا و سنین پیر دارند زیرا این مبلغ {0} را بیشتر میکند.\n\n{1} offerbook.warning.wrongTradeProtocol=این پیشنهاد نیاز به نسخه پروتکل متفاوتی مانند پروتکل نسخه نرمافزار خودتان دارد.\n\nلطفا پس از نصب آخرین آپدیت نرمافزار دوباره تلاش کنید. در غیر این صورت، کاربری که این پیشنهاد را ایجاد کرده است، از نسخهای قدیمیتر استفاده میکند.\n\nکاربران نمی توانند با نسخههای پروتکل معاملاتی ناسازگار، معامله کنند. offerbook.warning.userIgnored=شما آدرس onion کاربر را به لیست بیاعتنایی خودتان افزودهاید. @@ -394,7 +409,6 @@ offerbook.warning.offerBlocked=پیشنهاد توسط توسعه دهندگان offerbook.warning.currencyBanned=ارز مورد استفاده در آن پیشنهاد، توسط توسعهدهندگان Haveno مسدود شد.\nبرای اطلاعات بیشتر، لطفاً از انجمن Haveno بازدید نمایید. offerbook.warning.paymentMethodBanned=روش پرداخت مورد استفاده در آن پیشنهاد، توسط توسعه دهندگان Haveno مسدود شد.\nلطفاً برای اطلاعات بیشتر، از انجمن Haveno بازدید نمایید. offerbook.warning.nodeBlocked=آدرس onion آن معامله گر، توسط توسعه دهندگان Haveno مسدود شد.\nاحتمالاً هنگام گرفتن پیشنهاد از جانب آن معامله گر، یک اشکال ناامن موجب پدید آمدن مسائلی شده است. -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=با قیمت روز بازار خواهید فروخت (به روز رسانی در هر دقیقه). @@ -415,7 +429,7 @@ offerbook.info.roundedFiatVolume=مقدار برای حفظ حریم خصوصی createOffer.amount.prompt=مقدار را به بیتکوین وارد کنید. createOffer.price.prompt=قیمت را وارد کنید createOffer.volume.prompt=مقدار را در {0} وارد کنید -createOffer.amountPriceBox.amountDescription=مقدار BTC برای {0} +createOffer.amountPriceBox.amountDescription=مقدار XMR برای {0} createOffer.amountPriceBox.buy.volumeDescription=مقدار در {0} به منظور خرج کردن createOffer.amountPriceBox.sell.volumeDescription=مقدار در {0} به منظور دریافت نمودن createOffer.amountPriceBox.minAmountDescription=حداقل مقدار بیتکوین @@ -434,7 +448,7 @@ createOffer.info.sellAboveMarketPrice=شما همیشه {0}% بیشتر از ن createOffer.info.buyBelowMarketPrice=شما همیشه {0}% کمتر از نرخ روز فعلی بازار پرداخت خواهید کرد، زیرا قیمت پیشنهادتان به طور مداوم به روز رسانی خواهد شد. createOffer.warning.sellBelowMarketPrice=شما همیشه {0}% کمتر از نرخ روز فعلی بازار دریافت خواهید کرد، زیرا قیمت پیشنهادتان به طور مداوم به روز رسانی خواهد شد. createOffer.warning.buyAboveMarketPrice=شما همیشه {0}% کمتر از نرخ روز فعلی بازار پرداخت خواهید کرد، زیرا قیمت پیشنهادتان به طور مداوم به روز رسانی خواهد شد. -createOffer.tradeFee.descriptionBTCOnly=کارمزد معامله +createOffer.tradeFee.descriptionXMROnly=کارمزد معامله createOffer.tradeFee.descriptionBSQEnabled=انتخاب ارز برای کارمزد معامله createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +462,12 @@ createOffer.placeOfferButton=بررسی: پیشنهاد را برای {0} بی createOffer.createOfferFundWalletInfo.headline=پیشنهاد خود را تامین وجه نمایید # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=مقدار معامله:{0}\n -createOffer.createOfferFundWalletInfo.msg=شما باید {0} برای این پیشنهاد، سپرده بگذارید.\nآن وجوه در کیف پول محلی شما ذخیره شده اند و هنگامی که کسی پیشنهاد شما را دریافت می کند، به آدرس سپرده چند امضایی قفل خواهد شد.\n\nمقدار مذکور، مجموع موارد ذیل است:\n{1} - سپردهی اطمینان شما: {2}\n-هزینه معامله: {3}\n-هزینه تراکنش شبکه: {4}\nشما هنگام تامین مالی معاملهی خود، میتوانید بین دو گزینه انتخاب کنید:\n- از کیف پول Haveno خود استفاده کنید (این روش راحت است، اما ممکن است تراکنشها قابل رصد شوند)، یا\n- از کیف پول خارجی انتقال دهید (به طور بالقوهای این روش ایمنتر و محافظ حریم خصوصی شما است)\n\nشما تمام گزینهها و جزئیات تامین مالی را پس از بستن این پنجره، خواهید دید. +createOffer.createOfferFundWalletInfo.msg=شما باید {0} را برای این پیشنهاد واریز کنید.\n\n\ +این وجوه در کیف پول محلی شما رزرو میشوند و هنگامی که کسی پیشنهاد شما را قبول کند، به یک کیف پول مولتیسیگ قفل خواهند شد.\n\n\ +مقدار این مبلغ مجموع موارد زیر است:\n\ +{1}\ +- ودیعه امنیتی شما: {2}\n\ +- هزینه معامله: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=یک خطا هنگام قرار دادن پیشنهاد، رخ داده است:\n\n{0}\n\nهیچ پولی تاکنون از کیف پول شما کم نشده است.\nلطفاً برنامه را مجدداً راه اندازی کرده و ارتباط اینترنت خود را بررسی نمایید. @@ -470,7 +489,10 @@ createOffer.setDepositAsBuyer=تنظیم سپردهی اطمینان من ب createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=سپردهی اطمینان خریدار شما {0} خواهد بود createOffer.securityDepositInfoAsBuyer=سپردهی اطمینان شما به عنوان خریدار {0} خواهد بود -createOffer.minSecurityDepositUsed=Min. buyer security deposit is used +createOffer.minSecurityDepositUsed=حداقل سپرده امنیتی استفاده میشود +createOffer.buyerAsTakerWithoutDeposit=هیچ سپردهای از خریدار مورد نیاز نیست (محافظت شده با پسعبارت) +createOffer.myDeposit=سپرده امنیتی من (%) +createOffer.myDepositInfo=ودیعه امنیتی شما {0} خواهد بود #################################################################### @@ -482,7 +504,7 @@ takeOffer.amountPriceBox.buy.amountDescription=مقدار بیتکوین به م takeOffer.amountPriceBox.sell.amountDescription=مقدار بیتکوین به منظور خرید takeOffer.amountPriceBox.priceDescription=قیمت به ازای هر بیتکوین در {0} takeOffer.amountPriceBox.amountRangeDescription=محدودهی مقدار ممکن -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=مقداری که شما وارد کردهاید، از تعداد عددهای اعشاری مجاز فراتر رفته است.\nمقدار به 4 عدد اعشاری تنظیم شده است. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=مقداری که شما وارد کردهاید، از تعداد عددهای اعشاری مجاز فراتر رفته است.\nمقدار به 4 عدد اعشاری تنظیم شده است. takeOffer.validation.amountSmallerThanMinAmount=مقدار نمیتواند کوچکتر از حداقل مقدار تعیین شده در پیشنهاد باشد. takeOffer.validation.amountLargerThanOfferAmount=مقدار ورودی نمیتواند بالاتر از مقدار تعیین شده در پیشنهاد باشد. takeOffer.validation.amountLargerThanOfferAmountMinusFee=مقدار ورودی، باعث ایجاد تغییر جزئی برای فروشنده بیتکوین می شود. @@ -491,9 +513,11 @@ takeOffer.fundsBox.isOfferAvailable=بررسی کنید آیا پیشنهاد د takeOffer.fundsBox.tradeAmount=مبلغ فروش takeOffer.fundsBox.offerFee=کارمزد معامله takeOffer.fundsBox.networkFee=کل کارمزد استخراج -takeOffer.fundsBox.takeOfferSpinnerInfo=برداشتن پیشنهاد در حال انجام است... +takeOffer.fundsBox.takeOfferSpinnerInfo=پذیرفتن پیشنهاد: {0} takeOffer.fundsBox.paymentLabel=معامله Haveno با شناسهی {0} takeOffer.fundsBox.fundsStructure=({0} سپردهی اطمینان، {1} هزینهی معامله، {2} هزینه تراکنش شبکه) +takeOffer.fundsBox.noFundingRequiredTitle=نیاز به تأمین مالی نیست +takeOffer.fundsBox.noFundingRequiredDescription=برای پذیرش این پیشنهاد، رمزعبور آن را از فروشنده خارج از هاونئو دریافت کنید. takeOffer.success.headline=با موفقیت یک پیشنهاد را قبول کردهاید. takeOffer.success.info=شما میتوانید وضعیت معاملهی خود را در \"سبد سهام /معاملات باز\" ببینید. takeOffer.error.message=هنگام قبول کردن پیشنهاد، اتفاقی رخ داده است.\n\n{0} @@ -504,7 +528,7 @@ takeOffer.noPriceFeedAvailable=امکان پذیرفتن پیشنهاد وجود takeOffer.takeOfferFundWalletInfo.headline=معامله خود را تأمین وجه نمایید # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=مقدار معامله: {0}\n -takeOffer.takeOfferFundWalletInfo.msg=شما باید {0} برای قبول این پیشنهاد، سپرده بگذارید.\nاین مقدار مجموع موارد ذیل است:\n{1} - سپردهی اطمینان شما: {2}\n-هزینه معامله: {3}\n-تمامی هزینه های تراکنش شبکه: {4}\nشما هنگام تامین مالی معاملهی خود، میتوانید بین دو گزینه انتخاب کنید:\n- از کیف پول Haveno خود استفاده کنید (این روش راحت است، اما ممکن است تراکنشها قابل رصد شوند)، یا\n- از کیف پول خارجی انتقال دهید (به طور بالقوهای این روش ایمنتر و محافظ حریم خصوصی شما است)\n\nشما تمام گزینهها و جزئیات تامین مالی را پس از بستن این پنجره، خواهید دید. +takeOffer.takeOfferFundWalletInfo.msg=باید {0} را برای پذیرش این پیشنهاد واریز کنید.\n\nمبلغ مجموع موارد زیر است:\n{1}- سپرده امنیتی شما: {2}\n- هزینه معامله: {3} takeOffer.alreadyPaidInFunds=اگر شما در حال حاضر در وجوه، پرداختی داشته اید، می توانید آن را در صفحه ی \"وجوه/ارسال وجوه\" برداشت کنید. takeOffer.paymentInfo=اطلاعات پرداخت takeOffer.setAmountPrice=تنظیم مقدار @@ -597,7 +621,7 @@ portfolio.pending.step1.openForDispute=The deposit transaction is still not conf # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" @@ -615,9 +639,9 @@ portfolio.pending.step2_buyer.westernUnion.extra=مورد الزامی مهم:\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.postal=لطفاً {0} را توسط \"US Postal Money Order\" به فروشندهی بیتکوین پرداخت کنید.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.f2f=لطفا با استفاده از راههای ارتباطی ارائه شده توسط فروشنده با وی تماس بگیرید و قرار ملاقاتی را برای پرداخت {0} تنظیم کنید.\n portfolio.pending.step2_buyer.startPaymentUsing=آغاز پرداخت با استفاده از {0} @@ -641,14 +665,14 @@ portfolio.pending.step2_buyer.confirmStart.headline=تأیید کنید که پ portfolio.pending.step2_buyer.confirmStart.msg=آیا شما پرداخت {0} را به شریک معاملاتی خود آغاز کردید؟ portfolio.pending.step2_buyer.confirmStart.yes=بلی، پرداخت را آغاز کردهام portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=برای پرداخت منتظر باشید portfolio.pending.step2_seller.f2fInfo.headline=اطلاعات تماس خریدار portfolio.pending.step2_seller.waitPayment.msg=تراکنش سپرده، حداقل یک تأییدیه بلاکچین دارد.شما\nباید تا آغاز پرداخت {0} از جانب خریدار بیتکوین، صبر نمایید. portfolio.pending.step2_seller.warn=خریدار بیتکوین هنوز پرداخت {0} را انجام نداده است.\nشما باید تا آغاز پرداخت از جانب او، صبر نمایید.\nاگر معامله تا {1} تکمیل نشد، داور بررسی خواهد کرد. -portfolio.pending.step2_seller.openForDispute=The BTC buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. +portfolio.pending.step2_seller.openForDispute=The XMR buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. tradeChat.chatWindowTitle=Chat window for trade with ID ''{0}'' tradeChat.openChat=Open chat window tradeChat.rules=You can communicate with your trade peer to resolve potential problems with this trade.\nIt is not mandatory to reply in the chat.\nIf a trader violates any of the rules below, open a dispute and report it to the mediator or arbitrator.\n\nChat rules:\n\t● Do not send any links (risk of malware). You can send the transaction ID and the name of a block explorer.\n\t● Do not send your seed words, private keys, passwords or other sensitive information!\n\t● Do not encourage trading outside of Haveno (no security).\n\t● Do not engage in any form of social engineering scam attempts.\n\t● If a peer is not responding and prefers to not communicate via chat, respect their decision.\n\t● Keep conversation scope limited to the trade. This chat is not a messenger replacement or troll-box.\n\t● Keep conversation friendly and respectful. @@ -671,19 +695,19 @@ portfolio.pending.step3_buyer.wait.info=برای تأییدیه رسید پرد portfolio.pending.step3_buyer.wait.msgStateInfo.label=وضعیت پیام آغاز شدن پرداخت portfolio.pending.step3_buyer.warn.part1a=بر بلاکچین {0} portfolio.pending.step3_buyer.warn.part1b=در ارائه دهندهی پرداخت شما (برای مثال بانک) -portfolio.pending.step3_buyer.warn.part2=The BTC seller still has not confirmed your payment. Please check {0} if the payment sending was successful. -portfolio.pending.step3_buyer.openForDispute=The BTC seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. +portfolio.pending.step3_buyer.warn.part2=The XMR seller still has not confirmed your payment. Please check {0} if the payment sending was successful. +portfolio.pending.step3_buyer.openForDispute=The XMR seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=شریک معاملاتی شما تأیید کرده که پرداخت {0} را آغاز نموده است.\n\n portfolio.pending.step3_seller.crypto.explorer=در کاوشگر بلاکچین محبوبتان {0} portfolio.pending.step3_seller.crypto.wallet=در کیفپول {0} شما portfolio.pending.step3_seller.crypto={0} لطفا بررسی کنید {1} که آیا تراکنش مربوط به آدرس شما\n{2}\n تعداد تاییدیههای کافی بر روی بلاکچین دریافت کرده است یا خیر.\nمبلغ پرداخت باید {3} باشد\nشما میتوانید آدرس {4} خود را پس از بستن پنجره از صفحه اصلی کپی کنید. -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=چون پرداخت از طریق سپردهی نقدی انجام شده است، خریدار BTC باید عبارت \"غیر قابل استرداد\" را روی رسید کاغذی بنویسد، آن را به 2 قسمت پاره کند و از طریق ایمیل به شما یک عکس ارسال کند.\n\nبه منظور اجتناب از استرداد وجه، تنها در صورتی تایید کنید که ایمیل را دریافت کرده باشید و از صحت رسید کاغذی مطمئن باشید.\nاگر مطمئن نیستید، {0} +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=چون پرداخت از طریق سپردهی نقدی انجام شده است، خریدار XMR باید عبارت \"غیر قابل استرداد\" را روی رسید کاغذی بنویسد، آن را به 2 قسمت پاره کند و از طریق ایمیل به شما یک عکس ارسال کند.\n\nبه منظور اجتناب از استرداد وجه، تنها در صورتی تایید کنید که ایمیل را دریافت کرده باشید و از صحت رسید کاغذی مطمئن باشید.\nاگر مطمئن نیستید، {0} portfolio.pending.step3_seller.moneyGram=خریدار باید شماره مجوز و عکسی از رسید را به ایمیل شما ارسال کند.\nرسید باید به طور واضح نام کامل شما ، کشور، ایالت فروشنده و مقدار را نشان دهد. لطفاً ایمیل خود را بررسی کنید که آیا شماره مجوز را دریافت کردهاید یا خیر.\n\nپس از بستن پنجره، نام و آدرس خریدار بیتکوین را برای برداشت پول از مانیگرام خواهید دید.\n\nتنها پس از برداشت موفقیت آمیز پول، رسید را تأیید کنید! portfolio.pending.step3_seller.westernUnion=خریدار باید MTCN (شماره پیگیری) و عکسی از رسید را به ایمیل شما ارسال کند.\nرسید باید به طور واضح نام کامل شما، کشور، ایالت فروشنده و مقدار را نشان دهد. لطفاً ایمیل خود را بررسی کنید که آیا MTCN را دریافت کرده اید یا خیر.\nپس از بستن پنجره، نام و آدرس خریدار بیتکوین را برای برداشت پول از Western Union خواهید دید.\nتنها پس از برداشت موفقیت آمیز پول، رسید را تأیید کنید! portfolio.pending.step3_seller.halCash=خریدار باید کد HalCash را برای شما با پیامک بفرستد. علاوه برآن شما از HalCash پیامی را محتوی اطلاعات موردنیاز برای برداشت EUR از خودپردازهای پشتیبان HalCash دریافت خواهید کرد.\n\nپس از اینکه پول را از دستگاه خودپرداز دریافت کردید، لطفا در اینجا رسید پرداخت را تایید کنید. @@ -713,7 +737,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=آیا وجه {0} را ا # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Please also verify that the name of the sender specified on the trade contract matches the name that appears on your bank statement:\nSender''s name, per trade contract: {0}\n\nIf the names are not exactly the same, don''t confirm payment receipt. Instead, open a dispute by pressing \"alt + o\" or \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the BTC buyer and the security deposit will be refunded.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the XMR buyer and the security deposit will be refunded.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=تأیید کنید که وجه را دریافت کردهاید portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=بله وجه را دریافت کردهام portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANT: By confirming receipt of payment, you are also verifying the account of the counterparty and signing it accordingly. Since the account of the counterparty hasn't been signed yet, you should delay confirmation of the payment as long as possible to reduce the risk of a chargeback. @@ -723,7 +747,7 @@ portfolio.pending.step5_buyer.tradeFee=کارمزد معامله portfolio.pending.step5_buyer.makersMiningFee=کارمزد استخراج portfolio.pending.step5_buyer.takersMiningFee=کل کارمزد استخراج portfolio.pending.step5_buyer.refunded=سپرده اطمینان مسترد شده -portfolio.pending.step5_buyer.withdrawBTC=برداشت بیتکوین شما +portfolio.pending.step5_buyer.withdrawXMR=برداشت بیتکوین شما portfolio.pending.step5_buyer.amount=مبلغ قابل برداشت portfolio.pending.step5_buyer.withdrawToAddress=برداشت به آدرس portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet @@ -794,7 +818,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +857,7 @@ funds.deposit.fundHavenoWallet=تأمین مالی کیف پول Haveno funds.deposit.noAddresses=آدرسهایی برای سپرده ایجاد نشده است funds.deposit.fundWallet=تأمین مالی کیف پول شما funds.deposit.withdrawFromWallet=ارسال وجه از کیفپول -funds.deposit.amount=مبلغ به BTC (اختیاری) +funds.deposit.amount=مبلغ به XMR (اختیاری) funds.deposit.generateAddress=ایجاد آدرس جدید funds.deposit.generateAddressSegwit=Native segwit format (Bech32) funds.deposit.selectUnused=لطفاً به جای ایجاد یک آدرس جدید، یک آدرس استفاده نشده را از جدول بالا انتخاب کنید. @@ -890,7 +914,7 @@ funds.tx.revert=عودت funds.tx.txSent=تراکنش به طور موفقیت آمیز به یک آدرس جدید در کیف پول محلی Haveno ارسال شد. funds.tx.direction.self=ارسال شده به خودتان funds.tx.dustAttackTx=Received dust -funds.tx.dustAttackTx.popup=This transaction is sending a very small BTC amount to your wallet and might be an attempt from chain analysis companies to spy on your wallet.\n\nIf you use that transaction output in a spending transaction they will learn that you are likely the owner of the other address as well (coin merge).\n\nTo protect your privacy the Haveno wallet ignores such dust outputs for spending purposes and in the balance display. You can set the threshold amount when an output is considered dust in the settings. +funds.tx.dustAttackTx.popup=This transaction is sending a very small XMR amount to your wallet and might be an attempt from chain analysis companies to spy on your wallet.\n\nIf you use that transaction output in a spending transaction they will learn that you are likely the owner of the other address as well (coin merge).\n\nTo protect your privacy the Haveno wallet ignores such dust outputs for spending purposes and in the balance display. You can set the threshold amount when an output is considered dust in the settings. #################################################################### # Support @@ -904,7 +928,6 @@ support.filter=Search disputes support.filter.prompt=Enter trade ID, date, onion address or account data support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -954,8 +977,7 @@ support.sellerMaker=فروشنده/سفارش گذار بیتکوین support.buyerTaker=خریدار/پذیرندهی بیتکوین support.sellerTaker=فروشنده/پذیرندهی بیتکوین -support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\nTraders can communicate within the application via secure chat on the open trades screen to try solving disputes on their own. If that is not sufficient, a mediator can step in to help. The mediator will evaluate the situation and suggest a payout of trade funds. If both traders accept this suggestion, the payout transaction is completed and the trade is closed. If one or both traders do not agree to the mediator's suggested payout, they can request arbitration.The arbitrator will re-evaluate the situation and, if warranted, personally pay the trader back and request reimbursement for this payment from Haveno. -support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the BTC buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the BTC seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} +support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the XMR buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the XMR seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} support.systemMsg=پیغام سیستم: {0} support.youOpenedTicket=شما یک درخواست برای پشتیبانی باز کردید.\n\n{0}\n\nنسخه Haveno شما: {1} support.youOpenedDispute=شما یک درخواست برای یک اختلاف باز کردید.\n\n{0}\n\nنسخه Haveno شما: {1} @@ -979,13 +1001,14 @@ settings.tab.network=اطلاعات شبکه settings.tab.about=درباره setting.preferences.general=اولویتهای عمومی -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=حداکثر تفاوت از قیمت روز بازار setting.preferences.avoidStandbyMode=حالت «آماده باش» را نادیده بگیر +setting.preferences.useSoundForNotifications=پخش صداها برای اعلانها setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=مقادیر بزرگتر از {0}% مجاز نیست. setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1022,11 +1045,13 @@ settings.preferences.editCustomExplorer.name=نام settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=شبکه بیتکوین +settings.net.xmrHeader=شبکه بیتکوین settings.net.p2pHeader=Haveno network settings.net.onionAddressLabel=آدرس onion من settings.net.xmrNodesLabel=استفاده از گرههای Monero اختصاصی settings.net.moneroPeersLabel=همتایان متصل +settings.net.connection=اتصال +settings.net.connected=متصل settings.net.useTorForXmrJLabel=استفاده از Tor برای شبکه مونرو settings.net.moneroNodesLabel=گرههای Monero در دسترس settings.net.useProvidedNodesRadio=استفاده از نودهای بیتکوین ارائه شده @@ -1035,16 +1060,16 @@ settings.net.useCustomNodesRadio=استفاده از نودهای بیتکوین settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=خیر، از نودهای فراهم شده استفاده کنید. settings.net.warn.usePublicNodes.usePublic=بلی، از شبکه عمومی استفاده کنید. -settings.net.warn.useCustomNodes.B2XWarning=لطفا مطمئن شوید که گره بیتکوین شما یک گره مورد اعتماد Bitcoin Core است!\n\nمتصل شدن به گرههایی که از قوانین مورد اجماع موجود در Bitcoin Core پیروی نمیکنند میتواند باعث خراب شدن کیف پول شما شود و در فرآیند معامله مشکلاتی را به وجود بیاورد.\n\nکاربرانی که از گرههای ناقض قوانین مورد اجماع استفاده میکند مسئول هر گونه آسیب ایجاد شده هستند. اگر هر گونه اختلافی به وجود بیاید به نفع دیگر گرههایی که از قوانین مورد اجماع پیروی میکنند درمورد آن تصمیم گیری خواهد شد. به کاربرانی که این هشدار و سازوکار محافظتی را نادیده میگیرند هیچگونه پشتیبانی فنی ارائه نخواهد شد! -settings.net.warn.invalidBtcConfig=Connection to the Bitcoin network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Bitcoin nodes instead. You will need to restart the application. -settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Bitcoin node when starting. If it is found, Haveno will communicate with the Bitcoin network exclusively through it. +settings.net.warn.useCustomNodes.B2XWarning=لطفا مطمئن شوید که گره بیتکوین شما یک گره مورد اعتماد Monero Core است!\n\nمتصل شدن به گرههایی که از قوانین مورد اجماع موجود در Monero Core پیروی نمیکنند میتواند باعث خراب شدن کیف پول شما شود و در فرآیند معامله مشکلاتی را به وجود بیاورد.\n\nکاربرانی که از گرههای ناقض قوانین مورد اجماع استفاده میکند مسئول هر گونه آسیب ایجاد شده هستند. اگر هر گونه اختلافی به وجود بیاید به نفع دیگر گرههایی که از قوانین مورد اجماع پیروی میکنند درمورد آن تصمیم گیری خواهد شد. به کاربرانی که این هشدار و سازوکار محافظتی را نادیده میگیرند هیچگونه پشتیبانی فنی ارائه نخواهد شد! +settings.net.warn.invalidXmrConfig=Connection to the Monero network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Monero nodes instead. You will need to restart the application. +settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Monero node when starting. If it is found, Haveno will communicate with the Monero network exclusively through it. settings.net.p2PPeersLabel=همتایان متصل settings.net.onionAddressColumn=آدرس Onion settings.net.creationDateColumn=تثبیت شده settings.net.connectionTypeColumn=درون/بیرون settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=تاخیر چرخشی settings.net.sentBytesColumn=ارسال شده settings.net.receivedBytesColumn=دریافت شده @@ -1059,7 +1084,7 @@ settings.net.needRestart=به منظور اعمال آن تغییر باید ب settings.net.notKnownYet=هنوز شناخته شده نیست ... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[آدرس آی پی: پورت | نام میزبان: پورت | آدرس Onion : پورت] (جدا شده با ویرگول). اگر از پیش فرض (8333) استفاده می شود، پورت می تواند حذف شود. settings.net.seedNode=گره ی اصلی settings.net.directPeer=همتا (مستقیم) @@ -1105,7 +1130,7 @@ setting.about.shortcuts.openDispute.value=Select pending trade and click: {0} setting.about.shortcuts.walletDetails=Open wallet details window -setting.about.shortcuts.openEmergencyBtcWalletTool=Open emergency wallet tool for BTC wallet +setting.about.shortcuts.openEmergencyXmrWalletTool=Open emergency wallet tool for XMR wallet setting.about.shortcuts.showTorLogs=Toggle log level for Tor messages between DEBUG and WARN @@ -1131,7 +1156,7 @@ setting.about.shortcuts.sendPrivateNotification=Send private notification to pee setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1165,7 @@ account.tab.mediatorRegistration=Mediator registration account.tab.refundAgentRegistration=Refund agent registration account.tab.signing=Signing account.info.headline=به حساب Haveno خود خوش آمدید -account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Bitcoin wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Bitcoin wallet seed words (see tab on the top) and consider adding a password before funding. Bitcoin deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Bitcoin addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). +account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Monero wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Monero wallet seed words (see tab on the top) and consider adding a password before funding. Monero deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Monero addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). account.menu.paymentAccount=حساب های ارز ملی account.menu.altCoinsAccountView=حساب های آلت کوین @@ -1151,7 +1176,7 @@ account.menu.backup=پشتیبان account.menu.notifications=اعلانها account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1180,7 +1205,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Trading ARQ on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending ARQ, you need to use either the official ArQmA GUI wallet or ArQmA CLI wallet with the store-tx-info flag enabled (default in new versions). Please be sure you can access the tx key as that would be required in case of a dispute.\narqma-wallet-cli (use the command get_tx_key)\narqma-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nAt normal block explorers the transfer is not verifiable.\n\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The ARQ sender is responsible for providing verification of the ARQ transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process visit ArQmA discord channel (https://discord.gg/s9BQpJT) or the ArQmA forum (https://labs.arqma.com) to find more information. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1233,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin on Haveno requires that you unde account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Trading L-BTC on Haveno requires that you understand the following:\n\nWhen receiving L-BTC for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-BTC into the Liquid Elements Core wallet, or another L-BTC wallet which allows you to obtain the blinding key for your blinded L-BTC address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-BTC address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-BTC receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-BTC on Haveno. +account.crypto.popup.liquidmonero.msg=Trading L-XMR on Haveno requires that you understand the following:\n\nWhen receiving L-XMR for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-XMR into the Liquid Elements Core wallet, or another L-XMR wallet which allows you to obtain the blinding key for your blinded L-XMR address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-XMR address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-XMR receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-XMR on Haveno. account.traditional.yourTraditionalAccounts=حسابهای ارزهای ملی شما @@ -1227,9 +1252,9 @@ account.password.removePw.headline=حذف رمز محافظ برای کیف پو account.password.setPw.button=تنظیم رمز account.password.setPw.headline=تنظیم رمز محافظ برای کیف پول account.password.info=در صورت فعال بودن حفاظت از رمز عبور، شما باید هنگام راهاندازی برنامه، در هنگام برداشت مونرو از کیف پول خود و هنگام نمایش کلمات اصلی نهال خود، رمز عبور خود را وارد کنید. -account.seed.backup.title=پشتیبان گیری از کلمات رمز خصوصی کیف های پول شما -account.seed.info=لطفا هم کلمات seed و هم تاریخ را یادداشت کنید! شما هر زمانی که بخواهید میتوانید کیفپولتان را با استفاده از کلمات seed و تاریخ بازیابی کنید.\nهمین کلمات seed برای کیفپولهای BTC و BSQ هم استفاده میشود.\n\nشما باید کلمات seed را روی یک برگ کاغذ یادداشت کنید. آنها را روی کامپیوتر خودتان ذخیره نکنید.\n\nلطفا توجه کنید که کلمات seed جایگزینی برای یک پشتیبان نیستند.\nبرای بازیابی وضعیت و دادههای برنامه باید از طریق صفحه \"Account/Backup\" از کل پوشه برنامه پشتیبان بسازید.\nوارد کردن کلمات seed فقط در موارد اورژانسی توصیه میشود. برنامه بدون پشتیبان از پایگاه داده و کلیدهای مناسب درست عمل نخواهد کرد! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=پشتیبانگیری از کلمات انگیزه کیف پول خود +account.seed.info=لطفاً همهی کلمات انگیزه کیف پول و تاریخ را یادداشت کنید. شما هر زمان که با کلمات انگیزه و تاریخ آنها را وارد کنید، میتوانید کیف پول خود را بازیابی کنید.\n\nشما باید کلمات انگیزه را روی یک ورق کاغذ یادداشت کنید. آنها را در کامپیوتر ذخیره نکنید.\n\nلطفاً توجه داشته باشید که کلمات انگیزه جایگزینی برای یک فایل پشتیبان نمیباشند.\nشما باید یک نسخه پشتیبان از کل دایرکتوری برنامه از صفحه \"حساب/پشتیبان\" ایجاد کنید تا وضعیت و دادههای برنامه را بازیابی کنید. +account.seed.backup.warning=لطفاً توجه داشته باشید که کلمات انگیزه جایگزینی برای یک فایل پشتیبان نمیباشند.\nشما باید یک نسخه پشتیبان از کل دایرکتوری برنامه از صفحه "حساب/پشتیبان" ایجاد کنید تا وضعیت و دادههای برنامه را بازیابی کنید. account.seed.warn.noPw.msg=شما یک رمز عبور کیف پول تنظیم نکرده اید که از نمایش کلمات رمز خصوصی محافظت کند.\n\nآیا می خواهید کلمات رمز خصوصی نشان داده شود؟ account.seed.warn.noPw.yes=بلی، و دوباره از من نپرس account.seed.enterPw=وارد کردن رمز عبور به منظور مشاهده ی کلمات رمز خصوصی @@ -1258,13 +1283,13 @@ account.notifications.trade.label=دریافت پیامهای معامله account.notifications.market.label=دریافت هشدارهای مربوط به پیشنهادها account.notifications.price.label=دریافت هشدارهای مربوط به قیمت account.notifications.priceAlert.title=هشدارهای قیمت -account.notifications.priceAlert.high.label=با خبر کردن در صورتی که قیمت BTC بالاتر باشد -account.notifications.priceAlert.low.label=با خبر کردن در صورتی که قیمت BTC پایینتر باشد +account.notifications.priceAlert.high.label=با خبر کردن در صورتی که قیمت XMR بالاتر باشد +account.notifications.priceAlert.low.label=با خبر کردن در صورتی که قیمت XMR پایینتر باشد account.notifications.priceAlert.setButton=تنظیم هشدار قیمت account.notifications.priceAlert.removeButton=حذف هشدار قیمت account.notifications.trade.message.title=تغییر وضعیت معامله account.notifications.trade.message.msg.conf=تراکنش سپرده برای معامله با شناسه {0} تایید شده است. لطفا برنامه Haveno خود را بازکنید و پرداخت را شروع کنید. -account.notifications.trade.message.msg.started=خریدار BTC پرداخت با شناسه {0} را آغاز کرده است. +account.notifications.trade.message.msg.started=خریدار XMR پرداخت با شناسه {0} را آغاز کرده است. account.notifications.trade.message.msg.completed=معامله با شناسه {0} انجام شد. account.notifications.offer.message.title=پیشنهاد شما پذیرفته شد account.notifications.offer.message.msg=پیشنهاد شما با شناسه {0} پذیرفته شد @@ -1274,10 +1299,10 @@ account.notifications.dispute.message.msg=شما یک پیغام مرتبط با account.notifications.marketAlert.title=هشدارهای مربوط به پیشنهادها account.notifications.marketAlert.selectPaymentAccount=پیشنهادهای مرتبط با حساب پرداخت account.notifications.marketAlert.offerType.label=نوع پیشنهادهایی که من به آنها علاقمندم -account.notifications.marketAlert.offerType.buy=پیشنهادهای خرید (میخواهم BTC بفروشم) -account.notifications.marketAlert.offerType.sell=پیشنهادهای فروش (میخواهم BTC بخرم) +account.notifications.marketAlert.offerType.buy=پیشنهادهای خرید (میخواهم XMR بفروشم) +account.notifications.marketAlert.offerType.sell=پیشنهادهای فروش (میخواهم XMR بخرم) account.notifications.marketAlert.trigger=فاصله قیمتی پیشنهاد (%) -account.notifications.marketAlert.trigger.info=با تنظیم یک فاصله قیمتی، تنها در صورتی هشدار دریافت میکنید که پیشنهادی با پیشنیازهای شما (یا بهتر از آن) منتشر بشود. برای مثال: شما میخواهید BTC بفروشید، ولی میخواهید با 2% حق صراف نسبت به قیمت بازار آن را بفروشید. تنظیم این فیلد روی 2% به شما این اطمینان را میدهد که تنها بابت پیشنهادهایی هشدار دریافت کنید که حداقل 2% (یا بیشتر) بالای قیمت فعلی بازار هستند. +account.notifications.marketAlert.trigger.info=با تنظیم یک فاصله قیمتی، تنها در صورتی هشدار دریافت میکنید که پیشنهادی با پیشنیازهای شما (یا بهتر از آن) منتشر بشود. برای مثال: شما میخواهید XMR بفروشید، ولی میخواهید با 2% حق صراف نسبت به قیمت بازار آن را بفروشید. تنظیم این فیلد روی 2% به شما این اطمینان را میدهد که تنها بابت پیشنهادهایی هشدار دریافت کنید که حداقل 2% (یا بیشتر) بالای قیمت فعلی بازار هستند. account.notifications.marketAlert.trigger.prompt=درصد فاصله از قیمت بازار (برای مثال 2.50%, -0.50%) account.notifications.marketAlert.addButton=اضافه کردن هشدار برای پیشنهادها account.notifications.marketAlert.manageAlertsButton=مدیریت هشدارهای مربوط به پیشنهادها @@ -1304,10 +1329,10 @@ inputControlWindow.balanceLabel=موجودی در دسترس contractWindow.title=جزئیات مناقشه contractWindow.dates=تاریخ پیشنهاد / تاریخ معامله -contractWindow.btcAddresses=آدرس بیتکوین خریدار BTC / فروشنده BTC -contractWindow.onions=آدرس شبکه خریدار BTC / فروشنده BTC -contractWindow.accountAge=Account age BTC buyer / BTC seller -contractWindow.numDisputes=تعداد اختلافات خریدار BTC / فروشنده BTC +contractWindow.xmrAddresses=آدرس بیتکوین خریدار XMR / فروشنده XMR +contractWindow.onions=آدرس شبکه خریدار XMR / فروشنده XMR +contractWindow.accountAge=Account age XMR buyer / XMR seller +contractWindow.numDisputes=تعداد اختلافات خریدار XMR / فروشنده XMR contractWindow.contractHash=هش قرارداد displayAlertMessageWindow.headline=اطلاعات مهم! @@ -1333,8 +1358,8 @@ disputeSummaryWindow.title=خلاصه disputeSummaryWindow.openDate=تاریخ ایجاد تیکت disputeSummaryWindow.role=نقش معامله گر disputeSummaryWindow.payout=پرداختی مقدار معامله -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} پرداختی مبلغ معامله را دریافت می کند -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} پرداختی مبلغ معامله را دریافت می کند +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=پرداخت سفارشی disputeSummaryWindow.payoutAmount.buyer=مقدار پرداختی خریدار disputeSummaryWindow.payoutAmount.seller=مقدار پرداختی فروشنده @@ -1376,7 +1401,7 @@ disputeSummaryWindow.close.button=بستن تیکت # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1426,11 +1451,11 @@ filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addre filterWindow.disableTradeBelowVersion=Min. version required for trading filterWindow.add=افزودن فیلتر filterWindow.remove=حذف فیلتر -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=حداقل مقدار BTC +offerDetailsWindow.minXmrAmount=حداقل مقدار XMR offerDetailsWindow.min=(حداقل {0}) offerDetailsWindow.distance=(فاصله از قیمت روز بازار: {0}) offerDetailsWindow.myTradingAccount=حساب معاملاتی من @@ -1445,6 +1470,7 @@ offerDetailsWindow.confirm.maker=تأیید: پیشنهاد را به {0} بگذ offerDetailsWindow.confirm.taker=تأیید: پیشنهاد را به {0} بپذیرید offerDetailsWindow.creationDate=تاریخ ایجاد offerDetailsWindow.makersOnion=آدرس Onion سفارش گذار +offerDetailsWindow.challenge=Passphrase de l'offre qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1473,7 +1499,7 @@ showWalletDataWindow.walletData=داده های کیف پول showWalletDataWindow.includePrivKeys=شامل کلیدهای خصوصی setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1495,8 +1521,10 @@ tradeDetailsWindow.agentAddresses=Arbitrator/Mediator tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=شما XMR ارسال کردهاید. +txDetailsWindow.xmr.noteReceived=شما XMR دریافت کردهاید. +txDetailsWindow.sentTo=ارسال به +txDetailsWindow.receivedWith=دریافت با txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1505,7 +1533,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=وارد کردن رمز عبور به منظور باز کردن @@ -1531,12 +1559,12 @@ torNetworkSettingWindow.bridges.header=آیا Tor مسدود شده است؟ torNetworkSettingWindow.bridges.info=اگر Tor توسط ارائه دهنده اینترنت شما یا توسط کشور شما مسدود شده است، شما می توانید از پل های Tor استفاده کنید.\nاز صفحه وب Tor در https://bridges.torproject.org/bridges دیدن کنید تا مطالب بیشتری در مورد پل ها و نقل و انتقالات قابل اتصال یاد بگیرید. feeOptionWindow.headline=انتخاب ارز برای پرداخت هزینه معامله -feeOptionWindow.info=شما می توانید انتخاب کنید که هزینه معامله را در BSQ یا در BTC بپردازید. اگر BSQ را انتخاب می کنید، از تخفیف هزینه معامله برخوردار می شوید. +feeOptionWindow.info=شما می توانید انتخاب کنید که هزینه معامله را در BSQ یا در XMR بپردازید. اگر BSQ را انتخاب می کنید، از تخفیف هزینه معامله برخوردار می شوید. feeOptionWindow.optionsLabel=انتخاب ارز برای پرداخت کارمزد معامله -feeOptionWindow.useBTC=استفاده از BTC +feeOptionWindow.useXMR=استفاده از XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1578,9 +1606,9 @@ popup.warning.noTradingAccountSetup.msg=قبل از اینکه بتوانید ی popup.warning.noArbitratorsAvailable=هیچ داوری در دسترس نیست. popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=شما باید منتظر بمانید تا به طور کامل به شبکه متصل شوید. \nاین ممکن است در هنگام راه اندازی حدود 2 دقیقه طول بکشد. -popup.warning.notSufficientConnectionsToBtcNetwork=شما باید منتظر بمانید تا حداقل {0} اتصال به شبکه بیتکوین داشته باشید. +popup.warning.notSufficientConnectionsToXmrNetwork=شما باید منتظر بمانید تا حداقل {0} اتصال به شبکه بیتکوین داشته باشید. popup.warning.downloadNotComplete=شما باید منتظر بمانید تا بارگیری بلاک های بیتکوین باقیمانده کامل شود. -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.walletNotSynced=کیف پول Haveno با ارتفاع آخرین بلوکچین هماهنگ نشده است. لطفاً منتظر بمانید تا کیف پول هماهنگ شود یا اتصال خود را بررسی کنید. popup.warning.removeOffer=آیا شما مطمئن هستید که می خواهید این پیشنهاد را حذف کنید؟ popup.warning.tooLargePercentageValue=شما نمیتوانید درصد 100٪ یا بیشتر را تنظیم کنید. popup.warning.examplePercentageValue=لطفا یک عدد درصد مانند \"5.4\" برای 5.4% وارد کنید @@ -1599,14 +1627,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=رله قیمت popup.warning.seed=دانه popup.warning.mandatoryUpdate.trading=Please update to the latest Haveno version. A mandatory update was released which disables trading for old versions. Please check out the Haveno Forum for more information. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=This transaction is not possible, as the mining fees of {0} would exceed the amount to transfer of {1}. Please wait until the mining fees are low again or until you''ve accumulated more BTC to transfer. +popup.warning.burnXMR=This transaction is not possible, as the mining fees of {0} would exceed the amount to transfer of {1}. Please wait until the mining fees are low again or until you''ve accumulated more XMR to transfer. -popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Bitcoin network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Monero network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. @@ -1615,7 +1642,7 @@ popup.info.securityDepositInfo=برای اطمینان از اینکه هر دو popup.info.cashDepositInfo=لطفا مطمئن شوید که شما یک شعبه بانک در منطقه خود دارید تا بتوانید سپرده نقدی را بپردازید. شناسه بانکی (BIC/SWIFT) بانک فروشنده: {0}. popup.info.cashDepositInfo.confirm=تأیید می کنم که می توانم سپرده را ایجاد کنم popup.info.shutDownWithOpenOffers=Haveno در حال خاموش شدن است ولی پیشنهاداتی وجود دارند که باز هستند.\n\nزمانی که Haveno بسته باشد این پیشنهادات در شبکه P2P در دسترس نخواهند بود، ولی هر وقت دوباره Haveno را باز کنید این پیشنهادات دوباره در شبکه P2P منتشر خواهند شد.\n\n برای اینکه پیشنهادات شما برخط بمانند، بگذارید Haveno در حال اجرابماند و همچنین مطمئن شوید که این کامپیوتر به اینترنت متصل است. (به عنوان مثال مطمئن شوید که به حالت آماده باش نمیرود.. البته حالت آماده باش برای نمایشگر ایرادی ندارد). -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=اعلان خصوصی مهم! @@ -1667,6 +1694,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=هیچ پیشپرداختی از خریدار مورد نیاز نیست +popup.info.buyerAsTakerWithoutDeposit=پیشنهاد شما نیاز به ودیعه امنیتی یا هزینه از خریدار XMR ندارد.\n\nبرای پذیرفتن پیشنهاد شما، باید یک پسعبارت را با شریک تجاری خود خارج از Haveno به اشتراک بگذارید.\n\nپسعبارت بهطور خودکار تولید میشود و پس از ایجاد در جزئیات پیشنهاد نمایش داده میشود. + #################################################################### # Notifications #################################################################### @@ -1674,9 +1704,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign notification.trade.headline=اعلان برای معامله با شناسه {0} notification.ticket.headline=تیکت پشتیبانی برای معامله با شناسه {0} notification.trade.completed=معامله اکنون کامل شده است و می توانید وجوه خود را برداشت کنید. -notification.trade.accepted=پیشنهاد شما توسط BTC {0} پذیرفته شده است. +notification.trade.accepted=پیشنهاد شما توسط XMR {0} پذیرفته شده است. notification.trade.unlocked=معامله شما دارای حداقل یک تایید بلاک چین است.\n شما اکنون می توانید پرداخت را شروع کنید. -notification.trade.paymentSent=خریدار BTC پرداخت را آغاز کرده است. +notification.trade.paymentSent=خریدار XMR پرداخت را آغاز کرده است. notification.trade.selectTrade=انتخاب معامله notification.trade.peerOpenedDispute=همتای معامله شما یک {0} را باز کرده است. notification.trade.disputeClosed={0} بسته شده است. @@ -1695,7 +1725,7 @@ systemTray.show=نمایش پنجره ی برنامه systemTray.hide=مخفی کردن پنجره ی برنامه systemTray.info=اطلاعات درباره ی Haveno systemTray.exit=خروج -systemTray.tooltip=Haveno: A decentralized bitcoin exchange network +systemTray.tooltip=Haveno: A decentralized monero exchange network #################################################################### @@ -1746,7 +1776,7 @@ tooltip.openBlockchainForTx=باز کردن مرورگر بلاک چین خار confidence.unknown=وضعیت معامله ناشناخته confidence.seen=دیده شده توسط {0} همتا (s) / تأیید 0 -confidence.confirmed=تأیید شده در {0} بلاک(s) +confidence.confirmed=تأیید {0} confidence.invalid=تراکنش نامعتبر است peerInfo.title=اطلاعات همتا @@ -1792,6 +1822,7 @@ navigation.support=\"پشتیبانی\" formatter.formatVolumeLabel={0} مبلغ {1} formatter.makerTaker=سفارش گذار به عنوان {0} {1} / پذیرنده به عنوان {2} {3} +formatter.makerTakerLocked=سفارش گذار به عنوان {0} {1} / پذیرنده به عنوان {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=شما {0} {1} ({2} {3}) هستید @@ -1837,7 +1868,6 @@ password.deriveKey=کلید را از رمز عبور استنتاج کنید password.walletDecrypted=کیف پول با موفقیت رمزگشایی شد و حفاظت با رمز عبور حذف شد. password.wrongPw=شما رمز عبور را اشتباه وارد کرده اید.\n\n لطفا سعی کنید رمز عبور خود را وارد کنید و با دقت خطاها و اشتباهات املایی را بررسی کنید. password.walletEncrypted=کیف پول به طور موفقیت آمیز کدگذاری و حفاظت کیف پول فعال شد. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=2 رمز عبوری که وارد نموده اید باهم مطابقت ندارند. password.forgotPassword=رمز عبور را فراموش کرده اید؟ password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1851,7 +1881,7 @@ seed.date=تاریخ کیفپول seed.restore.title=بازگرداندن کیف های پول از کلمات رمز خصوصی seed.restore=بازگرداندن کیف های پول seed.creationDate=تاریخ ایجاد -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=میخواهم به هر حال بازگردانی کنم seed.warn.walletNotEmpty.emptyWallet=من ابتدا کیف پول هایم را خالی می کنم seed.warn.notEncryptedAnymore=کیف های پول شما رمزگذاری شده اند. \n\nپس از بازگرداندن، کیف های پول دیگر رمزگذاری نخواهند شد و شما باید رمز عبور جدید را تنظیم کنید.\n\n آیا می خواهید ادامه دهید؟ @@ -1868,7 +1898,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=حساب payment.account.no=شماره حساب payment.account.name=نام حساب -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=نام کامل مالک حساب payment.account.fullName=نام کامل (اول، وسط، آخر) @@ -1900,7 +1930,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=نام کاربری یا ایمیل یا شماره تلفن payment.moneyBeam.accountId=ایمیل یا شماره تلفن -payment.venmo.venmoUserName=نام کاربری Venmo payment.popmoney.accountId=ایمیل یا شماره تلفن payment.promptPay.promptPayId=شناسه شهروندی/شناسه مالیاتی یا شماره تلفن payment.supportedCurrencies=ارزهای مورد حمایت @@ -1942,28 +1971,28 @@ payment.checking=بررسی payment.savings=اندوخته ها payment.personalId=شناسه شخصی payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Haveno to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=زمانی که از HalCash استفاده میکنید، خریدار باید کد HalCash را از طریق پیام کوتاه موبایل به فروشنده BTC ارسال کند.\n\nلطفا مطمئن شوید که از حداکثر میزانی که بانک شما برای انتقال از طریق HalCash مجاز میداند تجاوز نکردهاید. حداقل مقداردر هر برداشت معادل 10 یورو و حداکثر مقدار 600 یورو میباشد. این محدودیت برای برداشتهای تکراری برای هر گیرنده در روز 3000 یورو و در ماه 6000 یورو میباشد. لطفا این محدودیتها را با بانک خود مطابقت دهید و مطمئن شوید که آنها هم همین محدودیها را دارند.\n\nمقدار برداشت باید شریبی از 10 یورو باشد چرا که مقادیر غیر از این را نمیتوانید از طریق ATM برداشت کنید. رابط کاربری در صفحه ساخت پینشهاد و پذیرش پیشنهاد مقدار BTC را به گونهای تنظیم میکنند که مقدار EUR درست باشد. شما نمیتوانید از قیمت بر مبنای بازار استفاده کنید چون مقدار یورو با تغییر قیمتها عوض خواهد شد.\n\nدر صورت بروز اختلاف خریدار BTC باید شواهد مربوط به ارسال یورو را ارائه دهد. +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=زمانی که از HalCash استفاده میکنید، خریدار باید کد HalCash را از طریق پیام کوتاه موبایل به فروشنده XMR ارسال کند.\n\nلطفا مطمئن شوید که از حداکثر میزانی که بانک شما برای انتقال از طریق HalCash مجاز میداند تجاوز نکردهاید. حداقل مقداردر هر برداشت معادل 10 یورو و حداکثر مقدار 600 یورو میباشد. این محدودیت برای برداشتهای تکراری برای هر گیرنده در روز 3000 یورو و در ماه 6000 یورو میباشد. لطفا این محدودیتها را با بانک خود مطابقت دهید و مطمئن شوید که آنها هم همین محدودیها را دارند.\n\nمقدار برداشت باید شریبی از 10 یورو باشد چرا که مقادیر غیر از این را نمیتوانید از طریق ATM برداشت کنید. رابط کاربری در صفحه ساخت پینشهاد و پذیرش پیشنهاد مقدار XMR را به گونهای تنظیم میکنند که مقدار EUR درست باشد. شما نمیتوانید از قیمت بر مبنای بازار استفاده کنید چون مقدار یورو با تغییر قیمتها عوض خواهد شد.\n\nدر صورت بروز اختلاف خریدار XMR باید شواهد مربوط به ارسال یورو را ارائه دهد. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=لطفا مطمئن شوید که بانک شما اجازه پرداخت سپرده نفد به حساب دیگر افراد را میدهد. برای مثال، Bank of America و Wells Fargo دیگر اجازه چنین پرداختهایی را نمیدهند. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=اطلاعات تماس payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1974,7 +2003,7 @@ payment.f2f.city.prompt=نام شهر به همراه پیشنهاد نمایش payment.shared.optionalExtra=اطلاعات اضافی اختیاری payment.shared.extraInfo=اطلاعات اضافی payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=باز کردن صفحه وب payment.f2f.offerbook.tooltip.countryAndCity=Country and city: {0} / {1} payment.f2f.offerbook.tooltip.extra=اطلاعات اضافی: {0} @@ -1986,7 +2015,7 @@ payment.japan.recipient=نام payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2144,7 +2173,7 @@ validation.zero=ورودی 0 مجاز نیست. validation.negative=یک مقدار منفی مجاز نیست. validation.traditional.tooSmall=ورودی کوچکتر از حداقل مقدار ممکن مجاز نیست. validation.traditional.tooLarge=ورودی بزرگتر از حداکثر مقدار ممکن مجاز نیست. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=ورودی بزرگتر از {0} مجاز نیست. validation.xmr.tooSmall=ورودی کوچکتر از {0} مجاز نیست. validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2154,10 +2183,10 @@ validation.sortCodeChars={0} باید شامل {1} کاراکتر باشد. validation.bankIdNumber={0} باید شامل {1} عدد باشد. validation.accountNr=عدد حساب باید متشکل از {0} عدد باشد. validation.accountNrChars=عدد حساب باید متشکل از {0} کاراکتر باشد. -validation.btc.invalidAddress=آدرس درست نیست. لطفا فرمت آدرس را بررسی کنید +validation.xmr.invalidAddress=آدرس درست نیست. لطفا فرمت آدرس را بررسی کنید validation.integerOnly=لطفا فقط اعداد صحیح را وارد کنید. validation.inputError=ورودی شما یک خطا ایجاد کرد: {0} -validation.btc.exceedsMaxTradeLimit=حدمعامله شما {0} است. +validation.xmr.exceedsMaxTradeLimit=حدمعامله شما {0} است. validation.nationalAccountId={0} باید شامل {1} عدد باشد. #new diff --git a/core/src/main/resources/i18n/displayStrings_fr.properties b/core/src/main/resources/i18n/displayStrings_fr.properties index c095a3fdf1..2712ff4163 100644 --- a/core/src/main/resources/i18n/displayStrings_fr.properties +++ b/core/src/main/resources/i18n/displayStrings_fr.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Je comprends shared.na=N/A shared.shutDown=Éteindre shared.reportBug=Signaler le bug sur Github -shared.buyBitcoin=Achat Bitcoin -shared.sellBitcoin=Vendre des Bitcoins +shared.buyMonero=Achat Monero +shared.sellMonero=Vendre des Moneros shared.buyCurrency=Achat {0} shared.sellCurrency=Vendre {0} -shared.buyingBTCWith=achat BTC avec {0} -shared.sellingBTCFor=vendre BTC pour {0} -shared.buyingCurrency=achat {0} (vente BTC) -shared.sellingCurrency=vente {0} (achat BTC) +shared.buyCurrencyLocked=Achat {0} 🔒 +shared.sellCurrencyLocked=Vendre {0} 🔒 +shared.buyingXMRWith=achat XMR avec {0} +shared.sellingXMRFor=vendre XMR pour {0} +shared.buyingCurrency=achat {0} (vente XMR) +shared.sellingCurrency=vente {0} (achat XMR) shared.buy=acheter shared.sell=vendre shared.buying=achat @@ -93,7 +95,7 @@ shared.amountMinMax=Montant (min-max) shared.amountHelp=Si un ordre comporte un montant minimum et un montant maximum, alors vous pouvez échanger n'importe quel montant dans cette fourchette. shared.remove=Enlever shared.goTo=Aller à {0} -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Retirer l'ordre shared.dontRemoveOffer=Ne pas retirer l'ordre shared.editOffer=Éditer l'ordre @@ -103,16 +105,16 @@ shared.faq=Visitez la page FAQ shared.yesCancel=Oui, annuler shared.nextStep=Étape suivante shared.selectTradingAccount=Sélectionner le compte de trading -shared.fundFromSavingsWalletButton=Transférer des fonds depuis le portefeuille Haveno +shared.fundFromSavingsWalletButton=Appliquer les fonds depuis le portefeuille Haveno shared.fundFromExternalWalletButton=Ouvrez votre portefeuille externe pour provisionner -shared.openDefaultWalletFailed=L'ouverture de l'application de portefeuille Bitcoin par défaut a échoué. Êtes-vous sûr de l'avoir installée? +shared.openDefaultWalletFailed=L'ouverture de l'application de portefeuille Monero par défaut a échoué. Êtes-vous sûr de l'avoir installée? shared.belowInPercent=% sous le prix du marché shared.aboveInPercent=% au-dessus du prix du marché shared.enterPercentageValue=Entrez la valeur en % shared.OR=OU -shared.notEnoughFunds=Il n'y a pas suffisamment de fonds dans votre portefeuille Haveno pour payer cette transaction. La transaction a besoin de {0} Votre solde disponible est de {1}. \n\nVeuillez ajouter des fonds à partir d'un portefeuille Bitcoin externe ou recharger votre portefeuille Haveno dans «Fonds / Dépôts > Recevoir des Fonds». +shared.notEnoughFunds=Il n'y a pas suffisamment de fonds dans votre portefeuille Haveno pour payer cette transaction. La transaction a besoin de {0} Votre solde disponible est de {1}. \n\nVeuillez ajouter des fonds à partir d'un portefeuille Monero externe ou recharger votre portefeuille Haveno dans «Fonds / Dépôts > Recevoir des Fonds». shared.waitingForFunds=En attente des fonds... -shared.TheBTCBuyer=L'acheteur de BTC +shared.TheXMRBuyer=L'acheteur de XMR shared.You=Vous shared.sendingConfirmation=Envoi de la confirmation... shared.sendingConfirmationAgain=Veuillez envoyer de nouveau la confirmation @@ -123,9 +125,8 @@ shared.noDateAvailable=Pas de date disponible shared.noDetailsAvailable=Pas de détails disponibles shared.notUsedYet=Pas encore utilisé shared.date=Date -shared.sendFundsDetailsWithFee=Envoi: {0}\nDepuis l'adresse: {1}\nVers l'adresse de réception: {2}\nLes frais de minage requis sont : {3} ({4} satoshis/byte)\nVsize de la transaction: {5} vKb\n\nLe destinataire recevra: {6}\n\nÊtes-vous certain de vouloir retirer ce montant? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno détecte que la transaction produira une sortie inférieure au seuil de fraction minimum (non autorisé par les règles de consensus Bitcoin). Au lieu de cela, ces fractions ({0} satoshi {1}) seront ajoutées aux frais de traitement minier.\n\n\n +shared.sendFundsDetailsDust=Haveno détecte que la transaction produira une sortie inférieure au seuil de fraction minimum (non autorisé par les règles de consensus Monero). Au lieu de cela, ces fractions ({0} satoshi {1}) seront ajoutées aux frais de traitement minier.\n\n\n shared.copyToClipboard=Copier dans le presse-papiers shared.language=Langue shared.country=Pays @@ -140,6 +141,7 @@ shared.addNewAccount=Ajouter un nouveau compte shared.ExportAccounts=Exporter les comptes shared.importAccounts=Importer les comptes shared.createNewAccount=Créer un nouveau compte +shared.createNewAccountDescription=Les détails de votre compte sont stockés localement sur votre appareil et partagés uniquement avec votre pair de trading et l'arbitre si un litige est ouvert. shared.saveNewAccount=Sauvegarder un nouveau compte shared.selectedAccount=Sélectionner un compte shared.deleteAccount=Supprimer le compte @@ -169,7 +171,7 @@ shared.payoutTxId=ID du versement de la transaction shared.contractAsJson=Contrat au format JSON shared.viewContractAsJson=Voir le contrat en format JSON shared.contract.title=Contrat pour la transaction avec l''ID : {0} -shared.paymentDetails=BTC {0} détails du paiement +shared.paymentDetails=XMR {0} détails du paiement shared.securityDeposit=Dépôt de garantie shared.yourSecurityDeposit=Votre dépôt de garantie shared.contract=Contrat @@ -179,19 +181,21 @@ shared.messageSendingFailed=Échec de l''envoi du message. Erreur: {0} shared.unlock=Déverrouiller shared.toReceive=à recevoir shared.toSpend=à dépenser -shared.btcAmount=Montant en BTC +shared.xmrAmount=Montant en XMR shared.yourLanguage=Vos langues shared.addLanguage=Ajouter une langue shared.total=Total shared.totalsNeeded=Fonds nécessaires shared.tradeWalletAddress=Adresse du portefeuille de trading shared.tradeWalletBalance=Solde du portefeuille de trading +shared.reserveExactAmount=Réservez uniquement les fonds nécessaires. Nécessite des frais de minage et environ 20 minutes avant que votre offre ne soit mise en ligne. shared.makerTxFee=Maker: {0} shared.takerTxFee=Taker: {0} shared.iConfirm=Je confirme shared.openURL=Ouvert {0} shared.fiat=Fiat shared.crypto=Crypto +shared.preciousMetals=Métaux précieux shared.all=Tout shared.edit=Modifier shared.advancedOptions=Options avancées @@ -226,8 +230,8 @@ shared.enabled=Activé #################################################################### mainView.menu.market=Marché -mainView.menu.buyBtc=Achat BTC -mainView.menu.sellBtc=Vendre des BTC +mainView.menu.buyXmr=Achat XMR +mainView.menu.sellXmr=Vendre des XMR mainView.menu.portfolio=Portfolio mainView.menu.funds=Fonds mainView.menu.support=Assistance @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Réservé mainView.balance.pending.short=Vérouillé mainView.footer.usingTor=(à travers Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(à travers clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Taux des frais: {0} sat/vB -mainView.footer.xmrInfo.initializing=Connexion au réseau Bitcoin en cours -mainView.footer.xmrInfo.synchronizingWith=Synchronisation avec {0} au block: {1}/ {2} -mainView.footer.xmrInfo.synchronizedWith=Synchronisé avec {0} au block {1} +mainView.footer.xmrFeeRate=/ Taux des frais: {0} sat/vB +mainView.footer.xmrInfo.initializing=Connexion au réseau Haveno en cours +mainView.footer.xmrInfo.synchronizingWith=Synchronisation avec {0} au bloc : {1} / {2} +mainView.footer.xmrInfo.connectedTo=Connecté à {0} au bloc {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Synchronisation du portefeuille avec {0} au bloc : {1} / {2} +mainView.footer.xmrInfo.syncedWith=Synchronisé avec {0} au bloc {1} mainView.footer.xmrInfo.connectingTo=Se connecte à mainView.footer.xmrInfo.connectionFailed=Échec de la connexion à mainView.footer.xmrPeers=Pairs du réseau Monero: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=L'initialisation du réseau H mainView.p2pNetworkWarnMsg.noNodesAvailable=Il n'y a pas de noeud de seed ou de persisted pairs disponibles pour demander des données.\nVeuillez vérifier votre connexion Internet ou essayer de redémarrer l'application. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=La connexion au réseau Haveno a échoué (erreur signalé: {0}).\nVeuillez vérifier votre connexion internet ou essayez de redémarrer l'application. -mainView.walletServiceErrorMsg.timeout=La connexion au réseau Bitcoin a échoué car le délai d'attente a expiré. -mainView.walletServiceErrorMsg.connectionError=La connexion au réseau Bitcoin a échoué à cause d''une erreur: {0} +mainView.walletServiceErrorMsg.timeout=La connexion au réseau Monero a échoué car le délai d'attente a expiré. +mainView.walletServiceErrorMsg.connectionError=La connexion au réseau Monero a échoué à cause d''une erreur: {0} mainView.walletServiceErrorMsg.rejectedTxException=Le réseau a rejeté une transaction.\n\n{0} mainView.networkWarning.allConnectionsLost=Vous avez perdu la connexion avec tous les {0} pairs du réseau.\nVous avez peut-être perdu votre connexion Internet ou votre ordinateur était passé en mode veille. -mainView.networkWarning.localhostBitcoinLost=Vous avez perdu la connexion avec le localhost Bitcoin node.\nVeuillez redémarrer l'application Haveno pour vous connecter à d'autres Bitcoin nodes ou redémarrer le localhost Bitcoin node. +mainView.networkWarning.localhostMoneroLost=Vous avez perdu la connexion avec le localhost Monero node.\nVeuillez redémarrer l'application Haveno pour vous connecter à d'autres Monero nodes ou redémarrer le localhost Monero node. mainView.version.update=(Mise à jour disponible) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=Achat {0} market.offerBook.sellWithTraditional=Vente {0} market.offerBook.sellOffersHeaderLabel=Vendre des {0} à market.offerBook.buyOffersHeaderLabel=Acheter des {0} à -market.offerBook.buy=Je veux acheter des Bitcoins -market.offerBook.sell=Je veux vendre des Bitcoins +market.offerBook.buy=Je veux acheter des Moneros +market.offerBook.sell=Je veux vendre des Moneros # SpreadView market.spread.numberOfOffersColumn=Tout les ordres ({0}) -market.spread.numberOfBuyOffersColumn=Achat BTC ({0}) -market.spread.numberOfSellOffersColumn=Vente BTC ({0}) -market.spread.totalAmountColumn=Total BTC ({0}) +market.spread.numberOfBuyOffersColumn=Achat XMR ({0}) +market.spread.numberOfSellOffersColumn=Vente XMR ({0}) +market.spread.totalAmountColumn=Total XMR ({0}) market.spread.spreadColumn=Écart market.spread.expanded=Vue étendue @@ -325,6 +332,7 @@ offerbook.createOffer=Créer un ordre offerbook.takeOffer=Accepter un ordre offerbook.takeOfferToBuy=Accepter l''ordre d''achat {0} offerbook.takeOfferToSell=Accepter l''ordre de vente {0} +offerbook.takeOffer.enterChallenge=Entrez la phrase secrète de l'offre offerbook.trader=Échanger offerbook.offerersBankId=ID de la banque du maker (BIC/SWIFT): {0} offerbook.offerersBankName=Nom de la banque du maker: {0} @@ -335,6 +343,8 @@ offerbook.availableOffers=Ordres disponibles offerbook.filterByCurrency=Filtrer par devise offerbook.filterByPaymentMethod=Filtrer par mode de paiement offerbook.matchingOffers=Offres correspondants à mes comptes +offerbook.filterNoDeposit=Aucun dépôt +offerbook.noDepositOffers=Offres sans dépôt (passphrase requise) offerbook.timeSinceSigning=Informations du compte offerbook.timeSinceSigning.info=Ce compte a été vérifié et {0} offerbook.timeSinceSigning.info.arbitrator=signé par un arbitre et pouvant signer des comptes pairs @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=Ce compte a été banni offerbook.timeSinceSigning.daysSinceSigning={0} jours offerbook.timeSinceSigning.daysSinceSigning.long={0} depuis la signature offerbook.xmrAutoConf=Est-ce-que la confirmation automatique est activée +offerbook.buyXmrWith=Acheter XMR avec : +offerbook.sellXmrFor=Vendre XMR pour : offerbook.timeSinceSigning.help=Lorsque vous effectuez avec succès une transaction avec un pair disposant d''un compte de paiement signé, votre compte de paiement est signé.\n{0} Jours plus tard, la limite initiale de {1} est levée et votre compte peut signer les comptes de paiement d''un autre pair. offerbook.timeSinceSigning.notSigned=Pas encore signé @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Les comptes pour crypto ne supportent pas la signatu offerbook.nrOffers=Nombre d''ordres: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Déposer BTC (%) +offerbook.deposit=Déposer XMR (%) offerbook.deposit.help=Les deux parties à la transaction ont payé un dépôt pour assurer que la transaction se déroule normalement. Ce montant sera remboursé une fois la transaction terminée. +offerbook.createNewOffer=Créer une offre à {0} {1} offerbook.createOfferToBuy=Créer un nouvel ordre d''achat pour {0} offerbook.createOfferToSell=Créer un nouvel ordre de vente pour {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=Grâce à cette version du logiciel, le popup.warning.tradeLimitDueAccountAgeRestriction.seller=Le montant de transaction autorisé est limité à {0} en raison des restrictions de sécurité basées sur les critères suivants:\n- Le compte de l''acheteur n''a pas été signé par un arbitre ou par un pair\n- Le délai depuis la signature du compte de l''acheteur est inférieur à 30 jours\n- Le mode de paiement pour cette offre est considéré comme présentant un risque de rétrofacturation bancaire\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=Le montant de transaction autorisé est limité à {0} en raison des restrictions de sécurité basées sur les critères suivants:\n- Votre compte n''a pas été signé par un arbitre ou par un pair\n- Le délai depuis la signature de votre compte est inférieur à 30 jours\n- Le mode de paiement pour cette offre est considéré comme présentant un risque de rétrofacturation bancaire\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Ce mode de paiement est temporairement limité à {0} jusqu'à {1} car tous les acheteurs ont de nouveaux comptes.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Votre offre sera limitée aux acheteurs avec des comptes signés et anciens car elle dépasse {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Cet ordre exige une version de protocole différente de celle utilisée actuellement par votre logiciel.\n\nVeuillez vérifier que vous avez bien la dernière version d'installée, il est possible que l'utilisateur qui a créé cet ordre utilise une ancienne version.\n\nIl n'est pas possible de trader avec des versions différentes de protocole. offerbook.warning.userIgnored=Vous avez ajouté l'adresse onion de cet utilisateur à votre liste noire. @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=Le montant a été arrondi pour accroître la c # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Entrer le montant en BTC +createOffer.amount.prompt=Entrer le montant en XMR createOffer.price.prompt=Entrer le prix createOffer.volume.prompt=Entrer le montant en {0} -createOffer.amountPriceBox.amountDescription=Somme en Bitcoin à {0} +createOffer.amountPriceBox.amountDescription=Somme en Monero à {0} createOffer.amountPriceBox.buy.volumeDescription=Somme en {0} à envoyer createOffer.amountPriceBox.sell.volumeDescription=Montant en {0} à recevoir -createOffer.amountPriceBox.minAmountDescription=Montant minimum de BTC +createOffer.amountPriceBox.minAmountDescription=Montant minimum de XMR createOffer.securityDeposit.prompt=Dépôt de garantie createOffer.fundsBox.title=Financer votre ordre createOffer.fundsBox.offerFee=Frais de transaction @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=Vous recevrez toujours {0}% de plus que le createOffer.info.buyBelowMarketPrice=Vous paierez toujours {0}% de moins que le prix actuel du marché car prix de votre ordre sera continuellement mis à jour. createOffer.warning.sellBelowMarketPrice=Vous obtiendrez toujours {0}% de moins que le prix actuel du marché car le prix de votre ordre sera continuellement mis à jour. createOffer.warning.buyAboveMarketPrice=Vous paierez toujours {0}% de plus que le prix actuel du marché car le prix de votre ordre sera continuellement mis à jour. -createOffer.tradeFee.descriptionBTCOnly=Frais de transaction +createOffer.tradeFee.descriptionXMROnly=Frais de transaction createOffer.tradeFee.descriptionBSQEnabled=Choisir la devise des frais de transaction createOffer.triggerPrice.prompt=Réglez le prix de déclenchement, optionnel @@ -448,7 +463,12 @@ createOffer.placeOfferButton=Review: Placer un ordre de {0} monero createOffer.createOfferFundWalletInfo.headline=Financer votre ordre # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=Montant du trade: {0}\n\n -createOffer.createOfferFundWalletInfo.msg=Vous devez déposer {0} pour cet ordre.\n\nCes fonds sont réservés dans votre portefeuille local et seront bloqués sur une adresse de dépôt multisig une fois que quelqu''un aura accepté votre ordre.\n\nLe montant correspond à la somme de:\n{1}- Votre dépôt de garantie: {2}\n- Frais de trading: {3}\n- Frais d''exploitation minière: {4}\n\nVous avez le choix entre deux options pour financer votre transaction :\n- Utilisez votre portefeuille Haveno (pratique, mais les transactions peuvent être associables) OU\n- Transfert depuis un portefeuille externe (potentiellement plus privé)\n\nVous pourrez voir toutes les options de financement et les détails après avoir fermé ce popup. +createOffer.createOfferFundWalletInfo.msg=Vous devez déposer {0} à cette offre.\n\n\ + Ces fonds sont réservés dans votre portefeuille local et seront verrouillés dans un portefeuille multisignature dès qu'une personne acceptera votre offre.\n\n\ + Le montant est la somme de :\n\ + {1}\ + - Votre dépôt de garantie : {2}\n\ + - Frais de transaction : {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Une erreur s''est produite lors du placement de cet ordre:\n\n{0}\n\nAucun fonds n''a été prélevé sur votre portefeuille pour le moment.\nVeuillez redémarrer l''application et vérifier votre connexion réseau. @@ -470,30 +490,35 @@ createOffer.setDepositAsBuyer=Définir mon dépôt de garantie en tant qu'achete createOffer.setDepositForBothTraders=Établissez le dépôt de sécurité des deux traders (%) createOffer.securityDepositInfo=Le dépôt de garantie de votre acheteur sera de {0} createOffer.securityDepositInfoAsBuyer=Votre dépôt de garantie en tant qu''acheteur sera de {0} -createOffer.minSecurityDepositUsed=Le minimum de dépôt de garantie de l'acheteur est utilisé +createOffer.minSecurityDepositUsed=Le dépôt de sécurité minimum est utilisé +createOffer.buyerAsTakerWithoutDeposit=Aucun dépôt requis de la part de l'acheteur (protégé par un mot de passe) +createOffer.myDeposit=Mon dépôt de garantie (%) +createOffer.myDepositInfo=Votre dépôt de garantie sera de {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Entrez le montant en BTC -takeOffer.amountPriceBox.buy.amountDescription=Montant en BTC à vendre -takeOffer.amountPriceBox.sell.amountDescription=Montant de BTC à acheter -takeOffer.amountPriceBox.priceDescription=Prix par Bitcoin en {0} +takeOffer.amount.prompt=Entrez le montant en XMR +takeOffer.amountPriceBox.buy.amountDescription=Montant en XMR à vendre +takeOffer.amountPriceBox.sell.amountDescription=Montant de XMR à acheter +takeOffer.amountPriceBox.priceDescription=Prix par Monero en {0} takeOffer.amountPriceBox.amountRangeDescription=Fourchette du montant possible -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=Le montant que vous avez saisi dépasse le nombre maximum de décimales autorisées.\nLe montant a été défini à 4 décimales près. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=Le montant que vous avez saisi dépasse le nombre maximum de décimales autorisées.\nLe montant a été défini à 4 décimales près. takeOffer.validation.amountSmallerThanMinAmount=Le montant ne peut pas être plus petit que le montant minimum défini dans l'ordre. takeOffer.validation.amountLargerThanOfferAmount=La saisie ne peut pas être plus grande que le montant défini dans l'ordre. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=La somme saisie va créer des dusts résultantes de la transaction pour le vendeur de BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=La somme saisie va créer des dusts résultantes de la transaction pour le vendeur de XMR. takeOffer.fundsBox.title=Provisionner votre trade takeOffer.fundsBox.isOfferAvailable=Vérifiez si l'ordre est disponible... takeOffer.fundsBox.tradeAmount=Montant à vendre takeOffer.fundsBox.offerFee=Frais de transaction du trade takeOffer.fundsBox.networkFee=Total des frais de minage -takeOffer.fundsBox.takeOfferSpinnerInfo=Take offer in progress ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Acceptation de l'offre : {0} takeOffer.fundsBox.paymentLabel=Transaction Haveno avec l''ID {0} takeOffer.fundsBox.fundsStructure=({0} dépôt de garantie, {1} frais de transaction, {2} frais de minage) +takeOffer.fundsBox.noFundingRequiredTitle=Aucun financement requis +takeOffer.fundsBox.noFundingRequiredDescription=Obtenez la phrase secrète de l'offre auprès du vendeur en dehors de Haveno pour accepter cette offre. takeOffer.success.headline=Vous avez accepté un ordre avec succès. takeOffer.success.info=Vous pouvez voir vos transactions dans \"Portfolio/Échanges en cours\". takeOffer.error.message=Une erreur s''est produite pendant l’'acceptation de l''ordre.\n\n{0} @@ -504,7 +529,7 @@ takeOffer.noPriceFeedAvailable=Vous ne pouvez pas accepter cet ordre, car celui- takeOffer.takeOfferFundWalletInfo.headline=Provisionner votre trade # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Montant du trade: {0}\n -takeOffer.takeOfferFundWalletInfo.msg=Vous devez envoyer {0} pour cet odre.\n\nLe montant est la somme de:\n{1}--Dépôt de garantie: {2}\n- Frais de transaction: {3}\n- Frais de minage: {4}\n\nVous avez deux choix pour payer votre transaction :\n- Utiliser votre portefeuille local Haveno (pratique, mais vos transactions peuvent être tracées) OU\n- Transférer d''un portefeuille externe (potentiellement plus confidentiel)\n\nVous retrouverez toutes les options de provisionnement après fermeture de ce popup. +takeOffer.takeOfferFundWalletInfo.msg=Vous devez déposer {0} pour accepter cette offre.\n\nLe montant est la somme de :\n{1}- Votre dépôt de garantie : {2}\n- Frais de transaction : {3} takeOffer.alreadyPaidInFunds=Si vous avez déjà provisionner des fonds vous pouvez les retirer dans l'onglet \"Fonds/Envoyer des fonds\". takeOffer.paymentInfo=Informations de paiement takeOffer.setAmountPrice=Définir le montant @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=La transaction de dépôt n'est toujours # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Votre trade a atteint au moins une confirmation de la part de la blockchain.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: Quand vous effectuez le paiement, laissez le champ \"raison du paiement\" vide. NE METTEZ PAS l'ID du trade ou n'importe quel autre texte, par exemple 'bitcoin', 'BTC' ou 'Haveno'. Vous êtez autorisés à discuter via le chat des trader si un autre \"raison du paiement\" est préférable pour vous deux. +portfolio.pending.step2_buyer.refTextWarn=Important: Quand vous effectuez le paiement, laissez le champ \"raison du paiement\" vide. NE METTEZ PAS l'ID du trade ou n'importe quel autre texte, par exemple 'monero', 'XMR' ou 'Haveno'. Vous êtez autorisés à discuter via le chat des trader si un autre \"raison du paiement\" est préférable pour vous deux. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=Si votre banque vous facture des frais pour effectuer le transfert, vous êtes responsable de payer ces frais. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Veuillez transférer à partir de votre portefeuille externe {0}.\n{1} au vendeur de BTC.\n\n\n +portfolio.pending.step2_buyer.crypto=Veuillez transférer à partir de votre portefeuille externe {0}.\n{1} au vendeur de XMR.\n\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Veuillez vous rendre dans une banque et payer {0} au vendeur de BTC.\n -portfolio.pending.step2_buyer.cash.extra=CONDITIONS REQUISES: \nAprès avoir effectué le paiement veuillez écrire sur le reçu papier : PAS DE REMBOURSEMENT.\nPuis déchirer le en 2, prenez en une photo et envoyer le à l'adresse email du vendeur de BTC. +portfolio.pending.step2_buyer.cash=Veuillez vous rendre dans une banque et payer {0} au vendeur de XMR.\n +portfolio.pending.step2_buyer.cash.extra=CONDITIONS REQUISES: \nAprès avoir effectué le paiement veuillez écrire sur le reçu papier : PAS DE REMBOURSEMENT.\nPuis déchirer le en 2, prenez en une photo et envoyer le à l'adresse email du vendeur de XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Veuillez s''il vous plaît payer {0} au vendeur de BTC en utilisant MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=CONDITIONS REQUISES:\nAprès avoir effectué le paiement envoyez le numéro d''autorisation et une photo du reçu par e-mail au vendeur de BTC.\nLe reçu doit faire clairement figurer le nom complet du vendeur, son pays, l''état et le montant. Le mail du vendeur est: {0}. +portfolio.pending.step2_buyer.moneyGram=Veuillez s''il vous plaît payer {0} au vendeur de XMR en utilisant MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=CONDITIONS REQUISES:\nAprès avoir effectué le paiement envoyez le numéro d''autorisation et une photo du reçu par e-mail au vendeur de XMR.\nLe reçu doit faire clairement figurer le nom complet du vendeur, son pays, l''état et le montant. Le mail du vendeur est: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Veuillez s''il vous plaît payer {0} au vendeur de BTC en utilisant Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=CONDITIONS REQUISES:\nAprès avoir effectué le paiement envoyez le MTCN (numéro de suivi) et une photo du reçu par e-mail au vendeur de BTC.\nLe reçu doit faire clairement figurer le nom complet du vendeur, son pays, l''état et le montant. Le mail du vendeur est: {0}. +portfolio.pending.step2_buyer.westernUnion=Veuillez s''il vous plaît payer {0} au vendeur de XMR en utilisant Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=CONDITIONS REQUISES:\nAprès avoir effectué le paiement envoyez le MTCN (numéro de suivi) et une photo du reçu par e-mail au vendeur de XMR.\nLe reçu doit faire clairement figurer le nom complet du vendeur, son pays, l''état et le montant. Le mail du vendeur est: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Merci d''envoyer {0} par \"US Postal Money Order\" au vendeur de BTC.\n\n +portfolio.pending.step2_buyer.postal=Merci d''envoyer {0} par \"US Postal Money Order\" au vendeur de XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Veuillez envoyer {0} en utlisant \"Pay by Mail\" au vendeur de BTC. Les instructions spécifiques sont dans le contrat de trade, ou si ce n'est pas clair, vous pouvez poser des questions via le chat des trader. Pour plus de détails sur Pay by Mail, allez sur le wiki Haveno \n[LIEN:https://bisq.wiki/Cash_by_Mail]\n +portfolio.pending.step2_buyer.payByMail=Veuillez envoyer {0} en utlisant \"Pay by Mail\" au vendeur de XMR. Les instructions spécifiques sont dans le contrat de trade, ou si ce n'est pas clair, vous pouvez poser des questions via le chat des trader. Pour plus de détails sur Pay by Mail, allez sur le wiki Haveno \n[LIEN:https://haveno.exchange/wiki/Cash_by_Mail]\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Veuillez payer {0} via la méthode de paiement spécifiée par le vendeur de BTC. Vous trouverez les informations du compte du vendeur à l'écran suivant.\n\n +portfolio.pending.step2_buyer.pay=Veuillez payer {0} via la méthode de paiement spécifiée par le vendeur de XMR. Vous trouverez les informations du compte du vendeur à l'écran suivant.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Veuillez s''il vous plaît contacter le vendeur de BTC via le contact fourni, et planifiez un rendez-vous pour effectuer le paiement {0}.\n\n +portfolio.pending.step2_buyer.f2f=Veuillez s''il vous plaît contacter le vendeur de XMR via le contact fourni, et planifiez un rendez-vous pour effectuer le paiement {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Initier le paiement en utilisant {0} portfolio.pending.step2_buyer.recipientsAccountData=Destinataires {0} portfolio.pending.step2_buyer.amountToTransfer=Montant à transférer @@ -629,27 +654,27 @@ portfolio.pending.step2_buyer.paymentSent=Paiement initié portfolio.pending.step2_buyer.fillInBsqWallet=Payer depuis le portefeuille BSQ portfolio.pending.step2_buyer.warn=Vous n''avez toujours pas effectué votre {0} paiement !\nVeuillez noter que l''échange doit être achevé avant {1}. portfolio.pending.step2_buyer.openForDispute=Vous n'avez pas effectué votre paiement !\nLe délai maximal alloué pour l'échange est écoulé, veuillez contacter le médiateur pour obtenir de l'aide. -portfolio.pending.step2_buyer.paperReceipt.headline=Avez-vous envoyé le reçu papier au vendeur de BTC? +portfolio.pending.step2_buyer.paperReceipt.headline=Avez-vous envoyé le reçu papier au vendeur de XMR? portfolio.pending.step2_buyer.paperReceipt.msg=Rappelez-vous: \nVous devez écrire sur le reçu papier: PAS DE REMBOURSEMENT.\nEnsuite, veuillez le déchirer en 2, faire une photo et l'envoyer à l'adresse email du vendeur. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Envoyer le numéro d'autorisation ainsi que le reçu -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Vous devez envoyez le numéro d''autorisation et une photo du reçu par email au vendeur de BTC.\nLe reçu doit faire clairement figurer le nom complet du vendeur, son pays, l''état, et le montant. Le mail du vendeur est: {0}.\n\nAvez-vous envoyé le numéro d''autorisation et le contrat au vendeur ? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Vous devez envoyez le numéro d''autorisation et une photo du reçu par email au vendeur de XMR.\nLe reçu doit faire clairement figurer le nom complet du vendeur, son pays, l''état, et le montant. Le mail du vendeur est: {0}.\n\nAvez-vous envoyé le numéro d''autorisation et le contrat au vendeur ? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Envoyer le MTCN et le reçu -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Vous devez envoyez le MTCN (numéro de suivi) et une photo du reçu par email au vendeur de BTC.\nLe reçu doit clairement faire figurer le nom complet du vendeur, son pays, l''état et le montant. Le mail du vendeur est: {0}.\n\nAvez-vous envoyé le MTCN et le contrat au vendeur ? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Vous devez envoyez le MTCN (numéro de suivi) et une photo du reçu par email au vendeur de XMR.\nLe reçu doit clairement faire figurer le nom complet du vendeur, son pays, l''état et le montant. Le mail du vendeur est: {0}.\n\nAvez-vous envoyé le MTCN et le contrat au vendeur ? portfolio.pending.step2_buyer.halCashInfo.headline=Envoyer le code HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=Vous devez envoyez un message au format texte SMS avec le code HalCash ainsi que l''ID de la transaction ({0}) au vendeur de BTC.\nLe numéro de mobile du vendeur est {1}.\n\nAvez-vous envoyé le code au vendeur ? +portfolio.pending.step2_buyer.halCashInfo.msg=Vous devez envoyez un message au format texte SMS avec le code HalCash ainsi que l''ID de la transaction ({0}) au vendeur de XMR.\nLe numéro de mobile du vendeur est {1}.\n\nAvez-vous envoyé le code au vendeur ? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Certaines banques pourraient vérifier le nom du receveur. Des comptes de paiement plus rapides créés dans des clients Haveno plus anciens ne fournissent pas le nom du receveur, veuillez donc utiliser le chat de trade pour l'obtenir (si nécessaire). portfolio.pending.step2_buyer.confirmStart.headline=Confirmez que vous avez initié le paiement portfolio.pending.step2_buyer.confirmStart.msg=Avez-vous initié le {0} paiement auprès de votre partenaire de trading? portfolio.pending.step2_buyer.confirmStart.yes=Oui, j'ai initié le paiement portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=Vous n'avez pas fourni de preuve de paiement -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Lorsque vous terminez une transaction BTC / XMR, vous pouvez utiliser la fonction de confirmation automatique pour vérifier si le montant correct de XMR a été envoyé à votre portefeuille, afin que Haveno puisse automatiquement marquer la transaction comme terminée et pour que tout le monde puisse aller plus vite. \n\nConfirmez automatiquement que les transactions XMR sont vérifiées sur au moins 2 nœuds d'explorateur de blocs XMR à l'aide de la clé de transaction fournie par l'expéditeur XMR. Par défaut, Haveno utilise un nœud d'explorateur de blocs exécuté par des contributeurs Haveno, mais nous vous recommandons d'exécuter votre propre nœud d'explorateur de blocs XMR pour maximiser la confidentialité et la sécurité. \n\nVous pouvez également définir le nombre maximum de BTC par transaction dans «Paramètres» pour confirmer automatiquement et le nombre de confirmations requises. \n\nPlus de détails sur Haveno Wiki (y compris comment configurer votre propre nœud d'explorateur de blocs): [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=Lorsque vous terminez une transaction XMR / XMR, vous pouvez utiliser la fonction de confirmation automatique pour vérifier si le montant correct de XMR a été envoyé à votre portefeuille, afin que Haveno puisse automatiquement marquer la transaction comme terminée et pour que tout le monde puisse aller plus vite. \n\nConfirmez automatiquement que les transactions XMR sont vérifiées sur au moins 2 nœuds d'explorateur de blocs XMR à l'aide de la clé de transaction fournie par l'expéditeur XMR. Par défaut, Haveno utilise un nœud d'explorateur de blocs exécuté par des contributeurs Haveno, mais nous vous recommandons d'exécuter votre propre nœud d'explorateur de blocs XMR pour maximiser la confidentialité et la sécurité. \n\nVous pouvez également définir le nombre maximum de XMR par transaction dans «Paramètres» pour confirmer automatiquement et le nombre de confirmations requises. \n\nPlus de détails sur Haveno Wiki (y compris comment configurer votre propre nœud d'explorateur de blocs): [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=La sasie n'est pas une valeur hexadécimale de 32 bits portfolio.pending.step2_buyer.confirmStart.warningButton=Ignorer et continuer tout de même portfolio.pending.step2_seller.waitPayment.headline=En attende du paiement portfolio.pending.step2_seller.f2fInfo.headline=Coordonnées de l'acheteur -portfolio.pending.step2_seller.waitPayment.msg=La transaction de dépôt a été vérifiée au moins une fois sur la blockchain\nVous devez attendre que l''acheteur de BTC lance le {0} payment. -portfolio.pending.step2_seller.warn=L''acheteur de BTC n''a toujours pas effectué le paiement {0}.\nVeuillez attendre qu''il effectue celui-ci.\nSi la transaction n''est pas effectuée le {1}, un arbitre enquêtera. -portfolio.pending.step2_seller.openForDispute=L'acheteur de BTC n'a pas initié son paiement !\nLa période maximale autorisée pour ce trade est écoulée.\nVous pouvez attendre plus longtemps et accorder plus de temps à votre pair de trading ou contacter le médiateur pour obtenir de l'aide. +portfolio.pending.step2_seller.waitPayment.msg=La transaction de dépôt a été vérifiée au moins une fois sur la blockchain\nVous devez attendre que l''acheteur de XMR lance le {0} payment. +portfolio.pending.step2_seller.warn=L''acheteur de XMR n''a toujours pas effectué le paiement {0}.\nVeuillez attendre qu''il effectue celui-ci.\nSi la transaction n''est pas effectuée le {1}, un arbitre enquêtera. +portfolio.pending.step2_seller.openForDispute=L'acheteur de XMR n'a pas initié son paiement !\nLa période maximale autorisée pour ce trade est écoulée.\nVous pouvez attendre plus longtemps et accorder plus de temps à votre pair de trading ou contacter le médiateur pour obtenir de l'aide. tradeChat.chatWindowTitle=Fenêtre de discussion pour la transaction avec l''ID ''{0}'' tradeChat.openChat=Ouvrir une fenêtre de discussion tradeChat.rules=Vous pouvez communiquer avec votre pair de trading pour résoudre les problèmes potentiels liés à cet échange.\nIl n'est pas obligatoire de répondre sur le chat.\nSi un trader enfreint l'une des règles ci-dessous, ouvrez un litige et signalez-le au médiateur ou à l'arbitre.\n\nRègles sur le chat:\n\t● N'envoyez pas de liens (risque de malware). Vous pouvez envoyer l'ID de transaction et le nom d'un explorateur de blocs.\n\t● N'envoyez pas les mots de votre seed, clés privées, mots de passe ou autre information sensible !\n\t● N'encouragez pas le trading en dehors de Haveno (non sécurisé).\n\t● Ne vous engagez dans aucune forme d'escroquerie d'ingénierie sociale.\n\t● Si un pair ne répond pas et préfère ne pas communiquer par chat, respectez sa décision.\n\t● Limitez la portée de la conversation à l'échange en cours. Ce chat n'est pas une alternative à messenger ou une troll-box.\n\t● Entretenez une conversation amicale et respectueuse. @@ -667,26 +692,26 @@ message.state.ACKNOWLEDGED=Le pair a confirmé la réception du message # suppress inspection "UnusedProperty" message.state.FAILED=Echec de l'envoi du message -portfolio.pending.step3_buyer.wait.headline=Attendre la confirmation de paiement du vendeur BTC -portfolio.pending.step3_buyer.wait.info=En attente de la confirmation du vendeur BTC pour la réception du paiement {0}. +portfolio.pending.step3_buyer.wait.headline=Attendre la confirmation de paiement du vendeur XMR +portfolio.pending.step3_buyer.wait.info=En attente de la confirmation du vendeur XMR pour la réception du paiement {0}. portfolio.pending.step3_buyer.wait.msgStateInfo.label=État du message de lancement du paiement portfolio.pending.step3_buyer.warn.part1a=sur la {0} blockchain portfolio.pending.step3_buyer.warn.part1b=chez votre prestataire de paiement (par ex. banque) -portfolio.pending.step3_buyer.warn.part2=Le vendeur de BTC n''a toujours pas confirmé votre paiement. . Veuillez vérifier {0} si l''envoi du paiement a bien fonctionné. -portfolio.pending.step3_buyer.openForDispute=Le vendeur de BTC n'a pas confirmé votre paiement ! Le délai maximal alloué pour ce trade est écoulé. Vous pouvez attendre plus longtemps et accorder plus de temps à votre pair de trading ou contacter le médiateur pour obtenir de l'aide. +portfolio.pending.step3_buyer.warn.part2=Le vendeur de XMR n''a toujours pas confirmé votre paiement. . Veuillez vérifier {0} si l''envoi du paiement a bien fonctionné. +portfolio.pending.step3_buyer.openForDispute=Le vendeur de XMR n'a pas confirmé votre paiement ! Le délai maximal alloué pour ce trade est écoulé. Vous pouvez attendre plus longtemps et accorder plus de temps à votre pair de trading ou contacter le médiateur pour obtenir de l'aide. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Votre partenaire de trading a confirmé qu''il a initié le paiement {0}.\n portfolio.pending.step3_seller.crypto.explorer=Sur votre explorateur blockchain {0} favori portfolio.pending.step3_seller.crypto.wallet=Dans votre portefeuille {0} portfolio.pending.step3_seller.crypto={0}Veuillez s''il vous plaît vérifier {1} que la transaction vers votre adresse de réception\n{2}\ndispose de suffisamment de confirmations sur la blockchain.\nLe montant du paiement doit être {3}\n\nVous pouvez copier & coller votre adresse {4} à partir de l''écran principal après avoir fermé ce popup. -portfolio.pending.step3_seller.postal={0}Veuillez vérifier si vous avez reçu {1} avec \"US Postal Money Order\" de la part de l'acheteur de BTC. +portfolio.pending.step3_seller.postal={0}Veuillez vérifier si vous avez reçu {1} avec \"US Postal Money Order\" de la part de l'acheteur de XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Veuillez vérifier si vous avez reçu {1} avec \"Pay by Mail\" de la part de l'acheteur de BTC +portfolio.pending.step3_seller.payByMail={0}Veuillez vérifier si vous avez reçu {1} avec \"Pay by Mail\" de la part de l'acheteur de XMR # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Votre partenaire de trading a confirmé qu'il a initié le {0} paiement.\n\nVeuillez vous rendre sur votre banque en ligne et vérifier si vous avez reçu {1} de la part de l'acheteur de BTC. -portfolio.pending.step3_seller.cash=Du fait que le paiement est réalisé via Cash Deposit l''acheteur de BTC doit inscrire \"NO REFUND\" sur le reçu papier, le déchirer en 2 et vous envoyer une photo par email.\n\nPour éviter un risque de rétrofacturation, ne confirmez que si vous recevez le mail et que vous êtes sûr que le reçu papier est valide.\nSi vous n''êtes pas sûr, {0} -portfolio.pending.step3_seller.moneyGram=L'acheteur doit vous envoyer le numéro d'autorisation et une photo du reçu par e-mail .\nLe reçu doit faire clairement figurer votre nom complet, votre pays, l'état et le montant. Veuillez s'il vous plaît vérifier que vous avez bien reçu par e-mail le numéro d'autorisation.\n\nAprès avoir fermé ce popup vous verrez le nom de l'acheteur de BTC et l'adresse où retirer l'argent depuis MoneyGram.\n\nN'accusez réception qu'après avoir retiré l'argent avec succès! -portfolio.pending.step3_seller.westernUnion=L'acheteur doit vous envoyer le MTCN (numéro de suivi) et une photo du reçu par e-mail .\nLe reçu doit faire clairement figurer votre nom complet, votre pays, l'état et le montant. Veuillez s'il vous plaît vérifier si vous avez reçu par e-mail le MTCN.\n\nAprès avoir fermé ce popup vous verrez le nom de l'acheteur de BTC et l'adresse où retirer l'argent depuis Western Union.\n\nN'accusez réception qu'après avoir retiré l'argent avec succès! +portfolio.pending.step3_seller.bank=Votre partenaire de trading a confirmé qu'il a initié le {0} paiement.\n\nVeuillez vous rendre sur votre banque en ligne et vérifier si vous avez reçu {1} de la part de l'acheteur de XMR. +portfolio.pending.step3_seller.cash=Du fait que le paiement est réalisé via Cash Deposit l''acheteur de XMR doit inscrire \"NO REFUND\" sur le reçu papier, le déchirer en 2 et vous envoyer une photo par email.\n\nPour éviter un risque de rétrofacturation, ne confirmez que si vous recevez le mail et que vous êtes sûr que le reçu papier est valide.\nSi vous n''êtes pas sûr, {0} +portfolio.pending.step3_seller.moneyGram=L'acheteur doit vous envoyer le numéro d'autorisation et une photo du reçu par e-mail .\nLe reçu doit faire clairement figurer votre nom complet, votre pays, l'état et le montant. Veuillez s'il vous plaît vérifier que vous avez bien reçu par e-mail le numéro d'autorisation.\n\nAprès avoir fermé ce popup vous verrez le nom de l'acheteur de XMR et l'adresse où retirer l'argent depuis MoneyGram.\n\nN'accusez réception qu'après avoir retiré l'argent avec succès! +portfolio.pending.step3_seller.westernUnion=L'acheteur doit vous envoyer le MTCN (numéro de suivi) et une photo du reçu par e-mail .\nLe reçu doit faire clairement figurer votre nom complet, votre pays, l'état et le montant. Veuillez s'il vous plaît vérifier si vous avez reçu par e-mail le MTCN.\n\nAprès avoir fermé ce popup vous verrez le nom de l'acheteur de XMR et l'adresse où retirer l'argent depuis Western Union.\n\nN'accusez réception qu'après avoir retiré l'argent avec succès! portfolio.pending.step3_seller.halCash=L'acheteur doit vous envoyer le code HalCash par message texte SMS. Par ailleurs, vous recevrez un message de la part d'HalCash avec les informations nécessaires pour retirer les EUR depuis un DAB Bancaire supportant HalCash.\n\nAprès avoir retiré l'argent au DAB, veuillez confirmer ici la réception du paiement ! portfolio.pending.step3_seller.amazonGiftCard=L'acheteur vous a envoyé une e-carte cadeau Amazon via email ou SMS vers votre téléphone. Veuillez récupérer maintenant la carte cadeau sur votre compte Amazon, et une fois activée, confirmez le reçu de paiement. @@ -702,7 +727,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID de la transaction portfolio.pending.step3_seller.xmrTxKey=Clé de Transaction portfolio.pending.step3_seller.buyersAccount=Données du compte de l'acheteur portfolio.pending.step3_seller.confirmReceipt=Confirmer la réception du paiement -portfolio.pending.step3_seller.buyerStartedPayment=L''acheteur BTC a commencé le {0} paiement.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=L''acheteur XMR a commencé le {0} paiement.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Vérifiez la présence de confirmations par la blockchain dans votre portefeuille crypto ou sur un explorateur de blocs et confirmez le paiement lorsque vous aurez suffisamment de confirmations sur la blockchain. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Vérifiez sur votre compte de trading (par ex. compte bancaire) et confirmez quand vous avez reçu le paiement. portfolio.pending.step3_seller.warn.part1a=sur la {0} blockchain @@ -714,7 +739,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Avez-vous reçu le paieme # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Veuillez également vérifier que le nom de l''expéditeur indiqué sur le contrat de l''échange correspond au nom qui apparaît sur votre relevé bancaire:\nNom de l''expéditeur, avec le contrat de l''échange: {0}\n\nSi les noms ne sont pas exactement identiques, ne confirmez pas la réception du paiement. Au lieu de cela, ouvrez un litige en appuyant sur \"alt + o\" ou \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Veuillez noter que dès que vous aurez confirmé la réception, le montant verrouillé pour l'échange sera remis à l'acheteur de BTC et le dépôt de garantie vous sera remboursé.\n +portfolio.pending.step3_seller.onPaymentReceived.note=Veuillez noter que dès que vous aurez confirmé la réception, le montant verrouillé pour l'échange sera remis à l'acheteur de XMR et le dépôt de garantie vous sera remboursé.\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Confirmez que vous avez bien reçu le paiement portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Oui, j'ai reçu le paiement portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANT : En confirmant la réception du paiement, vous vérifiez également le compte de la contrepartie et le signez en conséquence. Comme le compte de la contrepartie n'a pas encore été signé, vous devriez retarder la confirmation du paiement le plus longtemps possible afin de réduire le risque de rétrofacturation. @@ -724,7 +749,7 @@ portfolio.pending.step5_buyer.tradeFee=Frais de transaction portfolio.pending.step5_buyer.makersMiningFee=Frais de minage portfolio.pending.step5_buyer.takersMiningFee=Total des frais de minage portfolio.pending.step5_buyer.refunded=Dépôt de garantie remboursé -portfolio.pending.step5_buyer.withdrawBTC=Retirer vos Bitcoins +portfolio.pending.step5_buyer.withdrawXMR=Retirer vos Moneros portfolio.pending.step5_buyer.amount=Montant à retirer portfolio.pending.step5_buyer.withdrawToAddress=Retirer vers l'adresse portfolio.pending.step5_buyer.moveToHavenoWallet=Garder les fonds dans le portefeuille Haveno @@ -733,7 +758,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Vos fonds ont déjà été retir portfolio.pending.step5_buyer.confirmWithdrawal=Confirmer la demande de retrait portfolio.pending.step5_buyer.amountTooLow=Le montant à transférer est inférieur aux frais de transaction et à la valeur min. possible du tx (dust). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Retrait effectué -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Vos transactions terminées sont stockées sous /"Historique du portefeuille\".\nVous pouvez voir toutes vos transactions en bitcoin dans \"Fonds/Transactions\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Vos transactions terminées sont stockées sous /"Historique du portefeuille\".\nVous pouvez voir toutes vos transactions en monero dans \"Fonds/Transactions\" portfolio.pending.step5_buyer.bought=Vous avez acheté portfolio.pending.step5_buyer.paid=Vous avez payé @@ -795,7 +820,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Vous avez déjà accept portfolio.pending.failedTrade.taker.missingTakerFeeTx=Le frais de transaction du preneur est manquant.\n\nSans ce tx, le trade ne peut être complété. Aucun fonds ont été verrouillés et aucun frais de trade a été payé. Vous pouvez déplacer ce trade vers les trade échoués. portfolio.pending.failedTrade.maker.missingTakerFeeTx=Le frais de transaction du pair preneur est manquant.\n\nSans ce tx, le trade ne peut être complété. Aucun fonds ont été verrouillés. Votre offre est toujours valable pour les autres traders, vous n'avez donc pas perdu le frais de maker. Vous pouvez déplacer ce trade vers les trades échoués. portfolio.pending.failedTrade.missingDepositTx=Cette transaction de marge (transaction multi-signature de 2 à 2) est manquante.\n\nSans ce tx, la transaction ne peut pas être complétée. Aucun fonds n'est bloqué, mais vos frais de transaction sont toujours payés. Vous pouvez lancer une demande de compensation des frais de transaction ici: [HYPERLINK:https://github.com/bisq-network/support/issues] \nN'hésitez pas à déplacer la transaction vers la transaction échouée. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=La transaction de paiement différée est manquante, mais les fonds ont été verrouillés dans la transaction de dépôt.\n\nVeuillez NE PAS envoyer de Fiat ou d'crypto au vendeur de BTC, car avec le tx de paiement différé, le jugemenbt ne peut être ouvert. À la place, ouvrez un ticket de médiation avec Cmd/Ctrl+O. Le médiateur devrait suggérer que les deux pair reçoivent tous les deux le montant total de leurs dépôts de sécurité (le vendeur aussi doit reçevoir le montant total du trade). De cette manière, il n'y a pas de risque de non sécurité, et seuls les frais du trade sont perdus.\n\nVous pouvez demander le remboursement des frais de trade perdus ici;\n[LIEN:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=La transaction de paiement différée est manquante, mais les fonds ont été verrouillés dans la transaction de dépôt.\n\nVeuillez NE PAS envoyer de Fiat ou d'crypto au vendeur de XMR, car avec le tx de paiement différé, le jugemenbt ne peut être ouvert. À la place, ouvrez un ticket de médiation avec Cmd/Ctrl+O. Le médiateur devrait suggérer que les deux pair reçoivent tous les deux le montant total de leurs dépôts de sécurité (le vendeur aussi doit reçevoir le montant total du trade). De cette manière, il n'y a pas de risque de non sécurité, et seuls les frais du trade sont perdus.\n\nVous pouvez demander le remboursement des frais de trade perdus ici;\n[LIEN:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=La transaction de paiement différée est manquante, mais les fonds ont été verrouillés dans la transaction de dépôt.\n\nSi l'acheteur n'a pas non plus la transaction de paiement différée, il sera informé du fait de ne PAS envoyer le paiement et d'ouvrir un ticket de médiation à la place. Vous devriez aussi ouvrir un ticket de médiation avec Cmd/Ctrl+o.\n\nSi l'acheteur n'a pas encore envoyé le paiement, le médiateur devrait suggérer que les deux pairs reçoivent le montant total de leurs dépôts de sécurité (le vendeur doit aussi reçevoir le montant total du trade). Sinon, le montant du trade revient à l'acheteur.\n\nVous pouvez effectuer une demande de remboursement pour les frais de trade perdus ici: [LIEN:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=Il y'a eu une erreur durant l'exécution du protocole de trade.\n\nErreur: {0}\n\nIl est possible que cette erreur ne soit pas critique, et que le trade puisse être complété normalement. Si vous n'en êtes pas sûr, ouvrez un ticket de médiation pour avoir des conseils de la part des médiateurs de Haveno.\n\nSi cette erreur est critique et que le trade ne peut être complété, il est possible que vous ayez perdu le frais du trade. Effectuez une demande de remboursement ici: [LIEN:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=Le contrat de trade n'est pas complété.\n\nCe trade ne peut être complété et il est possible que vous ayiez perdu votre frais de trade. Dans ce cas, vous pouvez demander un remboursement des frais de trade perdus ici: [LIEN:https://github.com/bisq-network/support/issues] @@ -834,7 +859,7 @@ funds.deposit.fundHavenoWallet=Alimenter le portefeuille Haveno funds.deposit.noAddresses=Aucune adresse de dépôt n'a encore été générée funds.deposit.fundWallet=Alimenter votre portefeuille funds.deposit.withdrawFromWallet=Transférer des fonds depuis le portefeuille -funds.deposit.amount=Montant en BTC (optionnel) +funds.deposit.amount=Montant en XMR (optionnel) funds.deposit.generateAddress=Générer une nouvelle adresse funds.deposit.generateAddressSegwit=Format segwit natif (Bech32) funds.deposit.selectUnused=Merci de sélectionner une adresse inutilisée dans le champ ci-dessus plutôt que d'en générer une nouvelle. @@ -844,6 +869,7 @@ funds.withdrawal.inputs=Sélection de la valeur à saisir funds.withdrawal.useAllInputs=Utiliser toutes les valeurs disponibles funds.withdrawal.useCustomInputs=Utiliser une valeur de saisie personnalisée funds.withdrawal.receiverAmount=Montant du destinataire +funds.withdrawal.sendMax=Envoyer max disponible funds.withdrawal.senderAmount=Montant de l'expéditeur funds.withdrawal.feeExcluded=Montant excluant les frais de minage funds.withdrawal.feeIncluded=Montant incluant frais de minage @@ -891,7 +917,7 @@ funds.tx.revert=Revertir funds.tx.txSent=Transaction envoyée avec succès vers une nouvelle adresse dans le portefeuille local haveno. funds.tx.direction.self=Envoyé à vous même funds.tx.dustAttackTx=dust reçues -funds.tx.dustAttackTx.popup=Cette transaction va envoyer un faible montant en BTC sur votre portefeuille ce qui pourrait constituer une tentative d'espionnage de la part de sociétés qui analyse la chaine.\n\nSi vous utilisez cette transaction de sortie des données dans le cadre d'une transaction représentant une dépense il sera alors possible de comprendre que vous êtes probablement aussi le propriétaire de l'autre adresse (coin merge).\n\nAfin de protéger votre vie privée, le portefeuille Haveno ne tient pas compte de ces "dust outputs" dans le cadre des transactions de vente et dans l'affichage de la balance. Vous pouvez définir une quantité seuil lorsqu'une "output" est considérée comme poussière dans les réglages. +funds.tx.dustAttackTx.popup=Cette transaction va envoyer un faible montant en XMR sur votre portefeuille ce qui pourrait constituer une tentative d'espionnage de la part de sociétés qui analyse la chaine.\n\nSi vous utilisez cette transaction de sortie des données dans le cadre d'une transaction représentant une dépense il sera alors possible de comprendre que vous êtes probablement aussi le propriétaire de l'autre adresse (coin merge).\n\nAfin de protéger votre vie privée, le portefeuille Haveno ne tient pas compte de ces "dust outputs" dans le cadre des transactions de vente et dans l'affichage de la balance. Vous pouvez définir une quantité seuil lorsqu'une "output" est considérée comme poussière dans les réglages. #################################################################### # Support @@ -905,7 +931,7 @@ support.filter=Chercher les litiges support.filter.prompt=Saisissez l'ID du trade, la date, l'adresse "onion" ou les données du compte. support.sigCheck.button=Vérifier la signature -support.sigCheck.popup.info=Dans le cas d'une demande de remboursement au DAO vous devez copier-coller le message résumant la médiation et le processus de jugement dans votre demande de remboursement sur Github. Pour que cette information soit vérifiable, n'importe quel utilisateur peut vérifier avec cet outil si la signature du médiateur ou de l'arbitre correspond à celle du résumé. +support.sigCheck.popup.info=Collez le message récapitulatif du processus d'arbitrage. Avec cet outil, n'importe quel utilisateur peut vérifier si la signature de l'arbitre correspond au message récapitulatif. support.sigCheck.popup.header=Vérifier la signature du résultat du litige support.sigCheck.popup.msg.label=Message de résumé support.sigCheck.popup.msg.prompt=Copiez et collez le message résumant le litige @@ -941,8 +967,8 @@ support.savedInMailbox=Message sauvegardé dans la boîte mail du destinataire support.arrived=Message reçu par le destinataire support.acknowledged=Réception du message confirmée par le destinataire support.error=Le destinataire n''a pas pu traiter le message. Erreur : {0} -support.buyerAddress=Adresse de l'acheteur BTC -support.sellerAddress=Adresse du vendeur BTC +support.buyerAddress=Adresse de l'acheteur XMR +support.sellerAddress=Adresse du vendeur XMR support.role=Rôle support.agent=Agent d'assistance support.state=État @@ -950,13 +976,13 @@ support.chat=Chat support.closed=Fermé support.open=Ouvert support.process=Processus -support.buyerMaker=Acheteur BTC/Maker -support.sellerMaker=Vendeur BTC/Maker -support.buyerTaker=Acheteur BTC/Taker -support.sellerTaker=Vendeur BTC/Taker +support.buyerMaker=Acheteur XMR/Maker +support.sellerMaker=Vendeur XMR/Maker +support.buyerTaker=Acheteur XMR/Taker +support.sellerTaker=Vendeur XMR/Taker -support.backgroundInfo=Haveno n'est pas une entreprise, donc elle traite les litiges différemment.\n\nLes traders peuvent communiquer au sein de l'application via un chat sécurisé sur l'écran des transactions ouvertes pour essayer de résoudre les litiges par eux-mêmes. Si cela ne suffit pas, un médiateur peut intervenir pour les aider. Le médiateur évaluera la situation et suggérera un paiement des fonds de transaction. Si les deux traders acceptent cette suggestion, la transaction de paiement est réalisée et l'échange est clos. Si un ou les deux traders n'acceptent pas le paiement suggéré par le médiateur, ils peuvent demander un arbitrage. L'arbitre réévaluera la situation et, si cela est justifié, remboursera personnellement le négociateur et demandera le remboursement de ce paiement à la DAO Haveno. -support.initialInfo=Veuillez entrer une description de votre problème dans le champ texte ci-dessous. Ajoutez autant d''informations que possible pour accélérer le temps de résolution du litige.\n\nVoici une check list des informations que vous devez fournir :\n● Si vous êtes l''acheteur BTC : Avez-vous effectué le paiement Fiat ou Crypto ? Si oui, avez-vous cliqué sur le bouton "paiement commencé" dans l''application ?\n● Si vous êtes le vendeur BTC : Avez-vous reçu le paiement Fiat ou Crypto ? Si oui, avez-vous cliqué sur le bouton "paiement reçu" dans l''application ?\n● Quelle version de Haveno utilisez-vous ?\n● Quel système d''exploitation utilisez-vous ?\n● Si vous avez rencontré un problème avec des transactions qui ont échoué, veuillez envisager de passer à un nouveau répertoire de données.\nParfois, le répertoire de données est corrompu et conduit à des bogues étranges. \nVoir : https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nVeuillez vous familiariser avec les règles de base du processus de règlement des litiges :\n● Vous devez répondre aux demandes des {0} dans les 2 jours.\n● Les médiateurs répondent dans un délai de 2 jours. Les arbitres répondent dans un délai de 5 jours ouvrables.\n● Le délai maximum pour un litige est de 14 jours.\n● Vous devez coopérer avec les {1} et fournir les renseignements qu''ils demandent pour faire valoir votre cause.\n● Vous avez accepté les règles décrites dans le document de litige dans l''accord d''utilisation lorsque vous avez lancé l''application pour la première fois.\n\nVous pouvez en apprendre davantage sur le processus de litige à l''adresse suivante {2} +support.backgroundInfo=Haveno n'est pas une entreprise, donc il gère les litiges différemment.\n\nLes traders peuvent communiquer au sein de l'application via une discussion sécurisée sur l'écran des transactions ouvertes pour tenter de résoudre les litiges eux-mêmes. Si cela n'est pas suffisant, un médiateur évaluera la situation et décidera d'un paiement des fonds de transaction. +support.initialInfo=Veuillez entrer une description de votre problème dans le champ texte ci-dessous. Ajoutez autant d''informations que possible pour accélérer le temps de résolution du litige.\n\nVoici une check list des informations que vous devez fournir :\n● Si vous êtes l''acheteur XMR : Avez-vous effectué le paiement Fiat ou Crypto ? Si oui, avez-vous cliqué sur le bouton "paiement commencé" dans l''application ?\n● Si vous êtes le vendeur XMR : Avez-vous reçu le paiement Fiat ou Crypto ? Si oui, avez-vous cliqué sur le bouton "paiement reçu" dans l''application ?\n● Quelle version de Haveno utilisez-vous ?\n● Quel système d''exploitation utilisez-vous ?\n● Si vous avez rencontré un problème avec des transactions qui ont échoué, veuillez envisager de passer à un nouveau répertoire de données.\nParfois, le répertoire de données est corrompu et conduit à des bogues étranges. \nVoir : https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nVeuillez vous familiariser avec les règles de base du processus de règlement des litiges :\n● Vous devez répondre aux demandes des {0} dans les 2 jours.\n● Les médiateurs répondent dans un délai de 2 jours. Les arbitres répondent dans un délai de 5 jours ouvrables.\n● Le délai maximum pour un litige est de 14 jours.\n● Vous devez coopérer avec les {1} et fournir les renseignements qu''ils demandent pour faire valoir votre cause.\n● Vous avez accepté les règles décrites dans le document de litige dans l''accord d''utilisation lorsque vous avez lancé l''application pour la première fois.\n\nVous pouvez en apprendre davantage sur le processus de litige à l''adresse suivante {2} support.systemMsg=Message du système: {0} support.youOpenedTicket=Vous avez ouvert une demande de support.\n\n{0}\n\nHaveno version: {1} support.youOpenedDispute=Vous avez ouvert une demande de litige.\n\n{0}\n\nHaveno version: {1} @@ -980,13 +1006,14 @@ settings.tab.network=Info sur le réseau settings.tab.about=À propos setting.preferences.general=Préférences générales -setting.preferences.explorer=Exploreur Bitcoin +setting.preferences.explorer=Exploreur Monero setting.preferences.deviation=Ecart maximal par rapport au prix du marché setting.preferences.avoidStandbyMode=Éviter le mode veille +setting.preferences.useSoundForNotifications=Jouer des sons pour les notifications setting.preferences.autoConfirmXMR=Auto-confirmation XMR setting.preferences.autoConfirmEnabled=Activé setting.preferences.autoConfirmRequiredConfirmations=Confirmations requises -setting.preferences.autoConfirmMaxTradeSize=Montant maximum du trade (BTC) +setting.preferences.autoConfirmMaxTradeSize=Montant maximum du trade (XMR) setting.preferences.autoConfirmServiceAddresses=URLs de l'explorateur de Monero (utilise Tor, à part pour l'hôte local, les addresses IP locales, et les noms de domaine en *.local) setting.preferences.deviationToLarge=Les valeurs supérieures à {0}% ne sont pas autorisées. setting.preferences.txFee=Frais de transaction du retrait (satoshis/vbyte) @@ -1023,29 +1050,31 @@ settings.preferences.editCustomExplorer.name=Nom settings.preferences.editCustomExplorer.txUrl=URL de la transaction settings.preferences.editCustomExplorer.addressUrl=Addresse URL -settings.net.btcHeader=Réseau Bitcoin +settings.net.xmrHeader=Réseau Monero settings.net.p2pHeader=Le réseau Haveno settings.net.onionAddressLabel=Mon adresse onion settings.net.xmrNodesLabel=Utiliser des nœuds Monero personnalisés settings.net.moneroPeersLabel=Pairs connectés +settings.net.connection=Connexion +settings.net.connected=Connecté settings.net.useTorForXmrJLabel=Utiliser Tor pour le réseau Monero settings.net.moneroNodesLabel=Nœuds Monero pour se connecter à -settings.net.useProvidedNodesRadio=Utiliser les nœuds Bitcoin Core fournis -settings.net.usePublicNodesRadio=Utiliser le réseau Bitcoin public -settings.net.useCustomNodesRadio=Utiliser des nœuds Bitcoin Core personnalisés +settings.net.useProvidedNodesRadio=Utiliser les nœuds Monero Core fournis +settings.net.usePublicNodesRadio=Utiliser le réseau Monero public +settings.net.useCustomNodesRadio=Utiliser des nœuds Monero Core personnalisés settings.net.warn.usePublicNodes=Si vous utilisez des nœuds publics Monero, vous êtes exposé à tout risque lié à l'utilisation de nœuds distants non fiables.\n\nVeuillez lire plus de détails sur [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nÊtes-vous sûr de vouloir utiliser des nœuds publics ? settings.net.warn.usePublicNodes.useProvided=Non, utiliser les nœuds fournis. settings.net.warn.usePublicNodes.usePublic=Oui, utiliser un réseau public -settings.net.warn.useCustomNodes.B2XWarning=Veuillez vous assurer que votre nœud Bitcoin est un nœud Bitcoin Core de confiance !\n\nLa connexion à des nœuds qui ne respectent pas les règles du consensus de Bitcoin Core peut corrompre votre portefeuille et causer des problèmes dans le processus de trading.\n\nLes utilisateurs qui se connectent à des nœuds qui ne respectent pas les règles du consensus sont responsables des dommages qui en résultent. Tout litige qui en résulte sera tranché en faveur de l'autre pair. Aucune assistance technique ne sera apportée aux utilisateurs qui ignorent ces mécanismes d'alertes et de protections ! -settings.net.warn.invalidBtcConfig=La connection au réseau Bitcoin a échoué car votre configuration est invalide.\n\nVotre configuration a été réinitialisée afin d'utiliser les noeuds Bitcoin fournis à la place. Vous allez avoir besoin de relancer l'application. -settings.net.localhostXmrNodeInfo=Information additionnelle : Haveno cherche un noeud Bitcoin local au démarrage. Si il est trouvé, Haveno communiquera avec le réseau Bitcoin uniquement à travers ce noeud. +settings.net.warn.useCustomNodes.B2XWarning=Veuillez vous assurer que votre nœud Monero est un nœud Monero Core de confiance !\n\nLa connexion à des nœuds qui ne respectent pas les règles du consensus de Monero Core peut corrompre votre portefeuille et causer des problèmes dans le processus de trading.\n\nLes utilisateurs qui se connectent à des nœuds qui ne respectent pas les règles du consensus sont responsables des dommages qui en résultent. Tout litige qui en résulte sera tranché en faveur de l'autre pair. Aucune assistance technique ne sera apportée aux utilisateurs qui ignorent ces mécanismes d'alertes et de protections ! +settings.net.warn.invalidXmrConfig=La connection au réseau Monero a échoué car votre configuration est invalide.\n\nVotre configuration a été réinitialisée afin d'utiliser les noeuds Monero fournis à la place. Vous allez avoir besoin de relancer l'application. +settings.net.localhostXmrNodeInfo=Information additionnelle : Haveno cherche un noeud Monero local au démarrage. Si il est trouvé, Haveno communiquera avec le réseau Monero uniquement à travers ce noeud. settings.net.p2PPeersLabel=Pairs connectés settings.net.onionAddressColumn=Adresse onion settings.net.creationDateColumn=Établi settings.net.connectionTypeColumn=In/Out settings.net.sentDataLabel=Statistiques des données envoyées settings.net.receivedDataLabel=Statistiques des données reçues -settings.net.chainHeightLabel=Hauteur du dernier block BTC +settings.net.chainHeightLabel=Hauteur du dernier block XMR settings.net.roundTripTimeColumn=Roundtrip settings.net.sentBytesColumn=Envoyé settings.net.receivedBytesColumn=Reçu @@ -1060,7 +1089,7 @@ settings.net.needRestart=Vous devez redémarrer l'application pour appliquer cet settings.net.notKnownYet=Pas encore connu... settings.net.sentData=Données envoyées: {0}, {1} messages, {2} messages/seconde settings.net.receivedData=Données reçues: {0}, {1} messages, {2} messages/seconde -settings.net.chainHeight=Hauteur de la chaîne des pairs Bitcoin: {0} +settings.net.chainHeight=Hauteur de la chaîne des pairs Monero: {0} settings.net.ips=[IP address:port | host name:port | onion address:port] (séparés par des virgules). Le port peut être ignoré si utilisé par défaut (8333). settings.net.seedNode=Seed node settings.net.directPeer=Pair (direct) @@ -1069,7 +1098,7 @@ settings.net.peer=Pair settings.net.inbound=inbound settings.net.outbound=outbound setting.about.aboutHaveno=À propos de Haveno -setting.about.about=Haveno est un logiciel libre qui facilite l'échange de Bitcoins avec les devises nationales (et d'autres cryptomonnaies) au moyen d'un réseau pair-to-pair décentralisé, de manière à protéger au mieux la vie privée des utilisateurs. Pour en savoir plus sur Haveno, consultez la page Web du projet. +setting.about.about=Haveno est un logiciel libre qui facilite l'échange de Moneros avec les devises nationales (et d'autres cryptomonnaies) au moyen d'un réseau pair-to-pair décentralisé, de manière à protéger au mieux la vie privée des utilisateurs. Pour en savoir plus sur Haveno, consultez la page Web du projet. setting.about.web=Page web de Haveno setting.about.code=Code source setting.about.agpl=Licence AGPL @@ -1106,7 +1135,7 @@ setting.about.shortcuts.openDispute.value=Sélectionnez l''échange en cours et setting.about.shortcuts.walletDetails=Ouvrir la fenêtre avec les détails sur le portefeuille -setting.about.shortcuts.openEmergencyBtcWalletTool=Ouvrir l'outil de portefeuille d'urgence pour BTC +setting.about.shortcuts.openEmergencyXmrWalletTool=Ouvrir l'outil de portefeuille d'urgence pour XMR setting.about.shortcuts.showTorLogs=Basculer le niveau de log pour les messages Tor entre DEBUG et WARN @@ -1132,7 +1161,7 @@ setting.about.shortcuts.sendPrivateNotification=Envoyer une notification privée setting.about.shortcuts.sendPrivateNotification.value=Ouvrez l'information du pair via l'avatar et appuyez sur: {0} setting.info.headline=Nouvelle fonctionnalité, l'auto-confirmation XMR -setting.info.msg=Vous n'avez pas saisi l'ID et la clé de transaction. \n\nSi vous ne fournissez pas ces données, votre partenaire commercial ne peut pas utiliser la fonction de confirmation automatique pour libérer rapidement le BTC après avoir reçu le XMR.\nEn outre, Haveno demande aux expéditeurs XMR de fournir ces informations aux médiateurs et aux arbitres en cas de litige.\nPlus de détails sont dans Haveno Wiki: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=Vous n'avez pas saisi l'ID et la clé de transaction. \n\nSi vous ne fournissez pas ces données, votre partenaire commercial ne peut pas utiliser la fonction de confirmation automatique pour libérer rapidement le XMR après avoir reçu le XMR.\nEn outre, Haveno demande aux expéditeurs XMR de fournir ces informations aux médiateurs et aux arbitres en cas de litige.\nPlus de détails sont dans Haveno Wiki: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1141,7 +1170,7 @@ account.tab.mediatorRegistration=Enregistrement du médiateur account.tab.refundAgentRegistration=Enregistrement de l'agent de remboursement account.tab.signing=Signature en cours account.info.headline=Bienvenue sur votre compte Haveno -account.info.msg=Ici, vous pouvez ajouter des comptes de trading en devises nationales et en cryptos et créer une sauvegarde de votre portefeuille ainsi que des données de votre compte.\n\nUn nouveau portefeuille Bitcoin a été créé un premier lancement de Haveno.\n\nNous vous recommandons vivement d'écrire les mots-clés de votre seed de portefeuille Bitcoin (voir l'onglet en haut) et d'envisager d'ajouter un mot de passe avant le transfert de fonds. Les dépôts et retraits de Bitcoin sont gérés dans la section \"Fonds\".\n\nNotice de confidentialité et de sécurité : Haveno étant une plateforme d'échange décentralisée, toutes vos données sont conservées sur votre ordinateur. Il n'y a pas de serveurs, nous n'avons donc pas accès à vos informations personnelles, à vos fonds ou même à votre adresse IP. Les données telles que les numéros de compte bancaire, les adresses crypto & Bitcoin, etc ne sont partagées avec votre pair de trading que pour effectuer les transactions que vous initiez (en cas de litige, le médiateur et l’arbitre verront les mêmes données que votre pair de trading). +account.info.msg=Ici, vous pouvez ajouter des comptes de trading en devises nationales et en cryptos et créer une sauvegarde de votre portefeuille ainsi que des données de votre compte.\n\nUn nouveau portefeuille Monero a été créé un premier lancement de Haveno.\n\nNous vous recommandons vivement d'écrire les mots-clés de votre seed de portefeuille Monero (voir l'onglet en haut) et d'envisager d'ajouter un mot de passe avant le transfert de fonds. Les dépôts et retraits de Monero sont gérés dans la section \"Fonds\".\n\nNotice de confidentialité et de sécurité : Haveno étant une plateforme d'échange décentralisée, toutes vos données sont conservées sur votre ordinateur. Il n'y a pas de serveurs, nous n'avons donc pas accès à vos informations personnelles, à vos fonds ou même à votre adresse IP. Les données telles que les numéros de compte bancaire, les adresses crypto & Monero, etc ne sont partagées avec votre pair de trading que pour effectuer les transactions que vous initiez (en cas de litige, le médiateur et l’arbitre verront les mêmes données que votre pair de trading). account.menu.paymentAccount=Comptes en devise nationale account.menu.altCoinsAccountView=Compte Cryptos @@ -1152,7 +1181,7 @@ account.menu.backup=Sauvegarde account.menu.notifications=Notifications account.menu.walletInfo.balance.headLine=Solde du portefeuille -account.menu.walletInfo.balance.info=Ceci montre le solde du portefeuille interne en incluant les transactions non-confirmées.\nPour le BTC, le solde du portefeuille interne affiché ci-dessous devrait correspondre à la somme des soldes 'Disponibles' et 'Réservés' affichés en haut à droite de cette fenêtre. +account.menu.walletInfo.balance.info=Ceci montre le solde du portefeuille interne en incluant les transactions non-confirmées.\nPour le XMR, le solde du portefeuille interne affiché ci-dessous devrait correspondre à la somme des soldes 'Disponibles' et 'Réservés' affichés en haut à droite de cette fenêtre. account.menu.walletInfo.xpub.headLine=Afficher les clés (clés xpub) account.menu.walletInfo.walletSelector={0} {1} portefeuille account.menu.walletInfo.path.headLine=Chemin du trousseau HD @@ -1181,7 +1210,7 @@ account.crypto.popup.upx.msg=Pour échanger UPX sur Haveno, vous devez comprendr # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Le trading d'ARQ sur Haveno exige que vous compreniez et remplissiez les exigences suivantes:\n\nPour envoyer des ARQ, vous devez utiliser soit le portefeuille officiel ArQmA GUI soit le portefeuille ArQmA CLI avec le flag store-tx-info activé (par défaut dans les nouvelles versions). Veuillez vous assurer que vous pouvez accéder à la tx key car cela pourrait être nécessaire en cas de litige.\narqma-wallet-cli (utiliser la commande get_tx_key)\narqma-wallet-gui (allez dans l'onglet historique et cliquez sur le bouton (P) pour accéder à la preuve de paiement).\n\nAvec un l'explorateur de bloc normal, le transfert n'est pas vérifiable.\n\nVous devez fournir au médiateur ou à l'arbitre les données suivantes en cas de litige:\n- Le tx de la clé privée\n- Le hash de la transaction\n- L'adresse publique du destinataire\n\nSi vous manquez de communiquer les données ci-dessus ou si vous utilisez un portefeuille incompatible, vous perdrez le litige. L'expéditeur des ARQ est responsable de la transmission au médiateur ou à l'arbitre de la vérification du transfert ces informations relatives au litige.\n\nIl n'est pas nécessaire de fournir l'ID du paiement, seulement l'adresse publique normale.\nSi vous n'êtes pas sûr de ce processus, visitez le canal discord ArQmA (https://discord.gg/s9BQpJT) ou le forum ArQmA (https://labs.arqma.com) pour obtenir plus d'informations. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Pour échanger XMR sur Haveno, vous devez comprendre et respecter les exigences suivantes: \n\nSi vous vendez XMR, en cas de litige, vous devez fournir au médiateur ou à l'arbitre les informations suivantes: - clé de transaction (clé publique Tx, clé Tx, clé privée Tx) - ID de transaction (ID Tx Ou hachage Tx) - Adresse de destination de la transaction (adresse du destinataire) \n\nConsultez plus d'informations sur le portefeuille Monero dans le wiki: https: //bisq.wiki/Trading_Monero#Proving_payments \n\nSi vous ne fournissez pas les données de transaction requises, vous serez directement jugé échoue dans le litige. \n\nNotez également que Haveno fournit désormais la fonction de confirmation automatique des transactions XMR pour effectuer plus rapidement des transactions, mais vous devez l'activer dans les paramètres. \n\nPour plus d'informations sur la fonction de confirmation automatique, veuillez consulter le Wiki: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +account.crypto.popup.xmr.msg=Pour échanger XMR sur Haveno, vous devez comprendre et respecter les exigences suivantes: \n\nSi vous vendez XMR, en cas de litige, vous devez fournir au médiateur ou à l'arbitre les informations suivantes: - clé de transaction (clé publique Tx, clé Tx, clé privée Tx) - ID de transaction (ID Tx Ou hachage Tx) - Adresse de destination de la transaction (adresse du destinataire) \n\nConsultez plus d'informations sur le portefeuille Monero dans le wiki: https: //haveno.exchange/wiki/Trading_Monero#Proving_payments \n\nSi vous ne fournissez pas les données de transaction requises, vous serez directement jugé échoue dans le litige. \n\nNotez également que Haveno fournit désormais la fonction de confirmation automatique des transactions XMR pour effectuer plus rapidement des transactions, mais vous devez l'activer dans les paramètres. \n\nPour plus d'informations sur la fonction de confirmation automatique, veuillez consulter le Wiki: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Le navigateur blockchain pour échanger MSR sur Haveno vous oblige à comprendre et à respecter les exigences suivantes: \n\nLors de l'envoi de MSR, vous devez utiliser le portefeuille officiel Masari GUI, le portefeuille Masari CLI avec le logo store-tx-info activé (activé par défaut) ou le portefeuille web Masari (https://wallet.getmasari.org). Assurez-vous d'avoir accès à la clé tx, car cela est nécessaire en cas de litige. monero-wallet-cli (à l'aide de la commande get_Tx_key) monero-wallet-gui: sur la page Avancé> Preuve / Vérification. \n\nLe portefeuille web Masari (accédez à Compte-> Historique des transactions et vérifiez les détails de la transaction que vous avez envoyés) \n\nLa vérification peut être effectuée dans le portefeuille. monero-wallet-cli: utilisez la commande (check_tx_key). monero-wallet-gui: sur la page Avancé> Preuve / Vérification La vérification peut être effectuée dans le navigateur blockchain. Ouvrez le navigateur blockchain (https://explorer.getmasari.org) et utilisez la barre de recherche pour trouver votre hachage de transaction. Une fois que vous avez trouvé la transaction, faites défiler jusqu'à la zone «certificat à envoyer» en bas et remplissez les détails requis. En cas de litige, vous devez fournir les informations suivantes au médiateur ou à l'arbitre: - Clé privée Tx- Hachage de transaction- Adresse publique du destinataire \n\nAucun ID de transaction n'est requis, seule une adresse publique normale est requise. Si vous ne fournissez pas les informations ci-dessus ou si vous utilisez un portefeuille incompatible, vous perdrez le litige. En cas de litige, l'expéditeur XMR est responsable de fournir la vérification du transfert XMR au médiateur ou un arbitre. \n\nSi vous n'êtes pas sûr du processus, veuillez visiter le Masari Discord officiel (https://discord.gg/sMCwMqs) pour obtenir de l'aide. # suppress inspection "UnusedProperty" @@ -1209,7 +1238,7 @@ account.crypto.popup.pars.msg=Echanger ParsiCoin sur Haveno nécessite que vous account.crypto.popup.blk-burnt.msg=Pour échanger les monnaies brûlées, vous devez savoir ce qui suit: \n\nLes monnaies brûlées ne peuvent pas être dépensée. Pour les échanger sur Haveno, le script de sortie doit prendre la forme suivante: OP_RETURN OP_PUSHDATA, suivi des octets de données pertinents, ces octets forment l'adresse après le codage hexadécimal. Par exemple, une devise brûlée avec l'adresse 666f6f ("foo" en UTF-8) aura le script suivant: \n\nOP_RETURN OP_PUSHDATA 666f6f \n\nPour créer de la monnaie brûlée, vous pouvez utiliser la commande RPC «brûler», disponible dans certains portefeuilles. \n\nPour d'éventuelles situations, vous pouvez vérifier https://ibo.laboratorium.ee \n\nPuisque la monnaie brûlée ne peut pas être utilisée, elle ne peut pas être revendue. «Vendre» une devise brûlée signifie brûler la devise d'origine (données associées à l'adresse de destination). \n\nEn cas de litige, le vendeur BLK doit fournir le hachage de la transaction. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Pour échanger L-BTC sur Haveno, vous devez comprendre les termes suivants: \n\nLorsque vous acceptez des transactions L-BTC sur Haveno, vous ne pouvez pas utiliser Blockstream Green Wallet sur le téléphone mobile ou un portefeuille de dépôt / commercial. Vous ne devez recevoir du L-BTC que dans le portefeuille Liquid Elements Core ou un autre portefeuille L-BTC avec une adresse L-BTC et une clé de sécurité qui vous permettre d'être anonyme. \n\nEn cas de médiation ou en cas de litige de transaction, vous devez divulguer la clé de sécurité de l'adresse L-BTC au médiateur Haveno ou à l'agent de remboursement afin qu'ils puissent vérifier les détails de votre transaction anonyme sur leur propre nœud complet Elements Core. \n\nSi vous ne comprenez pas ou ne comprenez pas ces exigences, n'échangez pas de L-BTC sur Haveno. +account.crypto.popup.liquidmonero.msg=Pour échanger L-XMR sur Haveno, vous devez comprendre les termes suivants: \n\nLorsque vous acceptez des transactions L-XMR sur Haveno, vous ne pouvez pas utiliser Blockstream Green Wallet sur le téléphone mobile ou un portefeuille de dépôt / commercial. Vous ne devez recevoir du L-XMR que dans le portefeuille Liquid Elements Core ou un autre portefeuille L-XMR avec une adresse L-XMR et une clé de sécurité qui vous permettre d'être anonyme. \n\nEn cas de médiation ou en cas de litige de transaction, vous devez divulguer la clé de sécurité de l'adresse L-XMR au médiateur Haveno ou à l'agent de remboursement afin qu'ils puissent vérifier les détails de votre transaction anonyme sur leur propre nœud complet Elements Core. \n\nSi vous ne comprenez pas ou ne comprenez pas ces exigences, n'échangez pas de L-XMR sur Haveno. account.traditional.yourTraditionalAccounts=Vos comptes en devise nationale @@ -1229,13 +1258,13 @@ account.password.setPw.button=Définir un mot de passe account.password.setPw.headline=Définir le mot de passe de protection pour le portefeuille account.password.info=Avec la protection par mot de passe, vous devrez entrer votre mot de passe au démarrage de l'application, lors du retrait de monero depuis votre portefeuille et lors de l'affichage de vos mots de la graine (seed). -account.seed.backup.title=Sauvegarder les mots composant la seed de votre portefeuille -account.seed.info=Veuillez noter les mots de la seed du portefeuille ainsi que la date! Vous pouvez récupérer votre portefeuille à tout moment avec les mots de la seed et la date.\nLes mêmes mots-clés de la seed sont utilisés pour les portefeuilles BTC et BSQ.\n\nVous devriez écrire les mots de la seed sur une feuille de papier. Ne les enregistrez pas sur votre ordinateur.\n\nVeuillez noter que les mots de la seed ne remplacent PAS une sauvegarde.\nVous devez créer une sauvegarde de l'intégralité du répertoire de l'application à partir de l'écran \"Compte/Sauvergarde\" pour restaurer correctement les données de l'application.\nL'importation de mots de la seed n'est recommandée qu'en cas d'urgence. L'application ne sera pas fonctionnelle sans une sauvegarde adéquate des fichiers et des clés de la base de données ! -account.seed.backup.warning=Veuillez noter que les mots de départ ne peuvent pas remplacer les sauvegardes. Vous devez sauvegarder tout le répertoire de l'application (dans l'onglet «Compte / Sauvegarde») pour restaurer l'état et les données de l'application. L'importation de mots de départ n'est recommandée qu'en cas d'urgence. Si le fichier de base de données et la clé ne sont pas correctement sauvegardés, l'application ne fonctionnera pas! \n\nVoir plus d'informations sur le wiki Haveno: [HYPERLINK:https://bisq.wiki/Backing_up_application_data] +account.seed.backup.title=Sauvegardez les mots de votre portefeuille. +account.seed.info=Veuillez noter les mots de passe de votre portefeuille ainsi que la date. Vous pouvez récupérer votre portefeuille à tout moment avec les mots de passe et la date.\n\nVous devriez noter les mots de passe sur une feuille de papier. Ne les enregistrez pas sur l'ordinateur.\n\nVeuillez noter que les mots de passe ne remplacent pas une sauvegarde.\nVous devez créer une sauvegarde de l'ensemble du répertoire de l'application à partir de l'écran "Compte/Sauvegarde" pour récupérer l'état et les données de l'application. +account.seed.backup.warning=Veuillez noter que les mots de passe ne remplacent pas une sauvegarde.\nVous devez créer une sauvegarde de l'ensemble du répertoire de l'application à partir de l'écran "Compte/Sauvegarde" pour récupérer l'état et les données de l'application. account.seed.warn.noPw.msg=Vous n'avez pas configuré un mot de passe de portefeuille qui protégerait l'affichage des mots composant la seed.\n\nVoulez-vous afficher les mots composant la seed? account.seed.warn.noPw.yes=Oui, et ne me le demander plus à l'avenir account.seed.enterPw=Entrer le mot de passe afficher les mots composant la seed -account.seed.restore.info=Veuillez effectuer une sauvegarde avant de procéder à une restauration à partir du mot de passe. Sachez que la restauration d'un portefeuille n'est a faire qu'en cas d'urgence et qu'elle peut causer des problèmes avec la base de données interne du portefeuille.\nCe n'est pas une façon de faire une sauvegarde ! Veuillez utiliser une sauvegarde à partir du répertoire de données de l'application pour restaurer l'état antérieur de l'application.\n\nAprès la restauration, l'application s'arrêtera automatiquement. Après le redémarrage de l'application, elle sera resynchronisée avec le réseau Bitcoin. Cela peut prendre un certain temps et peut consommer beaucoup de puissance sur le CPU, surtout si le portefeuille était plus vieux et contient beaucoup de transactions. Veuillez éviter d'interrompre ce processus, sinon vous devrez peut-être supprimer à nouveau le fichier de chaîne SPV ou répéter le processus de restauration. +account.seed.restore.info=Veuillez effectuer une sauvegarde avant de procéder à une restauration à partir du mot de passe. Sachez que la restauration d'un portefeuille n'est a faire qu'en cas d'urgence et qu'elle peut causer des problèmes avec la base de données interne du portefeuille.\nCe n'est pas une façon de faire une sauvegarde ! Veuillez utiliser une sauvegarde à partir du répertoire de données de l'application pour restaurer l'état antérieur de l'application.\n\nAprès la restauration, l'application s'arrêtera automatiquement. Après le redémarrage de l'application, elle sera resynchronisée avec le réseau Monero. Cela peut prendre un certain temps et peut consommer beaucoup de puissance sur le CPU, surtout si le portefeuille était plus vieux et contient beaucoup de transactions. Veuillez éviter d'interrompre ce processus, sinon vous devrez peut-être supprimer à nouveau le fichier de chaîne SPV ou répéter le processus de restauration. account.seed.restore.ok=Ok, effectuer la restauration et arrêter Haveno @@ -1260,13 +1289,13 @@ account.notifications.trade.label=Recevoir des messages pour le trade account.notifications.market.label=Recevoir des alertes sur les ordres account.notifications.price.label=Recevoir des alertes de prix account.notifications.priceAlert.title=Alertes de prix -account.notifications.priceAlert.high.label=Me prévenir si le prix du BTC est supérieur à -account.notifications.priceAlert.low.label=Me prévenir si le prix du BTC est inférieur à +account.notifications.priceAlert.high.label=Me prévenir si le prix du XMR est supérieur à +account.notifications.priceAlert.low.label=Me prévenir si le prix du XMR est inférieur à account.notifications.priceAlert.setButton=Définir l'alerte de prix account.notifications.priceAlert.removeButton=Retirer l'alerte de prix account.notifications.trade.message.title=L'état du trade a été modifié. account.notifications.trade.message.msg.conf=La transaction de dépôt pour l''échange avec ID {0} est confirmée. Veuillez ouvrir votre application Haveno et initier le paiement. -account.notifications.trade.message.msg.started=L''acheteur de BTC a initié le paiement pour la transaction avec ID {0}. +account.notifications.trade.message.msg.started=L''acheteur de XMR a initié le paiement pour la transaction avec ID {0}. account.notifications.trade.message.msg.completed=La transaction avec l''ID {0} est terminée. account.notifications.offer.message.title=Votre ordre a été accepté account.notifications.offer.message.msg=Votre ordre avec l''ID {0} a été accepté @@ -1276,10 +1305,10 @@ account.notifications.dispute.message.msg=Vous avez reçu un message de contesta account.notifications.marketAlert.title=Alertes sur les ordres account.notifications.marketAlert.selectPaymentAccount=Ordres correspondants au compte de paiement account.notifications.marketAlert.offerType.label=Type d'ordre qui m'intéresse -account.notifications.marketAlert.offerType.buy=Ordres d'achat (je veux vendre des BTC) -account.notifications.marketAlert.offerType.sell=Ordres de vente (je veux acheter des BTC) +account.notifications.marketAlert.offerType.buy=Ordres d'achat (je veux vendre des XMR) +account.notifications.marketAlert.offerType.sell=Ordres de vente (je veux acheter des XMR) account.notifications.marketAlert.trigger=Écart par rapport au prix de l'ordre (%) -account.notifications.marketAlert.trigger.info=Avec la définition d'une distance par rapport au prix, vous ne recevrez une alerte que lorsqu'un odre qui répondra (ou dépassera) vos exigences sera publié. Exemple : vous voulez vendre des BTC, mais vous ne vendrez qu'avec une prime de 2% par rapport au prix actuel du marché. En réglant ce champ à 2%, vous ne recevrez que des alertes pour les ordres dont les prix sont de 2% (ou plus) au dessus du prix actuel du marché. +account.notifications.marketAlert.trigger.info=Avec la définition d'une distance par rapport au prix, vous ne recevrez une alerte que lorsqu'un odre qui répondra (ou dépassera) vos exigences sera publié. Exemple : vous voulez vendre des XMR, mais vous ne vendrez qu'avec une prime de 2% par rapport au prix actuel du marché. En réglant ce champ à 2%, vous ne recevrez que des alertes pour les ordres dont les prix sont de 2% (ou plus) au dessus du prix actuel du marché. account.notifications.marketAlert.trigger.prompt=Écart en pourcentage par rapport au prix du marché (par ex. 2,50 %, -0,50 %, etc.) account.notifications.marketAlert.addButton=Ajouter une alerte pour les ordres account.notifications.marketAlert.manageAlertsButton=Gérer les alertes des ordres @@ -1306,10 +1335,10 @@ inputControlWindow.balanceLabel=Solde disponible contractWindow.title=Détails du conflit contractWindow.dates=Date de l'ordre / date de l'échange -contractWindow.btcAddresses=Adresse Bitcoin BTC acheteur / vendeur BTC -contractWindow.onions=Adresse réseau de l'acheteur de BTC / du vendeur de BTC -contractWindow.accountAge=Âge du compte acheteur BTC / vendeur BTC -contractWindow.numDisputes=Nombre de litiges de l'acheteur de BTC / du vendeur de BTC +contractWindow.xmrAddresses=Adresse Monero XMR acheteur / vendeur XMR +contractWindow.onions=Adresse réseau de l'acheteur de XMR / du vendeur de XMR +contractWindow.accountAge=Âge du compte acheteur XMR / vendeur XMR +contractWindow.numDisputes=Nombre de litiges de l'acheteur de XMR / du vendeur de XMR contractWindow.contractHash=Contracter le hash displayAlertMessageWindow.headline=Information importante! @@ -1335,8 +1364,8 @@ disputeSummaryWindow.title=Résumé disputeSummaryWindow.openDate=Date d'ouverture du ticket disputeSummaryWindow.role=Rôle du trader disputeSummaryWindow.payout=Versement du montant de l'opération -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} obtient le montant du versement de la transaction -disputeSummaryWindow.payout.getsAll=Payement maximum en BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} obtient le montant du versement de la transaction +disputeSummaryWindow.payout.getsAll=Payement maximum en XMR {0} disputeSummaryWindow.payout.custom=Versement personnalisé disputeSummaryWindow.payoutAmount.buyer=Montant du versement de l'acheteur disputeSummaryWindow.payoutAmount.seller=Montant du versement au vendeur @@ -1378,7 +1407,7 @@ disputeSummaryWindow.close.button=Fermer le ticket # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Le ticket a été fermé {0}\n {1} Adresse du noeud: {2} \n\nRésumé: \nID de transaction: {3} \nDevise: {4} \n Montant de la transaction: {5} \nMontant du paiement de l'acheteur BTC: {6} \nMontant du paiement du vendeur BTC: {7} \n\nRaison du litige: {8} \n\nRésumé: {9} \n\n +disputeSummaryWindow.close.msg=Le ticket a été fermé {0}\n {1} Adresse du noeud: {2} \n\nRésumé: \nID de transaction: {3} \nDevise: {4} \n Montant de la transaction: {5} \nMontant du paiement de l'acheteur XMR: {6} \nMontant du paiement du vendeur XMR: {7} \n\nRaison du litige: {8} \n\nRésumé: {9} \n\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1421,18 +1450,18 @@ filterWindow.mediators=Médiateurs filtrés (adresses onion sep. par une virgule filterWindow.refundAgents=Agents de remboursement filtrés (adresses onion sep. par virgule) filterWindow.seedNode=Nœuds de seed filtrés (adresses onion séparées par une virgule) filterWindow.priceRelayNode=Nœuds relais avec prix filtrés (adresses onion séparées par une virgule) -filterWindow.xmrNode=Nœuds Bitcoin filtrés (adresses séparées par une virgule + port) -filterWindow.preventPublicXmrNetwork=Empêcher l'utilisation du réseau public Bitcoin +filterWindow.xmrNode=Nœuds Monero filtrés (adresses séparées par une virgule + port) +filterWindow.preventPublicXmrNetwork=Empêcher l'utilisation du réseau public Monero filterWindow.disableAutoConf=Désactiver la confirmation automatique filterWindow.autoConfExplorers=Explorateur d'auto-confirmations filtrés (addresses à virgule de séparation) filterWindow.disableTradeBelowVersion=Version min. nécessaire pour pouvoir échanger filterWindow.add=Ajouter le filtre filterWindow.remove=Retirer le filtre -filterWindow.xmrFeeReceiverAddresses=Adresse de réception des frais BTC +filterWindow.xmrFeeReceiverAddresses=Adresse de réception des frais XMR filterWindow.disableApi=Désactiver l'API filterWindow.disableMempoolValidation=Désactiver la validation du Mempool -offerDetailsWindow.minBtcAmount=Montant BTC min. +offerDetailsWindow.minXmrAmount=Montant XMR min. offerDetailsWindow.min=(min. {0}) offerDetailsWindow.distance=(écart par rapport au prix de marché: {0}) offerDetailsWindow.myTradingAccount=Mon compte de trading @@ -1447,6 +1476,7 @@ offerDetailsWindow.confirm.maker=Confirmer: Placer un ordre de {0} monero offerDetailsWindow.confirm.taker=Confirmer: Acceptez l''ordre de {0} monero offerDetailsWindow.creationDate=Date de création offerDetailsWindow.makersOnion=Adresse onion du maker +offerDetailsWindow.challenge=Phrase secrète de l'offre qRCodeWindow.headline=QR Code qRCodeWindow.msg=Veuillez utiliser le code QR pour recharger du portefeuille externe au portefeuille Haveno. @@ -1475,7 +1505,7 @@ showWalletDataWindow.walletData=Données du portefeuille showWalletDataWindow.includePrivKeys=Inclure les clés privées setXMRTxKeyWindow.headline=La preuve XMR a été envoyée. -setXMRTxKeyWindow.note=Ajoutez les informations tx au-dessous pour confirmer automatiquement les transactions plus rapidement. Plus d'informations: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Ajoutez les informations tx au-dessous pour confirmer automatiquement les transactions plus rapidement. Plus d'informations: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=ID de transaction (en option) setXMRTxKeyWindow.txKey=Clé de transaction (en option) @@ -1487,7 +1517,7 @@ tacWindow.disagree=Je ne suis pas d'accord et je quitte tacWindow.arbitrationSystem=Règlement du litige tradeDetailsWindow.headline=Échange -tradeDetailsWindow.disputedPayoutTxId=ID de la transaction de versement contestée : +tradeDetailsWindow.disputedPayoutTxId=ID de la transaction de versement contestée tradeDetailsWindow.tradeDate=Date de l'échange tradeDetailsWindow.txFee=Frais de minage tradeDetailsWindow.tradePeersOnion=Adresse onion du pair de trading @@ -1497,8 +1527,10 @@ tradeDetailsWindow.agentAddresses=Arbitre/Médiateur tradeDetailsWindow.detailData=Données détaillées txDetailsWindow.headline=Détails de la transaction -txDetailsWindow.xmr.note=Vous avez envoyé du BTC. +txDetailsWindow.xmr.noteSent=Vous avez envoyé du XMR. +txDetailsWindow.xmr.noteReceived=Vous avez reçu XMR. txDetailsWindow.sentTo=Envoyé à +txDetailsWindow.receivedWith=Reçu avec txDetailsWindow.txId=ID de transaction closedTradesSummaryWindow.headline=Résumé de l'historique de trade @@ -1507,7 +1539,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} avec le prix courant du mar closedTradesSummaryWindow.totalVolume.title=Montant total échangé en {0} closedTradesSummaryWindow.totalMinerFee.title=Somme de tous les frais de mineur closedTradesSummaryWindow.totalMinerFee.value={0} ({1} du montant total du trade) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Somme de tous les frais de trade payés en BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Somme de tous les frais de trade payés en XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} du montant total du trade) walletPasswordWindow.headline=Entrer le mot de passe pour déverouiller @@ -1533,12 +1565,12 @@ torNetworkSettingWindow.bridges.header=Tor est-il bloqué? torNetworkSettingWindow.bridges.info=Si Tor est bloqué par votre fournisseur Internet ou dans votre pays, vous pouvez essayer d'utiliser les passerelles Tor.\nVisitez la page web de Tor sur: https://bridges.torproject.org/bridges pour en savoir plus sur les bridges et les pluggable transports. feeOptionWindow.headline=Choisissez la devise pour le paiement des frais de transaction -feeOptionWindow.info=Vous pouvez choisir de payer les frais de transaction en BSQ ou en BTC. Si vous choisissez BSQ, vous bénéficierez de frais de transaction réduits. +feeOptionWindow.info=Vous pouvez choisir de payer les frais de transaction en BSQ ou en XMR. Si vous choisissez BSQ, vous bénéficierez de frais de transaction réduits. feeOptionWindow.optionsLabel=Choisissez la devise pour le paiement des frais de transaction -feeOptionWindow.useBTC=Utiliser BTC +feeOptionWindow.useXMR=Utiliser XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (environ {1}/{2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (environ {1}/{2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1580,9 +1612,9 @@ popup.warning.noTradingAccountSetup.msg=Vous devez configurer une devise nationa popup.warning.noArbitratorsAvailable=Les arbitres ne sont pas disponibles. popup.warning.noMediatorsAvailable=Il n'y a pas de médiateurs disponibles. popup.warning.notFullyConnected=Vous devez attendre d'être complètement connecté au réseau.\nCela peut prendre jusqu'à 2 minutes au démarrage. -popup.warning.notSufficientConnectionsToBtcNetwork=Vous devez attendre d''avoir au minimum {0} connexions au réseau Bitcoin. -popup.warning.downloadNotComplete=Vous devez attendre que le téléchargement des blocs Bitcoin manquants soit terminé. -popup.warning.chainNotSynced=La hauteur de la blockchain du portefeuille Haveno n'est pas synchronisée correctement. Si vous avez récemment démarré l'application, veuillez attendre qu'un block de Bitcoin a soit publié.\n\nVous pouvez vérifier la hauteur de la blockchain dans Paramètres/Informations Réseau. Si plus d'un block passe et que ce problème persiste, il est possible que ça soit bloqué, dans ce cas effectuez une resynchronisation SPV [LIEN:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Vous devez attendre d''avoir au minimum {0} connexions au réseau Monero. +popup.warning.downloadNotComplete=Vous devez attendre que le téléchargement des blocs Monero manquants soit terminé. +popup.warning.walletNotSynced=Le portefeuille Haveno n'est pas synchronisé avec la hauteur la plus récente de la blockchain. Veuillez patienter jusqu'à ce que le portefeuille soit synchronisé ou vérifiez votre connexion. popup.warning.removeOffer=Vous êtes certain de vouloir retirer cet ordre? popup.warning.tooLargePercentageValue=Vous ne pouvez pas définir un pourcentage de 100% ou plus grand. popup.warning.examplePercentageValue=Merci de saisir un nombre sous la forme d'un pourcentage tel que \"5.4\" pour 5.4% @@ -1602,13 +1634,13 @@ popup.warning.priceRelay=Relais de prix popup.warning.seed=seed popup.warning.mandatoryUpdate.trading=Veuillez faire une mise à jour vers la dernière version de Haveno. Une mise à jour obligatoire a été publiée, laquelle désactive le trading sur les anciennes versions. Veuillez consulter le Forum Haveno pour obtenir plus d'informations. popup.warning.noFilter=Nous n'avons pas reçu d'object de filtre de la part des noeuds source. Ceci n'est pas une situation attendue. Veuillez informer les développeurs de Haveno -popup.warning.burnBTC=Cette transaction n''est pas possible, car les frais de minage de {0} dépasseraient le montant à transférer de {1}. Veuillez patienter jusqu''à ce que les frais de minage soient de nouveau bas ou jusqu''à ce que vous ayez accumulé plus de BTC à transférer. +popup.warning.burnXMR=Cette transaction n''est pas possible, car les frais de minage de {0} dépasseraient le montant à transférer de {1}. Veuillez patienter jusqu''à ce que les frais de minage soient de nouveau bas ou jusqu''à ce que vous ayez accumulé plus de XMR à transférer. -popup.warning.openOffer.makerFeeTxRejected=La transaction de frais de maker pour l''offre avec ID {0} a été rejetée par le réseau Bitcoin.\nID de transaction={1}.\nL''offre a été retirée pour éviter d''autres problèmes.\nAllez dans \"Paramètres/Info sur le réseau réseau\" et faites une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l''équipe Haveno disposible sur Keybase. +popup.warning.openOffer.makerFeeTxRejected=La transaction de frais de maker pour l''offre avec ID {0} a été rejetée par le réseau Monero.\nID de transaction={1}.\nL''offre a été retirée pour éviter d''autres problèmes.\nAllez dans \"Paramètres/Info sur le réseau réseau\" et faites une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l''équipe Haveno disposible sur Keybase. popup.warning.trade.txRejected.tradeFee=frais de transaction popup.warning.trade.txRejected.deposit=dépôt -popup.warning.trade.txRejected=La transaction {0} pour le trade qui a pour ID {1} a été rejetée par le réseau Bitcoin.\nID de transaction={2}.\nLe trade a été déplacé vers les échanges échoués.\nAllez dans \"Paramètres/Info sur le réseau\" et effectuez une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l'équipe Haveno est disponible sur Keybase. +popup.warning.trade.txRejected=La transaction {0} pour le trade qui a pour ID {1} a été rejetée par le réseau Monero.\nID de transaction={2}.\nLe trade a été déplacé vers les échanges échoués.\nAllez dans \"Paramètres/Info sur le réseau\" et effectuez une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l'équipe Haveno est disponible sur Keybase. popup.warning.openOfferWithInvalidMakerFeeTx=La transaction de frais de maker pour l''offre avec ID {0} n''est pas valide.\nID de transaction={1}.\nAllez dans \"Paramètres/Info sur le réseau réseau\" et faites une resynchronisation SPV.\nPour obtenir de l''aide, le canal support de l''équipe Haveno est disponible sur Keybase. @@ -1617,15 +1649,15 @@ popup.info.securityDepositInfo=Afin de s'assurer que les deux traders suivent le popup.info.cashDepositInfo=Veuillez vous assurer d''avoir une succursale de l''établissement bancaire dans votre région afin de pouvoir effectuer le dépôt en espèces.\nL''identifiant bancaire (BIC/SWIFT) de la banque du vendeur est: {0}. popup.info.cashDepositInfo.confirm=Je confirme que je peux effectuer le dépôt. popup.info.shutDownWithOpenOffers=Haveno est en cours de fermeture, mais des ordres sont en attente.\n\nCes ordres ne seront pas disponibles sur le réseau P2P si Haveno est éteint, mais ils seront republiés sur le réseau P2P la prochaine fois que vous lancerez Haveno.\n\nPour garder vos ordres en ligne, laissez Haveno en marche et assurez-vous que cet ordinateur reste aussi en ligne (pour cela, assurez-vous qu'il ne passe pas en mode veille...la veille du moniteur ne pose aucun problème). -popup.info.qubesOSSetupInfo=Il semble que vous exécutez Haveno sous Qubes OS.\n\nVeuillez vous assurer que votre Haveno qube est mis en place de la manière expliquée dans notre guide [LIEN:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=Il semble que vous exécutez Haveno sous Qubes OS.\n\nVeuillez vous assurer que votre Haveno qube est mis en place de la manière expliquée dans notre guide [LIEN:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=La rétrogradation depuis la version {0} vers la version {1} n'est pas supportée. Veuillez utiliser la dernière version de Haveno. popup.privateNotification.headline=Notification privée importante! popup.securityRecommendation.headline=Recommendation de sécurité importante -popup.securityRecommendation.msg=Nous vous rappelons d'envisager d'utiliser la protection par mot de passe pour votre portefeuille si vous ne l'avez pas déjà activé.\n\nIl est également fortement recommandé d'écrire les mots de la seed de portefeuille. Ces mots de la seed sont comme un mot de passe principal pour récupérer votre portefeuille Bitcoin.\nVous trouverez plus d'informations à ce sujet dans l'onglet \"seed du portefeuille\".\n\nDe plus, il est recommandé de sauvegarder le dossier complet des données de l'application dans l'onglet \"Sauvegarde". +popup.securityRecommendation.msg=Nous vous rappelons d'envisager d'utiliser la protection par mot de passe pour votre portefeuille si vous ne l'avez pas déjà activé.\n\nIl est également fortement recommandé d'écrire les mots de la seed de portefeuille. Ces mots de la seed sont comme un mot de passe principal pour récupérer votre portefeuille Monero.\nVous trouverez plus d'informations à ce sujet dans l'onglet \"seed du portefeuille\".\n\nDe plus, il est recommandé de sauvegarder le dossier complet des données de l'application dans l'onglet \"Sauvegarde". -popup.moneroLocalhostNode.msg=Haveno a détecté un nœud Monero en cours d'exécution sur cette machine (sur l'hôte local).\n\nVeuillez vous assurer que le nœud est complètement synchronisé avant de démarrer Haveno. +popup.xmrLocalNode.msg=Haveno a détecté un nœud Monero en cours d'exécution sur cette machine (sur l'hôte local).\n\nVeuillez vous assurer que le nœud est complètement synchronisé avant de démarrer Haveno. popup.shutDownInProgress.headline=Fermeture en cours popup.shutDownInProgress.msg=La fermeture de l'application nécessite quelques secondes.\nVeuillez ne pas interrompre ce processus. @@ -1671,6 +1703,9 @@ popup.accountSigning.unsignedPubKeys.signed=Les clés publiques ont été signé popup.accountSigning.unsignedPubKeys.result.signed=Clés publiques signées popup.accountSigning.unsignedPubKeys.result.failed=Échec de la signature +popup.info.buyerAsTakerWithoutDeposit.headline=Aucun dépôt requis de la part de l'acheteur +popup.info.buyerAsTakerWithoutDeposit=Votre offre ne nécessitera pas de dépôt de sécurité ni de frais de la part de l'acheteur XMR.\n\nPour accepter votre offre, vous devez partager un mot de passe avec votre partenaire commercial en dehors de Haveno.\n\nLe mot de passe est généré automatiquement et affiché dans les détails de l'offre après sa création. + #################################################################### # Notifications #################################################################### @@ -1678,9 +1713,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Échec de la signature notification.trade.headline=Notification pour la transaction avec l''ID {0} notification.ticket.headline=Ticket de support pour l''échange avec l''ID {0} notification.trade.completed=La transaction est maintenant terminée et vous pouvez retirer vos fonds. -notification.trade.accepted=Votre ordre a été accepté par un BTC {0}. +notification.trade.accepted=Votre ordre a été accepté par un XMR {0}. notification.trade.unlocked=Votre échange avait au moins une confirmation sur la blockchain.\nVous pouvez effectuer le paiement maintenant. -notification.trade.paymentSent=L'acheteur de BTC a initié le paiement. +notification.trade.paymentSent=L'acheteur de XMR a initié le paiement. notification.trade.selectTrade=Choisir un trade notification.trade.peerOpenedDispute=Votre pair de trading a ouvert un {0}. notification.trade.disputeClosed=Le {0} a été fermé @@ -1699,7 +1734,7 @@ systemTray.show=Montrer la fenêtre de l'application systemTray.hide=Cacher la fenêtre de l'application systemTray.info=Informations au sujet de Haveno systemTray.exit=Sortir -systemTray.tooltip=Haveno: Une plateforme d''échange décentralisée sur le réseau bitcoin +systemTray.tooltip=Haveno: Une plateforme d''échange décentralisée sur le réseau monero #################################################################### @@ -1750,7 +1785,7 @@ tooltip.openBlockchainForTx=Ouvrir un explorateur de blockchain externe pour la confidence.unknown=Statut de transaction inconnu confidence.seen=Vu par {0} pair(s) / 0 confirmations -confidence.confirmed=Confirmé par {0} bloc(s) +confidence.confirmed={0} confirmations confidence.invalid=La transaction est invalide peerInfo.title=info sur le pair @@ -1761,10 +1796,10 @@ peerInfo.age.noRisk=Âge du compte de paiement peerInfo.age.chargeBackRisk=Temps depuis la signature peerInfo.unknownAge=Âge inconnu -addressTextField.openWallet=Ouvrir votre portefeuille Bitcoin par défaut +addressTextField.openWallet=Ouvrir votre portefeuille Monero par défaut addressTextField.copyToClipboard=Copier l'adresse dans le presse-papiers addressTextField.addressCopiedToClipboard=L'adresse a été copiée dans le presse-papier -addressTextField.openWallet.failed=L'ouverture d'un portefeuille Bitcoin par défaut a échoué. Peut-être que vous n'en avez aucun d'installé? +addressTextField.openWallet.failed=L'ouverture d'un portefeuille Monero par défaut a échoué. Peut-être que vous n'en avez aucun d'installé? peerInfoIcon.tooltip={0}\nTag: {1} @@ -1796,6 +1831,7 @@ navigation.support=\"Assistance\" formatter.formatVolumeLabel={0} montant{1} formatter.makerTaker=Maker comme {0} {1} / Taker comme {2} {3} +formatter.makerTakerLocked=Maker comme {0} {1} / Taker comme {2} {3} 🔒 formatter.youAreAsMaker=Vous êtes {1} {0} (maker) / Le preneur est: {3} {2} formatter.youAreAsTaker=Vous êtes: {1} {0} (preneur) / Le maker est: {3} {2} formatter.youAre=Vous êtes {0} {1} ({2} {3}) @@ -1841,7 +1877,6 @@ password.deriveKey=Récupérer la clé à partir du mot de passe password.walletDecrypted=Portefeuille décrypté avec succès et protection par mot de passe désactivée. password.wrongPw=Vous avez entré un mot de passe incorrect.\n\nVeuillez réessayer d'entrer votre mot de passe, en vérifiant soigneusement qu'il ne contient pas de fautes de frappe ou d'orthographe. password.walletEncrypted=Portefeuille crypté avec succès et protection par mot de passe activée. -password.walletEncryptionFailed=Le mot de passe du portefeuille n'a pas pu être défini. Il est possible que vous ayiez importé des mots sources qui ne correspondent pas à la base de données du portefeuille. Veuillez contacter les développeurs sur Keybase ([LIEN:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=Les 2 mots de passe entrés ne correspondent pas. password.forgotPassword=Mot de passe oublié? password.backupReminder=Veuillez noter que lors de la définition d'un mot de passe de portefeuille, toutes les sauvegardes créées automatiquement à partir du portefeuille non crypté seront supprimées.\n\nIl est fortement recommandé de faire une sauvegarde du répertoire de l'application et d'écrire les mots source avant de définir un mot de passe! @@ -1855,7 +1890,7 @@ seed.date=Date du portefeuille seed.restore.title=Restaurer les portefeuilles à partir des mots de la seed seed.restore=Restaurer les portefeuilles seed.creationDate=Date de création -seed.warn.walletNotEmpty.msg=Votre portefeuille Bitcoin n'est pas vide.\n\nVous devez vider ce portefeuille avant d'essayer de restaurer un portefeuille plus ancien, en effet mélanger les portefeuilles peut entraîner l'invalidation des sauvegardes.\n\nVeuillez finaliser vos trades, fermer toutes vos offres ouvertes et aller dans la section Fonds pour retirer votre Bitcoin.\nDans le cas où vous ne pouvez pas accéder à votre bitcoin, vous pouvez utiliser l'outil d'urgence afin de vider votre portefeuille.\nPour ouvrir l'outil d'urgence, pressez \"alt + e\" ou \"Cmd/Ctrl + e\". +seed.warn.walletNotEmpty.msg=Votre portefeuille Monero n'est pas vide.\n\nVous devez vider ce portefeuille avant d'essayer de restaurer un portefeuille plus ancien, en effet mélanger les portefeuilles peut entraîner l'invalidation des sauvegardes.\n\nVeuillez finaliser vos trades, fermer toutes vos offres ouvertes et aller dans la section Fonds pour retirer votre Monero.\nDans le cas où vous ne pouvez pas accéder à votre monero, vous pouvez utiliser l'outil d'urgence afin de vider votre portefeuille.\nPour ouvrir l'outil d'urgence, pressez \"alt + e\" ou \"Cmd/Ctrl + e\". seed.warn.walletNotEmpty.restore=Je veux quand même restaurer. seed.warn.walletNotEmpty.emptyWallet=Je viderai mes portefeuilles en premier. seed.warn.notEncryptedAnymore=Vos portefeuilles sont cryptés.\n\nAprès la restauration, les portefeuilles ne seront plus cryptés et vous devrez définir un nouveau mot de passe.\n\nSouhaitez-vous continuer ? @@ -1872,7 +1907,7 @@ seed.restore.openOffers.warn=Vous avez des offres ouvertes qui seront retirées payment.account=Compte payment.account.no=N° de compte payment.account.name=Nom du compte -payment.account.userName=Nom de l'utilisateur +payment.account.username=Nom de l'utilisateur payment.account.phoneNr=Numéro de téléphone payment.account.owner=Nom et prénoms du propriétaire du compte payment.account.fullName=Nom complet (prénom, deuxième prénom, nom de famille) @@ -1904,7 +1939,6 @@ payment.amazon.site=Acheter la carte cadeau à payment.ask=Demander dans le chat de trade payment.uphold.accountId=Nom d'utilisateur ou email ou N° de téléphone payment.moneyBeam.accountId=Email ou N° de téléphone -payment.venmo.venmoUserName=Nom d'utilisateur Venmo payment.popmoney.accountId=Email ou N° de téléphone payment.promptPay.promptPayId=N° de carte d'identité/d'identification du contribuable ou numéro de téléphone payment.supportedCurrencies=Devises acceptées @@ -1946,16 +1980,16 @@ payment.checking=Vérification payment.savings=Épargne payment.personalId=Pièce d'identité payment.makeOfferToUnsignedAccount.warning=Avec la récente montée en prix du XMR, soyez informés que vendre {0} ou moins cause un risque plus élevé qu'avant.\n\nIl est hautement recommandé de:\n- faire des offres au dessus de {0}, ainsi vous traiterez uniquement avec des acheteurs signés/de confiance\n- garder les offres pour vendre en desous de {0} à une valeur d'environ 100 USD, cette valeur a (historiquement) découragé les arnaqueurs\n\nLes développeurs de Haveno travaillent sur des meilleurs moyens de sécuriser le modèle de compte de paiement pour des trades plus petits. Rejoignez la discussion ici : [LIEN:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=Avec la récente montée en prix du BTC, soyez informés que vendre {0} ou moins cause un risque plus élevé qu'avant.\n\nIl est hautement recommandé de:\n- prendre les offres d'acheteurs signés uniquement\n- garder les offres pour vendre en desous de {0} à une valeur d'environ 100 USD, cette valeur a (historiquement) découragé les arnaqueurs\n\nLes développeurs de Haveno travaillent sur des meilleurs moyens de sécuriser le modèle de compte de paiement pour des trades plus petits. Rejoignez la discussion ici : [LIEN:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=Avec la récente montée en prix du XMR, soyez informés que vendre {0} ou moins cause un risque plus élevé qu'avant.\n\nIl est hautement recommandé de:\n- prendre les offres d'acheteurs signés uniquement\n- garder les offres pour vendre en desous de {0} à une valeur d'environ 100 USD, cette valeur a (historiquement) découragé les arnaqueurs\n\nLes développeurs de Haveno travaillent sur des meilleurs moyens de sécuriser le modèle de compte de paiement pour des trades plus petits. Rejoignez la discussion ici : [LIEN:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle est un service de transfert d'argent, qui fonctionne bien pour transférer de l'argent vers d'autres banques. \n\n1. Consultez cette page pour voir si (et comment) votre banque coopère avec Zelle: \n[HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Faites particulièrement attention à votre limite de transfert - les limites de versement varient d'une banque à l'autre, et les banques spécifient généralement des limites quotidiennes, hebdomadaires et mensuelles. \n\n3. Si votre banque ne peut pas utiliser Zelle, vous pouvez toujours l'utiliser via l'application mobile Zelle, mais votre limite de transfert sera bien inférieure. \n\n4. Le nom indiqué sur votre compte Haveno doit correspondre à celui du compte Zelle / bancaire. \n\nSi vous ne parvenez pas à réaliser la transaction Zelle comme stipulé dans le contrat commercial, vous risquez de perdre une partie (ou la totalité) de votre marge.\n\nComme Zelle présente un risque élevé de rétrofacturation, il est recommandé aux vendeurs de contacter les acheteurs non signés par e-mail ou SMS pour confirmer que les acheteurs ont le compte Zelle spécifié dans Haveno. payment.fasterPayments.newRequirements.info=Certaines banques ont déjà commencé à vérifier le nom complet du destinataire du paiement rapide. Votre compte de paiement rapide actuel ne remplit pas le nom complet. \n\nPensez à recréer votre compte de paiement rapide dans Haveno pour fournir un nom complet aux futurs {0} acheteurs. \n\nLors de la recréation d'un compte, assurez-vous de copier l'indicatif bancaire, le numéro de compte et le sel de vérification de l'âge de l'ancien compte vers le nouveau compte. Cela garantira que votre âge du compte et état de signature existant sont conservés. -payment.moneyGram.info=Lors de l'utilisation de MoneyGram, l'acheteur de BTC doit envoyer le numéro d'autorisation et une photo du reçu par email au vendeur de BTC. Le reçu doit clairement mentionner le nom complet du vendeur, le pays, la région et le montant. L'email du vendeur sera donné à l'acheteur durant le processus de transaction. -payment.westernUnion.info=Lors de l'utilisation de Western Union, l'acheteur BTC doit envoyer le MTCN (numéro de suivi) et une photo du reçu par e-mail au vendeur de BTC. Le reçu doit indiquer clairement le nom complet du vendeur, la ville, le pays et le montant. L'acheteur verra ensuite s'afficher l'email du vendeur pendant le processus de transaction. -payment.halCash.info=Lors de l'utilisation de HalCash, l'acheteur de BTC doit envoyer au vendeur de BTC le code HalCash par SMS depuis son téléphone portable.\n\nVeuillez vous assurer de ne pas dépasser le montant maximum que votre banque vous permet d'envoyer avec HalCash. Le montant minimum par retrait est de 10 EUR et le montant maximum est de 600 EUR. Pour les retraits récurrents, il est de 3000 EUR par destinataire par jour et 6000 EUR par destinataire par mois. Veuillez vérifier ces limites auprès de votre banque pour vous assurer qu'elles utilisent les mêmes limites que celles indiquées ici.\n\nLe montant du retrait doit être un multiple de 10 EUR car vous ne pouvez pas retirer d'autres montants à un distributeur automatique. Pendant les phases de create-offer et take-offer l'affichage de l'interface utilisateur ajustera le montant en BTC afin que le montant en euros soit correct. Vous ne pouvez pas utiliser le prix basé sur le marché, car le montant en euros varierait en fonction de l'évolution des prix.\n\nEn cas de litige, l'acheteur de BTC doit fournir la preuve qu'il a envoyé la somme en EUR. +payment.moneyGram.info=Lors de l'utilisation de MoneyGram, l'acheteur de XMR doit envoyer le numéro d'autorisation et une photo du reçu par email au vendeur de XMR. Le reçu doit clairement mentionner le nom complet du vendeur, le pays, la région et le montant. L'email du vendeur sera donné à l'acheteur durant le processus de transaction. +payment.westernUnion.info=Lors de l'utilisation de Western Union, l'acheteur XMR doit envoyer le MTCN (numéro de suivi) et une photo du reçu par e-mail au vendeur de XMR. Le reçu doit indiquer clairement le nom complet du vendeur, la ville, le pays et le montant. L'acheteur verra ensuite s'afficher l'email du vendeur pendant le processus de transaction. +payment.halCash.info=Lors de l'utilisation de HalCash, l'acheteur de XMR doit envoyer au vendeur de XMR le code HalCash par SMS depuis son téléphone portable.\n\nVeuillez vous assurer de ne pas dépasser le montant maximum que votre banque vous permet d'envoyer avec HalCash. Le montant minimum par retrait est de 10 EUR et le montant maximum est de 600 EUR. Pour les retraits récurrents, il est de 3000 EUR par destinataire par jour et 6000 EUR par destinataire par mois. Veuillez vérifier ces limites auprès de votre banque pour vous assurer qu'elles utilisent les mêmes limites que celles indiquées ici.\n\nLe montant du retrait doit être un multiple de 10 EUR car vous ne pouvez pas retirer d'autres montants à un distributeur automatique. Pendant les phases de create-offer et take-offer l'affichage de l'interface utilisateur ajustera le montant en XMR afin que le montant en euros soit correct. Vous ne pouvez pas utiliser le prix basé sur le marché, car le montant en euros varierait en fonction de l'évolution des prix.\n\nEn cas de litige, l'acheteur de XMR doit fournir la preuve qu'il a envoyé la somme en EUR. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Sachez que tous les virements bancaires comportent un certain risque de rétrofacturation. Pour mitiger ce risque, Haveno fixe des limites par trade en fonction du niveau estimé de risque de rétrofacturation pour la méthode de paiement utilisée.\n\nPour cette méthode de paiement, votre limite de trading pour l'achat et la vente est de {2}.\n\nCette limite ne s'applique qu'à la taille d'une seule transaction. Vous pouvez effectuer autant de transactions que vous le souhaitez.\n\nVous trouverez plus de détails sur le wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Sachez que tous les virements bancaires comportent un certain risque de rétrofacturation. Pour mitiger ce risque, Haveno fixe des limites par trade en fonction du niveau estimé de risque de rétrofacturation pour la méthode de paiement utilisée.\n\nPour cette méthode de paiement, votre limite de trading pour l'achat et la vente est de {2}.\n\nCette limite ne s'applique qu'à la taille d'une seule transaction. Vous pouvez effectuer autant de transactions que vous le souhaitez.\n\nVous trouverez plus de détails sur le wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=Afin de limiter le risque de rétrofacturation des achats, Haveno fixe des limites d'achat par transaction pour ce compte de paiement basé sur les 2 facteurs suivants :\n\n1. Risque de rétrofacturation pour le mode de paiement\n2. Statut de signature du compte\n\nCe compte de paiement n'est pas encore signé, il est donc limité à l'achat de {0} par trade. Après sa signature, les limites d'achat augmenteront comme suit :\n\n● Avant la signature, et jusqu'à 30 jours après la signature, votre limite d'achat par trade sera de {0}\n● 30 jours après la signature, votre limite d'achat par trade sera de {1}\n● 60 jours après la signature, votre limite d'achat par trade sera de {2}\n\nLes limites de vente ne sont pas affectées par la signature du compte. Vous pouvez vendre {2} en un seul trade immédiatement.\n\nCes limites s'appliquent uniquement à la taille d'un seul trade-vous pouvez placer autant de trades que vous voulez.\n\n Pour plus d''nformations, rendez vous à [LIEN:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=Afin de limiter le risque de rétrofacturation des achats, Haveno fixe des limites d'achat par transaction pour ce compte de paiement basé sur les 2 facteurs suivants :\n\n1. Risque de rétrofacturation pour le mode de paiement\n2. Statut de signature du compte\n\nCe compte de paiement n'est pas encore signé, il est donc limité à l'achat de {0} par trade. Après sa signature, les limites d'achat augmenteront comme suit :\n\n● Avant la signature, et jusqu'à 30 jours après la signature, votre limite d'achat par trade sera de {0}\n● 30 jours après la signature, votre limite d'achat par trade sera de {1}\n● 60 jours après la signature, votre limite d'achat par trade sera de {2}\n\nLes limites de vente ne sont pas affectées par la signature du compte. Vous pouvez vendre {2} en un seul trade immédiatement.\n\nCes limites s'appliquent uniquement à la taille d'un seul trade-vous pouvez placer autant de trades que vous voulez.\n\n Pour plus d''nformations, rendez vous à [LIEN:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Veuillez confirmer que votre banque vous permet d'envoyer des dépôts en espèces sur le compte d'autres personnes. Par exemple, Bank of America et Wells Fargo n'autorisent plus de tels dépôts. @@ -1967,7 +2001,7 @@ payment.amazonGiftCard.upgrade=La méthode de paiement via carte cadeaux Amazon payment.account.amazonGiftCard.addCountryInfo={0}\nVotre compte carte cadeau Amazon existant ({1}) n'a pas de pays spécifé.\nVeuillez entrer le pays de votre compte carte cadeau Amazon pour mettre à jour les données de votre compte.\nCeci n'affectera pas le statut de l'âge du compte. payment.amazonGiftCard.upgrade.headLine=Mettre à jour le compte des cartes cadeaux Amazon -payment.usPostalMoneyOrder.info=Pour échanger US Postal Money Orders (USPMO) sur Haveno, vous devez comprendre les termes suivants: \n\n- L'acheteur BTC doit écrire le nom du vendeur BTC dans les champs expéditeur et bénéficiaire, et prendre une photo à haute résolution de USPMO et de l'enveloppe avec une preuve de suivi avant l'envoi. \n\n- L'acheteur BTC doit envoyer USPMO avec la confirmation de livraison au vendeur BTC. \n\nSi une médiation est nécessaire, ou s'il y a un différend de transaction, vous devrez envoyer la photo avec le numéro USPMO, le numéro du bureau de poste et le montant de la transaction au médiateur Haveno ou à l'agent de remboursement afin qu'ils puissent vérifier les détails sur le site web de la poste américaine. \n\nSi vous ne fournissez pas les données de transaction requises, vous perdrez directement dans le différend. \n\nDans tous les cas de litige, l'expéditeur de l'USPMO assume à 100% la responsabilité lors de la fourniture de preuves / certification au médiateur ou à l'arbitre. \n\nSi vous ne comprenez pas ces exigences, veuillez ne pas échanger USPMO sur Haveno. +payment.usPostalMoneyOrder.info=Pour échanger US Postal Money Orders (USPMO) sur Haveno, vous devez comprendre les termes suivants: \n\n- L'acheteur XMR doit écrire le nom du vendeur XMR dans les champs expéditeur et bénéficiaire, et prendre une photo à haute résolution de USPMO et de l'enveloppe avec une preuve de suivi avant l'envoi. \n\n- L'acheteur XMR doit envoyer USPMO avec la confirmation de livraison au vendeur XMR. \n\nSi une médiation est nécessaire, ou s'il y a un différend de transaction, vous devrez envoyer la photo avec le numéro USPMO, le numéro du bureau de poste et le montant de la transaction au médiateur Haveno ou à l'agent de remboursement afin qu'ils puissent vérifier les détails sur le site web de la poste américaine. \n\nSi vous ne fournissez pas les données de transaction requises, vous perdrez directement dans le différend. \n\nDans tous les cas de litige, l'expéditeur de l'USPMO assume à 100% la responsabilité lors de la fourniture de preuves / certification au médiateur ou à l'arbitre. \n\nSi vous ne comprenez pas ces exigences, veuillez ne pas échanger USPMO sur Haveno. payment.payByMail.info=Effectuer un échange en utilisant Pay by Mail sur Haveno nécessite que vous compreniez ce qui suit :\n\ \n\ @@ -1997,7 +2031,7 @@ payment.f2f.city.prompt=La ville sera affichée en même temps que l'ordre payment.shared.optionalExtra=Informations complémentaires facultatives payment.shared.extraInfo=Informations complémentaires payment.shared.extraInfo.prompt=Définissez n'importe quels termes spécifiques, conditons ou détails que vous souhaiteriez voir affichés avec vos offres pour ce compte de paiement (les utilisateurs verront ces informations avant d'accepter les offres). -payment.f2f.info=Les transactions en 'face à face' ont des règles différentes et comportent des risques différents de ceux des transactions en ligne.\n\nLes principales différences sont les suivantes:\n● Les pairs de trading doivent échanger des informations sur le lieu et l'heure de la réunion en utilisant les coordonnées de contanct qu'ils ont fournies.\n● Les pairs de trading doivent apporter leur ordinateur portable et faire la confirmation du 'paiement envoyé' et du 'paiement reçu' sur le lieu de la réunion.\n● Si un maker a des 'termes et conditions' spéciaux, il doit les indiquer dans le champ 'Informations supplémentaires' dans le compte.\n● En acceptant une offre, le taker accepte les 'termes et conditions' du maker.\n● En cas de litige, le médiateur ou l'arbitre ne peut pas beaucoup aider car il est généralement difficile d'obtenir des preuves irréfutables de ce qui s'est passé lors de la réunion. Dans ce cas, les fonds en BTC peuvent être bloqué s indéfiniment tant que les pairs ne parviennent pas à un accord.\n\nPour vous assurer de bien comprendre les spécificités des transactions 'face à face', veuillez lire les instructions et les recommandations à [LIEN:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info=Les transactions en 'face à face' ont des règles différentes et comportent des risques différents de ceux des transactions en ligne.\n\nLes principales différences sont les suivantes:\n● Les pairs de trading doivent échanger des informations sur le lieu et l'heure de la réunion en utilisant les coordonnées de contanct qu'ils ont fournies.\n● Les pairs de trading doivent apporter leur ordinateur portable et faire la confirmation du 'paiement envoyé' et du 'paiement reçu' sur le lieu de la réunion.\n● Si un maker a des 'termes et conditions' spéciaux, il doit les indiquer dans le champ 'Informations supplémentaires' dans le compte.\n● En acceptant une offre, le taker accepte les 'termes et conditions' du maker.\n● En cas de litige, le médiateur ou l'arbitre ne peut pas beaucoup aider car il est généralement difficile d'obtenir des preuves irréfutables de ce qui s'est passé lors de la réunion. Dans ce cas, les fonds en XMR peuvent être bloqué s indéfiniment tant que les pairs ne parviennent pas à un accord.\n\nPour vous assurer de bien comprendre les spécificités des transactions 'face à face', veuillez lire les instructions et les recommandations à [LIEN:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Ouvrir la page web payment.f2f.offerbook.tooltip.countryAndCity=Pays et ville: {0} / {1} payment.f2f.offerbook.tooltip.extra=Informations complémentaires: {0} @@ -2009,7 +2043,7 @@ payment.japan.recipient=Nom payment.australia.payid=ID de paiement payment.payid=ID de paiement lié à une institution financière. Comme l'addresse email ou le téléphone portable. payment.payid.info=Un PayID, tel qu'un numéro de téléphone, une adresse électronique ou un numéro d'entreprise australien (ABN), que vous pouvez lier en toute sécurité à votre compte bancaire, votre crédit mutuel ou votre société de crédit immobilier. Vous devez avoir déjà créé un PayID auprès de votre institution financière australienne. Les institutions financières émettrices et réceptrices doivent toutes deux prendre en charge PayID. Pour plus d'informations, veuillez consulter [LIEN:https://payid.com.au/faqs/]. -payment.amazonGiftCard.info=Pour payer avec une carte cadeau Amazon eGift Card, vous devrez envoyer une carte cadeau Amazon eGift Card au vendeur de BTC via votre compte Amazon. \n\nHaveno indiquera l'adresse e-mail ou le numéro de téléphone du vendeur BTC où la carte cadeau doit être envoyée, et vous devrez inclure l'ID du trade dans le champ de messagerie de la carte cadeau. Veuillez consulter le wiki [LIEN:https://bisq.wiki/Amazon_eGift_card] pour plus de détails et pour les meilleures pratiques à adopter. \n\nTrois remarques importantes :\n- essayez d'envoyer des cartes-cadeaux d'un montant inférieur ou égal à 100 USD, car Amazon est connu pour signaler les cartes-cadeaux plus importantes comme frauduleuses\n- essayez d'utiliser un texte créatif et crédible pour le message de la carte cadeau (par exemple, "Joyeux anniversaire Susan !") ainsi que l'ID du trade (et utilisez le chat du trader pour indiquer à votre pair de trading le texte de référence que vous avez choisi afin qu'il puisse vérifier votre paiement).\n- Les cartes cadeaux électroniques Amazon ne peuvent être échangées que sur le site Amazon où elles ont été achetées (par exemple, une carte cadeau achetée sur amazon.it ne peut être échangée que sur amazon.it). +payment.amazonGiftCard.info=Pour payer avec une carte cadeau Amazon eGift Card, vous devrez envoyer une carte cadeau Amazon eGift Card au vendeur de XMR via votre compte Amazon. \n\nHaveno indiquera l'adresse e-mail ou le numéro de téléphone du vendeur XMR où la carte cadeau doit être envoyée, et vous devrez inclure l'ID du trade dans le champ de messagerie de la carte cadeau. Veuillez consulter le wiki [LIEN:https://haveno.exchange/wiki/Amazon_eGift_card] pour plus de détails et pour les meilleures pratiques à adopter. \n\nTrois remarques importantes :\n- essayez d'envoyer des cartes-cadeaux d'un montant inférieur ou égal à 100 USD, car Amazon est connu pour signaler les cartes-cadeaux plus importantes comme frauduleuses\n- essayez d'utiliser un texte créatif et crédible pour le message de la carte cadeau (par exemple, "Joyeux anniversaire Susan !") ainsi que l'ID du trade (et utilisez le chat du trader pour indiquer à votre pair de trading le texte de référence que vous avez choisi afin qu'il puisse vérifier votre paiement).\n- Les cartes cadeaux électroniques Amazon ne peuvent être échangées que sur le site Amazon où elles ont été achetées (par exemple, une carte cadeau achetée sur amazon.it ne peut être échangée que sur amazon.it). # We use constants from the code so we do not use our normal naming convention @@ -2167,7 +2201,7 @@ validation.zero=La saisie d'une valeur égale à 0 n'est pas autorisé. validation.negative=Une valeur négative n'est pas autorisée. validation.traditional.tooSmall=La saisie d'une valeur plus petite que le montant minimal possible n'est pas autorisée. validation.traditional.tooLarge=La saisie d'une valeur supérieure au montant maximal possible n'est pas autorisée. -validation.xmr.fraction=L'entrée résultera dans une valeur bitcoin plus petite qu'1 satoshi +validation.xmr.fraction=L'entrée résultera dans une valeur monero plus petite qu'1 satoshi validation.xmr.tooLarge=La saisie d''une valeur supérieure à {0} n''est pas autorisée. validation.xmr.tooSmall=La saisie d''une valeur inférieure à {0} n''est pas autorisée. validation.passwordTooShort=Le mot de passe que vous avez saisi est trop court. Il doit comporter un minimum de 8 caractères. @@ -2177,10 +2211,10 @@ validation.sortCodeChars={0} doit être composer de {1} caractères. validation.bankIdNumber={0} doit être composer de {1} chiffres. validation.accountNr=Le numéro du compte doit comporter {0} chiffres. validation.accountNrChars=Le numéro du compte doit comporter {0} caractères. -validation.btc.invalidAddress=L''adresse n''est pas correcte. Veuillez vérifier le format de l''adresse. +validation.xmr.invalidAddress=L''adresse n''est pas correcte. Veuillez vérifier le format de l''adresse. validation.integerOnly=Veuillez seulement entrer des nombres entiers. validation.inputError=Votre saisie a causé une erreur:\n{0} -validation.btc.exceedsMaxTradeLimit=Votre seuil maximum d''échange est {0}. +validation.xmr.exceedsMaxTradeLimit=Votre seuil maximum d''échange est {0}. validation.nationalAccountId={0} doit être composé de {1} nombres. #new diff --git a/core/src/main/resources/i18n/displayStrings_it.properties b/core/src/main/resources/i18n/displayStrings_it.properties index a6540764b7..9e52fd8976 100644 --- a/core/src/main/resources/i18n/displayStrings_it.properties +++ b/core/src/main/resources/i18n/displayStrings_it.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Capisco shared.na=N/A shared.shutDown=Spegni shared.reportBug=Report bug on GitHub -shared.buyBitcoin=Acquista bitcoin -shared.sellBitcoin=Vendi bitcoin +shared.buyMonero=Acquista monero +shared.sellMonero=Vendi monero shared.buyCurrency=Acquista {0} shared.sellCurrency=Vendi {0} -shared.buyingBTCWith=acquistando BTC con {0} -shared.sellingBTCFor=vendendo BTC per {0} -shared.buyingCurrency=comprando {0} (vendendo BTC) -shared.sellingCurrency=vendendo {0} (comprando BTC) +shared.buyCurrencyLocked=Acquista {0} 🔒 +shared.sellCurrencyLocked=Vendi {0} 🔒 +shared.buyingXMRWith=acquistando XMR con {0} +shared.sellingXMRFor=vendendo XMR per {0} +shared.buyingCurrency=comprando {0} (vendendo XMR) +shared.sellingCurrency=vendendo {0} (comprando XMR) shared.buy=compra shared.sell=vendi shared.buying=comprando @@ -93,7 +95,7 @@ shared.amountMinMax=Importo (min - max) shared.amountHelp=Se un'offerta ha un valore massimo e minimo definito, puoi scambiare qualsiasi valore compreso in questo range shared.remove=Rimuovi shared.goTo=Vai a {0} -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Rimuovi offerta shared.dontRemoveOffer=Non rimuovere offerta shared.editOffer=Modifica offerta @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=Si, annulla shared.nextStep=Passo successivo shared.selectTradingAccount=Seleziona conto di trading -shared.fundFromSavingsWalletButton=Trasferisci fondi dal portafoglio Haveno +shared.fundFromSavingsWalletButton=Applica fondi dal portafoglio Haveno shared.fundFromExternalWalletButton=Apri il tuo portafoglio esterno per aggiungere fondi -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=Sotto % del prezzo di mercato shared.aboveInPercent=Sopra % del prezzo di mercato shared.enterPercentageValue=Immetti il valore % shared.OR=OPPURE shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=In attesa dei fondi... -shared.TheBTCBuyer=L'acquirente di BTC +shared.TheXMRBuyer=L'acquirente di XMR shared.You=Tu shared.sendingConfirmation=Invio della conferma in corso... shared.sendingConfirmationAgain=Invia nuovamente la conferma @@ -123,9 +125,8 @@ shared.noDateAvailable=Nessuna data disponibile shared.noDetailsAvailable=Dettagli non disponibili shared.notUsedYet=Non ancora usato shared.date=Data -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=Copia negli appunti shared.language=Lingua shared.country=Paese @@ -140,6 +141,7 @@ shared.addNewAccount=Aggiungi nuovo account shared.ExportAccounts=Esporta Account shared.importAccounts=Importa Account shared.createNewAccount=Crea nuovo account +shared.createNewAccountDescription=I dettagli del tuo account sono memorizzati localmente sul tuo dispositivo e condivisi solo con il tuo partner commerciale e l'arbitro se viene aperta una disputa. shared.saveNewAccount=Salva nuovo account shared.selectedAccount=Account selezionato shared.deleteAccount=Elimina account @@ -169,7 +171,7 @@ shared.payoutTxId=ID transazione di pagamento shared.contractAsJson=Contratto in formato JSON shared.viewContractAsJson=Visualizza il contratto in formato JSON shared.contract.title=Contratto per lo scambio con ID: {0} -shared.paymentDetails=Dettagli pagamento BTC {0}: +shared.paymentDetails=Dettagli pagamento XMR {0}: shared.securityDeposit=Deposito di sicurezza shared.yourSecurityDeposit=Il tuo deposito di sicurezza shared.contract=Contratto @@ -179,19 +181,21 @@ shared.messageSendingFailed=Invio del messaggio fallito. Errore: {0} shared.unlock=Sblocca shared.toReceive=per ricevere shared.toSpend=da spendere -shared.btcAmount=Importo BTC +shared.xmrAmount=Importo XMR shared.yourLanguage=Le tue lingue shared.addLanguage=Aggiungi lingua shared.total=Totale shared.totalsNeeded=Fondi richiesti shared.tradeWalletAddress=Indirizzo del portafoglio per gli scambi shared.tradeWalletBalance=Saldo del portafogli per gli scambi +shared.reserveExactAmount=Riserva solo i fondi necessari. Richiede una tassa di mining e circa 20 minuti prima che la tua offerta diventi attiva. shared.makerTxFee=Maker: {0} shared.takerTxFee=Taker: {0} shared.iConfirm=Confermo shared.openURL=Aperti {0} shared.fiat=Fiat shared.crypto=Crypto +shared.preciousMetals=Metalli Preziosi shared.all=Tutti shared.edit=Modifica shared.advancedOptions=Opzioni avanzate @@ -226,8 +230,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=Mercato -mainView.menu.buyBtc=Compra BTC -mainView.menu.sellBtc=Vendi BTC +mainView.menu.buyXmr=Compra XMR +mainView.menu.sellXmr=Vendi XMR mainView.menu.portfolio=Portafoglio mainView.menu.funds=Fondi mainView.menu.support=Supporto @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Riservati mainView.balance.pending.short=Bloccati mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Connessione alla rete Bitcoin -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=Connessione alla rete Haveno +mainView.footer.xmrInfo.synchronizingWith=Sincronizzazione con {0} al blocco: {1} / {2} +mainView.footer.xmrInfo.connectedTo=Connesso a {0} al blocco {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Sincronizzazione del portafoglio con {0} al blocco: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Sincronizzato con {0} al blocco {1} mainView.footer.xmrInfo.connectingTo=Connessione a mainView.footer.xmrInfo.connectionFailed=Connessione fallita mainView.footer.xmrPeers=Monero network peers: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=Il bootstrap sulla rete Haven mainView.p2pNetworkWarnMsg.noNodesAvailable=Non ci sono nodi seed o peer persistenti disponibili per la richiesta di dati.\nControlla la tua connessione Internet o prova a riavviare l'applicazione. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Connessione alla rete Haveno non riuscita (errore segnalato: {0}).\nControlla la tua connessione Internet o prova a riavviare l'applicazione. -mainView.walletServiceErrorMsg.timeout=Connessione alla rete Bitcoin fallita a causa di un timeout. -mainView.walletServiceErrorMsg.connectionError=Connessione alla rete Bitcoin fallita a causa di un errore: {0} +mainView.walletServiceErrorMsg.timeout=Connessione alla rete Monero fallita a causa di un timeout. +mainView.walletServiceErrorMsg.connectionError=Connessione alla rete Monero fallita a causa di un errore: {0} mainView.walletServiceErrorMsg.rejectedTxException=Una transazione è stata rifiutata dalla rete.\n\n{0} mainView.networkWarning.allConnectionsLost=Hai perso la connessione a tutti i {0} peer di rete.\nForse hai perso la connessione a Internet o il computer era in modalità standby. -mainView.networkWarning.localhostBitcoinLost=Hai perso la connessione al nodo Bitcoin in localhost.\nRiavvia l'applicazione Haveno per connetterti ad altri nodi Bitcoin o riavvia il nodo Bitcoin in localhost. +mainView.networkWarning.localhostMoneroLost=Hai perso la connessione al nodo Monero in localhost.\nRiavvia l'applicazione Haveno per connetterti ad altri nodi Monero o riavvia il nodo Monero in localhost. mainView.version.update=(Aggiornamento disponibile) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=Acquista {0} market.offerBook.sellWithTraditional=Vendi {0} market.offerBook.sellOffersHeaderLabel=Vendi {0} a market.offerBook.buyOffersHeaderLabel=Compra {0} da -market.offerBook.buy=Voglio comprare bitcoin -market.offerBook.sell=Voglio vendere bitcoin +market.offerBook.buy=Voglio comprare monero +market.offerBook.sell=Voglio vendere monero # SpreadView market.spread.numberOfOffersColumn=Tutte le offerte ({0}) -market.spread.numberOfBuyOffersColumn=Acquista BTC ({0}) -market.spread.numberOfSellOffersColumn=Vendi BTC ({0}) -market.spread.totalAmountColumn=Totale BTC ({0}) +market.spread.numberOfBuyOffersColumn=Acquista XMR ({0}) +market.spread.numberOfSellOffersColumn=Vendi XMR ({0}) +market.spread.totalAmountColumn=Totale XMR ({0}) market.spread.spreadColumn=Spread market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=Crea offerta offerbook.takeOffer=Accetta offerta offerbook.takeOfferToBuy=Accetta l'offerta per acquistare {0} offerbook.takeOfferToSell=Accetta l'offerta per vendere {0} +offerbook.takeOffer.enterChallenge=Inserisci la passphrase dell'offerta offerbook.trader=Trader offerbook.offerersBankId=ID banca del Maker (BIC/SWIFT): {0} offerbook.offerersBankName=Nome della banca del Maker: {0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=Sede accettata dei paesi bancari (acquirente offerbook.availableOffers=Offerte disponibili offerbook.filterByCurrency=Filtra per valuta offerbook.filterByPaymentMethod=Filtra per metodo di pagamento -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=Offerte che corrispondono ai miei account +offerbook.filterNoDeposit=Nessun deposito +offerbook.noDepositOffers=Offerte senza deposito (passphrase richiesta) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Questo account è stato verificato e {0} offerbook.timeSinceSigning.info.arbitrator=firmato da un arbitro e può firmare account peer @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned= \nl'account è stato bannato offerbook.timeSinceSigning.daysSinceSigning={0} giorni offerbook.timeSinceSigning.daysSinceSigning.long={0} dalla firma offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=Compra XMR con: +offerbook.sellXmrFor=Vendi XMR per: offerbook.timeSinceSigning.help=Quando completi correttamente un'operazione con un peer che ha un account di pagamento firmato, il tuo account di pagamento viene firmato.\n{0} giorni dopo, il limite iniziale di {1} viene alzato e il tuo account può firmare account di pagamento di altri peer. offerbook.timeSinceSigning.notSigned=Non ancora firmato @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=N. di offerte: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=Crea offerta per {0} {1} offerbook.createOfferToBuy=Crea una nuova offerta per comprare {0} offerbook.createOfferToSell=Crea una nuova offerta per vendere {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=L'importo di scambio consentito è limitato a {0} a causa delle restrizioni di sicurezza basate sui seguenti criteri:\n- L'account dell'acquirente non è stato firmato da un arbitro o da un pari\n- Il tempo trascorso dalla firma dell'account dell'acquirente non è di almeno 30 giorni\n- Il metodo di pagamento per questa offerta è considerato rischioso per le richieste di storno bancarie\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=L'importo di scambio consentito è limitato a {0} a causa delle restrizioni di sicurezza basate sui seguenti criteri:\n- Il tuo account non è stato firmato da un arbitro o da un pari\n- Il tempo trascorso dalla firma del tuo account non è di almeno 30 giorni\n- Il metodo di pagamento per questa offerta è considerato rischioso per le richieste di storno bancarie\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Questo metodo di pagamento è temporaneamente limitato a {0} fino a {1} perché tutti gli acquirenti hanno nuovi account.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=La tua offerta sarà limitata ai compratori con account firmati e datati perché supera {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Questa offerta richiede una versione di protocollo diversa da quella utilizzata nella versione del tuo software.\n\nVerifica di aver installato l'ultima versione, altrimenti l'utente che ha creato l'offerta ha utilizzato una versione precedente.\n\nGli utenti non possono effettuare scambi con una versione di protocollo di scambio incompatibile. offerbook.warning.userIgnored=Hai aggiunto l'indirizzo onion dell'utente al tuo elenco di persone da ignorare. @@ -394,7 +409,6 @@ offerbook.warning.offerBlocked=Tale offerta è stata bloccata dagli sviluppatori offerbook.warning.currencyBanned=La valuta utilizzata in quell'offerta è stata bloccata dagli sviluppatori Haveno.\nPer ulteriori informazioni, visitare il forum di Haveno. offerbook.warning.paymentMethodBanned=Il metodo di pagamento utilizzato in quell'offerta è stato bloccato dagli sviluppatori Haveno.\nPer ulteriori informazioni, visitare il forum di Haveno. offerbook.warning.nodeBlocked=L'indirizzo onion di quel trader è stato bloccato dagli sviluppatori Haveno.\nProbabilmente c'è un bug non gestito che causa problemi quando si accettano offerte da quel trader. -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=Venderai al prezzo di mercato (aggiornato ogni minuto). @@ -412,13 +426,13 @@ offerbook.info.roundedFiatVolume=L'importo è stato arrotondato per aumentare la # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Inserisci quantità in BTC +createOffer.amount.prompt=Inserisci quantità in XMR createOffer.price.prompt=Inserisci prezzo createOffer.volume.prompt=Inserisci importo in {0} -createOffer.amountPriceBox.amountDescription=Quantità di BTC a {0} +createOffer.amountPriceBox.amountDescription=Quantità di XMR a {0} createOffer.amountPriceBox.buy.volumeDescription=Quantità in {0} da spendere createOffer.amountPriceBox.sell.volumeDescription=Quantità in {0} da ricevere -createOffer.amountPriceBox.minAmountDescription=Quantità minima di BTC +createOffer.amountPriceBox.minAmountDescription=Quantità minima di XMR createOffer.securityDeposit.prompt=Deposito di sicurezza createOffer.fundsBox.title=Finanzia la tua offerta createOffer.fundsBox.offerFee=Commissione di scambio @@ -434,7 +448,7 @@ createOffer.info.sellAboveMarketPrice=Otterrai sempre il {0}% in più rispetto a createOffer.info.buyBelowMarketPrice=Pagherai sempre il {0}% in meno rispetto al prezzo di mercato corrente poiché il prezzo della tua offerta verrà costantemente aggiornato. createOffer.warning.sellBelowMarketPrice=Otterrai sempre il {0}% in meno rispetto al prezzo di mercato corrente poiché il prezzo della tua offerta verrà costantemente aggiornato. createOffer.warning.buyAboveMarketPrice=Pagherai sempre il {0}% in più rispetto al prezzo di mercato corrente poiché il prezzo della tua offerta verrà costantemente aggiornato. -createOffer.tradeFee.descriptionBTCOnly=Commissione di scambio +createOffer.tradeFee.descriptionXMROnly=Commissione di scambio createOffer.tradeFee.descriptionBSQEnabled=Seleziona la valuta della commissione di scambio createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +462,12 @@ createOffer.placeOfferButton=Revisione: piazza l'offerta a {0} monero createOffer.createOfferFundWalletInfo.headline=Finanzia la tua offerta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Importo di scambio: {0} \n -createOffer.createOfferFundWalletInfo.msg=Devi depositare {0} a questa offerta.\n\nTali fondi sono riservati nel tuo portafoglio locale e verranno bloccati nell'indirizzo di deposito multisig una volta che qualcuno accetta la tua offerta.\n\nL'importo è la somma di:\n{1} - Il tuo deposito cauzionale: {2}\n- Commissione di scambio: {3}\n- Commissione di mining: {4}\n\nPuoi scegliere tra due opzioni quando finanzi il tuo scambio:\n- Usa il tuo portafoglio Haveno (comodo, ma le transazioni possono essere collegabili) OPPURE\n- Effettua il trasferimento da un portafoglio esterno (potenzialmente più privato)\n\nVedrai tutte le opzioni di finanziamento e i dettagli dopo aver chiuso questo popup. +createOffer.createOfferFundWalletInfo.msg=Devi depositare {0} per questa offerta.\n\n\ + Questi fondi sono riservati nel tuo portafoglio locale e verranno bloccati in un portafoglio multisig una volta che qualcuno accetta la tua offerta.\n\n\ + L'importo è la somma di:\n\ + {1}\ + - Il tuo deposito di sicurezza: {2}\n\ + - Tassa di trading: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Si è verificato un errore durante l'immissione dell'offerta:\n\n{0}\n\nNon sono ancora usciti fondi dal tuo portafoglio.\nRiavvia l'applicazione e controlla la connessione di rete. @@ -470,30 +489,35 @@ createOffer.setDepositAsBuyer=Imposta il mio deposito cauzionale come acquirente createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=Il deposito cauzionale dell'acquirente sarà {0} createOffer.securityDepositInfoAsBuyer=Il tuo deposito cauzionale come acquirente sarà {0} -createOffer.minSecurityDepositUsed=Viene utilizzato il minimo deposito cauzionale dell'acquirente +createOffer.minSecurityDepositUsed=Il deposito di sicurezza minimo è utilizzato +createOffer.buyerAsTakerWithoutDeposit=Nessun deposito richiesto dal compratore (protetto da passphrase) +createOffer.myDeposit=Il mio deposito di sicurezza (%) +createOffer.myDepositInfo=Il tuo deposito di sicurezza sarà {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Inserisci importo in BTC -takeOffer.amountPriceBox.buy.amountDescription=Importo di BTC da vendere -takeOffer.amountPriceBox.sell.amountDescription=Importo di BTC da acquistare -takeOffer.amountPriceBox.priceDescription=Prezzo per bitcoin in {0} +takeOffer.amount.prompt=Inserisci importo in XMR +takeOffer.amountPriceBox.buy.amountDescription=Importo di XMR da vendere +takeOffer.amountPriceBox.sell.amountDescription=Importo di XMR da acquistare +takeOffer.amountPriceBox.priceDescription=Prezzo per monero in {0} takeOffer.amountPriceBox.amountRangeDescription=Range di importo possibile -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=L'importo che hai inserito supera il numero di decimali permessi.\nL'importo è stato regolato a 4 decimali. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=L'importo che hai inserito supera il numero di decimali permessi.\nL'importo è stato regolato a 4 decimali. takeOffer.validation.amountSmallerThanMinAmount=L'importo non può essere più piccolo dell'importo minimo definito nell'offerta. takeOffer.validation.amountLargerThanOfferAmount=L'importo inserito non può essere più alto dell'importo definito nell'offerta. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Questo importo inserito andrà a creare un resto di basso valore per il venditore di BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Questo importo inserito andrà a creare un resto di basso valore per il venditore di XMR. takeOffer.fundsBox.title=Finanzia il tuo scambio takeOffer.fundsBox.isOfferAvailable=Controlla se l'offerta è disponibile ... takeOffer.fundsBox.tradeAmount=Importo da vendere takeOffer.fundsBox.offerFee=Commissione di scambio takeOffer.fundsBox.networkFee=Totale commissioni di mining -takeOffer.fundsBox.takeOfferSpinnerInfo=Accettazione dell'offerta in corso ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Accettare l'offerta: {0} takeOffer.fundsBox.paymentLabel=Scambia Haveno con ID {0} takeOffer.fundsBox.fundsStructure=({0} deposito cauzionale, {1} commissione commerciale, {2} commissione mineraria) +takeOffer.fundsBox.noFundingRequiredTitle=Nessun finanziamento richiesto +takeOffer.fundsBox.noFundingRequiredDescription=Ottieni la passphrase dell'offerta dal venditore fuori da Haveno per accettare questa offerta. takeOffer.success.headline=Hai accettato con successo un'offerta. takeOffer.success.info=Puoi vedere lo stato del tuo scambio su \"Portafoglio/Scambi aperti\". takeOffer.error.message=Si è verificato un errore durante l'accettazione dell'offerta.\n\n{0} @@ -504,7 +528,7 @@ takeOffer.noPriceFeedAvailable=Non puoi accettare questa offerta poiché utilizz takeOffer.takeOfferFundWalletInfo.headline=Finanzia il tuo scambio # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Importo di scambio: {0} \n -takeOffer.takeOfferFundWalletInfo.msg=Devi depositare {0} per accettare questa offerta.\n\nL'importo è la somma de:\n{1} - Il tuo deposito cauzionale: {2}\n- La commissione di trading: {3}\n- I costi di mining: {4}\n\nPuoi scegliere tra due opzioni quando finanzi il tuo scambio:\n- Usare il tuo portafoglio Haveno (comodo, ma le transazioni possono essere collegabili) OPPURE\n- Trasferimento da un portafoglio esterno (potenzialmente più privato)\n\nVedrai tutte le opzioni di finanziamento e i dettagli dopo aver chiuso questo popup. +takeOffer.takeOfferFundWalletInfo.msg=Devi depositare {0} per accettare questa offerta.\n\nL'importo è la somma di:\n{1}- Il tuo deposito di sicurezza: {2}\n- Commissione di trading: {3} takeOffer.alreadyPaidInFunds=Se hai già pagato in fondi puoi effettuare il ritiro nella schermata \"Fondi/Invia fondi\". takeOffer.paymentInfo=Informazioni sul pagamento takeOffer.setAmountPrice=Importo stabilito @@ -597,29 +621,29 @@ portfolio.pending.step1.openForDispute=La transazione di deposito non è ancora # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Trasferisci dal tuo portafoglio esterno {0}\n{1} al venditore BTC.\n\n +portfolio.pending.step2_buyer.crypto=Trasferisci dal tuo portafoglio esterno {0}\n{1} al venditore XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Vai in banca e paga {0} al venditore BTC.\n\n -portfolio.pending.step2_buyer.cash.extra=REQUISITI IMPORTANTI:\nDopo aver effettuato il pagamento scrivi sulla ricevuta cartacea: NESSUN RIMBORSO.\nQuindi strappalo in 2 parti, fai una foto e inviala all'indirizzo e-mail del venditore BTC. +portfolio.pending.step2_buyer.cash=Vai in banca e paga {0} al venditore XMR.\n\n +portfolio.pending.step2_buyer.cash.extra=REQUISITI IMPORTANTI:\nDopo aver effettuato il pagamento scrivi sulla ricevuta cartacea: NESSUN RIMBORSO.\nQuindi strappalo in 2 parti, fai una foto e inviala all'indirizzo e-mail del venditore XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Si prega di pagare {0} al venditore BTC utilizzando MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=REQUISITO IMPORTANTE:\nDopo aver effettuato il pagamento, invia il numero di autorizzazione e una foto della ricevuta via e-mail al venditore BTC.\nLa ricevuta deve mostrare chiaramente il nome completo, il paese, lo stato e l'importo del venditore. L'email del venditore è: {0}. +portfolio.pending.step2_buyer.moneyGram=Si prega di pagare {0} al venditore XMR utilizzando MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=REQUISITO IMPORTANTE:\nDopo aver effettuato il pagamento, invia il numero di autorizzazione e una foto della ricevuta via e-mail al venditore XMR.\nLa ricevuta deve mostrare chiaramente il nome completo, il paese, lo stato e l'importo del venditore. L'email del venditore è: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Si prega di pagare {0} al venditore BTC utilizzando Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=REQUISITO IMPORTANTE:\nDopo aver effettuato il pagamento, invia l'MTCN (numero di tracciamento) e una foto della ricevuta via e-mail al venditore BTC.\nLa ricevuta deve mostrare chiaramente il nome completo, la città, il paese e l'importo del venditore. L'email del venditore è: {0}. +portfolio.pending.step2_buyer.westernUnion=Si prega di pagare {0} al venditore XMR utilizzando Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=REQUISITO IMPORTANTE:\nDopo aver effettuato il pagamento, invia l'MTCN (numero di tracciamento) e una foto della ricevuta via e-mail al venditore XMR.\nLa ricevuta deve mostrare chiaramente il nome completo, la città, il paese e l'importo del venditore. L'email del venditore è: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Invia {0} tramite \"Vaglia Postale Statunitense\" al venditore BTC.\n\n +portfolio.pending.step2_buyer.postal=Invia {0} tramite \"Vaglia Postale Statunitense\" al venditore XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Contatta il venditore BTC tramite il contatto fornito e organizza un incontro per pagare {0}.\n\n +portfolio.pending.step2_buyer.f2f=Contatta il venditore XMR tramite il contatto fornito e organizza un incontro per pagare {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Inizia il pagamento utilizzando {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=Importo da trasferire @@ -628,27 +652,27 @@ portfolio.pending.step2_buyer.buyerAccount=Il tuo conto di pagamento da utilizza portfolio.pending.step2_buyer.paymentSent=Il pagamento è iniziato portfolio.pending.step2_buyer.warn=Non hai ancora effettuato il tuo pagamento {0}!\nSi prega di notare che lo scambio è stato completato da {1}. portfolio.pending.step2_buyer.openForDispute=Non hai completato il pagamento!\nÈ trascorso il massimo periodo di scambio. Si prega di contattare il mediatore per assistenza. -portfolio.pending.step2_buyer.paperReceipt.headline=Hai inviato la ricevuta cartacea al venditore BTC? -portfolio.pending.step2_buyer.paperReceipt.msg=Ricorda:\nDevi scrivere sulla ricevuta cartacea: NESSUN RIMBORSO.\nQuindi strappala in 2 parti, fai una foto e inviala all'indirizzo e-mail del venditore BTC. +portfolio.pending.step2_buyer.paperReceipt.headline=Hai inviato la ricevuta cartacea al venditore XMR? +portfolio.pending.step2_buyer.paperReceipt.msg=Ricorda:\nDevi scrivere sulla ricevuta cartacea: NESSUN RIMBORSO.\nQuindi strappala in 2 parti, fai una foto e inviala all'indirizzo e-mail del venditore XMR. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Invia numero di autorizzazione e ricevuta -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=È necessario inviare il numero di Autorizzazione e una foto della ricevuta via e-mail al venditore BTC.\nLa ricevuta deve indicare chiaramente il nome completo, il paese, lo stato e l'importo del venditore. L'email del venditore è: {0}.\n\nHai inviato il numero di Autorizzazione e il contratto al venditore? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=È necessario inviare il numero di Autorizzazione e una foto della ricevuta via e-mail al venditore XMR.\nLa ricevuta deve indicare chiaramente il nome completo, il paese, lo stato e l'importo del venditore. L'email del venditore è: {0}.\n\nHai inviato il numero di Autorizzazione e il contratto al venditore? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Invia MTCN e ricevuta -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Devi inviare l'MTCN (numero di tracciamento) e una foto della ricevuta via e-mail al venditore BTC.\nLa ricevuta deve indicare chiaramente il nome completo, la città, il paese e l'importo del venditore. L'email del venditore è: {0}.\n\nHai inviato l'MTCN e la ricevuta al venditore? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Devi inviare l'MTCN (numero di tracciamento) e una foto della ricevuta via e-mail al venditore XMR.\nLa ricevuta deve indicare chiaramente il nome completo, la città, il paese e l'importo del venditore. L'email del venditore è: {0}.\n\nHai inviato l'MTCN e la ricevuta al venditore? portfolio.pending.step2_buyer.halCashInfo.headline=Invia il codice HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=È necessario inviare un messaggio di testo con il codice HalCash e l'ID dello scambio ({0}) al venditore BTC.\nIl numero di cellulare del venditore è {1}.\n\nHai inviato il codice al venditore? +portfolio.pending.step2_buyer.halCashInfo.msg=È necessario inviare un messaggio di testo con il codice HalCash e l'ID dello scambio ({0}) al venditore XMR.\nIl numero di cellulare del venditore è {1}.\n\nHai inviato il codice al venditore? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Alcune banche potrebbero richiedere il nome del destinatario. Gli account di Pagamento Veloci creati dai vecchi client Haveno non forniscono il nome del destinatario, quindi (se necessario) utilizza la chat dell scambio per fartelo comunicare. portfolio.pending.step2_buyer.confirmStart.headline=Conferma di aver avviato il pagamento portfolio.pending.step2_buyer.confirmStart.msg=Hai avviato il pagamento {0} al tuo partner commerciale? portfolio.pending.step2_buyer.confirmStart.yes=Sì, ho avviato il pagamento portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=In attesa del pagamento portfolio.pending.step2_seller.f2fInfo.headline=Informazioni di contatto dell'acquirente -portfolio.pending.step2_seller.waitPayment.msg=La transazione di deposito necessita di almeno una conferma blockchain.\nDevi attendere fino a quando l'acquirente BTC invia il pagamento {0}. -portfolio.pending.step2_seller.warn=L'acquirente BTC non ha ancora effettuato il pagamento {0}.\nDevi aspettare fino a quando non invia il pagamento.\nSe lo scambio non sarà completato il {1}, l'arbitro comincierà ad indagare. -portfolio.pending.step2_seller.openForDispute=L'acquirente BTC non ha ancora inviato il pagamento!\nIl periodo massimo consentito per lo scambio è trascorso.\nPuoi aspettare più a lungo e dare più tempo al partner di scambio oppure puoi contattare il mediatore per ricevere assistenza. +portfolio.pending.step2_seller.waitPayment.msg=La transazione di deposito necessita di almeno una conferma blockchain.\nDevi attendere fino a quando l'acquirente XMR invia il pagamento {0}. +portfolio.pending.step2_seller.warn=L'acquirente XMR non ha ancora effettuato il pagamento {0}.\nDevi aspettare fino a quando non invia il pagamento.\nSe lo scambio non sarà completato il {1}, l'arbitro comincierà ad indagare. +portfolio.pending.step2_seller.openForDispute=L'acquirente XMR non ha ancora inviato il pagamento!\nIl periodo massimo consentito per lo scambio è trascorso.\nPuoi aspettare più a lungo e dare più tempo al partner di scambio oppure puoi contattare il mediatore per ricevere assistenza. tradeChat.chatWindowTitle=Finestra di chat per scambi con ID '' {0} '' tradeChat.openChat=Apri la finestra di chat tradeChat.rules=Puoi comunicare con il tuo peer di trading per risolvere potenziali problemi con questo scambio.\nNon è obbligatorio rispondere nella chat.\nSe un trader viola una delle seguenti regole, apri una controversia ed effettua una segnalazione al mediatore o all'arbitro.\n\nRegole della chat:\n● Non inviare nessun link (rischio di malware). È possibile inviare l'ID transazione e il nome di un block explorer.\n● Non inviare parole del seed, chiavi private, password o altre informazioni sensibili!\n● Non incoraggiare il trading al di fuori di Haveno (non garantisce nessuna sicurezza).\n● Non intraprendere alcuna forma di tentativo di frode di ingegneria sociale.\n● Se un peer non risponde e preferisce non comunicare tramite chat, rispettane la decisione.\n● Limita l'ambito della conversazione allo scambio. Questa chat non è una sostituzione di messenger o un troll-box.\n● Mantieni la conversazione amichevole e rispettosa.\n @@ -666,26 +690,26 @@ message.state.ACKNOWLEDGED=Il peer ha confermato la ricezione de messaggio # suppress inspection "UnusedProperty" message.state.FAILED=Invio del messaggio fallito -portfolio.pending.step3_buyer.wait.headline=Attendi la conferma del pagamento del venditore BTC -portfolio.pending.step3_buyer.wait.info=In attesa della conferma del venditore BTC per la ricezione del pagamento {0}. +portfolio.pending.step3_buyer.wait.headline=Attendi la conferma del pagamento del venditore XMR +portfolio.pending.step3_buyer.wait.info=In attesa della conferma del venditore XMR per la ricezione del pagamento {0}. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Stato del messaggio di pagamento avviato portfolio.pending.step3_buyer.warn.part1a=sulla {0} blockchain portfolio.pending.step3_buyer.warn.part1b=presso il tuo fornitore di servizi di pagamento (ad es. banca) -portfolio.pending.step3_buyer.warn.part2=Il venditore BTC non ha ancora confermato il pagamento. Controlla {0} se l'invio del pagamento è andato a buon fine. -portfolio.pending.step3_buyer.openForDispute=Il venditore BTC non ha confermato il tuo pagamento! Il max. periodo per lo scambio è trascorso. Puoi aspettare più a lungo e dare più tempo al peer di trading o richiedere assistenza al mediatore. +portfolio.pending.step3_buyer.warn.part2=Il venditore XMR non ha ancora confermato il pagamento. Controlla {0} se l'invio del pagamento è andato a buon fine. +portfolio.pending.step3_buyer.openForDispute=Il venditore XMR non ha confermato il tuo pagamento! Il max. periodo per lo scambio è trascorso. Puoi aspettare più a lungo e dare più tempo al peer di trading o richiedere assistenza al mediatore. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Il tuo partner commerciale ha confermato di aver avviato il pagamento {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=sul tuo {0} blockchain explorer preferito portfolio.pending.step3_seller.crypto.wallet=sul tuo portafoglio {0} portfolio.pending.step3_seller.crypto={0}Controlla {1} se la transazione è indirizzata correttamente al tuo indirizzo di ricezione\n{2}\nha già sufficienti conferme sulla blockchain.\nL'importo del pagamento deve essere {3}\n\nPuoi copiare e incollare il tuo indirizzo {4} dalla schermata principale dopo aver chiuso questo popup. -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=Poiché il pagamento viene effettuato tramite deposito in contanti, l'acquirente BTC deve scrivere \"NESSUN RIMBORSO\" sulla ricevuta cartacea, strapparlo in 2 parti e inviarti una foto via e-mail.\n\nPer evitare il rischio di storno, conferma solamente se hai ricevuto l'e-mail e se sei sicuro che la ricevuta cartacea sia valida.\nSe non sei sicuro, {0} -portfolio.pending.step3_seller.moneyGram=L'acquirente deve inviarti il numero di autorizzazione e una foto della ricevuta via e-mail.\nLa ricevuta deve mostrare chiaramente il tuo nome completo, il paese, lo stato e l'importo. Controlla nella tua e-mail se hai ricevuto il numero di autorizzazione.\n\nDopo aver chiuso il popup, vedrai il nome e l'indirizzo dell'acquirente BTC per effettuare il ritiro dell'importo da MoneyGram.\n\nConferma la ricevuta solo dopo aver ricevuto con successo i soldi! -portfolio.pending.step3_seller.westernUnion=L'acquirente deve inviarti l'MTCN (numero di tracciamento) e una foto della ricevuta via e-mail.\nLa ricevuta deve mostrare chiaramente il tuo nome completo, la città, il paese e l'importo. Controlla nella tua e-mail se hai ricevuto l'MTCN.\n\nDopo aver chiuso il popup, vedrai il nome e l'indirizzo dell'acquirente BTC per effettuare il ritiro dell'importo da Western Union.\n\nConferma la ricevuta solo dopo aver ricevuto con successo i soldi! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=Poiché il pagamento viene effettuato tramite deposito in contanti, l'acquirente XMR deve scrivere \"NESSUN RIMBORSO\" sulla ricevuta cartacea, strapparlo in 2 parti e inviarti una foto via e-mail.\n\nPer evitare il rischio di storno, conferma solamente se hai ricevuto l'e-mail e se sei sicuro che la ricevuta cartacea sia valida.\nSe non sei sicuro, {0} +portfolio.pending.step3_seller.moneyGram=L'acquirente deve inviarti il numero di autorizzazione e una foto della ricevuta via e-mail.\nLa ricevuta deve mostrare chiaramente il tuo nome completo, il paese, lo stato e l'importo. Controlla nella tua e-mail se hai ricevuto il numero di autorizzazione.\n\nDopo aver chiuso il popup, vedrai il nome e l'indirizzo dell'acquirente XMR per effettuare il ritiro dell'importo da MoneyGram.\n\nConferma la ricevuta solo dopo aver ricevuto con successo i soldi! +portfolio.pending.step3_seller.westernUnion=L'acquirente deve inviarti l'MTCN (numero di tracciamento) e una foto della ricevuta via e-mail.\nLa ricevuta deve mostrare chiaramente il tuo nome completo, la città, il paese e l'importo. Controlla nella tua e-mail se hai ricevuto l'MTCN.\n\nDopo aver chiuso il popup, vedrai il nome e l'indirizzo dell'acquirente XMR per effettuare il ritiro dell'importo da Western Union.\n\nConferma la ricevuta solo dopo aver ricevuto con successo i soldi! portfolio.pending.step3_seller.halCash=L'acquirente deve inviarti il codice HalCash come messaggio di testo. Riceverai un secondo un messaggio da HalCash con le informazioni richieste per poter ritirare gli EUR da un bancomat supportato da HalCash.\n\nDopo aver ritirato i soldi dal bancomat, conferma qui la ricevuta del pagamento! portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. @@ -701,7 +725,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID Transazione portfolio.pending.step3_seller.xmrTxKey=Transaction key portfolio.pending.step3_seller.buyersAccount=Buyers account data portfolio.pending.step3_seller.confirmReceipt=Conferma pagamento ricevuto -portfolio.pending.step3_seller.buyerStartedPayment=L'acquirente BTC ha avviato il pagamento {0}.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=L'acquirente XMR ha avviato il pagamento {0}.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Controlla le conferme blockchain sul tuo portafoglio crypto o block explorer e conferma il pagamento quando hai sufficienti conferme blockchain portfolio.pending.step3_seller.buyerStartedPayment.traditional=Controlla sul tuo conto di trading (ad es. Conto bancario) e conferma quando hai ricevuto il pagamento. portfolio.pending.step3_seller.warn.part1a=sulla {0} blockchain @@ -713,7 +737,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Hai ricevuto il pagamento # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Verifica inoltre che il nome del mittente specificato nel contratto di scambio corrisponda al nome che appare sul tuo estratto conto bancario:\nNome del mittente, per contratto di scambio: {0}\n\nSe i nomi non sono uguali, non confermare la ricevuta del pagamento. Apri invece una disputa premendo \"alt + o\" oppure \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Tieni presente che non appena avrai confermato la ricevuta, l'importo commerciale bloccato verrà rilasciato all'acquirente BTC e il deposito cauzionale verrà rimborsato. +portfolio.pending.step3_seller.onPaymentReceived.note=Tieni presente che non appena avrai confermato la ricevuta, l'importo commerciale bloccato verrà rilasciato all'acquirente XMR e il deposito cauzionale verrà rimborsato. portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Conferma di aver ricevuto il pagamento portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Si, ho ricevuto il pagamento portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANTE: confermando la ricezione del pagamento, stai anche verificando il conto della controparte e, di conseguenza, lo stai firmando. Poiché il conto della controparte non è stato ancora firmato, è necessario ritardare la conferma del pagamento il più a lungo possibile per ridurre il rischio di uno storno di addebito. @@ -723,7 +747,7 @@ portfolio.pending.step5_buyer.tradeFee=Commissione di scambio portfolio.pending.step5_buyer.makersMiningFee=Commissione di mining portfolio.pending.step5_buyer.takersMiningFee=Totale commissioni di mining portfolio.pending.step5_buyer.refunded=Deposito di sicurezza rimborsato -portfolio.pending.step5_buyer.withdrawBTC=Preleva i tuoi bitcoin +portfolio.pending.step5_buyer.withdrawXMR=Preleva i tuoi monero portfolio.pending.step5_buyer.amount=Importo da prelevare portfolio.pending.step5_buyer.withdrawToAddress=Ritirare all'indirizzo portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet @@ -732,7 +756,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=I tuoi fondi sono già stati riti portfolio.pending.step5_buyer.confirmWithdrawal=Conferma richiesta di prelievo portfolio.pending.step5_buyer.amountTooLow=L'importo da trasferire è inferiore alla commissione di transazione e al min. valore tx possibile (polvere). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Prelievo completato -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Gli scambi completati vengono archiviati in \"Portafoglio/Storia\".\nPuoi rivedere tutte le tue transazioni bitcoin in \"Fondi/Transazioni\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Gli scambi completati vengono archiviati in \"Portafoglio/Storia\".\nPuoi rivedere tutte le tue transazioni monero in \"Fondi/Transazioni\" portfolio.pending.step5_buyer.bought=Hai acquistato portfolio.pending.step5_buyer.paid=Hai pagato @@ -794,7 +818,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Hai già accettato portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +857,7 @@ funds.deposit.fundHavenoWallet=Finanzia portafoglio Haveno funds.deposit.noAddresses=Non sono stati ancora generati indirizzi di deposito funds.deposit.fundWallet=Finanzia il tuo portafoglio funds.deposit.withdrawFromWallet=Invia fondi dal portafoglio -funds.deposit.amount=Importo in BTC (facoltativo) +funds.deposit.amount=Importo in XMR (facoltativo) funds.deposit.generateAddress=Crea nuovo indirizzo funds.deposit.generateAddressSegwit=Native segwit format (Bech32) funds.deposit.selectUnused=Seleziona un indirizzo inutilizzato dalla tabella sopra anziché generarne uno nuovo. @@ -843,6 +867,7 @@ funds.withdrawal.inputs=Selezione input funds.withdrawal.useAllInputs=Utilizza tutti gli input disponibili funds.withdrawal.useCustomInputs=Utilizza input personalizzati funds.withdrawal.receiverAmount=Importo del destinatario +funds.withdrawal.sendMax=Inviare massimo disponibile funds.withdrawal.senderAmount=Importo del mittente funds.withdrawal.feeExcluded=L'importo esclude la commissione di mining funds.withdrawal.feeIncluded=L'importo include la commissione di mining @@ -890,7 +915,7 @@ funds.tx.revert=Storna funds.tx.txSent=Transazione inviata con successo ad un nuovo indirizzo nel portafoglio Haveno locale. funds.tx.direction.self=Invia a te stesso funds.tx.dustAttackTx=Polvere ricevuta -funds.tx.dustAttackTx.popup=Questa transazione sta inviando un importo BTC molto piccolo al tuo portafoglio e potrebbe essere un tentativo da parte delle società di chain analysis per spiare il tuo portafoglio.\n\nSe usi quell'output della transazione in una transazione di spesa, scopriranno che probabilmente sei anche il proprietario dell'altro indirizzo (combinazione di monete).\n\nPer proteggere la tua privacy, il portafoglio Haveno ignora tali output di polvere a fini di spesa e nella visualizzazione del saldo. È possibile impostare la soglia al di sotto della quale un output è considerato polvere.\n +funds.tx.dustAttackTx.popup=Questa transazione sta inviando un importo XMR molto piccolo al tuo portafoglio e potrebbe essere un tentativo da parte delle società di chain analysis per spiare il tuo portafoglio.\n\nSe usi quell'output della transazione in una transazione di spesa, scopriranno che probabilmente sei anche il proprietario dell'altro indirizzo (combinazione di monete).\n\nPer proteggere la tua privacy, il portafoglio Haveno ignora tali output di polvere a fini di spesa e nella visualizzazione del saldo. È possibile impostare la soglia al di sotto della quale un output è considerato polvere.\n #################################################################### # Support @@ -904,7 +929,6 @@ support.filter=Search disputes support.filter.prompt=Inserisci ID commerciale, data, indirizzo onion o dati dell'account support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -940,8 +964,8 @@ support.savedInMailbox=Messaggio salvato nella cassetta postale del destinatario support.arrived=Il messaggio è arrivato al destinatario support.acknowledged=Arrivo del messaggio confermato dal destinatario support.error=Il destinatario non ha potuto elaborare il messaggio. Errore: {0} -support.buyerAddress=Indirizzo BTC dell'acquirente -support.sellerAddress=Indirizzo BTC del venditore +support.buyerAddress=Indirizzo XMR dell'acquirente +support.sellerAddress=Indirizzo XMR del venditore support.role=Ruolo support.agent=Support agent support.state=Stato @@ -949,13 +973,13 @@ support.chat=Chat support.closed=Chiuso support.open=Aperto support.process=Process -support.buyerMaker=Acquirente/Maker BTC -support.sellerMaker=Venditore/Maker BTC -support.buyerTaker=Acquirente/Taker BTC -support.sellerTaker=Venditore/Taker BTC +support.buyerMaker=Acquirente/Maker XMR +support.sellerMaker=Venditore/Maker XMR +support.buyerTaker=Acquirente/Taker XMR +support.sellerTaker=Venditore/Taker XMR -support.backgroundInfo=Haveno non è una società, quindi gestisce le controversie in modo diverso.\n\nI trader possono comunicare all'interno dell'applicazione tramite chat sicura nella schermata degli scambi aperti per provare a risolvere le controversie da soli. Se ciò non è sufficiente, un mediatore può intervenire per aiutare. Il mediatore valuterà la situazione e suggerirà un pagamento di fondi commerciali. Se entrambi i trader accettano questo suggerimento, la transazione di pagamento è completata e lo scambio è chiuso. Se uno o entrambi i trader non accettano il pagamento suggerito dal mediatore, possono richiedere l'arbitrato. L'arbitro rivaluterà la situazione e, se garantito, ripagherà personalmente il trader e chiederà il rimborso per questo pagamento dal DAO Haveno. -support.initialInfo=Inserisci una descrizione del tuo problema nel campo di testo qui sotto. Aggiungi quante più informazioni possibili per accelerare i tempi di risoluzione della disputa.\n\nEcco una lista delle informazioni che dovresti fornire:\n● Se sei l'acquirente BTC: hai effettuato il trasferimento Traditional o Cryptocurrency? In tal caso, hai fatto clic sul pulsante "pagamento avviato" nell'applicazione?\n● Se sei il venditore BTC: hai ricevuto il pagamento Traditional o Cryptocurrency? In tal caso, hai fatto clic sul pulsante "pagamento ricevuto" nell'applicazione?\n● Quale versione di Haveno stai usando?\n● Quale sistema operativo stai usando?\n● Se si è verificato un problema con transazioni non riuscite, prendere in considerazione la possibilità di passare a una nuova directory di dati.\n A volte la directory dei dati viene danneggiata e porta a strani bug.\n Vedi: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nAcquisire familiarità con le regole di base per la procedura di disputa:\n● È necessario rispondere alle richieste di {0} entro 2 giorni.\n● I mediatori rispondono entro 2 giorni. Gli arbitri rispondono entro 5 giorni lavorativi.\n● Il periodo massimo per una disputa è di 14 giorni.\n● È necessario collaborare con {1} e fornire le informazioni richieste per presentare il proprio caso.\n● Hai accettato le regole delineate nel documento di contestazione nel contratto con l'utente al primo avvio dell'applicazione.\n\nPuoi leggere ulteriori informazioni sulla procedura di contestazione all'indirizzo: {2}\n +support.backgroundInfo=Haveno non è un'azienda, quindi gestisce le controversie in modo diverso.\n\nI commercianti possono comunicare all'interno dell'applicazione tramite una chat sicura sulla schermata delle negoziazioni aperte per cercare di risolvere le controversie da soli. Se ciò non è sufficiente, un arbitro valuterà la situazione e deciderà un pagamento dei fondi commerciali. +support.initialInfo=Inserisci una descrizione del tuo problema nel campo di testo qui sotto. Aggiungi quante più informazioni possibili per accelerare i tempi di risoluzione della disputa.\n\nEcco una lista delle informazioni che dovresti fornire:\n● Se sei l'acquirente XMR: hai effettuato il trasferimento Traditional o Cryptocurrency? In tal caso, hai fatto clic sul pulsante "pagamento avviato" nell'applicazione?\n● Se sei il venditore XMR: hai ricevuto il pagamento Traditional o Cryptocurrency? In tal caso, hai fatto clic sul pulsante "pagamento ricevuto" nell'applicazione?\n● Quale versione di Haveno stai usando?\n● Quale sistema operativo stai usando?\n● Se si è verificato un problema con transazioni non riuscite, prendere in considerazione la possibilità di passare a una nuova directory di dati.\n A volte la directory dei dati viene danneggiata e porta a strani bug.\n Vedi: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nAcquisire familiarità con le regole di base per la procedura di disputa:\n● È necessario rispondere alle richieste di {0} entro 2 giorni.\n● I mediatori rispondono entro 2 giorni. Gli arbitri rispondono entro 5 giorni lavorativi.\n● Il periodo massimo per una disputa è di 14 giorni.\n● È necessario collaborare con {1} e fornire le informazioni richieste per presentare il proprio caso.\n● Hai accettato le regole delineate nel documento di contestazione nel contratto con l'utente al primo avvio dell'applicazione.\n\nPuoi leggere ulteriori informazioni sulla procedura di contestazione all'indirizzo: {2}\n support.systemMsg=Messaggio di sistema: {0} support.youOpenedTicket=Hai aperto una richiesta di supporto.\n\n{0}\n\nVersione Haveno: {1} support.youOpenedDispute=Hai aperto una richiesta per una controversia.\n\n{0}\n\nVersione Haveno: {1} @@ -979,13 +1003,14 @@ settings.tab.network=Informazioni della Rete settings.tab.about=Circa setting.preferences.general=Preferenze generali -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Deviazione massima del prezzo di mercato setting.preferences.avoidStandbyMode=Evita modalità standby +setting.preferences.useSoundForNotifications=Riproduci suoni per le notifiche setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Non sono ammessi valori superiori a {0}%. setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1022,29 +1047,31 @@ settings.preferences.editCustomExplorer.name=Nome settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=Network Bitcoin +settings.net.xmrHeader=Network Monero settings.net.p2pHeader=Rete Haveno settings.net.onionAddressLabel=Il mio indirizzo onion settings.net.xmrNodesLabel=Usa nodi Monero personalizzati settings.net.moneroPeersLabel=Peer connessi +settings.net.connection=Connessione +settings.net.connected=Connesso settings.net.useTorForXmrJLabel=Usa Tor per la rete Monero settings.net.moneroNodesLabel=Nodi Monero a cui connettersi -settings.net.useProvidedNodesRadio=Usa i nodi Bitcoin Core forniti -settings.net.usePublicNodesRadio=Usa la rete pubblica di Bitcoin -settings.net.useCustomNodesRadio=Usa nodi Bitcoin Core personalizzati +settings.net.useProvidedNodesRadio=Usa i nodi Monero Core forniti +settings.net.usePublicNodesRadio=Usa la rete pubblica di Monero +settings.net.useCustomNodesRadio=Usa nodi Monero Core personalizzati settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=No, utilizza i nodi forniti settings.net.warn.usePublicNodes.usePublic=Sì, usa la rete pubblica -settings.net.warn.useCustomNodes.B2XWarning=Assicurati che il tuo nodo Bitcoin sia un nodo Bitcoin Core di fiducia!\n\nLa connessione a nodi che non seguono le regole di consenso di Bitcoin Core potrebbe corrompere il tuo portafoglio e causare problemi nel processo di scambio.\n\nGli utenti che si connettono a nodi che violano le regole di consenso sono responsabili per qualsiasi danno risultante. Eventuali controversie risultanti saranno decise a favore dell'altro pari. Nessun supporto tecnico verrà fornito agli utenti che ignorano questo meccanismo di avvertimento e protezione! -settings.net.warn.invalidBtcConfig=Connessione alla rete Bitcoin non riuscita perché la configurazione non è valida.\n\nLa tua configurazione è stata ripristinata per utilizzare invece i nodi Bitcoin forniti. Dovrai riavviare l'applicazione. -settings.net.localhostXmrNodeInfo=Informazioni di base: Haveno cerca un nodo Bitcoin locale all'avvio. Se viene trovato, Haveno comunicherà con la rete Bitcoin esclusivamente attraverso di esso. +settings.net.warn.useCustomNodes.B2XWarning=Assicurati che il tuo nodo Monero sia un nodo Monero Core di fiducia!\n\nLa connessione a nodi che non seguono le regole di consenso di Monero Core potrebbe corrompere il tuo portafoglio e causare problemi nel processo di scambio.\n\nGli utenti che si connettono a nodi che violano le regole di consenso sono responsabili per qualsiasi danno risultante. Eventuali controversie risultanti saranno decise a favore dell'altro pari. Nessun supporto tecnico verrà fornito agli utenti che ignorano questo meccanismo di avvertimento e protezione! +settings.net.warn.invalidXmrConfig=Connessione alla rete Monero non riuscita perché la configurazione non è valida.\n\nLa tua configurazione è stata ripristinata per utilizzare invece i nodi Monero forniti. Dovrai riavviare l'applicazione. +settings.net.localhostXmrNodeInfo=Informazioni di base: Haveno cerca un nodo Monero locale all'avvio. Se viene trovato, Haveno comunicherà con la rete Monero esclusivamente attraverso di esso. settings.net.p2PPeersLabel=Peer connessi settings.net.onionAddressColumn=Indirizzo onion settings.net.creationDateColumn=Stabilito settings.net.connectionTypeColumn=Dentro/Fuori settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=Ritorno settings.net.sentBytesColumn=Inviato settings.net.receivedBytesColumn=Ricevuto @@ -1059,7 +1086,7 @@ settings.net.needRestart=È necessario riavviare l'applicazione per applicare ta settings.net.notKnownYet=Non ancora noto... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[Indirizzo IP:porta | hostname:porta | indirizzo onion:porta] (separato da una virgola). La porta può essere omessa se è usata quella predefinita (8333). settings.net.seedNode=Nodo seme settings.net.directPeer=Peer (diretto) @@ -1068,7 +1095,7 @@ settings.net.peer=Peer settings.net.inbound=in entrata settings.net.outbound=in uscita setting.about.aboutHaveno=Riguardo Haveno -setting.about.about=Haveno è un software open source che facilita lo scambio di bitcoin con valute nazionali (e altre criptovalute) attraverso una rete peer-to-peer decentralizzata in modo da proteggere fortemente la privacy degli utenti. Leggi di più riguardo Haveno sulla pagina web del progetto. +setting.about.about=Haveno è un software open source che facilita lo scambio di monero con valute nazionali (e altre criptovalute) attraverso una rete peer-to-peer decentralizzata in modo da proteggere fortemente la privacy degli utenti. Leggi di più riguardo Haveno sulla pagina web del progetto. setting.about.web=Pagina web Haveno setting.about.code=Codice sorgente setting.about.agpl=Licenza AGPL @@ -1105,7 +1132,7 @@ setting.about.shortcuts.openDispute.value=Seleziona lo scambio in sospeso e fai setting.about.shortcuts.walletDetails=Apri la finestra dei dettagli del portafoglio -setting.about.shortcuts.openEmergencyBtcWalletTool=Apri lo strumento portafoglio di emergenza per il portafoglio BTC +setting.about.shortcuts.openEmergencyXmrWalletTool=Apri lo strumento portafoglio di emergenza per il portafoglio XMR setting.about.shortcuts.showTorLogs=Attiva / disattiva il livello di registro per i messaggi Tor tra DEBUG e WARN @@ -1131,7 +1158,7 @@ setting.about.shortcuts.sendPrivateNotification=Invia notifica privata al peer ( setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1167,7 @@ account.tab.mediatorRegistration=Registrazione del mediatore account.tab.refundAgentRegistration=Registrazione agente di rimborso account.tab.signing=Signing account.info.headline=Benvenuto nel tuo Account Haveno -account.info.msg=Qui puoi aggiungere conti di trading per valute nazionali e crypto e creare un backup dei tuoi dati di portafoglio e conto.\n\nUn nuovo portafoglio Bitcoin è stato creato la prima volta che hai avviato Haveno.\n\nTi consigliamo vivamente di annotare le parole del seme del portafoglio Bitcoin (vedi la scheda in alto) e prendere in considerazione l'aggiunta di una password prima del finanziamento. I depositi e prelievi di bitcoin sono gestiti nella sezione \"Fondi\".\n\nInformativa sulla privacy e sulla sicurezza: poiché Haveno è un exchange decentralizzato, tutti i tuoi dati vengono conservati sul tuo computer. Non ci sono server, quindi non abbiamo accesso alle tue informazioni personali, ai tuoi fondi o persino al tuo indirizzo IP. Dati come numeri di conto bancario, crypto e indirizzi Bitcoin, ecc. vengono condivisi con il proprio partner commerciale per adempiere alle negoziazioni avviate (in caso di controversia il mediatore o l'arbitro vedrà gli stessi dati del proprio peer di negoziazione). +account.info.msg=Qui puoi aggiungere conti di trading per valute nazionali e crypto e creare un backup dei tuoi dati di portafoglio e conto.\n\nUn nuovo portafoglio Monero è stato creato la prima volta che hai avviato Haveno.\n\nTi consigliamo vivamente di annotare le parole del seme del portafoglio Monero (vedi la scheda in alto) e prendere in considerazione l'aggiunta di una password prima del finanziamento. I depositi e prelievi di monero sono gestiti nella sezione \"Fondi\".\n\nInformativa sulla privacy e sulla sicurezza: poiché Haveno è un exchange decentralizzato, tutti i tuoi dati vengono conservati sul tuo computer. Non ci sono server, quindi non abbiamo accesso alle tue informazioni personali, ai tuoi fondi o persino al tuo indirizzo IP. Dati come numeri di conto bancario, crypto e indirizzi Monero, ecc. vengono condivisi con il proprio partner commerciale per adempiere alle negoziazioni avviate (in caso di controversia il mediatore o l'arbitro vedrà gli stessi dati del proprio peer di negoziazione). account.menu.paymentAccount=Conti in valuta nazionale account.menu.altCoinsAccountView=Conti crypto @@ -1151,7 +1178,7 @@ account.menu.backup=Backup account.menu.notifications=Notifiche account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1180,7 +1207,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Il trading di ARQ su Haveno richiede di comprendere e soddisfare i seguenti requisiti:\n\nPer inviare ARQ, è necessario utilizzare il portafoglio GUI ArQmA ufficiale o il portafoglio CLI ArQmA con il flag store-tx-info abilitato (impostazione predefinita nelle nuove versioni). Assicurati di poter accedere alla chiave tx come sarebbe richiesto in caso di controversia.\narqma-wallet-cli (utilizzare il comando get_tx_key)\narqma-wallet-gui (vai allo storico trnsazioni e fai clic sul pulsante (P) per la prova del pagamento)\n\nNegli explorer di blocchi normali il trasferimento non è verificabile.\n\nÈ necessario fornire al mediatore o all'arbitro i seguenti dati in caso di controversia:\n- La chiave privata tx\n- L'hash della transazione\n- L'indirizzo pubblico del destinatario\n\nIl mancato conferimento dei dati di cui sopra o l'utilizzo di un portafoglio incompatibile comporterà la perdita del caso di contestazione. Il mittente ARQ è responsabile di fornire la verifica del trasferimento ARQ al mediatore o all'arbitro in caso di controversia.\n\nNon è richiesto un ID di pagamento, ma solo il normale indirizzo pubblico.\nSe non si è sicuri di tale processo, visitare il canale discord ArQmA (https://discord.gg/s9BQpJT) o il forum ArQmA (https://labs.arqma.com) per trovare ulteriori informazioni.\n # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1235,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin on Haveno requires that you unde account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Il trading di L-BTC su Haveno richiede la comprensione di quanto segue:\n\nQuando ricevi L-BTC per uno scambio su Haveno, non puoi utilizzare l'applicazione mobile Blockstream Green Wallet o un portafoglio di custodia/scambio. Devi ricevere L-BTC solo nel portafoglio Liquid Elements Core o in un altro portafoglio L-BTC che ti consenta di ottenere la chiave per il tuo indirizzo L-BTC.\n\nNel caso in cui sia necessaria la mediazione o in caso di disputa nello scambio, è necessario divulgare la chiave di ricezione per il proprio indirizzo L-BTC al mediatore Haveno o all'agente di rimborso in modo che possano verificare i dettagli della propria Transazione riservata sul proprio full node Elements Core.\n\nLa mancata fornitura delle informazioni richieste dal mediatore o dall'agente di rimborso comporterà la perdita della disputa. In tutti i casi di disputa, il ricevente L-BTC si assume al 100% l'onere della responsabilità nel fornire prove crittografiche al mediatore o all'agente di rimborso.\n\nSe non comprendi i sopracitati requisiti, non scambiare L-BTC su Haveno. +account.crypto.popup.liquidmonero.msg=Il trading di L-XMR su Haveno richiede la comprensione di quanto segue:\n\nQuando ricevi L-XMR per uno scambio su Haveno, non puoi utilizzare l'applicazione mobile Blockstream Green Wallet o un portafoglio di custodia/scambio. Devi ricevere L-XMR solo nel portafoglio Liquid Elements Core o in un altro portafoglio L-XMR che ti consenta di ottenere la chiave per il tuo indirizzo L-XMR.\n\nNel caso in cui sia necessaria la mediazione o in caso di disputa nello scambio, è necessario divulgare la chiave di ricezione per il proprio indirizzo L-XMR al mediatore Haveno o all'agente di rimborso in modo che possano verificare i dettagli della propria Transazione riservata sul proprio full node Elements Core.\n\nLa mancata fornitura delle informazioni richieste dal mediatore o dall'agente di rimborso comporterà la perdita della disputa. In tutti i casi di disputa, il ricevente L-XMR si assume al 100% l'onere della responsabilità nel fornire prove crittografiche al mediatore o all'agente di rimborso.\n\nSe non comprendi i sopracitati requisiti, non scambiare L-XMR su Haveno. account.traditional.yourTraditionalAccounts=I tuoi conti in valuta nazionale @@ -1228,13 +1255,13 @@ account.password.setPw.button=Imposta password account.password.setPw.headline=Imposta la protezione con password per il portafoglio account.password.info=Con la protezione tramite password, dovrai inserire la password all'avvio dell'applicazione, quando prelevi monero dal tuo portafoglio e quando mostri le tue parole chiave di ripristino. -account.seed.backup.title=Effettua il backup delle parole del seed dei tuoi portafogli -account.seed.info=Si prega di scrivere sia le parole del seed del portafoglio che la data! Puoi recuperare il tuo portafoglio in qualsiasi momento con le parole del seed e la data.\nLe stesse parole del seed vengono utilizzate per il portafoglio BTC e BSQ.\n\nDovresti scrivere le parole del seed su un foglio di carta. Non salvarli sul tuo computer.\n\nSi noti che le parole del seed NON sostituiscono un backup.\nÈ necessario creare un backup dell'intera directory dell'applicazione dalla schermata \"Account/Backup\" per ripristinare lo stato e i dati dell'applicazione.\nL'importazione delle parole del seed è consigliata solo in casi di emergenza. L'applicazione non funzionerà senza un corretto backup dei file del database e delle chiavi del seed! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Effettua il backup delle parole chiave del tuo portafoglio. +account.seed.info=Per favore, annota sia le parole chiave del tuo portafoglio che la data. Puoi recuperare il tuo portafoglio in qualsiasi momento con le parole chiave e la data.\n\nDovresti annotare le parole chiave su un foglio di carta. Non salvarle sul computer.\n\nPer favore, nota che le parole chiave NON sostituiscono un backup.\nÈ necessario creare un backup dell'intera directory dell'applicazione dalla schermata "Account/Backup" per recuperare lo stato e i dati dell'applicazione. +account.seed.backup.warning=Per favore, nota che le parole chiave non sostituiscono un backup.\nÈ necessario creare un backup dell'intera directory dell'applicazione dalla schermata "Account/Backup" per recuperare lo stato e i dati dell'applicazione. account.seed.warn.noPw.msg=Non hai impostato una password per il portafoglio che protegga la visualizzazione delle parole del seed.\n\nVuoi visualizzare le parole del seed? account.seed.warn.noPw.yes=Sì, e non chiedermelo più account.seed.enterPw=Immettere la password per visualizzare le parole chiave -account.seed.restore.info=Effettuare un backup prima di cominciare il ripristino dalle parole del seed. Tenere presente che il ripristino del portafoglio è solo per casi di emergenza e potrebbe causare problemi con il database del portafoglio interno.\nNon è un modo per effettuare un backup! Utilizzare un backup della directory dei dati dell'applicazione per ripristinare uno stato dell'applicazione precedente.\n\nDopo aver ripristinato, l'applicazione si spegnerà automaticamente. Dopo aver riavviato l'applicazione, si risincronizzerà con la rete Bitcoin. Questo può richiedere del tempo e può consumare molta CPU, soprattutto se il portafoglio era vecchio e aveva molte transazioni. Evita di interrompere tale processo, altrimenti potrebbe essere necessario eliminare nuovamente il file della catena SPV o ripetere il processo di ripristino. +account.seed.restore.info=Effettuare un backup prima di cominciare il ripristino dalle parole del seed. Tenere presente che il ripristino del portafoglio è solo per casi di emergenza e potrebbe causare problemi con il database del portafoglio interno.\nNon è un modo per effettuare un backup! Utilizzare un backup della directory dei dati dell'applicazione per ripristinare uno stato dell'applicazione precedente.\n\nDopo aver ripristinato, l'applicazione si spegnerà automaticamente. Dopo aver riavviato l'applicazione, si risincronizzerà con la rete Monero. Questo può richiedere del tempo e può consumare molta CPU, soprattutto se il portafoglio era vecchio e aveva molte transazioni. Evita di interrompere tale processo, altrimenti potrebbe essere necessario eliminare nuovamente il file della catena SPV o ripetere il processo di ripristino. account.seed.restore.ok=Ok, fai il ripristino e spegni Haveno @@ -1259,13 +1286,13 @@ account.notifications.trade.label=Ricevi messaggi commerciali account.notifications.market.label=Ricevi avvisi sulle offerte account.notifications.price.label=Ricevi avvisi sui prezzi account.notifications.priceAlert.title=Avvisi sui prezzi -account.notifications.priceAlert.high.label=Notifica se il prezzo BTC è superiore -account.notifications.priceAlert.low.label=Notifica se il prezzo BTC è inferiore +account.notifications.priceAlert.high.label=Notifica se il prezzo XMR è superiore +account.notifications.priceAlert.low.label=Notifica se il prezzo XMR è inferiore account.notifications.priceAlert.setButton=Imposta un avviso di prezzo account.notifications.priceAlert.removeButton=Rimuovi avviso di prezzo account.notifications.trade.message.title=Lo stato dello scambio è cambiato account.notifications.trade.message.msg.conf=La transazione di deposito per lo scambio con ID {0} è confermata. Si prega di aprire l'applicazione Haveno e avviare il pagamento. -account.notifications.trade.message.msg.started=L'acquirente BTC ha avviato il pagamento per lo scambio con ID {0}. +account.notifications.trade.message.msg.started=L'acquirente XMR ha avviato il pagamento per lo scambio con ID {0}. account.notifications.trade.message.msg.completed=Lo scambio con ID {0} è completato. account.notifications.offer.message.title=La tua offerta è stata presa account.notifications.offer.message.msg=La tua offerta con ID {0} è stata accettata @@ -1275,10 +1302,10 @@ account.notifications.dispute.message.msg=Hai ricevuto un messaggio di contestaz account.notifications.marketAlert.title=Offri avvisi account.notifications.marketAlert.selectPaymentAccount=Offre un account di pagamento corrispondente account.notifications.marketAlert.offerType.label=Tipo di offerta che mi interessa -account.notifications.marketAlert.offerType.buy=Acquista offerte (voglio vendere BTC) -account.notifications.marketAlert.offerType.sell=Offerte di vendita (Voglio comprare BTC) +account.notifications.marketAlert.offerType.buy=Acquista offerte (voglio vendere XMR) +account.notifications.marketAlert.offerType.sell=Offerte di vendita (Voglio comprare XMR) account.notifications.marketAlert.trigger=Distanza prezzo offerta (%) -account.notifications.marketAlert.trigger.info=Con una distanza di prezzo impostata, riceverai un avviso solo quando viene pubblicata un'offerta che soddisfa (o supera) i tuoi requisiti. Esempio: vuoi vendere BTC, ma venderai solo con un premio del 2% dal prezzo di mercato attuale. Se si imposta questo campo su 2%, si riceveranno avvisi solo per offerte con prezzi superiori del 2% (o più) dal prezzo di mercato corrente.\n +account.notifications.marketAlert.trigger.info=Con una distanza di prezzo impostata, riceverai un avviso solo quando viene pubblicata un'offerta che soddisfa (o supera) i tuoi requisiti. Esempio: vuoi vendere XMR, ma venderai solo con un premio del 2% dal prezzo di mercato attuale. Se si imposta questo campo su 2%, si riceveranno avvisi solo per offerte con prezzi superiori del 2% (o più) dal prezzo di mercato corrente.\n account.notifications.marketAlert.trigger.prompt=Distanza percentuale dal prezzo di mercato (ad es. 2,50%, -0,50%, ecc.) account.notifications.marketAlert.addButton=Aggiungi avviso offerta account.notifications.marketAlert.manageAlertsButton=Gestisci avvisi di offerta @@ -1305,10 +1332,10 @@ inputControlWindow.balanceLabel=Saldo disponibile contractWindow.title=Dettagli disputa contractWindow.dates=Data dell'offerta / Data di scambio -contractWindow.btcAddresses=Indirizzo Bitcoin acquirente BTC / venditore BTC -contractWindow.onions=Indirizzo di rete acquirente BTC / venditore BTC -contractWindow.accountAge=Età account acquirente BTC / venditore BTC -contractWindow.numDisputes=Numero di controversie acquirente BTC / venditore BTC +contractWindow.xmrAddresses=Indirizzo Monero acquirente XMR / venditore XMR +contractWindow.onions=Indirizzo di rete acquirente XMR / venditore XMR +contractWindow.accountAge=Età account acquirente XMR / venditore XMR +contractWindow.numDisputes=Numero di controversie acquirente XMR / venditore XMR contractWindow.contractHash=Hash contratto displayAlertMessageWindow.headline=Informazioni importanti! @@ -1334,8 +1361,8 @@ disputeSummaryWindow.title=Sommario disputeSummaryWindow.openDate=Data di apertura del ticket disputeSummaryWindow.role=Ruolo del trader disputeSummaryWindow.payout=Pagamento dell'importo di scambio -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} ottiene il pagamento dell'importo commerciale -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} ottiene il pagamento dell'importo commerciale +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=Pagamento personalizzato disputeSummaryWindow.payoutAmount.buyer=Importo pagamento dell'acquirente disputeSummaryWindow.payoutAmount.seller=Importo pagamento del venditore @@ -1377,7 +1404,7 @@ disputeSummaryWindow.close.button=Chiudi ticket # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1420,18 +1447,18 @@ filterWindow.mediators=Mediatori filtrati (indirizzi onion separati con una virg filterWindow.refundAgents=Agenti di rimborso filtrati (virgola sep. indirizzi onion) filterWindow.seedNode=Nodi seme filtrati (separati con una virgola) filterWindow.priceRelayNode=Prezzo filtrato dai nodi relay (virgola sep. indirizzi onion) -filterWindow.xmrNode=Nodi Bitcoin filtrati (indirizzo + porta separati con una virgola) -filterWindow.preventPublicXmrNetwork=Impedisci l'utilizzo della rete pubblica Bitcoin +filterWindow.xmrNode=Nodi Monero filtrati (indirizzo + porta separati con una virgola) +filterWindow.preventPublicXmrNetwork=Impedisci l'utilizzo della rete pubblica Monero filterWindow.disableAutoConf=Disable auto-confirm filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) filterWindow.disableTradeBelowVersion=Versione minima richiesta per il trading filterWindow.add=Aggiungi filtro filterWindow.remove=Rimuovi filtro -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Importo BTC minimo +offerDetailsWindow.minXmrAmount=Importo XMR minimo offerDetailsWindow.min=(min. {0}) offerDetailsWindow.distance=(distanza dal prezzo di mercato: {0}) offerDetailsWindow.myTradingAccount=Il mio account di scambio @@ -1446,6 +1473,7 @@ offerDetailsWindow.confirm.maker=Conferma: Piazza l'offerta a {0} monero offerDetailsWindow.confirm.taker=Conferma: Accetta l'offerta a {0} monero offerDetailsWindow.creationDate=Data di creazione offerDetailsWindow.makersOnion=Indirizzo .onion del maker +offerDetailsWindow.challenge=Passphrase dell'offerta qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1474,7 +1502,7 @@ showWalletDataWindow.walletData=Dati portafoglio showWalletDataWindow.includePrivKeys=Includi chiavi private setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1486,7 +1514,7 @@ tacWindow.disagree=Non accetto ed esco tacWindow.arbitrationSystem=Risoluzione disputa tradeDetailsWindow.headline=Scambio -tradeDetailsWindow.disputedPayoutTxId=ID transazione di pagamento contestato: +tradeDetailsWindow.disputedPayoutTxId=ID transazione di pagamento contestato tradeDetailsWindow.tradeDate=Data di scambio tradeDetailsWindow.txFee=Commissione di mining tradeDetailsWindow.tradePeersOnion=Indirizzi onion peer di trading @@ -1496,8 +1524,10 @@ tradeDetailsWindow.agentAddresses=Arbitro/Mediatore tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=Hai inviato XMR. +txDetailsWindow.xmr.noteReceived=Hai ricevuto XMR. +txDetailsWindow.sentTo=Inviato a +txDetailsWindow.receivedWith=Ricevuto con txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1506,7 +1536,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Inserisci la password per sbloccare @@ -1532,12 +1562,12 @@ torNetworkSettingWindow.bridges.header=Tor è bloccato? torNetworkSettingWindow.bridges.info=Se Tor è bloccato dal tuo provider di servizi Internet o dal tuo paese, puoi provare a utilizzare i bridge Tor.\nVisitare la pagina Web Tor all'indirizzo: https://bridges.torproject.org/bridges per ulteriori informazioni sui bridge e sui trasporti collegabili.\n feeOptionWindow.headline=Scegli la valuta per il pagamento delle commissioni commerciali -feeOptionWindow.info=Puoi scegliere di pagare la commissione commerciale in BSQ o in BTC. Se scegli BSQ approfitti della commissione commerciale scontata. +feeOptionWindow.info=Puoi scegliere di pagare la commissione commerciale in BSQ o in XMR. Se scegli BSQ approfitti della commissione commerciale scontata. feeOptionWindow.optionsLabel=Scegli la valuta per il pagamento delle commissioni commerciali -feeOptionWindow.useBTC=Usa BTC +feeOptionWindow.useXMR=Usa XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1609,9 @@ popup.warning.noTradingAccountSetup.msg=È necessario impostare un conto in valu popup.warning.noArbitratorsAvailable=Non ci sono arbitri disponibili. popup.warning.noMediatorsAvailable=Non ci sono mediatori disponibili. popup.warning.notFullyConnected=È necessario attendere fino a quando non si è completamente connessi alla rete.\nQuesto potrebbe richiedere fino a circa 2 minuti all'avvio. -popup.warning.notSufficientConnectionsToBtcNetwork=Devi aspettare fino a quando non hai almeno {0} connessioni alla rete Bitcoin. -popup.warning.downloadNotComplete=Devi aspettare fino al completamento del download dei blocchi Bitcoin mancanti. -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Devi aspettare fino a quando non hai almeno {0} connessioni alla rete Monero. +popup.warning.downloadNotComplete=Devi aspettare fino al completamento del download dei blocchi Monero mancanti. +popup.warning.walletNotSynced=Il portafoglio Haveno non è sincronizzato con l'altezza più recente della blockchain. Si prega di attendere finché il portafoglio si sincronizza o controllare la connessione. popup.warning.removeOffer=Sei sicuro di voler rimuovere quell'offerta? popup.warning.tooLargePercentageValue=Non è possibile impostare una percentuale del 100% o superiore. popup.warning.examplePercentageValue=Inserisci un numero percentuale come \"5.4\" per il 5,4% @@ -1600,14 +1630,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=ripetitore di prezzo popup.warning.seed=seme popup.warning.mandatoryUpdate.trading=Si prega di aggiornare Haveno all'ultima versione. È stato rilasciato un aggiornamento obbligatorio che disabilita il trading per le vecchie versioni. Per ulteriori informazioni, consultare il forum Haveno. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=Questa transazione non è possibile, poiché le commissioni di mining di {0} supererebbero l'importo da trasferire di {1}. Attendi fino a quando le commissioni di mining non saranno nuovamente basse o fino a quando non avrai accumulato più BTC da trasferire. +popup.warning.burnXMR=Questa transazione non è possibile, poiché le commissioni di mining di {0} supererebbero l'importo da trasferire di {1}. Attendi fino a quando le commissioni di mining non saranno nuovamente basse o fino a quando non avrai accumulato più XMR da trasferire. -popup.warning.openOffer.makerFeeTxRejected=La commissione della transazione del creatore dell'offerta con ID {0} è stata rifiutata dalla rete Bitcoin.\nTransazione ID={1}.\nL'offerta è stata rimossa per evitare ulteriori problemi.\nVai su \"Impostazioni/Informazioni di rete\" ed esegui una risincronizzazione SPV.\nPer ulteriore assistenza, contattare il canale di supporto Haveno nel team di Haveno Keybase. +popup.warning.openOffer.makerFeeTxRejected=La commissione della transazione del creatore dell'offerta con ID {0} è stata rifiutata dalla rete Monero.\nTransazione ID={1}.\nL'offerta è stata rimossa per evitare ulteriori problemi.\nVai su \"Impostazioni/Informazioni di rete\" ed esegui una risincronizzazione SPV.\nPer ulteriore assistenza, contattare il canale di supporto Haveno nel team di Haveno Keybase. popup.warning.trade.txRejected.tradeFee=commissione di scambio popup.warning.trade.txRejected.deposit=deposita -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=La commissione della transazione del creatore dell'offerta con ID {0} non è valida.\nTransazione ID={1}.\nVai su \"Impostazioni/Informazioni di rete\" ed esegui una risincronizzazione SPV.\nPer ulteriore assistenza, contattare il canale di supporto Haveno nel team di Haveno Keybase. @@ -1616,13 +1645,13 @@ popup.info.securityDepositInfo=Per garantire che i trader seguano il protocollo popup.info.cashDepositInfo=Assicurati di avere una filiale bancaria nella tua zona per poter effettuare il deposito in contanti.\nL'ID bancario (BIC/SWIFT) della banca del venditore è: {0}. popup.info.cashDepositInfo.confirm=Confermo di poter effettuare il deposito popup.info.shutDownWithOpenOffers=Haveno viene chiuso, ma ci sono offerte aperte.\n\nQueste offerte non saranno disponibili sulla rete P2P mentre Haveno rimane chiuso, ma verranno ripubblicate sulla rete P2P al prossimo avvio di Haveno.\n\nPer mantenere le tue offerte attive è necessario che Haveno rimanga in funzione ed il computer online (assicurati che non vada in modalità standby. Il solo monitor in standby non è un problema). -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=Notifica privata importante! popup.securityRecommendation.headline=Raccomandazione di sicurezza importante -popup.securityRecommendation.msg=Vorremmo ricordarti di prendere in considerazione l'utilizzo della protezione con password per il tuo portafoglio se non l'avessi già abilitato.\n\nSi consiglia inoltre di annotare le parole seme del portafoglio. Le parole seme sono come una password principale per recuperare il tuo portafoglio Bitcoin.\nNella sezione \"Wallet Seed\" trovi ulteriori informazioni.\n\nInoltre, è necessario eseguire il backup della cartella completa dei dati dell'applicazione nella sezione \"Backup\". +popup.securityRecommendation.msg=Vorremmo ricordarti di prendere in considerazione l'utilizzo della protezione con password per il tuo portafoglio se non l'avessi già abilitato.\n\nSi consiglia inoltre di annotare le parole seme del portafoglio. Le parole seme sono come una password principale per recuperare il tuo portafoglio Monero.\nNella sezione \"Wallet Seed\" trovi ulteriori informazioni.\n\nInoltre, è necessario eseguire il backup della cartella completa dei dati dell'applicazione nella sezione \"Backup\". popup.shutDownInProgress.headline=Arresto in corso popup.shutDownInProgress.msg=La chiusura dell'applicazione può richiedere un paio di secondi.\nNon interrompere il processo. @@ -1668,6 +1697,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=Nessun deposito richiesto dal compratore +popup.info.buyerAsTakerWithoutDeposit=La tua offerta non richiederà un deposito di sicurezza o una commissione da parte dell'acquirente XMR.\n\nPer accettare la tua offerta, devi condividere una passphrase con il tuo partner commerciale al di fuori di Haveno.\n\nLa passphrase viene generata automaticamente e mostrata nei dettagli dell'offerta dopo la creazione. + #################################################################### # Notifications #################################################################### @@ -1675,9 +1707,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign notification.trade.headline=Notifica per scambi con ID {0} notification.ticket.headline=Biglietto di supporto per scambi con ID {0} notification.trade.completed=Il commercio è ora completato e puoi ritirare i tuoi fondi. -notification.trade.accepted=La tua offerta è stata accettata da un BTC {0}. +notification.trade.accepted=La tua offerta è stata accettata da un XMR {0}. notification.trade.unlocked=Il tuo trade ha almeno una conferma blockchain.\nPuoi iniziare il pagamento ora. -notification.trade.paymentSent=L'acquirente BTC ha avviato il pagamento. +notification.trade.paymentSent=L'acquirente XMR ha avviato il pagamento. notification.trade.selectTrade=Seleziona scambio notification.trade.peerOpenedDispute=Il tuo peer di trading ha aperto un {0}. notification.trade.disputeClosed={0} è stato chiuso. @@ -1696,7 +1728,7 @@ systemTray.show=Mostra la finestra dell'applicazione systemTray.hide=Nascondi la finestra dell'applicazione systemTray.info=Informazioni su Haveno systemTray.exit=Esci -systemTray.tooltip=Haveno: una rete di scambio decentralizzata di bitcoin +systemTray.tooltip=Haveno: una rete di scambio decentralizzata di monero #################################################################### @@ -1747,7 +1779,7 @@ tooltip.openBlockchainForTx=Apri Explorer blockchain esterno per la transazione: confidence.unknown=Stato della transazione sconosciuto confidence.seen=Visto da {0} conferme peer / 0 -confidence.confirmed=Confermato in {0} blocco (chi) +confidence.confirmed={0} conferma(e) confidence.invalid=La transazione non è valida peerInfo.title=Info peer @@ -1758,10 +1790,10 @@ peerInfo.age.noRisk=Età del conto di pagamento peerInfo.age.chargeBackRisk=Tempo dall'iscrizione peerInfo.unknownAge=Età sconosciuta -addressTextField.openWallet=Apri il tuo portafoglio Bitcoin predefinito +addressTextField.openWallet=Apri il tuo portafoglio Monero predefinito addressTextField.copyToClipboard=Copia l'indirizzo negli appunti addressTextField.addressCopiedToClipboard=L'indirizzo è stato copiato negli appunti -addressTextField.openWallet.failed=Il tentativo di aprire un portafoglio bitcoin predefinito è fallito. Forse non ne hai installato uno? +addressTextField.openWallet.failed=Il tentativo di aprire un portafoglio monero predefinito è fallito. Forse non ne hai installato uno? peerInfoIcon.tooltip={0}\nTag: {1} @@ -1793,6 +1825,7 @@ navigation.support=\"Supporto\" formatter.formatVolumeLabel={0} importo{1} formatter.makerTaker=Maker come {0} {1} / Taker come {2} {3} +formatter.makerTakerLocked=Maker come {0} {1} / Taker come {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Sei {0} {1} ({2} {3}) @@ -1809,11 +1842,11 @@ formatter.asTaker={0} {1} come taker # we use enum values here # dynamic values are not recognized by IntelliJ # suppress inspection "UnusedProperty" -XMR_MAINNET=Mainnet Bitcoin +XMR_MAINNET=Mainnet Monero # suppress inspection "UnusedProperty" -XMR_LOCAL=Testnet Bitcoin +XMR_LOCAL=Testnet Monero # suppress inspection "UnusedProperty" -XMR_STAGENET=Regtest Bitcoin +XMR_STAGENET=Regtest Monero time.year=Anno time.month=Mese @@ -1838,7 +1871,6 @@ password.deriveKey=Deriva la chiave dalla password password.walletDecrypted=Portafoglio decodificato correttamente e protezione con password rimossa. password.wrongPw=Hai inserito la password errata.\n\nProva a inserire nuovamente la password, verificando attentamente errori di battitura o errori di ortografia. password.walletEncrypted=Portafoglio crittografato correttamente e protezione con password abilitata. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=Le 2 password inserite non corrispondono. password.forgotPassword=Password dimenticata? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1852,7 +1884,7 @@ seed.date=Data portafoglio seed.restore.title=Ripristina portafogli dalle parole del seed seed.restore=Ripristina portafogli seed.creationDate=Data di creazione -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Voglio comunque effettuare il ripristino seed.warn.walletNotEmpty.emptyWallet=Prima svuoterò i miei portafogli seed.warn.notEncryptedAnymore=I tuoi portafogli sono crittografati.\n\nDopo il ripristino, i portafogli non saranno più crittografati ed è necessario impostare una nuova password.\n\nVuoi procedere? @@ -1869,7 +1901,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=Account payment.account.no=Account n° payment.account.name=Nome conto -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=Nome completo del proprietario del conto payment.account.fullName=Nome completo (nome, secondo nome, cognome) @@ -1901,7 +1933,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=Nome utente o e-mail o n. di telefono payment.moneyBeam.accountId=Email o numero di telefono fisso -payment.venmo.venmoUserName=Nome utente Venmo payment.popmoney.accountId=Email o numero di telefono fisso payment.promptPay.promptPayId=Codice fiscale/P.IVA o n. di telefono payment.supportedCurrencies=Valute supportate @@ -1943,28 +1974,28 @@ payment.checking=Verifica payment.savings=Risparmi payment.personalId=ID personale payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Alcune banche hanno iniziato a verificare il nome completo del destinatario per i trasferimenti di Faster Payments (UK). Il tuo attuale account Faster Payments non specifica un nome completo.\n\nTi consigliamo di ricreare il tuo account Faster Payments in Haveno per fornire ai futuri acquirenti {0} un nome completo.\n\nQuando si ricrea l'account, assicurarsi di copiare il codice di ordinamento preciso, il numero di account e i valori salt della verifica dell'età dal vecchio account al nuovo account. Ciò garantirà il mantenimento dell'età del tuo account esistente e lo stato della firma.\n -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=Quando utilizza HalCash, l'acquirente BTC deve inviare al venditore BTC il codice HalCash tramite un messaggio di testo dal proprio telefono cellulare.\n\nAssicurati di non superare l'importo massimo che la tua banca ti consente di inviare con HalCash. L'importo minimo per prelievo è di 10 EURO, l'importo massimo è di 600 EURO. Per prelievi ripetuti è di 3000 EURO per destinatario al giorno e 6000 EURO per destintario al mese. Verifica i limiti con la tua banca per accertarti che utilizzino gli stessi limiti indicati qui.\n\nL'importo del prelievo deve essere un multiplo di 10 EURO in quanto non è possibile prelevare altri importi da un bancomat. L'interfaccia utente nella schermata di creazione offerta e accettazione offerta modificherà l'importo BTC in modo che l'importo in EURO sia corretto. Non è possibile utilizzare il prezzo di mercato poiché l'importo in EURO cambierebbe al variare dei prezzi.\n\nIn caso di controversia, l'acquirente BTC deve fornire la prova di aver inviato gli EURO. +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=Quando utilizza HalCash, l'acquirente XMR deve inviare al venditore XMR il codice HalCash tramite un messaggio di testo dal proprio telefono cellulare.\n\nAssicurati di non superare l'importo massimo che la tua banca ti consente di inviare con HalCash. L'importo minimo per prelievo è di 10 EURO, l'importo massimo è di 600 EURO. Per prelievi ripetuti è di 3000 EURO per destinatario al giorno e 6000 EURO per destintario al mese. Verifica i limiti con la tua banca per accertarti che utilizzino gli stessi limiti indicati qui.\n\nL'importo del prelievo deve essere un multiplo di 10 EURO in quanto non è possibile prelevare altri importi da un bancomat. L'interfaccia utente nella schermata di creazione offerta e accettazione offerta modificherà l'importo XMR in modo che l'importo in EURO sia corretto. Non è possibile utilizzare il prezzo di mercato poiché l'importo in EURO cambierebbe al variare dei prezzi.\n\nIn caso di controversia, l'acquirente XMR deve fornire la prova di aver inviato gli EURO. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Conferma che la tua banca ti consente di inviare depositi in contanti su conti di altre persone. Ad esempio, Bank of America e Wells Fargo non consentono più tali depositi. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=Informazioni di contatto payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1975,7 +2006,7 @@ payment.f2f.city.prompt=La città verrà visualizzata con l'offerta payment.shared.optionalExtra=Ulteriori informazioni opzionali payment.shared.extraInfo=Informazioni aggiuntive payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Apri sito web payment.f2f.offerbook.tooltip.countryAndCity=Paese e città: {0} / {1} payment.f2f.offerbook.tooltip.extra=Ulteriori informazioni: {0} @@ -1987,7 +2018,7 @@ payment.japan.recipient=Nome payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2145,7 +2176,7 @@ validation.zero=Un input di 0 non è consentito. validation.negative=Un valore negativo non è consentito. validation.traditional.tooSmall=Non è consentito un input inferiore al minimo possibile. validation.traditional.tooLarge=Non è consentito un input maggiore del massimo possibile. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=L'immissione maggiore di {0} non è consentita. validation.xmr.tooSmall=L'immissione inferiore a {0} non è consentita. validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2155,10 +2186,10 @@ validation.sortCodeChars={0} deve essere composto da {1} caratteri. validation.bankIdNumber={0} deve essere composto da {1} numeri. validation.accountNr=Il numero di conto deve essere composto da {0} numeri. validation.accountNrChars=Il numero di conto deve contenere {0} caratteri. -validation.btc.invalidAddress=L'indirizzo non è corretto Si prega di controllare il formato dell'indirizzo. +validation.xmr.invalidAddress=L'indirizzo non è corretto Si prega di controllare il formato dell'indirizzo. validation.integerOnly=Inserisci solo numeri interi. validation.inputError=Il tuo input ha causato un errore:\n{0} -validation.btc.exceedsMaxTradeLimit=Il tuo limite commerciale è {0}. +validation.xmr.exceedsMaxTradeLimit=Il tuo limite commerciale è {0}. validation.nationalAccountId={0} deve essere composto da {1} numeri. #new diff --git a/core/src/main/resources/i18n/displayStrings_ja.properties b/core/src/main/resources/i18n/displayStrings_ja.properties index b87d1621d8..c1331ac5b2 100644 --- a/core/src/main/resources/i18n/displayStrings_ja.properties +++ b/core/src/main/resources/i18n/displayStrings_ja.properties @@ -36,14 +36,16 @@ shared.iUnderstand=了解 shared.na=N/A shared.shutDown=終了 shared.reportBug=Githubでバグを報告 -shared.buyBitcoin=ビットコインを買う -shared.sellBitcoin=ビットコインを売る +shared.buyMonero=ビットコインを買う +shared.sellMonero=ビットコインを売る shared.buyCurrency={0}を買う shared.sellCurrency={0}を売る -shared.buyingBTCWith=BTCを{0}で買う -shared.sellingBTCFor=BTCを{0}で売る -shared.buyingCurrency={0}を購入中 (BTCを売却中) -shared.sellingCurrency={0}を売却中 (BTCを購入中) +shared.buyCurrencyLocked={0}を買う 🔒 +shared.sellCurrencyLocked={0}を売る 🔒 +shared.buyingXMRWith=XMRを{0}で買う +shared.sellingXMRFor=XMRを{0}で売る +shared.buyingCurrency={0}を購入中 (XMRを売却中) +shared.sellingCurrency={0}を売却中 (XMRを購入中) shared.buy=買う shared.sell=売る shared.buying=購入中 @@ -93,7 +95,7 @@ shared.amountMinMax=金額(下限 - 上限) shared.amountHelp=オファーに最小金額と最大金額が設定されている場合は、この範囲内の任意の金額で取引できます。 shared.remove=取り消す shared.goTo={0} へ -shared.BTCMinMax=BTC (下限 - 上限) +shared.XMRMinMax=XMR (下限 - 上限) shared.removeOffer=オファー取消 shared.dontRemoveOffer=オファー取り消さない shared.editOffer=オファーを編集 @@ -103,7 +105,7 @@ shared.faq=FAQを参照する shared.yesCancel=はい、取り消します shared.nextStep=次へ shared.selectTradingAccount=取引アカウントを選択 -shared.fundFromSavingsWalletButton=Havenoウォレットから資金を移動する +shared.fundFromSavingsWalletButton=Havenoウォレットから資金を適用 shared.fundFromExternalWalletButton=外部のwalletを開く shared.openDefaultWalletFailed=ビットコインウォレットのアプリを開けませんでした。インストールされているか確認して下さい。 shared.belowInPercent=市場価格から%以下 @@ -112,7 +114,7 @@ shared.enterPercentageValue=%を入力 shared.OR=または shared.notEnoughFunds=このトランザクションには、Havenoウォレットに資金が足りません。\n{0}が必要ですが、Havenoウォレットには{1}しかありません。\n\n外部のビットコインウォレットから入金するか、または「資金 > 資金の受取」でHavenoウォレットに入金してください。 shared.waitingForFunds=資金を待っています -shared.TheBTCBuyer=BTC買い手 +shared.TheXMRBuyer=XMR買い手 shared.You=あなた shared.sendingConfirmation=承認を送信中 shared.sendingConfirmationAgain=もう一度承認を送信してください @@ -123,7 +125,6 @@ shared.noDateAvailable=日付がありません shared.noDetailsAvailable=詳細不明 shared.notUsedYet=未使用 shared.date=日付 -shared.sendFundsDetailsWithFee=送金中: {0}\n送金元アドレス: {1}\n入金先アドレス: {2}\n必要なマイニング手数料: {3} ({4} Satoshis/byte)\nトランザクションvサイズ: {5} vKb\n\n入金先の受け取る金額: {6}\n\n本当にこの金額を出金しますか? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Havenoがこのトランザクションはダストの最小閾値以下のおつりアウトプットを生じることを検出しました(それにしたがって、ビットコインのコンセンサス・ルールによって許されない)。代わりに、その ({0} satoshi{1}) のダストはマイニング手数料に追加されます。\n\n\n shared.copyToClipboard=クリップボードにコピー @@ -140,6 +141,7 @@ shared.addNewAccount=アカウントを追加 shared.ExportAccounts=アカウントをエクスポート shared.importAccounts=アカウントをインポート shared.createNewAccount=新しいアカウントを作る +shared.createNewAccountDescription=あなたのアカウント詳細は、デバイスにローカルに保存され、取引相手および紛争が発生した場合には仲裁人とのみ共有されます。 shared.saveNewAccount=新しいアカウントを保存する shared.selectedAccount=選択したアカウント shared.deleteAccount=アカウントを削除 @@ -169,7 +171,7 @@ shared.payoutTxId=支払いトランザクションID shared.contractAsJson=JSON形式の契約 shared.viewContractAsJson=JSON形式で見る shared.contract.title=次のIDとのトレードの契約: {0} -shared.paymentDetails=BTC {0} 支払い詳細 +shared.paymentDetails=XMR {0} 支払い詳細 shared.securityDeposit=セキュリティデポジット shared.yourSecurityDeposit=あなたのセキュリティデポジット shared.contract=契約 @@ -179,19 +181,21 @@ shared.messageSendingFailed=メッセージ送信失敗。エラー: {0} shared.unlock=ロック解除 shared.toReceive=受け取る shared.toSpend=費やす -shared.btcAmount=BTC金額 +shared.xmrAmount=XMR金額 shared.yourLanguage=あなたの言語 shared.addLanguage=言語を追加 shared.total=合計 shared.totalsNeeded=必要な資金 shared.tradeWalletAddress=トレードウォレットアドレス shared.tradeWalletBalance=トレードウォレット残高 +shared.reserveExactAmount=必要な資金のみを予約してください。オファーが公開されるまでにマイニング手数料と約20分が必要です。 shared.makerTxFee=メイカー: {0} shared.takerTxFee=テイカー: {0} shared.iConfirm=確認します shared.openURL={0} をオープン shared.fiat=法定通貨 shared.crypto=暗号通貨 +shared.preciousMetals=貴金属 shared.all=全て shared.edit=編集 shared.advancedOptions=高度なオプション @@ -226,8 +230,8 @@ shared.enabled=有効されました #################################################################### mainView.menu.market=相場 -mainView.menu.buyBtc=BTCを購入 -mainView.menu.sellBtc=BTCを売却 +mainView.menu.buyXmr=XMRを購入 +mainView.menu.sellXmr=XMRを売却 mainView.menu.portfolio=ポートフォリオ mainView.menu.funds=資金 mainView.menu.support=サポート @@ -244,13 +248,16 @@ mainView.balance.pending=トレードにロック中 mainView.balance.reserved.short=予約済 mainView.balance.pending.short=ロック中 -mainView.footer.usingTor=(Tor経由で) -mainView.footer.localhostBitcoinNode=(ローカルホスト) +mainView.footer.usingTor=(Tor 経由) +mainView.footer.localhostMoneroNode=(ローカルホスト) +mainView.footer.clearnet=(clearnet 経由) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ 手数料率: {0} サトシ/vB -mainView.footer.xmrInfo.initializing=ビットコインネットワークに接続中 -mainView.footer.xmrInfo.synchronizingWith={0}と同期中、ブロック: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith={0}と同期されています、ブロック{1}に +mainView.footer.xmrFeeRate=/ 手数料率: {0} サトシ/vB +mainView.footer.xmrInfo.initializing=Havenoネットワークに接続中 +mainView.footer.xmrInfo.synchronizingWith=ブロック {1} / {2} で {0} と同期しています +mainView.footer.xmrInfo.connectedTo=ブロック {1} で {0} に接続しました +mainView.footer.xmrInfo.synchronizingWalletWith=ブロック {1} / {2} で {0} のウォレットを同期しています +mainView.footer.xmrInfo.syncedWith=ブロック {1} で {0} と同期しました mainView.footer.xmrInfo.connectingTo=接続中: mainView.footer.xmrInfo.connectionFailed=接続失敗 mainView.footer.xmrPeers=Moneroネットワークピア: {0} @@ -274,7 +281,7 @@ mainView.walletServiceErrorMsg.connectionError=次のエラーのためビット mainView.walletServiceErrorMsg.rejectedTxException=トランザクションはネットワークに拒否されました。\n\n{0} mainView.networkWarning.allConnectionsLost=全ての{0}のネットワークピアへの接続が切断されました。\nインターネット接続が切断されたか、コンピュータがスタンバイモードになった可能性があります。 -mainView.networkWarning.localhostBitcoinLost=ローカルホストビットコインノードへの接続が切断されました。\nHavenoアプリケーションを再起動して他のビットコインノードに接続するか、ローカルホストのビットコインノードを再起動してください。 +mainView.networkWarning.localhostMoneroLost=ローカルホストビットコインノードへの接続が切断されました。\nHavenoアプリケーションを再起動して他のビットコインノードに接続するか、ローカルホストのビットコインノードを再起動してください。 mainView.version.update=(更新が利用可能) @@ -299,9 +306,9 @@ market.offerBook.sell=ビットコインを売りたい # SpreadView market.spread.numberOfOffersColumn=全てのオファー ({0}) -market.spread.numberOfBuyOffersColumn=BTCを買う ({0}) -market.spread.numberOfSellOffersColumn=BTCを売る ({0}) -market.spread.totalAmountColumn=BTC合計 ({0}) +market.spread.numberOfBuyOffersColumn=XMRを買う ({0}) +market.spread.numberOfSellOffersColumn=XMRを売る ({0}) +market.spread.totalAmountColumn=XMR合計 ({0}) market.spread.spreadColumn=スプレッド market.spread.expanded=拡張された表示 @@ -325,6 +332,7 @@ offerbook.createOffer=オファーを作る offerbook.takeOffer=オファーを受ける offerbook.takeOfferToBuy={0}購入オファーを受ける offerbook.takeOfferToSell={0}売却オファーを受ける +offerbook.takeOffer.enterChallenge=オファーのパスフレーズを入力してください offerbook.trader=取引者 offerbook.offerersBankId=メイカーの銀行ID (BIC/SWIFT): {0} offerbook.offerersBankName=メーカーの銀行名: {0} @@ -335,6 +343,8 @@ offerbook.availableOffers=利用可能なオファー offerbook.filterByCurrency=通貨でフィルター offerbook.filterByPaymentMethod=支払い方法でフィルター offerbook.matchingOffers=アカウントと一致するオファー +offerbook.filterNoDeposit=デポジットなし +offerbook.noDepositOffers=預金不要のオファー(パスフレーズ必須) offerbook.timeSinceSigning=アカウント情報 offerbook.timeSinceSigning.info=このアカウントは認証されまして、{0} offerbook.timeSinceSigning.info.arbitrator=調停人に署名されました。ピアアカウントも署名できます @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=このアカウントは禁止されま offerbook.timeSinceSigning.daysSinceSigning={0}日 offerbook.timeSinceSigning.daysSinceSigning.long=署名する後から {0} offerbook.xmrAutoConf=自動確認は有効されますか? +offerbook.buyXmrWith=XMRを購入: +offerbook.sellXmrFor=XMRを売る: offerbook.timeSinceSigning.help=署名された支払いアカウントを持っているピアと成功にトレードすると、自身の支払いアカウントも署名されることになります。\n{0} 日後に、{1} という初期の制限は解除され、他のピアの支払いアカウントを署名できるようになります。 offerbook.timeSinceSigning.notSigned=まだ署名されていません @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=アルトコインのアカウントには署名や offerbook.nrOffers=オファー数: {0} offerbook.volume={0} (下限 - 上限) -offerbook.deposit=BTCの敷金(%) +offerbook.deposit=XMRの敷金(%) offerbook.deposit.help=トレードを保証するため、両方の取引者が支払う敷金。トレードが完了されたら、返還されます。 +offerbook.createNewOffer={0} {1}にオファーを作成する offerbook.createOfferToBuy={0} を購入するオファーを作成 offerbook.createOfferToSell={0} を売却するオファーを作成 @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=このバージョンのソフトウェ popup.warning.tradeLimitDueAccountAgeRestriction.seller=許可されたトレード金額は以下のセキュリティ基準に基づいて {0} に制限されました:\n- 買い手のアカウントは調停人やピアに署名されていません\n- 買い手のアカウントが署名された時から30日未満がたちました\n- このオファーの支払い方法は、銀行のチャージバックのリスクが高いと考えられます\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=許可されたトレード金額は以下のセキュリティ基準に基づいて {0} に制限されました:\n- このアカウントは調停人やピアに署名されていません\n- このアカウントが署名された時から30日未満がたちました\n- このオファーの支払い方法は、銀行のチャージバックのリスクが高いと考えられます\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=この支払い方法は、すべての購入者が新しいアカウントを持っているため、{0}までの一時的な制限があります{1}。\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=あなたのオファーは、署名済みで経年の古いアカウントを持つバイヤーに限定されます。なぜなら、それが {0} を超えているためです。\n\n{1} offerbook.warning.wrongTradeProtocol=そのオファーには、ご使用のソフトウェアのバージョンで使用されているものとは異なるプロトコルバージョンが必要です。\n\n最新バージョンがインストールされているかどうかを確認してください。そうでなければ、オファーを作成したユーザーが古いバージョンを使用しています。\n\nユーザーは、互換性のないトレードプロトコルバージョンと取引することはできません。 offerbook.warning.userIgnored=そのユーザのonionアドレスを無視リストに追加しました。 @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=金額は取引のプライバシーを高め # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=BTCの金額を入力 +createOffer.amount.prompt=XMRの金額を入力 createOffer.price.prompt=価格を入力 createOffer.volume.prompt={0}の金額を入力 -createOffer.amountPriceBox.amountDescription=以下の金額でBTCを{0} +createOffer.amountPriceBox.amountDescription=以下の金額でXMRを{0} createOffer.amountPriceBox.buy.volumeDescription=支払う{0}の金額 createOffer.amountPriceBox.sell.volumeDescription=受け取る{0}の金額 -createOffer.amountPriceBox.minAmountDescription=BTCの最小額 +createOffer.amountPriceBox.minAmountDescription=XMRの最小額 createOffer.securityDeposit.prompt=セキュリティデポジット createOffer.fundsBox.title=あなたのオファーへ入金 createOffer.fundsBox.offerFee=取引手数料 @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=オファーの価格は継続的に更新 createOffer.info.buyBelowMarketPrice=オファーの価格は継続的に更新されるため、常に現在の市場価格より{0}%以下で支払いするでしょう。 createOffer.warning.sellBelowMarketPrice=オファーの価格は継続的に更新されるため、常に現在の市場価格より{0}%以下で入手するでしょう。 createOffer.warning.buyAboveMarketPrice=オファーの価格は継続的に更新されるため、常に現在の市場価格より{0}%以上で支払いするでしょう。 -createOffer.tradeFee.descriptionBTCOnly=取引手数料 +createOffer.tradeFee.descriptionXMROnly=取引手数料 createOffer.tradeFee.descriptionBSQEnabled=トレード手数料通貨を選択 createOffer.triggerPrice.prompt=任意選択価格トリガーを設定する @@ -448,7 +463,12 @@ createOffer.placeOfferButton=再確認: ビットコインを{0}オファーを createOffer.createOfferFundWalletInfo.headline=あなたのオファーへ入金 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 取引額: {0}\n -createOffer.createOfferFundWalletInfo.msg=このオファーに対して {0} のデポジットを送金する必要があります。\n\nこの資金はあなたのローカルウォレットに予約済として保管され、オファーが受け入れられた時にマルチシグデポジットアドレスに移動しロックされます。\n\n金額の合計は以下の通りです\n{1} - セキュリティデポジット: {2}\n- 取引手数料: {3}\n- マイニング手数料: {4}\n\nこのオファーにデポジットを送金するには、以下の2つの方法があります。\n- Havenoウォレットを使う (便利ですがトランザクションが追跡される可能性があります)\n- 外部のウォレットから送金する (機密性の高い方法です)\n\nこのポップアップを閉じると全ての送金方法について詳細な情報が表示されます。 +createOffer.createOfferFundWalletInfo.msg=このオファーには {0} をデポジットする必要があります。\n\n\ + この資金はあなたのローカルウォレットに予約され、誰かがあなたのオファーを受け入れるとマルチシグウォレットにロックされます。\n\n\ + 金額は以下の合計です:\n\ + {1}\ + - あなたの保証金: {2}\n\ + - 取引手数料: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=オファーを出す時にエラーが発生しました:\n\n{0}\n\nウォレットにまだ資金がありません。\nアプリケーションを再起動してネットワーク接続を確認してください。 @@ -470,30 +490,35 @@ createOffer.setDepositAsBuyer=購入時のセキュリティデポジット (%) createOffer.setDepositForBothTraders=両方の取引者の保証金を設定する(%) createOffer.securityDepositInfo=あなたの買い手のセキュリティデポジットは{0}です createOffer.securityDepositInfoAsBuyer=あなたの購入時のセキュリティデポジットは{0}です -createOffer.minSecurityDepositUsed=最小値の買い手の保証金は使用されます +createOffer.minSecurityDepositUsed=最低セキュリティデポジットが使用されます +createOffer.buyerAsTakerWithoutDeposit=購入者に保証金は不要(パスフレーズ保護) +createOffer.myDeposit=私の保証金(%) +createOffer.myDepositInfo=あなたのセキュリティデポジットは{0}です #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=BTCの金額を入力 -takeOffer.amountPriceBox.buy.amountDescription=BTC売却額 -takeOffer.amountPriceBox.sell.amountDescription=BTC購入額 +takeOffer.amount.prompt=XMRの金額を入力 +takeOffer.amountPriceBox.buy.amountDescription=XMR売却額 +takeOffer.amountPriceBox.sell.amountDescription=XMR購入額 takeOffer.amountPriceBox.priceDescription={0}のビットコインあたりの価格 takeOffer.amountPriceBox.amountRangeDescription=可能な金額の範囲 -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=入力した金額が、許容される小数点以下の桁数を超えています。\n金額は小数点以下第4位に調整されています。 +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=入力した金額が、許容される小数点以下の桁数を超えています。\n金額は小数点以下第4位に調整されています。 takeOffer.validation.amountSmallerThanMinAmount=金額はオファーで示された下限額を下回ることができません takeOffer.validation.amountLargerThanOfferAmount=オファーで示された上限額を上回る金額は入力できません -takeOffer.validation.amountLargerThanOfferAmountMinusFee=その入力額はBTCの売り手にダストチェンジを引き起こします。 +takeOffer.validation.amountLargerThanOfferAmountMinusFee=その入力額はXMRの売り手にダストチェンジを引き起こします。 takeOffer.fundsBox.title=あなたのトレードへ入金 takeOffer.fundsBox.isOfferAvailable=オファーが有効か確認中... takeOffer.fundsBox.tradeAmount=売却額 takeOffer.fundsBox.offerFee=取引手数料 takeOffer.fundsBox.networkFee=合計マイニング手数料 -takeOffer.fundsBox.takeOfferSpinnerInfo=オファー受け入れ処理中 ... +takeOffer.fundsBox.takeOfferSpinnerInfo=オファーを受け入れる: {0} takeOffer.fundsBox.paymentLabel=次のIDとのHavenoトレード: {0} takeOffer.fundsBox.fundsStructure=({0} セキュリティデポジット, {1} 取引手数料, {2}マイニング手数料) +takeOffer.fundsBox.noFundingRequiredTitle=資金は必要ありません +takeOffer.fundsBox.noFundingRequiredDescription=このオファーを受けるには、Haveno外で売り手からオファーパスフレーズを取得してください。 takeOffer.success.headline=オファー受け入れに成功しました takeOffer.success.info=あなたのトレード状態は「ポートフォリオ/オープントレード」で見られます takeOffer.error.message=オファーの受け入れ時にエラーが発生しました。\n\n{0} @@ -504,7 +529,7 @@ takeOffer.noPriceFeedAvailable=そのオファーは市場価格に基づくパ takeOffer.takeOfferFundWalletInfo.headline=あなたのオファーへ入金 # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount= - 取引額: {0}\n -takeOffer.takeOfferFundWalletInfo.msg=このオファーに対して {0} のデポジットを送金する必要があります。\n\n金額の合計は以下の通りです\n{1} - セキュリティデポジット: {2}\n- 取引手数料: {3}\n- マイニング手数料: {4}\n\nこのオファーにデポジットを送金するには、以下の2つの方法があります。\n- Havenoウォレットを使う (便利ですがトランザクションが追跡される可能性があります)\nまたは\n- 外部のウォレットから送金する (機密性の高い方法です)\n\nこのポップアップを閉じると全ての送金方法について詳細な情報が表示されます。 +takeOffer.takeOfferFundWalletInfo.msg=このオファーを受けるには、{0} を預ける必要があります。\n\n金額は以下の合計です:\n{1}- あなたの保証金: {2}\n- 取引手数料: {3} takeOffer.alreadyPaidInFunds=あなたがすでに資金を支払っている場合は「資金/送金する」画面でそれを出金することができます。 takeOffer.paymentInfo=支払い情報 takeOffer.setAmountPrice=金額を設定 @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=デポジットトランザクション # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=トレードは少なくとも1つのブロックチェーン承認に達しました。\n\n -portfolio.pending.step2_buyer.refTextWarn=注意点:支払う時に、\"支払理由\"のフィールドを空白にしておいて下さい。いかなる場合でも、トレードIDそれとも「ビットコイン」、「BTC」、「Haveno」などを入力しないで下さい。両者にとって許容できる別の\"支払理由\"があれば、自由に取引者チャットで話し合いをして下さい。 +portfolio.pending.step2_buyer.refTextWarn=注意点:支払う時に、\"支払理由\"のフィールドを空白にしておいて下さい。いかなる場合でも、トレードIDそれとも「ビットコイン」、「XMR」、「Haveno」などを入力しないで下さい。両者にとって許容できる別の\"支払理由\"があれば、自由に取引者チャットで話し合いをして下さい。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=銀行口座振替を行うには手数料がある場合、その手数料を払う責任があります。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=外部{0}ウォレットから転送してください\nBTCの売り手へ{1}。\n\n +portfolio.pending.step2_buyer.crypto=外部{0}ウォレットから転送してください\nXMRの売り手へ{1}。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=銀行に行き、BTCの売り手へ{0}を支払ってください。\n\n -portfolio.pending.step2_buyer.cash.extra=重要な要件:\n支払いが完了したら、領収書に「返金無し(NO REFUNDS)」と記載してください。\nそれからそれを2部に分け、写真を撮り、そしてBTCの売り手のEメールアドレスへそれを送ってください。 +portfolio.pending.step2_buyer.cash=銀行に行き、XMRの売り手へ{0}を支払ってください。\n\n +portfolio.pending.step2_buyer.cash.extra=重要な要件:\n支払いが完了したら、領収書に「返金無し(NO REFUNDS)」と記載してください。\nそれからそれを2部に分け、写真を撮り、そしてXMRの売り手のEメールアドレスへそれを送ってください。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=MoneyGramを使用してBTC売り手へ{0}をお支払いください。\n\n -portfolio.pending.step2_buyer.moneyGram.extra=重要な要件: \n支払いが完了したら、認証番号と領収書の写真を電子メールでBTCの売り手へ送信して下さい。\n領収書には、売り手の氏名、国、都道府県、および金額を明確に表示する必要があります。売り手のメールアドレス: {0} +portfolio.pending.step2_buyer.moneyGram=MoneyGramを使用してXMR売り手へ{0}をお支払いください。\n\n +portfolio.pending.step2_buyer.moneyGram.extra=重要な要件: \n支払いが完了したら、認証番号と領収書の写真を電子メールでXMRの売り手へ送信して下さい。\n領収書には、売り手の氏名、国、都道府県、および金額を明確に表示する必要があります。売り手のメールアドレス: {0} # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Western Unionを使用してBTCの売り手へ{0}をお支払いください。\n\n -portfolio.pending.step2_buyer.westernUnion.extra=重要な要件: \n支払いが完了したら、MTCN(追跡番号)と領収書の写真を電子メールでBTCの売り手へ送信して下さい。\n領収書には、売り手の氏名、市区町村、国、金額が明確に示されている必要があります。売り手のメールアドレス: {0} +portfolio.pending.step2_buyer.westernUnion=Western Unionを使用してXMRの売り手へ{0}をお支払いください。\n\n +portfolio.pending.step2_buyer.westernUnion.extra=重要な要件: \n支払いが完了したら、MTCN(追跡番号)と領収書の写真を電子メールでXMRの売り手へ送信して下さい。\n領収書には、売り手の氏名、市区町村、国、金額が明確に示されている必要があります。売り手のメールアドレス: {0} # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal={0}を「米国の郵便為替」でBTCの売り手に送付してください。\n\n +portfolio.pending.step2_buyer.postal={0}を「米国の郵便為替」でXMRの売り手に送付してください。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=\"郵送で現金\"で、{0}をBTC売り手に送って下さい。詳細な指示はトレード契約書に書いてあります、そして分からない点があれば取引者チャットで質問できます。「郵送で現金」について詳しくはHavenoのWikiを参照:[HYPERLINK:https://bisq.wiki/Cash_by_Mail]\n +portfolio.pending.step2_buyer.payByMail=\"郵送で現金\"で、{0}をXMR売り手に送って下さい。詳細な指示はトレード契約書に書いてあります、そして分からない点があれば取引者チャットで質問できます。「郵送で現金」について詳しくはHavenoのWikiを参照:[HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail]\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=特定された支払い方法で{0}をBTCの売り手に支払ってお願いします。売り手のアカウント詳細は次の画面に表示されます。\n\n +portfolio.pending.step2_buyer.pay=特定された支払い方法で{0}をXMRの売り手に支払ってお願いします。売り手のアカウント詳細は次の画面に表示されます。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=提供された連絡先でBTCの売り手に連絡し、{0}を支払うためのミーティングを準備してください。\n\n +portfolio.pending.step2_buyer.f2f=提供された連絡先でXMRの売り手に連絡し、{0}を支払うためのミーティングを準備してください。\n\n portfolio.pending.step2_buyer.startPaymentUsing={0}を使用して支払いを開始 portfolio.pending.step2_buyer.recipientsAccountData=受領者 {0} portfolio.pending.step2_buyer.amountToTransfer=振替金額 @@ -628,27 +653,27 @@ portfolio.pending.step2_buyer.buyerAccount=使用されるあなたの支払い portfolio.pending.step2_buyer.paymentSent=支払いが開始されました portfolio.pending.step2_buyer.warn={0}の支払いはまだ完了していません!\nトレードは{1}までに完了しなければなりません。 portfolio.pending.step2_buyer.openForDispute=支払いを完了していません!\nトレードの最大期間が経過しました。助けを求めるには調停人に連絡してください。 -portfolio.pending.step2_buyer.paperReceipt.headline=領収書をBTCの売り手へ送付しましたか? -portfolio.pending.step2_buyer.paperReceipt.msg=覚えておいてください:\n領収書に「返金無し(NO REFUNDS)」と記載してください。\nそれからそれを2部に分け、写真を撮り、そしてBTCの売り手のEメールアドレスへそれを送ってください。 +portfolio.pending.step2_buyer.paperReceipt.headline=領収書をXMRの売り手へ送付しましたか? +portfolio.pending.step2_buyer.paperReceipt.msg=覚えておいてください:\n領収書に「返金無し(NO REFUNDS)」と記載してください。\nそれからそれを2部に分け、写真を撮り、そしてXMRの売り手のEメールアドレスへそれを送ってください。 portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=認証番号と領収書を送信 -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=認証番号と領収書の写真を電子メールでBTCの売り手へ送信する必要があります。\n領収書には、売り手の氏名、国、都道府県、および金額を明確に表示する必要があります。売却者のメールアドレス: {0}\n\n認証番号と契約書を売り手へ送付しましたか? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=認証番号と領収書の写真を電子メールでXMRの売り手へ送信する必要があります。\n領収書には、売り手の氏名、国、都道府県、および金額を明確に表示する必要があります。売却者のメールアドレス: {0}\n\n認証番号と契約書を売り手へ送付しましたか? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=MTCNと領収書を送信 -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=あなたはMTCN(追跡番号)とレシートの写真をBTCの売り手にEメールで送る必要があります。\n領収書には、売り手の氏名、市区町村、国、金額が明確に示されている必要があります。 販売者のメールアドレス: {0}\n\nMTCNと契約書を売り手へ送付しましたか? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=あなたはMTCN(追跡番号)とレシートの写真をXMRの売り手にEメールで送る必要があります。\n領収書には、売り手の氏名、市区町村、国、金額が明確に示されている必要があります。 販売者のメールアドレス: {0}\n\nMTCNと契約書を売り手へ送付しましたか? portfolio.pending.step2_buyer.halCashInfo.headline=HalCashコードを送信 -portfolio.pending.step2_buyer.halCashInfo.msg=HalCashコードと取引ID({0})を含むテキストメッセージをBTCの売り手に送信する必要があります。\n売り手の携帯電話番号は {1} です。\n\n売り手にコードを送信しましたか? +portfolio.pending.step2_buyer.halCashInfo.msg=HalCashコードと取引ID({0})を含むテキストメッセージをXMRの売り手に送信する必要があります。\n売り手の携帯電話番号は {1} です。\n\n売り手にコードを送信しましたか? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=銀行によっては、受信者の名前を検証する場合があります。 旧バージョンのHavenoクライアントで作成した「Faster Payments」アカウントでは、受信者の名前は提供されませんので、(必要ならば)トレードチャットで尋ねて下さい。 portfolio.pending.step2_buyer.confirmStart.headline=支払いが開始したことを確認 portfolio.pending.step2_buyer.confirmStart.msg=トレーディングパートナーへの{0}支払いを開始しましたか? portfolio.pending.step2_buyer.confirmStart.yes=はい、支払いを開始しました portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=支払証明を提出していません -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=トランザクションIDとトランザクション・キーを入力していません。\n\nこのデータを提供しなければ、ピアはXMRを受取る直後にBTCを解放するため自動確認機能を利用できません。\nその上、係争の場合にHavenoはXMRトランザクションの送信者がこの情報を調停者や調停人に送れることを必要とします。\n詳しくはHavenoのWikiを参照 [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] 。 +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=トランザクションIDとトランザクション・キーを入力していません。\n\nこのデータを提供しなければ、ピアはXMRを受取る直後にXMRを解放するため自動確認機能を利用できません。\nその上、係争の場合にHavenoはXMRトランザクションの送信者がこの情報を調停者や調停人に送れることを必要とします。\n詳しくはHavenoのWikiを参照 [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] 。 portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=入力が32バイトの16進値ではありません。 portfolio.pending.step2_buyer.confirmStart.warningButton=無視して続ける portfolio.pending.step2_seller.waitPayment.headline=支払いをお待ちください portfolio.pending.step2_seller.f2fInfo.headline=買い手の連絡先 -portfolio.pending.step2_seller.waitPayment.msg=デポジットトランザクションには、少なくとも1つのブロックチェーン承認があります。\nBTCの買い手が{0}の支払いを開始するまで待つ必要があります。 -portfolio.pending.step2_seller.warn=BTCの買い手はまだ{0}の支払いを行っていません。\n支払いが開始されるまで待つ必要があります。\n取引が{1}で完了していない場合は、調停人が調査します。 -portfolio.pending.step2_seller.openForDispute=BTCの買い手は支払いを開始していません!\nトレードの許可された最大期間が経過しました。\nもっと長く待ってトレードピアにもっと時間を与えるか、助けを求めるために調停者に連絡することができます。 +portfolio.pending.step2_seller.waitPayment.msg=デポジットトランザクションには、少なくとも1つのブロックチェーン承認があります。\nXMRの買い手が{0}の支払いを開始するまで待つ必要があります。 +portfolio.pending.step2_seller.warn=XMRの買い手はまだ{0}の支払いを行っていません。\n支払いが開始されるまで待つ必要があります。\n取引が{1}で完了していない場合は、調停人が調査します。 +portfolio.pending.step2_seller.openForDispute=XMRの買い手は支払いを開始していません!\nトレードの許可された最大期間が経過しました。\nもっと長く待ってトレードピアにもっと時間を与えるか、助けを求めるために調停者に連絡することができます。 tradeChat.chatWindowTitle=トレードID '{0}'' のチャットウィンドウ tradeChat.openChat=チャットウィンドウを開く tradeChat.rules=このトレードに対する潜在的な問題を解決するため、トレードピアと連絡できます。\nチャットに返事する義務はありません。\n取引者が以下のルールを破ると、係争を開始して調停者や調停人に報告して下さい。\n\nチャット・ルール:\n\t●リンクを送らないこと(マルウェアの危険性)。トランザクションIDとブロックチェーンエクスプローラの名前を送ることができます。\n\t●シードワード、プライベートキー、パスワードなどの機密な情報を送らないこと。\n\t●Haveno外のトレードを助長しないこと(セキュリティーがありません)。\n\t●ソーシャル・エンジニアリングや詐欺の行為に参加しないこと。\n\t●チャットで返事されない場合、それともチャットでの連絡が断られる場合、ピアの決断を尊重すること。\n\t●チャットの範囲をトレードに集中しておくこと。チャットはメッセンジャーの代わりや釣りをする場所ではありません。\n\t●礼儀正しく丁寧に話すこと。 @@ -666,26 +691,26 @@ message.state.ACKNOWLEDGED=相手がメッセージ受信を確認 # suppress inspection "UnusedProperty" message.state.FAILED=メッセージ送信失敗 -portfolio.pending.step3_buyer.wait.headline=BTCの売り手の支払い承認をお待ち下さい -portfolio.pending.step3_buyer.wait.info={0}の支払いを受け取るためのBTCの売り手の承認を待っています。 +portfolio.pending.step3_buyer.wait.headline=XMRの売り手の支払い承認をお待ち下さい +portfolio.pending.step3_buyer.wait.info={0}の支払いを受け取るためのXMRの売り手の承認を待っています。 portfolio.pending.step3_buyer.wait.msgStateInfo.label=支払いはメッセージステータスを開始 portfolio.pending.step3_buyer.warn.part1a={0} ブロックチェーン上で portfolio.pending.step3_buyer.warn.part1b=支払いプロバイダ(銀行など)で -portfolio.pending.step3_buyer.warn.part2=BTCの売り手はまだあなたの支払いを確認していません!支払いの送信が成功したかどうか{0}を確認してください。 -portfolio.pending.step3_buyer.openForDispute=BTCの売り手があなたの支払いを確認していません!トレードの最大期間が経過しました。もっと長く待って取引相手にもっと時間を与えるか、調停人から援助を求めることができます。 +portfolio.pending.step3_buyer.warn.part2=XMRの売り手はまだあなたの支払いを確認していません!支払いの送信が成功したかどうか{0}を確認してください。 +portfolio.pending.step3_buyer.openForDispute=XMRの売り手があなたの支払いを確認していません!トレードの最大期間が経過しました。もっと長く待って取引相手にもっと時間を与えるか、調停人から援助を求めることができます。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=あなたのトレード相手は、彼らが{0}の支払いを開始したことを確認しました。\n\n portfolio.pending.step3_seller.crypto.explorer=あなたの好きな{0}ブロックチェーンエクスプローラで portfolio.pending.step3_seller.crypto.wallet=あなたの{0}ウォレットで portfolio.pending.step3_seller.crypto={0}あなたの受け取りアドレスへのトランザクションが{1}かどうかを確認してください\n{2}\nはすでに十分なブロックチェーンの承認があります。\n支払い額は{3}です\n\nポップアップを閉じた後、メイン画面から{4}アドレスをコピーして貼り付けることができます。 -portfolio.pending.step3_seller.postal={0}\"米国の郵便為替\"でBTCの買い手から{1}を受け取ったか確認して下さい。 +portfolio.pending.step3_seller.postal={0}\"米国の郵便為替\"でXMRの買い手から{1}を受け取ったか確認して下さい。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}\"郵送で現金\"でBTCの買い手から{1}を受け取ったか確認して下さい。 +portfolio.pending.step3_seller.payByMail={0}\"郵送で現金\"でXMRの買い手から{1}を受け取ったか確認して下さい。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=トレード相手は{0}の支払いを開始した確認をしました。\n\nオンラインバンキングのWebページにアクセスして、BTCの買い手から{1}を受け取ったか確認してください。 -portfolio.pending.step3_seller.cash=支払いは現金入金で行われるので、BTCの買い手は領収書に「返金無し(NO REFUND)」と記入し、2部に分けて写真を電子メールで送ってください。\n\nチャージバックのリスクを回避するために、Eメールを受信したかどうか、および領収書が有効であることが確実であるかどうかを確認してください。\nよくわからない場合は、{0} -portfolio.pending.step3_seller.moneyGram=買い手は承認番号と領収書の写真を電子メールで送信する必要があります。\n領収書には、氏名、国、州、および金額を明確に記載する必要があります。 認証番号を受け取った場合は、メールを確認してください。\n\nそのポップアップを閉じた後、あなたはMoneyGramからお金を得るためのBTC買い手の名前と住所を見られるでしょう。\n\nあなたが正常にお金を得た後にのみ領収書を承認してください! -portfolio.pending.step3_seller.westernUnion=買い手はMTCN(追跡番号)と領収書の写真をEメールで送信する必要があります。\n領収書には、氏名、市区町村、国、金額が明確に記載されている必要があります。 MTCNを受け取った場合は、メールを確認してください。\n\nそのポップアップを閉じた後、あなたはWestern Unionからお金を得るためのBTC買い手の名前と住所を見られるでしょう。\n\nあなたが正常にお金を得た後にのみ領収書を承認してください! +portfolio.pending.step3_seller.bank=トレード相手は{0}の支払いを開始した確認をしました。\n\nオンラインバンキングのWebページにアクセスして、XMRの買い手から{1}を受け取ったか確認してください。 +portfolio.pending.step3_seller.cash=支払いは現金入金で行われるので、XMRの買い手は領収書に「返金無し(NO REFUND)」と記入し、2部に分けて写真を電子メールで送ってください。\n\nチャージバックのリスクを回避するために、Eメールを受信したかどうか、および領収書が有効であることが確実であるかどうかを確認してください。\nよくわからない場合は、{0} +portfolio.pending.step3_seller.moneyGram=買い手は承認番号と領収書の写真を電子メールで送信する必要があります。\n領収書には、氏名、国、州、および金額を明確に記載する必要があります。 認証番号を受け取った場合は、メールを確認してください。\n\nそのポップアップを閉じた後、あなたはMoneyGramからお金を得るためのXMR買い手の名前と住所を見られるでしょう。\n\nあなたが正常にお金を得た後にのみ領収書を承認してください! +portfolio.pending.step3_seller.westernUnion=買い手はMTCN(追跡番号)と領収書の写真をEメールで送信する必要があります。\n領収書には、氏名、市区町村、国、金額が明確に記載されている必要があります。 MTCNを受け取った場合は、メールを確認してください。\n\nそのポップアップを閉じた後、あなたはWestern Unionからお金を得るためのXMR買い手の名前と住所を見られるでしょう。\n\nあなたが正常にお金を得た後にのみ領収書を承認してください! portfolio.pending.step3_seller.halCash=買い手はHalCashコードをテキストメッセージとして送信する必要があります。それに加えて、HalCash対応ATMからEURを出金するために必要な情報を含むメッセージがHalCashから届きます。\n\nあなたはATMからお金を得た後、ここで支払いの領収書を承認して下さい! portfolio.pending.step3_seller.amazonGiftCard=買い手はEメールアドレス、それともSMSで携帯電話番号までアマゾンeGiftカードを送りました。アマゾンアカウントにeGiftカードを受け取って、済ましたら支払いの受領を確認して下さい。 @@ -701,7 +726,7 @@ portfolio.pending.step3_seller.xmrTxHash=トランザクションID portfolio.pending.step3_seller.xmrTxKey=トランザクション・キー portfolio.pending.step3_seller.buyersAccount=買い手のアカウント・データ portfolio.pending.step3_seller.confirmReceipt=支払い受領を確認 -portfolio.pending.step3_seller.buyerStartedPayment=BTCの買い手が{0}の支払いを開始しました。\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=XMRの買い手が{0}の支払いを開始しました。\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=あなたのアルトコインウォレットやブロックエクスプローラーでブロックチェーンの確認を確認し、十分なブロックチェーンの承認があるときに支払いを確認してください。 portfolio.pending.step3_seller.buyerStartedPayment.traditional=あなたのトレードアカウント(例えば銀行口座)をチェックして、あなたが支払いを受領した時に承認して下さい。 portfolio.pending.step3_seller.warn.part1a={0} blockchain上で @@ -713,7 +738,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=あなたの取引相手 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=また、銀行取引明細書に記載されている送付者の名前が、トレード契約書のものと一致していることも確認してください:\nトレード契約書とおり、送信者の名前: {0}\n\n送付者の名前がここに表示されているものと異なる場合は、支払いの受領を承認しないで下さい。「alt + o」または「option + o」を入力して係争を開始して下さい。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=領収書の確認が済むとすぐに、ロックされたトレード金額がBTCの買い手に解放され、保証金が返金されます。\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=領収書の確認が済むとすぐに、ロックされたトレード金額がXMRの買い手に解放され、保証金が返金されます。\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=支払いを受け取ったことを確認 portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=はい、支払いを受け取りました portfolio.pending.step3_seller.onPaymentReceived.signer=重要:支払いの受け取りを承認すると、相手方のアカウントを検証して署名することになります。相手方のアカウントはまだ署名されていないので、支払取り消しリスクを減らすために支払いの承認をできる限り延期して下さい。 @@ -723,7 +748,7 @@ portfolio.pending.step5_buyer.tradeFee=取引手数料 portfolio.pending.step5_buyer.makersMiningFee=マイニング手数料 portfolio.pending.step5_buyer.takersMiningFee=合計マイニング手数料 portfolio.pending.step5_buyer.refunded=返金されたセキュリティデポジット -portfolio.pending.step5_buyer.withdrawBTC=ビットコインを出金する +portfolio.pending.step5_buyer.withdrawXMR=ビットコインを出金する portfolio.pending.step5_buyer.amount=出金額 portfolio.pending.step5_buyer.withdrawToAddress=出金先アドレス portfolio.pending.step5_buyer.moveToHavenoWallet=資金をHavenoウォレットに保管する @@ -794,7 +819,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=すでに受け入れて portfolio.pending.failedTrade.taker.missingTakerFeeTx=欠測テイカー手数料のトランザクション。\n\nこのtxがなければ、トレードを完了できません。資金はロックされず、トレード手数料は支払いませんでした。「失敗トレード」へ送ることができます。 portfolio.pending.failedTrade.maker.missingTakerFeeTx=ピアのテイカー手数料のトランザクションは欠測します。\n\nこのtxがなければ、トレードを完了できません。資金はロックされませんでした。あなたのオファーがまだ他の取引者には有効ですので、メイカー手数料は失っていません。このトレードを「失敗トレード」へ送ることができます。 portfolio.pending.failedTrade.missingDepositTx=入金トランザクション(2-of-2マルチシグトランザクション)は欠測します。\n\nこのtxがなければ、トレードを完了できません。資金はロックされませんでしたが、トレード手数料は支払いました。トレード手数料の返済要求はここから提出できます: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nこのトレードを「失敗トレード」へ送れます。 -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=遅延支払いトランザクションは欠測しますが、資金は入金トランザクションにロックされました。\n\nこの法定通貨・アルトコイン支払いをBTC売り手に送信しないで下さい。遅延支払いtxがなければ、係争仲裁は開始されることができません。代りに、「Cmd/Ctrl+o」で調停チケットをオープンして下さい。調停者はおそらく両方のピアへセキュリティデポジットの全額を払い戻しを提案します(売り手はトレード金額も払い戻しを受ける)。このような方法でセキュリティーのリスクがなし、トレード手数料のみが失われます。\n\n失われたトレード手数料の払い戻し要求はここから提出できます: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=遅延支払いトランザクションは欠測しますが、資金は入金トランザクションにロックされました。\n\nこの法定通貨・アルトコイン支払いをXMR売り手に送信しないで下さい。遅延支払いtxがなければ、係争仲裁は開始されることができません。代りに、「Cmd/Ctrl+o」で調停チケットをオープンして下さい。調停者はおそらく両方のピアへセキュリティデポジットの全額を払い戻しを提案します(売り手はトレード金額も払い戻しを受ける)。このような方法でセキュリティーのリスクがなし、トレード手数料のみが失われます。\n\n失われたトレード手数料の払い戻し要求はここから提出できます: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=遅延支払いトランザクションは欠測しますが、資金は入金トランザクションにロックされました。\n\n買い手の遅延支払いトランザクションが同じく欠測される場合、相手は支払いを送信せず調停チケットをオープンするように指示されます。同様に「Cmd/Ctrl+o」で調停チケットをオープンするのは賢明でしょう。\n\n買い手はまだ支払いを送信しなかった場合、調停者はおそらく両方のピアへセキュリティデポジットの全額を払い戻しを提案します(売り手はトレード金額も払い戻しを受ける)。さもなければ、トレード金額は買い手に支払われるでしょう。\n\n失われたトレード手数料の払い戻し要求はここから提出できます: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=トレードプロトコルの実行にはエラーが生じました。\n\nエラー: {0}\n\nクリティカル・エラーではない可能性はあり、トレードは普通に完了できるかもしれない。迷う場合は調停チケットをオープンして、Haveno調停者からアドバイスを受けることができます。\n\nクリティカル・エラーでトレードが完了できなかった場合はトレード手数料は失われた可能性があります。失われたトレード手数料の払い戻し要求はここから提出できます: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=トレード契約書は設定されません。\n\nトレードは完了できません。トレード手数料は失われた可能性もあります。その場合は失われたトレード手数料の払い戻し要求はここから提出できます: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +858,7 @@ funds.deposit.fundHavenoWallet=Havenoウォレットに入金 funds.deposit.noAddresses=デポジットアドレスはまだ生成されていません funds.deposit.fundWallet=あなたのウォレットに入金 funds.deposit.withdrawFromWallet=ウォレットから資金を送金 -funds.deposit.amount=BTCの金額(オプション) +funds.deposit.amount=XMRの金額(オプション) funds.deposit.generateAddress=新しいアドレスの生成 funds.deposit.generateAddressSegwit=ネイティブセグウィットのフォーマット(Bech32) funds.deposit.selectUnused=新しいアドレスを生成するのではなく、上の表から未使用のアドレスを選択してください。 @@ -890,7 +915,7 @@ funds.tx.revert=元に戻す funds.tx.txSent=トランザクションはローカルHavenoウォレットの新しいアドレスに正常に送信されました。 funds.tx.direction.self=自分自身に送信済み funds.tx.dustAttackTx=ダストを受取りました -funds.tx.dustAttackTx.popup=このトランザクションはごくわずかなBTC金額をあなたのウォレットに送っているので、あなたのウォレットを盗もうとするチェーン解析会社による試みかもしれません。\n\nあなたが支払い取引でそのトランザクションアウトプットを使うならば、彼らはあなたが他のアドレスの所有者である可能性が高いことを学びます(コインマージ)。\n\nあなたのプライバシーを保護するために、Havenoウォレットは、支払い目的および残高表示において、そのようなダストアウトプットを無視します。 設定でアウトプットがダストと見なされるときのしきい値を設定できます。 +funds.tx.dustAttackTx.popup=このトランザクションはごくわずかなXMR金額をあなたのウォレットに送っているので、あなたのウォレットを盗もうとするチェーン解析会社による試みかもしれません。\n\nあなたが支払い取引でそのトランザクションアウトプットを使うならば、彼らはあなたが他のアドレスの所有者である可能性が高いことを学びます(コインマージ)。\n\nあなたのプライバシーを保護するために、Havenoウォレットは、支払い目的および残高表示において、そのようなダストアウトプットを無視します。 設定でアウトプットがダストと見なされるときのしきい値を設定できます。 #################################################################### # Support @@ -904,7 +929,7 @@ support.filter=係争を検索 support.filter.prompt=トレードID、日付、onionアドレスまたはアカウントデータを入力してください support.sigCheck.button=Check signature -support.sigCheck.popup.info=DAOに払い戻しリクエストを提出する場合、調停・仲裁プロセスの概要メッセージをGithubで提出された払い戻しリクエストに張り付ける必要があります。検証を可能にするため、ユーザがこのツールで概要メッセージと調停者や調停人の署名が照合するかどうか確かめることができます。 +support.sigCheck.popup.info=仲裁プロセスの要約メッセージを貼り付けてください。このツールを使用すると、どんなユーザーでも仲裁者の署名が要約メッセージと一致するかどうかを確認できます。 support.sigCheck.popup.header=係争結果の署名を検証する support.sigCheck.popup.msg.label=概要メッセージ support.sigCheck.popup.msg.prompt=係争からの概要メッセージをコピーして貼り付ける @@ -940,8 +965,8 @@ support.savedInMailbox=メッセージ受信箱に保存されました support.arrived=メッセージが受信者へ届きました support.acknowledged=受信者からメッセージ到着が確認されました support.error=受信者がメッセージを処理できませんでした。エラー: {0} -support.buyerAddress=BTC買い手のアドレス -support.sellerAddress=BTC売り手のアドレス +support.buyerAddress=XMR買い手のアドレス +support.sellerAddress=XMR売り手のアドレス support.role=役割 support.agent=サポート代理人 support.state=状態 @@ -949,13 +974,13 @@ support.chat=Chat support.closed=クローズ support.open=オープン support.process=Process -support.buyerMaker=BTC 買い手/メイカー -support.sellerMaker=BTC 売り手/メイカー -support.buyerTaker=BTC 買い手/テイカー -support.sellerTaker=BTC 売り手/テイカー +support.buyerMaker=XMR 買い手/メイカー +support.sellerMaker=XMR 売り手/メイカー +support.buyerTaker=XMR 買い手/テイカー +support.sellerTaker=XMR 売り手/テイカー -support.backgroundInfo=Havenoは会社ではないので、係争の扱いが異なります。\n\n取引者はアプリ内の「オープントレード」画面からセキュアチャットでお互いに紛争を解決しようと努めれる。その方法は十分でない場合、調停者は間に入って助けることもできます。調停者は状況を判断して、トレード資金の支払い配分を提案します。両当事者は提案に同意する場合、支払いトランザクションは完了され、トレードは閉じられます。片当事者もしくは両当事者は調停者の支払い提案に同意しない場合、仲裁を求めることができます。調停人は再びに問題を検討し、正当な場合は個人的に取引者に払い戻す、そしてHavenoのDAOからその分の払い戻し要求を提出します。 -support.initialInfo=下のテキストフィールドに問題の説明を入力してください。係争解決の時間を短縮するために、可能な限り多くの情報を追加してください。\n\n提供する必要がある情報のチェックリストを次に示します:\n\t●BTC買い手の場合:法定通貨またはアルトコインの送金を行いましたか?その場合、アプリケーションの「支払い開始」ボタンをクリックしましたか?\n\t●BTC売り手の場合:法定通貨またはアルトコインの支払いを受け取りましたか?その場合、アプリケーションの「支払いを受け取った」ボタンをクリックしましたか?\n\t●どのバージョンのHavenoを使用していますか?\n\t●どのオペレーティングシステムを使用していますか?\n\t●失敗したトランザクションで問題が発生した場合は、新しいデータディレクトリへの切り替えを検討してください。\n\t データディレクトリが破損し、不可解なバグが発生している場合があります。\n\t 参照:https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n係争プロセスの基本的なルールをよく理解してください:\n\t●2日以内に{0}の要求に応答する必要があります。\n\t●調停者は2日以内に返事をするでしょう。調停人は5営業日以内に返事をするでしょう。\n\t●係争の最大期間は14日間です。\n\t●{1}と協力し、彼らがあなたの主張をするために、要求された情報を提供する必要があります\n\t●あなたは申請を最初に開始したときに、ユーザー契約の係争文書に記載されている規則を受け入れています。\n\n係争プロセスの詳細については、{2} をご覧ください。 +support.backgroundInfo=Havenoは企業ではないため、紛争の処理が異なります。\n\n取引者は、アプリケーション内でセキュアなチャットを使用してオープンな取引画面でコミュニケーションを取り、自分自身で紛争を解決しようとすることができます。それが十分でない場合、仲裁者が状況を評価し、取引資金の支払いを決定します。 +support.initialInfo=下のテキストフィールドに問題の説明を入力してください。係争解決の時間を短縮するために、可能な限り多くの情報を追加してください。\n\n提供する必要がある情報のチェックリストを次に示します:\n\t●XMR買い手の場合:法定通貨またはアルトコインの送金を行いましたか?その場合、アプリケーションの「支払い開始」ボタンをクリックしましたか?\n\t●XMR売り手の場合:法定通貨またはアルトコインの支払いを受け取りましたか?その場合、アプリケーションの「支払いを受け取った」ボタンをクリックしましたか?\n\t●どのバージョンのHavenoを使用していますか?\n\t●どのオペレーティングシステムを使用していますか?\n\t●失敗したトランザクションで問題が発生した場合は、新しいデータディレクトリへの切り替えを検討してください。\n\t データディレクトリが破損し、不可解なバグが発生している場合があります。\n\t 参照:https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n係争プロセスの基本的なルールをよく理解してください:\n\t●2日以内に{0}の要求に応答する必要があります。\n\t●調停者は2日以内に返事をするでしょう。調停人は5営業日以内に返事をするでしょう。\n\t●係争の最大期間は14日間です。\n\t●{1}と協力し、彼らがあなたの主張をするために、要求された情報を提供する必要があります\n\t●あなたは申請を最初に開始したときに、ユーザー契約の係争文書に記載されている規則を受け入れています。\n\n係争プロセスの詳細については、{2} をご覧ください。 support.systemMsg=システムメッセージ: {0} support.youOpenedTicket=サポートのリクエスト開始しました。\n\n{0}\n\nHavenoバージョン: {1} support.youOpenedDispute=係争のリクエスト開始しました。\n\n{0}\n\nHavenoバージョン: {1} @@ -982,10 +1007,11 @@ setting.preferences.general=一般設定 setting.preferences.explorer=ビットコインのエクスプローラ setting.preferences.deviation=市場価格からの最大偏差 setting.preferences.avoidStandbyMode=スタンバイモードを避ける +setting.preferences.useSoundForNotifications=通知音の再生 setting.preferences.autoConfirmXMR=XMR自動確認 setting.preferences.autoConfirmEnabled=有効されました setting.preferences.autoConfirmRequiredConfirmations=必要承認 -setting.preferences.autoConfirmMaxTradeSize=最大トレード金額(BTC) +setting.preferences.autoConfirmMaxTradeSize=最大トレード金額(XMR) setting.preferences.autoConfirmServiceAddresses=モネロエクスプローラURL(localhost、LANのIPアドレス、または*.localのホストネーム以外はTorを利用します) setting.preferences.deviationToLarge={0}%以上の値は許可されていません。 setting.preferences.txFee=出金トランザクション手数料 (satoshis/vbyte) @@ -1022,21 +1048,23 @@ settings.preferences.editCustomExplorer.name=名義 settings.preferences.editCustomExplorer.txUrl=トランザクションURL settings.preferences.editCustomExplorer.addressUrl=アドレスURL -settings.net.btcHeader=ビットコインのネットワーク +settings.net.xmrHeader=ビットコインのネットワーク settings.net.p2pHeader=Havenoネットワーク settings.net.onionAddressLabel=私のonionアドレス settings.net.xmrNodesLabel=任意のモネロノードを使う settings.net.moneroPeersLabel=接続されたピア +settings.net.connection=接続 +settings.net.connected=接続されました settings.net.useTorForXmrJLabel=MoneroネットワークにTorを使用 settings.net.moneroNodesLabel=接続するMoneroノード: -settings.net.useProvidedNodesRadio=提供されたBitcoin Core ノードを使う +settings.net.useProvidedNodesRadio=提供されたMonero Core ノードを使う settings.net.usePublicNodesRadio=ビットコインの公共ネットワークを使用 settings.net.useCustomNodesRadio=任意のビットコインノードを使う settings.net.warn.usePublicNodes=パブリックなMoneroノードを使用する場合、信頼できないリモートノードを使用するリスクにさらされる可能性があります。\n\n詳細については、[HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html] をご覧ください。\n\nパブリックノードを使用することを確認してもよろしいですか? settings.net.warn.usePublicNodes.useProvided=いいえ、提供されたノードを使用します settings.net.warn.usePublicNodes.usePublic=はい、公共ネットワークを使います -settings.net.warn.useCustomNodes.B2XWarning=あなたのBitcoinノードが信頼できるBitcoin Coreノードであることを確認してください!\n\nBitcoin Coreのコンセンサスルールに従わないノードに接続すると、ウォレットが破損し、トレードプロセスに問題が生じる可能性があります。\n\nコンセンサスルールに違反するノードへ接続したユーザーは、引き起こされるいかなる損害に対しても責任を負います。 結果として生じる係争は、他のピアによって決定されます。この警告と保護のメカニズムを無視しているユーザーには、テクニカルサポートは提供されません! -settings.net.warn.invalidBtcConfig=無効な設定によりビットコインネットワークとの接続は失敗しました。\n\n代りに提供されたビットコインノードを利用するのに設定はリセットされました。アプリを再起動する必要があります。 +settings.net.warn.useCustomNodes.B2XWarning=あなたのMoneroノードが信頼できるMonero Coreノードであることを確認してください!\n\nMonero Coreのコンセンサスルールに従わないノードに接続すると、ウォレットが破損し、トレードプロセスに問題が生じる可能性があります。\n\nコンセンサスルールに違反するノードへ接続したユーザーは、引き起こされるいかなる損害に対しても責任を負います。 結果として生じる係争は、他のピアによって決定されます。この警告と保護のメカニズムを無視しているユーザーには、テクニカルサポートは提供されません! +settings.net.warn.invalidXmrConfig=無効な設定によりビットコインネットワークとの接続は失敗しました。\n\n代りに提供されたビットコインノードを利用するのに設定はリセットされました。アプリを再起動する必要があります。 settings.net.localhostXmrNodeInfo=バックグラウンド情報:Havenoが起動時に、ローカルビットコインノードを探します。見つかれば、Havenoはそのノードを排他的に介してビットコインネットワークと接続します。 settings.net.p2PPeersLabel=接続されたピア settings.net.onionAddressColumn=Onionアドレス @@ -1044,7 +1072,7 @@ settings.net.creationDateColumn=既定 settings.net.connectionTypeColumn=イン/アウト settings.net.sentDataLabel=通信されたデータ統計 settings.net.receivedDataLabel=受信されたデータ統計 -settings.net.chainHeightLabel=BTCの最新ブロック高さ +settings.net.chainHeightLabel=XMRの最新ブロック高さ settings.net.roundTripTimeColumn=往復 settings.net.sentBytesColumn=送信済 settings.net.receivedBytesColumn=受信済 @@ -1059,7 +1087,7 @@ settings.net.needRestart=その変更を適用するには、アプリケーシ settings.net.notKnownYet=まだわかりません... settings.net.sentData=通信されたデータ: {0}, {1} メッセージ、 {2} メッセージ/秒 settings.net.receivedData=受信されたデータ: {0}, {1} メッセージ、 {2} メッセージ/秒 -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[IPアドレス:ポート | ホスト名:ポート | onionアドレス:ポート](コンマ区切り)。デフォルト(8333)が使用される場合、ポートは省略できます。 settings.net.seedNode=シードノード settings.net.directPeer=ピア (ダイレクト) @@ -1105,7 +1133,7 @@ setting.about.shortcuts.openDispute.value=未決トレードを選択してク setting.about.shortcuts.walletDetails=ウォレット詳細ウィンドウを開く -setting.about.shortcuts.openEmergencyBtcWalletTool=BTCウォレットに対する緊急ウォレットツールを開く +setting.about.shortcuts.openEmergencyXmrWalletTool=XMRウォレットに対する緊急ウォレットツールを開く setting.about.shortcuts.showTorLogs=TorメッセージのログレベルをDEBUGとWARNを切り替える @@ -1131,7 +1159,7 @@ setting.about.shortcuts.sendPrivateNotification=ピアにプライベート通 setting.about.shortcuts.sendPrivateNotification.value=アバターからピア情報を開いて押す:{0} setting.info.headline=新しいXMR自動確認の機能 -setting.info.msg=BTC売ってXMR買う場合、Havenoが自動的にトレードを完了としてマークできるように自動確認機能で適正量のXMRはウォレットに送られたかを検証できます。その際、皆にトレードをより早く完了できるようにします。\n\n自動確認はXMR送信者が提供するプライベート・トランザクション・キーを利用して少なくとも2つのXMRエクスプローラノードでXMRトランザクションを確認します。デフォルト設定でHavenoは貢献者に管理されるエクスプローラノードを利用しますが、最大のプライバシーやセキュリティーのため自分のXMRエクスプローラノードを管理するのをおすすめします。\n\n1つのトレードにつき自動確認する最大額のBTC、そして必要承認の数をこの画面で設定できます。\n\nHavenoのWikiから詳細(自分のエクスプローラノードを管理する方法も含めて)を参照できます: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=XMR売ってXMR買う場合、Havenoが自動的にトレードを完了としてマークできるように自動確認機能で適正量のXMRはウォレットに送られたかを検証できます。その際、皆にトレードをより早く完了できるようにします。\n\n自動確認はXMR送信者が提供するプライベート・トランザクション・キーを利用して少なくとも2つのXMRエクスプローラノードでXMRトランザクションを確認します。デフォルト設定でHavenoは貢献者に管理されるエクスプローラノードを利用しますが、最大のプライバシーやセキュリティーのため自分のXMRエクスプローラノードを管理するのをおすすめします。\n\n1つのトレードにつき自動確認する最大額のXMR、そして必要承認の数をこの画面で設定できます。\n\nHavenoのWikiから詳細(自分のエクスプローラノードを管理する方法も含めて)を参照できます: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1151,7 +1179,7 @@ account.menu.backup=バックアップ account.menu.notifications=通知 account.menu.walletInfo.balance.headLine=ウォレット残高 -account.menu.walletInfo.balance.info=非確認されたトランザクションも含めて、内部ウォレット残高を表示します。\nBTCの場合、下に表示される「内部ウォレット残高」はこのウィンドウの右上に表示される「利用可能」と「予約済」の和に等しいはずです。 +account.menu.walletInfo.balance.info=非確認されたトランザクションも含めて、内部ウォレット残高を表示します。\nXMRの場合、下に表示される「内部ウォレット残高」はこのウィンドウの右上に表示される「利用可能」と「予約済」の和に等しいはずです。 account.menu.walletInfo.xpub.headLine=ウォッチキー(xpubキー) account.menu.walletInfo.walletSelector={0} {1} ウォレット account.menu.walletInfo.path.headLine=HDキーチェーンのパス @@ -1180,7 +1208,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=HavenoでARQをトレードするには、次の要件を理解し、満たす必要があります。\n\nARQを送信するには、store-tx-infoフラグを有効(新しいバージョンではデフォルト)にした公式のArQmA GUIウォレットまたはArQmA CLIウォレットのいずれかを使用する必要があります。係争が発生した場合に必要になるため、txキーにアクセスできることを確認してください。\narqma-wallet-cli(コマンドget_tx_keyを使用)\narqma-wallet-gui(履歴タブに移動し、支払い証明のために(P)ボタンをクリックします)\n\n通常のブロックエクスプローラーでは、転送は検証できません。\n\n係争の場合、調停人に次のデータを提供する必要があります。\n-txプライベートキー\n-トランザクションハッシュ\n-受信者のパブリックアドレス\n\n上記のデータを提供しない場合、または互換性のないウォレットを使用した場合は、係争のケースが失われます。 ARQ送信者は、係争の場合にARQ転送の検証を調停人に提供する責任があります。\n\n支払いIDは不要で、通常のパブリックアドレスのみです。\nこのプロセスがわからない場合は、ArQmA Discordチャンネル( https://discord.gg/s9BQpJT )またはArQmAフォーラム( https://labs.arqma.com )にアクセスして、詳細を確認してください。 # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=HavenoでXMRをトレードするには、以下の要件を理解し、満たす必要があります。\n\nXMRを売る場合、係争を解決するため調停者や調停人に以下の情報を提供できる必要があります:\n- トランザクションキー(Txキー、Tx秘密キー、Txプライベートキー)\n- トランザクションID(TxID、Txハッシュ)\n- 宛先アドレス(受領者のアドレス)\n\n人気のモネロウォレットからこういう情報を見つける方法について、HavenoのWikiを参照して下さい [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments]\n必要のトランザクションデータを提供しなければ、係争で不利な裁定を下されます。\n\nHavenoではXMRトランザクションに自動確認機能を提供しますが、設で有効にする必要があります。\n\n自動確認機能について詳しくはWikiで参照して下さい:\n[HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +account.crypto.popup.xmr.msg=HavenoでXMRをトレードするには、以下の要件を理解し、満たす必要があります。\n\nXMRを売る場合、係争を解決するため調停者や調停人に以下の情報を提供できる必要があります:\n- トランザクションキー(Txキー、Tx秘密キー、Txプライベートキー)\n- トランザクションID(TxID、Txハッシュ)\n- 宛先アドレス(受領者のアドレス)\n\n人気のモネロウォレットからこういう情報を見つける方法について、HavenoのWikiを参照して下さい [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments]\n必要のトランザクションデータを提供しなければ、係争で不利な裁定を下されます。\n\nHavenoではXMRトランザクションに自動確認機能を提供しますが、設で有効にする必要があります。\n\n自動確認機能について詳しくはWikiで参照して下さい:\n[HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1236,7 @@ account.crypto.popup.pars.msg=ParsiCoinをHavenoでトレードするには、 account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=HavenoでL-BTCをトレードするには、以下を理解する必要があります:\n\nHavenoでのトレードにL-BTCを受け取る場合、モバイル用「Blockstream Green」ウォレットアプリそれとも取引場などの第三者によって保管されるウォレットの利用は不可能です。「Liquid Elements Core」ウォレット、あるいは機密L-BTCアドレスの「blindingキー」が入手可能のウォレットのみにL-BTCを受け取って下さい。\n\n調停が必要になる場合、あるいはトレード係争が開始される場合、調停者や調停人が「Elements Core」フルノードで機密トランザクションを検証できるように、受取アドレスのblindingキーを明かす必要があります。\n\n調停者や調停人に必要な情報を提供しなければ、係争で不利な裁定を下されます。全ての係争には、調停者や調停人に暗号証明を提供するのは100%受信者の責任です。\n\n以上の条件を理解しない場合、HavenoでL-BTCのトレードをしないで下さい。 +account.crypto.popup.liquidmonero.msg=HavenoでL-XMRをトレードするには、以下を理解する必要があります:\n\nHavenoでのトレードにL-XMRを受け取る場合、モバイル用「Blockstream Green」ウォレットアプリそれとも取引場などの第三者によって保管されるウォレットの利用は不可能です。「Liquid Elements Core」ウォレット、あるいは機密L-XMRアドレスの「blindingキー」が入手可能のウォレットのみにL-XMRを受け取って下さい。\n\n調停が必要になる場合、あるいはトレード係争が開始される場合、調停者や調停人が「Elements Core」フルノードで機密トランザクションを検証できるように、受取アドレスのblindingキーを明かす必要があります。\n\n調停者や調停人に必要な情報を提供しなければ、係争で不利な裁定を下されます。全ての係争には、調停者や調停人に暗号証明を提供するのは100%受信者の責任です。\n\n以上の条件を理解しない場合、HavenoでL-XMRのトレードをしないで下さい。 account.traditional.yourTraditionalAccounts=あなたの各国通貨口座 @@ -1228,9 +1256,9 @@ account.password.setPw.button=パスワードをセット account.password.setPw.headline=ウォレットのパスワード保護をセット account.password.info=パスワード保護が有効な場合、アプリケーションを起動する際、ウォレットからモネロを引き出す際、およびシードワードを表示する際にパスワードを入力する必要があります。 -account.seed.backup.title=あなたのウォレットのシードワードをバックアップ -account.seed.info=ウォレットのシードワードと日付の両方を書き留めてください!あなたはシードワードと日付でいつでもウォレットを復元することができます。\nBTCおよびBSQウォレットには同じシードワードが使用されています。\n\nあなたは一枚の紙にシードワードを書き留めるべきです。コンピュータに保存しないでください。\n\nシードワードはバックアップの代わりにはならないことに気をつけて下さい。\nアプリケーションの状態とデータを復元するには「アカウント/バックアップ」画面からアプリケーションディレクトリ全体のバックアップを作成する必要があります。\nシードワードのインポートは緊急の場合にのみ推奨されます。データベースファイルとキーの適切なバックアップがなければ、アプリケーションは機能しません! -account.seed.backup.warning=ここで留意すべきはシードワードがバックアップの代りとして機能を果たさないことです。\nアプリケーションステートとデータを復元するのに、「アカウント/バックアップ」画面からアプリケーションディレクトリの完全バックアップを作成する必要があります。\nシードワードのインポートは緊急の場合のみにおすすめします。データベースファイルとキーの正当なバックアップがなければ、アプリケーションは機能するようになれません!\n\n詳しくはWikiのページから: [HYPERLINK:https://bisq.wiki/Backing_up_application_data] +account.seed.backup.title=ウォレットのシードワードをバックアップしてください。 +account.seed.info=ウォレットのシードワードと日付を両方記録してください。シードワードと日付があれば、いつでもウォレットを回復できます。\n\nシードワードは紙に記録してください。コンピュータに保存しないでください。\n\nシードワードはバックアップの代替ではないことに注意してください。\nアプリケーションの状態とデータを回復するには、\"アカウント/バックアップ\"画面からアプリケーションディレクトリ全体のバックアップを作成する必要があります。 +account.seed.backup.warning=シードワードはバックアップの代替ではありません。\nアプリケーションの状態とデータを回復するには、\"アカウント/バックアップ\"画面からアプリケーションディレクトリ全体のバックアップを作成する必要があります。 account.seed.warn.noPw.msg=シードワードの表示を保護するためのウォレットパスワードを設定していません。 \n\nシードワードを表示しますか? account.seed.warn.noPw.yes=はい、そして次回から確認しないで下さい account.seed.enterPw=シードワードを見るためにパスワードを入力 @@ -1259,13 +1287,13 @@ account.notifications.trade.label=トレードメッセージを受信 account.notifications.market.label=オファーアラートを受信 account.notifications.price.label=価格アラートを受信 account.notifications.priceAlert.title=価格アラート -account.notifications.priceAlert.high.label=BTC価格が次を上回ったら通知 -account.notifications.priceAlert.low.label=BTC価格が次を下回ったら通知 +account.notifications.priceAlert.high.label=XMR価格が次を上回ったら通知 +account.notifications.priceAlert.low.label=XMR価格が次を下回ったら通知 account.notifications.priceAlert.setButton=価格アラートをセット account.notifications.priceAlert.removeButton=価格アラートを削除 account.notifications.trade.message.title=トレード状態が変わった account.notifications.trade.message.msg.conf=ID {0}とのトレードのデポジットトランザクションが承認されました。 Havenoアプリケーションを開いて支払いを開始してください。 -account.notifications.trade.message.msg.started=BTCの買い手がID {0}とのトレードの支払いを開始しました。 +account.notifications.trade.message.msg.started=XMRの買い手がID {0}とのトレードの支払いを開始しました。 account.notifications.trade.message.msg.completed=ID {0}とのトレードが完了しました。 account.notifications.offer.message.title=オファーが受け入れられました account.notifications.offer.message.msg=ID {0}とのオファーが受け入れられました @@ -1275,10 +1303,10 @@ account.notifications.dispute.message.msg=ID {0}とのトレードに関する account.notifications.marketAlert.title=オファーのアラート account.notifications.marketAlert.selectPaymentAccount=支払いアカウントと一致するオファー account.notifications.marketAlert.offerType.label=興味のあるオファータイプ -account.notifications.marketAlert.offerType.buy=購入のオファー(BTCを売りたい) -account.notifications.marketAlert.offerType.sell=売却のオファー(BTCを買いたい) +account.notifications.marketAlert.offerType.buy=購入のオファー(XMRを売りたい) +account.notifications.marketAlert.offerType.sell=売却のオファー(XMRを買いたい) account.notifications.marketAlert.trigger=オファー価格の乖離 (%) -account.notifications.marketAlert.trigger.info=価格乖離を設定すると、要件を満たす(または超える)オファーが公開されたときにのみアラートを受信します。例:BTCを売りたい時、現在の市場価格に対して2%のプレミアムでのみ販売。このフィールドを2%に設定すると、現在の市場価格よりも2%(またはそれ以上)高い価格のオファーのアラートのみを受け取るようになります。 +account.notifications.marketAlert.trigger.info=価格乖離を設定すると、要件を満たす(または超える)オファーが公開されたときにのみアラートを受信します。例:XMRを売りたい時、現在の市場価格に対して2%のプレミアムでのみ販売。このフィールドを2%に設定すると、現在の市場価格よりも2%(またはそれ以上)高い価格のオファーのアラートのみを受け取るようになります。 account.notifications.marketAlert.trigger.prompt=市場価格からの乖離の割合(例:2.50%、-0.50%など) account.notifications.marketAlert.addButton=オファーアラートを追加 account.notifications.marketAlert.manageAlertsButton=オファーアラートを管理 @@ -1305,10 +1333,10 @@ inputControlWindow.balanceLabel=利用可能残高 contractWindow.title=係争の詳細 contractWindow.dates=オファーの日付 / トレードの日付 -contractWindow.btcAddresses=ビットコインアドレス BTC買い手 / BTC売り手 -contractWindow.onions=ネットワークアドレス BTC買い手 / BTC売り手 -contractWindow.accountAge=アカウント年齢 BTC買い手 / BTC売り手 -contractWindow.numDisputes=調停人の数 BTCの買い手 / BTCの売り手 +contractWindow.xmrAddresses=ビットコインアドレス XMR買い手 / XMR売り手 +contractWindow.onions=ネットワークアドレス XMR買い手 / XMR売り手 +contractWindow.accountAge=アカウント年齢 XMR買い手 / XMR売り手 +contractWindow.numDisputes=調停人の数 XMRの買い手 / XMRの売り手 contractWindow.contractHash=契約ハッシュ displayAlertMessageWindow.headline=重要な情報! @@ -1334,8 +1362,8 @@ disputeSummaryWindow.title=概要 disputeSummaryWindow.openDate=チケットオープン日 disputeSummaryWindow.role=取引者の役割 disputeSummaryWindow.payout=トレード金額の支払い -disputeSummaryWindow.payout.getsTradeAmount=BTC {0}はトレード金額の支払いを受け取ります -disputeSummaryWindow.payout.getsAll=BTCへの最高額支払い {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0}はトレード金額の支払いを受け取ります +disputeSummaryWindow.payout.getsAll=XMRへの最高額支払い {0} disputeSummaryWindow.payout.custom=任意の支払い disputeSummaryWindow.payoutAmount.buyer=買い手の支払額 disputeSummaryWindow.payoutAmount.seller=売り手の支払額 @@ -1377,7 +1405,7 @@ disputeSummaryWindow.close.button=チケットを閉じる # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=チケットは {0} に閉じられました\n{1} ノードアドレス: {2}\n\nまとめ\nトレードID: {3}\n通貨: {4}\nトレード金額: {5}\n買い手のBTC支払額: {6}\n売り手のBTC支払額 {7}\n\n係争の理由: {8}\n\n概要ノート:\n{9}\n +disputeSummaryWindow.close.msg=チケットは {0} に閉じられました\n{1} ノードアドレス: {2}\n\nまとめ\nトレードID: {3}\n通貨: {4}\nトレード金額: {5}\n買い手のXMR支払額: {6}\n売り手のXMR支払額 {7}\n\n係争の理由: {8}\n\n概要ノート:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1427,11 +1455,11 @@ filterWindow.autoConfExplorers=フィルター済自動確認エクスプロー filterWindow.disableTradeBelowVersion=トレードに必要な最低バージョン filterWindow.add=フィルターを追加 filterWindow.remove=フィルターを削除 -filterWindow.xmrFeeReceiverAddresses=BTC手数料受信アドレス +filterWindow.xmrFeeReceiverAddresses=XMR手数料受信アドレス filterWindow.disableApi=APIを無効化 filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=最小のBTC金額 +offerDetailsWindow.minXmrAmount=最小のXMR金額 offerDetailsWindow.min=(最小 {0}) offerDetailsWindow.distance=(市場価格からの乖離: {0}) offerDetailsWindow.myTradingAccount=私のトレードアカウント @@ -1446,6 +1474,7 @@ offerDetailsWindow.confirm.maker=承認: ビットコインを{0}オファーを offerDetailsWindow.confirm.taker=承認: ビットコインを{0}オファーを受ける offerDetailsWindow.creationDate=作成日 offerDetailsWindow.makersOnion=メイカーのonionアドレス +offerDetailsWindow.challenge=オファーパスフレーズ qRCodeWindow.headline=QRコード qRCodeWindow.msg=外部ウォレットからHavenoウォレットへ送金するのに、このQRコードを利用して下さい。 @@ -1474,7 +1503,7 @@ showWalletDataWindow.walletData=ウォレットデータ showWalletDataWindow.includePrivKeys=プライベートキーを含む setXMRTxKeyWindow.headline=XMR送金を証明 -setXMRTxKeyWindow.note=以下にtx情報を追加すると、より早いトレードのため自動確認を有効にします。詳しくは:https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=以下にtx情報を追加すると、より早いトレードのため自動確認を有効にします。詳しくは:https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=トランザクションID(任意) setXMRTxKeyWindow.txKey=トランザクション・キー(任意) @@ -1486,7 +1515,7 @@ tacWindow.disagree=同意せずにに終了 tacWindow.arbitrationSystem=紛争解決 tradeDetailsWindow.headline=トレード -tradeDetailsWindow.disputedPayoutTxId=係争中の支払い取引ID: +tradeDetailsWindow.disputedPayoutTxId=係争中の支払い取引ID tradeDetailsWindow.tradeDate=取引日 tradeDetailsWindow.txFee=マイニング手数料 tradeDetailsWindow.tradePeersOnion=トレード相手のonionアドレス @@ -1496,8 +1525,10 @@ tradeDetailsWindow.agentAddresses=仲裁者 / 調停人 tradeDetailsWindow.detailData=詳細データ txDetailsWindow.headline=トランザクション詳細 -txDetailsWindow.xmr.note=BTCを送金しました。 +txDetailsWindow.xmr.noteSent=XMRを送金しました。 +txDetailsWindow.xmr.noteReceived=XMRを受け取りました。 txDetailsWindow.sentTo=送信先 +txDetailsWindow.receivedWith=受け取りました。 txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1506,7 +1537,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=アンロックするためにパスワードを入力してください @@ -1532,12 +1563,12 @@ torNetworkSettingWindow.bridges.header=Torはブロックされていますか torNetworkSettingWindow.bridges.info=Torがあなたのインターネットプロバイダや国にブロックされている場合、Torブリッジによる接続を試みることができます。\nTorのWebページ https://bridges.torproject.org/bridges にアクセスして、ブリッジとプラガブル転送について学べます feeOptionWindow.headline=取引手数料の支払いに使用する通貨を選択してください -feeOptionWindow.info=あなたは取引手数料の支払いにBSQまたはBTCを選択できます。 BSQを選択した場合は、割引された取引手数料に気付くでしょう。 +feeOptionWindow.info=あなたは取引手数料の支払いにBSQまたはXMRを選択できます。 BSQを選択した場合は、割引された取引手数料に気付くでしょう。 feeOptionWindow.optionsLabel=取引手数料の支払いに使用する通貨を選択してください -feeOptionWindow.useBTC=BTCを使用 +feeOptionWindow.useXMR=XMRを使用 feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1610,9 @@ popup.warning.noTradingAccountSetup.msg=オファーを作成する前に、国 popup.warning.noArbitratorsAvailable=利用可能な調停人がいません。 popup.warning.noMediatorsAvailable=利用可能な調停人がいません。 popup.warning.notFullyConnected=ネットワークへ完全に接続するまで待つ必要があります。\n起動までに約2分かかります。 -popup.warning.notSufficientConnectionsToBtcNetwork=少なくとも{0}のビットコインネットワークへの接続が確立されるまでお待ちください。 +popup.warning.notSufficientConnectionsToXmrNetwork=少なくとも{0}のビットコインネットワークへの接続が確立されるまでお待ちください。 popup.warning.downloadNotComplete=欠落しているビットコインブロックのダウンロードが完了するまで待つ必要があります。 -popup.warning.chainNotSynced=Havenoウォレットのブロックチェーン高さは正しく同期されていません。アプリを最近起動した場合、1つのビットコインブロックが発行されるまで待って下さい。\n\nブロックチェーン高さは\"設定/ネットワーク情報\"に表示されます。 2つ以上のブロックが発行されても問題が解決されない場合、フリーズしている可能性があります。その場合には、SPV再同期を行って下さい [HYPERLINK: https://bisq.wiki/Resyncing_SPV_file ]。 +popup.warning.walletNotSynced=Havenoウォレットのブロックチェーン高さは正しく同期されていません。アプリを最近起動した場合、1つのビットコインブロックが発行されるまで待って下さい。\n\nブロックチェーン高さは\"設定/ネットワーク情報\"に表示されます。 2つ以上のブロックが発行されても問題が解決されない場合、フリーズしている可能性があります。その場合には、SPV再同期を行って下さい [HYPERLINK: https://haveno.exchange/wiki/Resyncing_SPV_file ]。 popup.warning.removeOffer=本当にオファーを削除しますか? popup.warning.tooLargePercentageValue=100%以上のパーセントを設定できません popup.warning.examplePercentageValue=パーセントの数字を入力してください。5.4%は「5.4」のように入力します。 @@ -1600,8 +1631,7 @@ popup.warning.nodeBanned={0}ノードの1つが禁止されました。 popup.warning.priceRelay=価格中継 popup.warning.seed=シード popup.warning.mandatoryUpdate.trading=最新のHavenoバージョンに更新してください。古いバージョンのトレードを無効にする必須の更新プログラムがリリースされました。詳細については、Havenoフォーラムをご覧ください。 -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC={0}のマイニング手数料が{1}の送金額を超えるため、このトランザクションは利用不可です。マイニング手数料が再び低くなるか、送金するBTCがさらに蓄積されるまでお待ちください。 +popup.warning.burnXMR={0}のマイニング手数料が{1}の送金額を超えるため、このトランザクションは利用不可です。マイニング手数料が再び低くなるか、送金するXMRがさらに蓄積されるまでお待ちください。 popup.warning.openOffer.makerFeeTxRejected=ID{0}で識別されるオファーのためのメイカー手数料トランザクションがビットコインネットワークに拒否されました。\nトランザクションID= {1} 。\n更なる問題を避けるため、そのオファーは削除されました。\n\"設定/ネットワーク情報\"を開いてSPV再同期を行って下さい。\nさらにサポートを受けるため、Haveno Keybaseチームのサポートチャンネルに連絡して下さい。 @@ -1616,7 +1646,7 @@ popup.info.securityDepositInfo=両方の取引者がトレードプロトコル popup.info.cashDepositInfo=あなたの地域の銀行支店が現金デポジットが作成できることを確認してください。\n売り手の銀行ID(BIC / SWIFT)は{0}です。 popup.info.cashDepositInfo.confirm=デポジットを作成できるか確認します popup.info.shutDownWithOpenOffers=Havenoはシャットダウン中ですが、オファーはあります。\n\nこれらのオファーは、Havenoがシャットダウンされている間はP2Pネットワークでは利用できませんが、次回Havenoを起動したときにP2Pネットワークに再公開されます。\n\nオファーをオンラインに保つには、Havenoを実行したままにして、このコンピュータもオンラインにしたままにします(つまり、スタンバイモードにならないようにしてください。モニタースタンバイは問題ありません)。 -popup.info.qubesOSSetupInfo=Qubes OS内でHavenoを実行しているようです。\n\nHavenoのqubeはセットアップガイドに従って設定されていることを確かめて下さい: [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes] +popup.info.qubesOSSetupInfo=Qubes OS内でHavenoを実行しているようです。\n\nHavenoのqubeはセットアップガイドに従って設定されていることを確かめて下さい: [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes] popup.warn.downGradePrevention=バージョン{0}からバージョン{1}に戻すことはサポートされていません。最新のHavenoバージョンを利用して下さい。 popup.privateNotification.headline=重要なプライベート通知! @@ -1624,7 +1654,7 @@ popup.privateNotification.headline=重要なプライベート通知! popup.securityRecommendation.headline=重要なセキュリティ勧告 popup.securityRecommendation.msg=ウォレットのパスワード保護をまだ有効にしてない場合は、使用することを検討してください。\n\nウォレットシードワードを書き留めることも強くお勧めします。 これらのシードワードは、あなたのビットコインウォレットを復元するためのマスターパスワードのようなものです。\n「ウォレットシード」セクションにてより詳細な情報を確認できます。\n\nまた、「バックアップ」セクションのアプリケーションデータフォルダ全体をバックアップするべきでしょう。 -popup.moneroLocalhostNode.msg=Haveno检测到本机(localhost上)运行了一个门罗币节点。\n\n在启动Haveno之前,请确保节点已完全同步。 +popup.xmrLocalNode.msg=Haveno检测到本机(localhost上)运行了一个门罗币节点。\n\n在启动Haveno之前,请确保节点已完全同步。 popup.shutDownInProgress.headline=シャットダウン中 popup.shutDownInProgress.msg=アプリケーションのシャットダウンには数秒かかることがあります。\nこのプロセスを中断しないでください。 @@ -1670,6 +1700,9 @@ popup.accountSigning.unsignedPubKeys.signed=パブリックキーは署名され popup.accountSigning.unsignedPubKeys.result.signed=署名されたパブリックキー popup.accountSigning.unsignedPubKeys.result.failed=署名が失敗しました +popup.info.buyerAsTakerWithoutDeposit.headline=購入者による保証金は不要 +popup.info.buyerAsTakerWithoutDeposit=あなたのオファーには、XMR購入者からのセキュリティデポジットや手数料は必要ありません。\n\nオファーを受け入れるには、Haveno外で取引相手とパスフレーズを共有する必要があります。\n\nパスフレーズは自動的に生成され、作成後にオファーの詳細に表示されます。 + #################################################################### # Notifications #################################################################### @@ -1677,9 +1710,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=署名が失敗しました notification.trade.headline=ID {0}とのトレードの通知 notification.ticket.headline=ID {0}とのトレード用サポートチケット notification.trade.completed=これでトレードは完了し、資金を出金することができます。 -notification.trade.accepted=あなたのオファーはBTC {0}によって承認されました。 +notification.trade.accepted=あなたのオファーはXMR {0}によって承認されました。 notification.trade.unlocked=あなたのトレードには少なくとも1つのブロックチェーン承認があります。\nあなたは今、支払いを始めることができます。 -notification.trade.paymentSent=BTCの買い手が支払いを開始しました。 +notification.trade.paymentSent=XMRの買い手が支払いを開始しました。 notification.trade.selectTrade=取引を選択 notification.trade.peerOpenedDispute=あなたの取引相手は{0}をオープンしました。 notification.trade.disputeClosed={0}は閉じられました。 @@ -1749,7 +1782,7 @@ tooltip.openBlockchainForTx=外部ブロックチェーンエクスプローラ confidence.unknown=不明なトランザクションステータス confidence.seen={0} 人のピアに見られた / 0 承認 -confidence.confirmed={0}ブロックで承認済み。 +confidence.confirmed={0} 承認 confidence.invalid=トランザクションが不正です peerInfo.title=ピア情報 @@ -1795,6 +1828,7 @@ navigation.support=「サポート」 formatter.formatVolumeLabel={0} 額{1} formatter.makerTaker=メイカーは{0} {1} / テイカーは{2} {3} +formatter.makerTakerLocked=メイカーは{0} {1} / テイカーは{2} {3} 🔒 formatter.youAreAsMaker=あなたは:{1} {0}(メイカー) / テイカーは:{3} {2} formatter.youAreAsTaker=あなたは:{1} {0}(テイカー) / メイカーは{3} {2} formatter.youAre=あなたは{0} {1} ({2} {3}) @@ -1840,7 +1874,6 @@ password.deriveKey=パスワードから鍵を引き出す password.walletDecrypted=ウォレットは正常に復号化され、パスワード保護が解除されました。 password.wrongPw=間違ったパスワードを入力しています。\n\nパスワードをもう一度入力してみてください。入力ミスやスペルミスがないか慎重に確認してください。 password.walletEncrypted=ウォレットは正常に暗号化され、パスワード保護が有効になりました。 -password.walletEncryptionFailed=ウォレットのパスワードを設定できませんでした。ウォレットデータベースと一致しないシードワードをインポートした可能性があります。Keybase ([HYPERLINK:https://keybase.io/team/haveno]) で開発者と連絡して下さい。 password.passwordsDoNotMatch=入力した2つのパスワードが一致しません。 password.forgotPassword=パスワードを忘れましたか? password.backupReminder=ウォレットパスワードを設定すると、暗号化されていないウォレットから自動的に作成されたすべてのバックアップが削除されます。\n\nパスワードを設定する前に、アプリケーションディレクトリのバックアップを作成してシードワードを書き留めておくことを強く推奨します。 @@ -1871,7 +1904,7 @@ seed.restore.openOffers.warn=シードワードから復元すると削除され payment.account=アカウント payment.account.no=アカウント番号 payment.account.name=アカウント名 -payment.account.userName=ユーザ名 +payment.account.username=ユーザ名 payment.account.phoneNr=電話番号 payment.account.owner=アカウント所有者の氏名 payment.account.fullName=氏名(名、ミドルネーム、姓) @@ -1903,7 +1936,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=ユーザーネームかメールか電話番号 payment.moneyBeam.accountId=メールか電話番号 -payment.venmo.venmoUserName=Venmo ユーザー名 payment.popmoney.accountId=メールか電話番号 payment.promptPay.promptPayId=市民ID/納税者番号または電話番号 payment.supportedCurrencies=サポートされている通貨 @@ -1945,16 +1977,16 @@ payment.checking=当座口座 payment.savings=普通口座 payment.personalId=個人ID payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelleは他の銀行を介して利用するとよりうまくいく送金サービスです。\n\n1. あなたの銀行がZelleと協力するか(そして利用の方法)をここから確認して下さい: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. 送金制限に注意して下さい。制限は銀行によって異なり、1日、1週、1月当たりの制限に分けられていることが多い。\n\n3. 銀行がZelleと協力しない場合でも、Zelleのモバイルアプリ版を使えますが、送金制限ははるかに低くなります。\n\n4. Havenoアカウントで特定される名前は必ずZelleアカウントと銀行口座に特定される名前と合う必要があります。\n\nトレード契約書とおりにZelleトランザクションを完了できなければ、一部(あるいは全て)のセキュリティデポジットを失う可能性はあります。\n\nZelleにおいてやや高い支払取り消しリスクがあるので、売り手はメールやSMSで無署名買い手に連絡して、Havenoに特定されるZelleアカウントの所有者かどうかを確かめるようにおすすめします。 payment.fasterPayments.newRequirements.info=「Faster Payments」で送金する場合、銀行が受信者の姓名を確認するケースが最近多くなりました。現在の「Faster Payments」アカウントは姓名を特定しません。\n\nこれからの{0}買い手に姓名を提供するため、Haveno内に新しい「Faster Payments」アカウントを作成するのを検討して下さい。\n\n新しいアカウントを作成すると、完全に同じ分類コード、アカウントの口座番号、そしてアカウント年齢検証ソルト値を古いアカウントから新しいアカウントにコピーして下さい。こうやって現在のアカウントの年齢そして署名状況は維持されます。 -payment.moneyGram.info=MoneyGramを使用する場合、BTCの買い手は認証番号と領収書の写真をEメールでBTCの売り手に送信する必要があります。領収書には、売り手の氏名、市区町村、国、金額を明確に記載する必要があります。トレードプロセスにて、売り手のEメールは買い手に表示されます。 -payment.westernUnion.info=Western Unionを使用する場合、BTCの買い手はMTCN(追跡番号)と領収書の写真をEメールでBTCの売り手に送信する必要があります。領収書には、売り手の氏名、市区町村、国、金額を明確に記載する必要があります。トレードプロセスにて、売り手のEメールは買い手に表示されます。 -payment.halCash.info=HalCashを使用する場合、BTCの買い手は携帯電話からのテキストメッセージを介してBTCの売り手にHalCashコードを送信する必要があります。\n\n銀行がHalCashで送金できる最大額を超えないようにしてください。 1回の出金あたりの最小金額は10EURで、最大金額は600EURです。繰り返し出金する場合は、1日に受取人1人あたり3000EUR、1ヶ月に受取人1人あたり6000EURです。あなたの銀行でも、ここに記載されているのと同じ制限を使用しているか、これらの制限を銀行と照合して確認してください。\n\n出金額は10の倍数EURでなければ、ATMから出金できません。 オファーの作成画面およびオファー受け入れ画面のUIは、EUR金額が正しくなるようにBTC金額を調整します。価格の変化とともにEURの金額は変化するため、市場ベースの価格を使用することはできません。\n\n係争が発生した場合、BTCの買い手はEURを送ったという証明を提出する必要があります。 +payment.moneyGram.info=MoneyGramを使用する場合、XMRの買い手は認証番号と領収書の写真をEメールでXMRの売り手に送信する必要があります。領収書には、売り手の氏名、市区町村、国、金額を明確に記載する必要があります。トレードプロセスにて、売り手のEメールは買い手に表示されます。 +payment.westernUnion.info=Western Unionを使用する場合、XMRの買い手はMTCN(追跡番号)と領収書の写真をEメールでXMRの売り手に送信する必要があります。領収書には、売り手の氏名、市区町村、国、金額を明確に記載する必要があります。トレードプロセスにて、売り手のEメールは買い手に表示されます。 +payment.halCash.info=HalCashを使用する場合、XMRの買い手は携帯電話からのテキストメッセージを介してXMRの売り手にHalCashコードを送信する必要があります。\n\n銀行がHalCashで送金できる最大額を超えないようにしてください。 1回の出金あたりの最小金額は10EURで、最大金額は600EURです。繰り返し出金する場合は、1日に受取人1人あたり3000EUR、1ヶ月に受取人1人あたり6000EURです。あなたの銀行でも、ここに記載されているのと同じ制限を使用しているか、これらの制限を銀行と照合して確認してください。\n\n出金額は10の倍数EURでなければ、ATMから出金できません。 オファーの作成画面およびオファー受け入れ画面のUIは、EUR金額が正しくなるようにXMR金額を調整します。価格の変化とともにEURの金額は変化するため、市場ベースの価格を使用することはできません。\n\n係争が発生した場合、XMRの買い手はEURを送ったという証明を提出する必要があります。 # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=すべての銀行振込にはある程度の支払取り消しのリスクがあることに気を付けて下さい。\n\nこのリスクを軽減するために、Havenoは使用する支払い方法での支払取り消しリスクの推定レベルに基づいてトレードごとの制限を設定します。\n\n現在使用する支払い方法では、トレードごとの売買制限は{2}です。\n\n制限は各トレードの量のみに適用されることに注意して下さい。トレードできる合計回数には制限はありません。\n\n詳しくはWikiを調べて下さい [HYPERLINK:https://bisq.wiki/Account_limits] 。 +payment.limits.info=すべての銀行振込にはある程度の支払取り消しのリスクがあることに気を付けて下さい。\n\nこのリスクを軽減するために、Havenoは使用する支払い方法での支払取り消しリスクの推定レベルに基づいてトレードごとの制限を設定します。\n\n現在使用する支払い方法では、トレードごとの売買制限は{2}です。\n\n制限は各トレードの量のみに適用されることに注意して下さい。トレードできる合計回数には制限はありません。\n\n詳しくはWikiを調べて下さい [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits] 。 # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=支払取り消しのリスクを軽減するために、Havenoはこの支払いアカウントに下記の2つの要因に基づいてトレードごとの制限を設定します。\n\n1.使用する支払い方法での支払取り消しリスクの推定レベル\n2.アカウントの署名状況\n\nこの支払いアカウントはまだ無署名ですので、トレードごとに{0}の買い制限があります。 アカウントが署名される後、トレードごとの制限は以下のように成長します:\n\n●署名の前、そして署名から30日間までに、1トレードあたりの買い制限は{0}になります\n●署名から30日間後に、1トレードあたりの買い制限は{1}になります\n●署名から60日間後に、1トレードあたりの買い制限は{2}になります\n\n売り制限は署名状況に関係がありません。現在のところ、1トレードあたりに{2}を売ることができます。\n\n制限は各トレードの量のみに適用されることに注意して下さい。取引できる合計回数には制限はありません。\n\n詳しくは: [HYPERLINK:https://bisq.wiki/Account_limits] +payment.limits.info.withSigning=支払取り消しのリスクを軽減するために、Havenoはこの支払いアカウントに下記の2つの要因に基づいてトレードごとの制限を設定します。\n\n1.使用する支払い方法での支払取り消しリスクの推定レベル\n2.アカウントの署名状況\n\nこの支払いアカウントはまだ無署名ですので、トレードごとに{0}の買い制限があります。 アカウントが署名される後、トレードごとの制限は以下のように成長します:\n\n●署名の前、そして署名から30日間までに、1トレードあたりの買い制限は{0}になります\n●署名から30日間後に、1トレードあたりの買い制限は{1}になります\n●署名から60日間後に、1トレードあたりの買い制限は{2}になります\n\n売り制限は署名状況に関係がありません。現在のところ、1トレードあたりに{2}を売ることができます。\n\n制限は各トレードの量のみに適用されることに注意して下さい。取引できる合計回数には制限はありません。\n\n詳しくは: [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits] payment.cashDeposit.info=あなたの銀行が他の人の口座に現金入金を送ることを許可していることを確認してください。たとえば、Bank of America と Wells Fargo では、こうした預金は許可されなくなりました。 @@ -1966,7 +1998,7 @@ payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the cou payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Havenoでアメリカ合衆国郵便為替(USPMO)をトレードするには、以下を理解する必要があります:\n\n-送る前に、BTC買い手は必ずBTC売り手の名前を支払人そして支払先フィールド両方に書いて、追跡証明も含めるUSPMOそして封筒の高解像度写真を取る必要があります。\n-BTC買い手は必ず配達確認を利用してBTC売り手にUSPMOを送る必要があります。\n\n調停が必要になる場合、あるいはトレード係争が開始される場合、調停者や調停人がアメリカ合衆国郵便のサイトで詳細を確認できるように、取った写真、USPMOシリアル番号、郵便局番号、そしてドル金額を送る必要があります。\n\n調停者や調停人に必要な情報を提供しなければ、係争で不利な裁定を下されます。\n\n全ての係争には、調停者や調停人に証明を提供するのは100%USPMO送付者の責任です。\n\n以上の条件を理解しない場合、HavenoでUSPMOのトレードをしないで下さい。 +payment.usPostalMoneyOrder.info=Havenoでアメリカ合衆国郵便為替(USPMO)をトレードするには、以下を理解する必要があります:\n\n-送る前に、XMR買い手は必ずXMR売り手の名前を支払人そして支払先フィールド両方に書いて、追跡証明も含めるUSPMOそして封筒の高解像度写真を取る必要があります。\n-XMR買い手は必ず配達確認を利用してXMR売り手にUSPMOを送る必要があります。\n\n調停が必要になる場合、あるいはトレード係争が開始される場合、調停者や調停人がアメリカ合衆国郵便のサイトで詳細を確認できるように、取った写真、USPMOシリアル番号、郵便局番号、そしてドル金額を送る必要があります。\n\n調停者や調停人に必要な情報を提供しなければ、係争で不利な裁定を下されます。\n\n全ての係争には、調停者や調停人に証明を提供するのは100%USPMO送付者の責任です。\n\n以上の条件を理解しない場合、HavenoでUSPMOのトレードをしないで下さい。 payment.payByMail.info=Havenoを利用したPay by Mailでの取引には、以下を理解する必要があります:\n\ ● XMRの買い手は現金を封がれた袋に入れる必要があります。\n\ @@ -1996,7 +2028,7 @@ payment.f2f.city.prompt=オファーとともに市区町村が表示されま payment.shared.optionalExtra=オプションの追加情報 payment.shared.extraInfo=追加情報 payment.shared.extraInfo.prompt=この支払いアカウントのオファーと一緒に表示したい特別な契約条件または詳細を定義して下さい(オファーを受ける前に、ユーザはこの情報を見れます)。 -payment.f2f.info=「対面」トレードには違うルールがあり、オンライントレードとは異なるリスクを伴います。\n\n主な違いは以下の通りです。\n●取引者は、提供される連絡先の詳細を使用して、出会う場所と時間に関する情報を交換する必要があります。\n●取引者は自分のノートパソコンを持ってきて、集合場所で「送金」と「入金」の確認をする必要があります。\n●メイカーに特別な「取引条件」がある場合は、アカウントの「追加情報」テキストフィールドにその旨を記載する必要があります。\n●オファーを受けると、テイカーはメイカーの「トレード条件」に同意したものとします。\n●係争が発生した場合、集合場所で何が起きたのかについての改ざん防止証明を入手することは通常困難であるため、調停者や調停人はあまりサポートをできません。このような場合、BTCの資金は無期限に、または取引者が合意に達するまでロックされる可能性があります。\n\n「対面」トレードでの違いを完全に理解しているか確認するためには、次のURLにある手順と推奨事項をお読みください:[HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info=「対面」トレードには違うルールがあり、オンライントレードとは異なるリスクを伴います。\n\n主な違いは以下の通りです。\n●取引者は、提供される連絡先の詳細を使用して、出会う場所と時間に関する情報を交換する必要があります。\n●取引者は自分のノートパソコンを持ってきて、集合場所で「送金」と「入金」の確認をする必要があります。\n●メイカーに特別な「取引条件」がある場合は、アカウントの「追加情報」テキストフィールドにその旨を記載する必要があります。\n●オファーを受けると、テイカーはメイカーの「トレード条件」に同意したものとします。\n●係争が発生した場合、集合場所で何が起きたのかについての改ざん防止証明を入手することは通常困難であるため、調停者や調停人はあまりサポートをできません。このような場合、XMRの資金は無期限に、または取引者が合意に達するまでロックされる可能性があります。\n\n「対面」トレードでの違いを完全に理解しているか確認するためには、次のURLにある手順と推奨事項をお読みください:[HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Webページを開く payment.f2f.offerbook.tooltip.countryAndCity=国と都市: {0} / {1} payment.f2f.offerbook.tooltip.extra=追加情報: {0} @@ -2008,7 +2040,7 @@ payment.japan.recipient=名義 payment.australia.payid=PayID payment.payid=金融機関と繋がっているPayID。例えばEメールアドレスそれとも携帯電話番号。 payment.payid.info=銀行、信用金庫、あるいは住宅金融組合アカウントと安全に繋がれるPayIDとして使われる電話番号、Eメールアドレス、それともオーストラリア企業番号(ABN)。すでにオーストラリアの金融機関とPayIDを作った必要があります。送金と受取の金融機関は両方PayIDをサポートする必要があります。詳しくは以下を訪れて下さい [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=アマゾンeGiftカードで支払うには、アマゾンアカウントを使ってeGiftカードをBTC売り手に送る必要があります。\n\nHavenoはeGiftカードの送り先になるBTC売り手のメールアドレスそれとも電話番号を表示します。そしてeGiftカードのメッセージフィールドに、必ずトレードIDを入力して下さい。最良の慣行について詳しくはWikiを参照して下さい:[HYPERLINK:https://bisq.wiki/Amazon_eGift_card]\n\n3つの注意点:\n- 可能であれば、100米ドル価格以下のeGiftカードを送って下さい。それ以上の価格はアマゾンに不正な取引というフラグが立てられることがあります。\n- eGiftカードのメッセージフィールドに、トレードIDと一緒に信ぴょう性のあるメッセージを入力して下さい。(例えば隆さん、「お誕生日おめでとう!」)。(そして確認のため、取引者チャットでトレードピアにメッセージの内容を伝えて下さい)。\n- アマゾンeGiftカードは買われたサイトのみに交換できます(例えば、amazon.jpから買われたカードはamazon.jpのみに交換できます)。 +payment.amazonGiftCard.info=アマゾンeGiftカードで支払うには、アマゾンアカウントを使ってeGiftカードをXMR売り手に送る必要があります。\n\nHavenoはeGiftカードの送り先になるXMR売り手のメールアドレスそれとも電話番号を表示します。そしてeGiftカードのメッセージフィールドに、必ずトレードIDを入力して下さい。最良の慣行について詳しくはWikiを参照して下さい:[HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card]\n\n3つの注意点:\n- 可能であれば、100米ドル価格以下のeGiftカードを送って下さい。それ以上の価格はアマゾンに不正な取引というフラグが立てられることがあります。\n- eGiftカードのメッセージフィールドに、トレードIDと一緒に信ぴょう性のあるメッセージを入力して下さい。(例えば隆さん、「お誕生日おめでとう!」)。(そして確認のため、取引者チャットでトレードピアにメッセージの内容を伝えて下さい)。\n- アマゾンeGiftカードは買われたサイトのみに交換できます(例えば、amazon.jpから買われたカードはamazon.jpのみに交換できます)。 # We use constants from the code so we do not use our normal naming convention @@ -2176,10 +2208,10 @@ validation.sortCodeChars={0}は{1}文字で構成されている必要があり validation.bankIdNumber={0}は{1}個の数字で構成されている必要があります。 validation.accountNr=アカウント番号は{0}個の数字で構成されている必要があります。 validation.accountNrChars=アカウント番号は{0}文字で構成されている必要があります。 -validation.btc.invalidAddress=アドレスが正しくありません。アドレス形式を確認してください。 +validation.xmr.invalidAddress=アドレスが正しくありません。アドレス形式を確認してください。 validation.integerOnly=整数のみを入力してください。 validation.inputError=入力エラーを起こしました:\n{0} -validation.btc.exceedsMaxTradeLimit=あなたのトレード制限は{0}です。 +validation.xmr.exceedsMaxTradeLimit=あなたのトレード制限は{0}です。 validation.nationalAccountId={0}は{1}個の数字で構成されている必要があります。 #new diff --git a/core/src/main/resources/i18n/displayStrings_pt-br.properties b/core/src/main/resources/i18n/displayStrings_pt-br.properties index 700e076cda..d7006d4659 100644 --- a/core/src/main/resources/i18n/displayStrings_pt-br.properties +++ b/core/src/main/resources/i18n/displayStrings_pt-br.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Eu compreendo shared.na=N/D shared.shutDown=Desligar shared.reportBug=Report bug on GitHub -shared.buyBitcoin=Comprar bitcoin -shared.sellBitcoin=Vender bitcoin +shared.buyMonero=Comprar monero +shared.sellMonero=Vender monero shared.buyCurrency=Comprar {0} shared.sellCurrency=Vender {0} -shared.buyingBTCWith=comprando BTC com {0} -shared.sellingBTCFor=vendendo BTC por {0} -shared.buyingCurrency=comprando {0} (vendendo BTC) -shared.sellingCurrency=vendendo {0} (comprando BTC) +shared.buyCurrencyLocked=Comprar {0} 🔒 +shared.sellCurrencyLocked=Vender {0} 🔒 +shared.buyingXMRWith=comprando XMR com {0} +shared.sellingXMRFor=vendendo XMR por {0} +shared.buyingCurrency=comprando {0} (vendendo XMR) +shared.sellingCurrency=vendendo {0} (comprando XMR) shared.buy=comprar shared.sell=vender shared.buying=comprando @@ -93,7 +95,7 @@ shared.amountMinMax=Quantidade (min - max) shared.amountHelp=Se uma oferta possuir uma quantia mínima e máxima definidas, você poderá negociar qualquer quantia dentro dessa faixa. shared.remove=Remover shared.goTo=Ir para {0} -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Remover oferta shared.dontRemoveOffer=Não remover a oferta shared.editOffer=Editar oferta @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=Sim, cancelar shared.nextStep=Próximo passo shared.selectTradingAccount=Selecionar conta de negociação -shared.fundFromSavingsWalletButton=Transferir fundos da carteira Haveno +shared.fundFromSavingsWalletButton=Aplicar fundos da carteira Haveno shared.fundFromExternalWalletButton=Abrir sua carteira externa para prover fundos -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=% abaixo do preço de mercado shared.aboveInPercent=% acima do preço de mercado shared.enterPercentageValue=Insira a % shared.OR=OU shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=Aguardando pagamento... -shared.TheBTCBuyer=O comprador de BTC +shared.TheXMRBuyer=O comprador de XMR shared.You=Você shared.sendingConfirmation=Enviando confirmação... shared.sendingConfirmationAgain=Por favor, envie a confirmação novamente @@ -123,9 +125,8 @@ shared.noDateAvailable=Sem data disponível shared.noDetailsAvailable=Sem detalhes disponíveis shared.notUsedYet=Ainda não usado shared.date=Data -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=Copiar para área de transferência shared.language=Idioma shared.country=País @@ -140,6 +141,7 @@ shared.addNewAccount=Adicionar conta nova shared.ExportAccounts=Exportar Contas shared.importAccounts=Importar Contas shared.createNewAccount=Criar nova conta +shared.createNewAccountDescription=Os detalhes da sua conta são armazenados localmente no seu dispositivo e compartilhados apenas com seu parceiro de negociação e o árbitro, caso uma disputa seja aberta. shared.saveNewAccount=Salvar nova conta shared.selectedAccount=Conta selecionada shared.deleteAccount=Apagar conta @@ -169,7 +171,7 @@ shared.payoutTxId=ID da transação de pagamento shared.contractAsJson=Contrato em formato JSON shared.viewContractAsJson=Ver contrato em formato JSON shared.contract.title=Contrato para negociação com ID: {0} -shared.paymentDetails=Detalhes de pagamento do {0} de BTC +shared.paymentDetails=Detalhes de pagamento do {0} de XMR shared.securityDeposit=Depósito de segurança shared.yourSecurityDeposit=Seu depósito de segurança shared.contract=Contrato @@ -179,19 +181,21 @@ shared.messageSendingFailed=Falha no envio da mensagem. Erro: {0} shared.unlock=Destravar shared.toReceive=a receber shared.toSpend=a ser gasto -shared.btcAmount=Quantidade de BTC +shared.xmrAmount=Quantidade de XMR shared.yourLanguage=Seus idiomas shared.addLanguage=Adicionar idioma shared.total=Total shared.totalsNeeded=Fundos necessária shared.tradeWalletAddress=Endereço da carteira de negociação shared.tradeWalletBalance=Saldo da carteira de negociação +shared.reserveExactAmount=Reserve apenas os fundos necessários. Requer uma taxa de mineração e cerca de 20 minutos antes que sua oferta seja publicada. shared.makerTxFee=Ofertante: {0} shared.takerTxFee=Aceitador: {0} shared.iConfirm=Eu confirmo shared.openURL=Aberto {0} shared.fiat=Fiat shared.crypto=Cripto +shared.preciousMetals=Metais Preciosos shared.all=Todos shared.edit=Editar shared.advancedOptions=Opções avançadas @@ -229,8 +233,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=Mercado -mainView.menu.buyBtc=Comprar BTC -mainView.menu.sellBtc=Vender BTC +mainView.menu.buyXmr=Comprar XMR +mainView.menu.sellXmr=Vender XMR mainView.menu.portfolio=Portfolio mainView.menu.funds=Fundos mainView.menu.support=Suporte @@ -248,12 +252,15 @@ mainView.balance.reserved.short=Reservado mainView.balance.pending.short=Travado mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Conectando-se à rede Bitcoin -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=Conectando-se à rede Haveno +mainView.footer.xmrInfo.synchronizingWith=Sincronizando com {0} no bloco: {1} / {2} +mainView.footer.xmrInfo.connectedTo=Conectado a {0} no bloco {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Sincronizando a carteira com {0} no bloco: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Sincronizado com {0} no bloco {1} mainView.footer.xmrInfo.connectingTo=Conectando-se a mainView.footer.xmrInfo.connectionFailed=Falha na conexão à mainView.footer.xmrPeers=Monero network peers: {0} @@ -271,13 +278,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=A inicialização para a rede mainView.p2pNetworkWarnMsg.noNodesAvailable=Não há nós semente ou pares persistentes para requisição de dados.\nPor gentileza verifique sua conexão com a internet ou tente reiniciar o programa. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Falha ao conectar com a rede Haveno (erro reportado: {0}).\nPor gentileza verifique sua conexão ou tente reiniciar o programa. -mainView.walletServiceErrorMsg.timeout=Não foi possível conectar-se à rede Bitcoin, pois o tempo limite expirou. -mainView.walletServiceErrorMsg.connectionError=Não foi possível conectar-se à rede Bitcoin, devido ao seguinte erro: {0} +mainView.walletServiceErrorMsg.timeout=Não foi possível conectar-se à rede Monero, pois o tempo limite expirou. +mainView.walletServiceErrorMsg.connectionError=Não foi possível conectar-se à rede Monero, devido ao seguinte erro: {0} mainView.walletServiceErrorMsg.rejectedTxException=Uma transação foi rejeitada pela rede.\n\n{0} mainView.networkWarning.allConnectionsLost=Você perdeu sua conexão com todos os pontos da rede {0}.\nTalvez você tenha perdido a conexão com a internet ou seu computador estava em modo de espera. -mainView.networkWarning.localhostBitcoinLost=Você perdeu a conexão ao nó Bitcoin do localhost.\nPor favor, reinicie o aplicativo Haveno para conectar-se a outros nós Bitcoin ou reinicie o nó Bitcoin do localhost. +mainView.networkWarning.localhostMoneroLost=Você perdeu a conexão ao nó Monero do localhost.\nPor favor, reinicie o aplicativo Haveno para conectar-se a outros nós Monero ou reinicie o nó Monero do localhost. mainView.version.update=(Atualização disponível) @@ -297,14 +304,14 @@ market.offerBook.buyWithTraditional=Comprar {0} market.offerBook.sellWithTraditional=Vender {0} market.offerBook.sellOffersHeaderLabel=Vender {0} para market.offerBook.buyOffersHeaderLabel=Comprar {0} de -market.offerBook.buy=Eu quero comprar bitcoin -market.offerBook.sell=Eu quero vender bitcoin +market.offerBook.buy=Eu quero comprar monero +market.offerBook.sell=Eu quero vender monero # SpreadView market.spread.numberOfOffersColumn=Todas as ofertas ({0}) -market.spread.numberOfBuyOffersColumn=Comprar BTC ({0}) -market.spread.numberOfSellOffersColumn=Vender BTC ({0}) -market.spread.totalAmountColumn=Total de BTC ({0}) +market.spread.numberOfBuyOffersColumn=Comprar XMR ({0}) +market.spread.numberOfSellOffersColumn=Vender XMR ({0}) +market.spread.totalAmountColumn=Total de XMR ({0}) market.spread.spreadColumn=Spread market.spread.expanded=Expanded view @@ -328,6 +335,7 @@ offerbook.createOffer=Criar oferta offerbook.takeOffer=Aceitar oferta offerbook.takeOfferToBuy=Comprar {0} offerbook.takeOfferToSell=Vender {0} +offerbook.takeOffer.enterChallenge=Digite a senha da oferta offerbook.trader=Trader offerbook.offerersBankId=ID do banco do ofertante (BIC/SWIFT): {0} offerbook.offerersBankName=Nome do banco do ofertante: {0} @@ -337,7 +345,9 @@ offerbook.offerersAcceptedBankSeats=Países aceitos como sede bancária (tomador offerbook.availableOffers=Ofertas disponíveis offerbook.filterByCurrency=Filtrar por moeda offerbook.filterByPaymentMethod=Filtrar por método de pagamento -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=Ofertas que correspondem às minhas contas +offerbook.filterNoDeposit=Sem depósito +offerbook.noDepositOffers=Ofertas sem depósito (senha necessária) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Esta conta foi verificada e {0} offerbook.timeSinceSigning.info.arbitrator=assinada por um árbitro e pode assinar contas de pares @@ -348,6 +358,8 @@ offerbook.timeSinceSigning.info.banned=conta foi banida offerbook.timeSinceSigning.daysSinceSigning={0} dias offerbook.timeSinceSigning.daysSinceSigning.long={0} desde a assinatura offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=Compre XMR com: +offerbook.sellXmrFor=Venda XMR por: offerbook.timeSinceSigning.help=Quando você completa uma negociação bem sucedida com um par que tem uma conta de pagamento assinada, a sua conta de pagamento é assinada.\n{0} dias depois, o limite inicial de {1} é levantado e sua conta pode assinar as contas de pagamento de outros pares. offerbook.timeSinceSigning.notSigned=Ainda não assinada @@ -360,8 +372,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=N.º de ofertas: {0} offerbook.volume={0} (mín. - máx.) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=Criar oferta para {0} {1} offerbook.createOfferToBuy=Criar oferta para comprar {0} offerbook.createOfferToSell=Criar oferta para vender {0} @@ -390,6 +403,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=A quantia permitida para a negociação está limitada a {0} devido a restrições de segurança baseadas nos seguintes critérios:\n- A conta do comprador não foi assinada por um árbitro ou um par\n- A conta do comprador foi assinada há menos de 30 dias\n- O meio de pagamento para essa oferta é considerado de risco para estornos bancários.\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=A quantia permitida para a negociação está limitada a {0} devido a restrições de segurança baseadas nos seguintes critérios:\n- A sua conta não foi assinada por um árbitro ou um par\n- A sua conta foi assinada há menos de 30 dias\n- O meio de pagamento para essa oferta é considerado de risco para estornos bancários.\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Este método de pagamento está temporariamente limitado a {0} até {1} porque todos os compradores têm novas contas.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Sua oferta será limitada a compradores com contas assinadas e antigas porque excede {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Essa oferta requer uma versão do protocolo diferente da usada em sua versão do software.\n\nVerifique se você possui a versão mais nova instalada, caso contrário o usuário que criou a oferta usou uma versão ultrapassada.\n\nUsuários não podem negociar com uma versão incompatível do protocolo. offerbook.warning.userIgnored=Você adicionou o endereço onion à sua lista de endereços ignorados. @@ -397,7 +412,6 @@ offerbook.warning.offerBlocked=Essa oferta foi bloqueada pelos desenvolvedores d offerbook.warning.currencyBanned=A moeda usada nesta oferta foi bloqueada pelos desenvolvedores do Haveno.\nPor favor, visite o Fórum do Haveno para maiores informações. offerbook.warning.paymentMethodBanned=O método de pagamento usado nesta oferta foi bloqueado pelos desenvolvedores do Haveno.\nPor favor, visite o Fórum do Haveno para maiores informações. offerbook.warning.nodeBlocked=O endereço onion daquele negociador foi bloqueado pelos desenvolvedores do Haveno.\nProvavelmente há um problema não resolvido associado àquele negociador. -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=Você irá vender a preço de mercado (atualizado a cada minuto). @@ -415,13 +429,13 @@ offerbook.info.roundedFiatVolume=O valor foi arredondado para aumentar a privaci # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Insira o valor em BTC +createOffer.amount.prompt=Insira o valor em XMR createOffer.price.prompt=Insira o preço createOffer.volume.prompt=Insira o valor em {0} -createOffer.amountPriceBox.amountDescription=Quantia em BTC para {0} +createOffer.amountPriceBox.amountDescription=Quantia em XMR para {0} createOffer.amountPriceBox.buy.volumeDescription=Valor em {0} a ser gasto createOffer.amountPriceBox.sell.volumeDescription=Valor em {0} a ser recebido -createOffer.amountPriceBox.minAmountDescription=Quantia mínima de BTC +createOffer.amountPriceBox.minAmountDescription=Quantia mínima de XMR createOffer.securityDeposit.prompt=Depósito de segurança createOffer.fundsBox.title=Financie sua oferta createOffer.fundsBox.offerFee=Taxa de negociação @@ -437,7 +451,7 @@ createOffer.info.sellAboveMarketPrice=Você irá sempre receber {0}% a mais do q createOffer.info.buyBelowMarketPrice=Você irá sempre pagar {0}% a menos do que o atual preço de mercado e o preço de sua oferta será atualizado constantemente. createOffer.warning.sellBelowMarketPrice=Você irá sempre receber {0}% a menos do que o atual preço de mercado e o preço da sua oferta será atualizado constantemente. createOffer.warning.buyAboveMarketPrice=Você irá sempre pagar {0}% a mais do que o atual preço de mercado e o preço da sua oferta será atualizada constantemente. -createOffer.tradeFee.descriptionBTCOnly=Taxa de negociação +createOffer.tradeFee.descriptionXMROnly=Taxa de negociação createOffer.tradeFee.descriptionBSQEnabled=Escolha a moeda da taxa de transação createOffer.triggerPrice.prompt=Set optional trigger price @@ -451,7 +465,12 @@ createOffer.placeOfferButton=Revisar: Criar oferta para {0} monero createOffer.createOfferFundWalletInfo.headline=Financiar sua oferta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Quantia da negociação: {0} \n -createOffer.createOfferFundWalletInfo.msg=Você precisa depositar {0} para esta oferta.\n\nEsses fundos ficam reservados na sua carteira local e ficarão travados no endereço de depósito multisig quando alguém aceitar a sua oferta.\n\nA quantia equivale à soma de:\n{1}- Seu depósito de segurança: {2}\n- Taxa de negociação: {3}\n- Taxa de mineração: {4}\n\nVocê pode financiar sua negociação das seguintes maneiras:\n- Usando a sua carteira Haveno (conveniente, mas transações poderão ser associadas entre si) OU\n- Usando uma carteira externa (maior privacidade)\n\nVocê verá todas as opções de financiamento e detalhes após fechar esta janela. +createOffer.createOfferFundWalletInfo.msg=Você precisa depositar {0} para esta oferta.\n\n\ + Esses fundos são reservados em sua carteira local e serão bloqueados em uma carteira multisig assim que alguém aceitar sua oferta.\n\n\ + O valor é a soma de:\n\ + {1}\ + - Seu depósito de segurança: {2}\n\ + - Taxa de negociação: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Um erro ocorreu ao emitir uma oferta:\n\n{0}\n\nNenhum fundo foi retirado de sua carteira até agora.\nPor favor, reinicie o programa e verifique sua conexão de internet. @@ -461,7 +480,7 @@ createOffer.timeoutAtPublishing=Um erro ocorreu ao publicar a oferta: tempo esgo createOffer.errorInfo=\n\nA taxa já está paga. No pior dos casos, você perdeu essa taxa.\nPor favor, tente reiniciar o seu aplicativo e verifique sua conexão de rede para ver se você pode resolver o problema. createOffer.tooLowSecDeposit.warning=Você definiu o depósito de segurança para um valor mais baixo do que o valor padrão recomendado de {0}.\nVocê tem certeza de que deseja usar um depósito de segurança menor? createOffer.tooLowSecDeposit.makerIsSeller=Há menos proteção caso a outra parte da negociação não siga o protocolo de negociação. -createOffer.tooLowSecDeposit.makerIsBuyer=Os seus compradores se sentirão menos seguros, pois você terá menos bitcoins sob risco. Isso pode fazer com que eles prefiram escolher outras ofertas ao invés da sua. +createOffer.tooLowSecDeposit.makerIsBuyer=Os seus compradores se sentirão menos seguros, pois você terá menos moneros sob risco. Isso pode fazer com que eles prefiram escolher outras ofertas ao invés da sua. createOffer.resetToDefault=Não, voltar ao valor padrão createOffer.useLowerValue=Sim, usar meu valor mais baixo createOffer.priceOutSideOfDeviation=O preço submetido está fora do desvio máximo com relação ao preço de mercado.\nO desvio máximo é {0} e pode ser alterado nas preferências. @@ -473,30 +492,35 @@ createOffer.setDepositAsBuyer=Definir o meu depósito de segurança como comprad createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=O seu depósito de segurança do comprador será de {0} createOffer.securityDepositInfoAsBuyer=O seu depósito de segurança como comprador será de {0} -createOffer.minSecurityDepositUsed=Depósito de segurança mínimo para compradores foi usado +createOffer.minSecurityDepositUsed=O depósito de segurança mínimo é utilizado +createOffer.buyerAsTakerWithoutDeposit=Nenhum depósito necessário do comprador (protegido por senha) +createOffer.myDeposit=Meu depósito de segurança (%) +createOffer.myDepositInfo=Seu depósito de segurança será {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Insira a quantia em BTC -takeOffer.amountPriceBox.buy.amountDescription=Quantia de BTC para vender -takeOffer.amountPriceBox.sell.amountDescription=Quantia de BTC para comprar -takeOffer.amountPriceBox.priceDescription=Preço por bitcoin em {0} +takeOffer.amount.prompt=Insira a quantia em XMR +takeOffer.amountPriceBox.buy.amountDescription=Quantia de XMR para vender +takeOffer.amountPriceBox.sell.amountDescription=Quantia de XMR para comprar +takeOffer.amountPriceBox.priceDescription=Preço por monero em {0} takeOffer.amountPriceBox.amountRangeDescription=Quantias permitidas -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=A quantia que você inseriu excede o número máximo de casas decimais permitida.\nA quantia foi ajustada para 4 casas decimais. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=A quantia que você inseriu excede o número máximo de casas decimais permitida.\nA quantia foi ajustada para 4 casas decimais. takeOffer.validation.amountSmallerThanMinAmount=A quantia não pode ser inferior à quantia mínima definida na oferta. takeOffer.validation.amountLargerThanOfferAmount=A quantia inserida não pode ser superior à quantia definida na oferta. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Essa quantia inserida criaria um troco pequeno demais para o vendedor de BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Essa quantia inserida criaria um troco pequeno demais para o vendedor de XMR. takeOffer.fundsBox.title=Financiar sua negociação takeOffer.fundsBox.isOfferAvailable=Verificando se a oferta está disponível ... takeOffer.fundsBox.tradeAmount=Quantia a ser vendida takeOffer.fundsBox.offerFee=Taxa de negociação takeOffer.fundsBox.networkFee=Total em taxas de mineração -takeOffer.fundsBox.takeOfferSpinnerInfo=Aceitação da oferta em progresso ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Aceitando a oferta: {0} takeOffer.fundsBox.paymentLabel=negociação Haveno com ID {0} takeOffer.fundsBox.fundsStructure=({0} depósito de segurança, {1} taxa de transação, {2} taxa de mineração) +takeOffer.fundsBox.noFundingRequiredTitle=Sem financiamento necessário +takeOffer.fundsBox.noFundingRequiredDescription=Obtenha a frase secreta da oferta com o vendedor fora do Haveno para aceitar esta oferta. takeOffer.success.headline=Você aceitou uma oferta com sucesso. takeOffer.success.info=Você pode ver o status de sua negociação em \"Portfolio/Negociações em aberto\". takeOffer.error.message=Ocorreu um erro ao aceitar a oferta.\n\n{0} @@ -507,7 +531,7 @@ takeOffer.noPriceFeedAvailable=Você não pode aceitar essa oferta pois ela usa takeOffer.takeOfferFundWalletInfo.headline=Financiar sua negociação # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Quantia a negociar: {0} \n -takeOffer.takeOfferFundWalletInfo.msg=Você precisa depositar {0} para aceitar esta oferta.\n\nA quantia equivale a soma de:\n{1}- Seu depósito de segurança: {2}\n- Taxa de negociação: {3}\n- Taxas de mineração: {4}\n\nVocê pode escolher entre duas opções para financiar sua negociação:\n- Usar a sua carteira Haveno (conveniente, mas transações podem ser associadas entre si) OU\n- Transferir a partir de uma carteira externa (potencialmente mais privado)\n\nVocê verá todas as opções de financiamento e detalhes após fechar esta janela. +takeOffer.takeOfferFundWalletInfo.msg=Você precisa depositar {0} para aceitar esta oferta.\n\nO valor é a soma de:\n{1}- Seu depósito de segurança: {2}\n- Taxa de negociação: {3} takeOffer.alreadyPaidInFunds=Se você já pagou por essa oferta, você pode retirar seus fundos na seção \"Fundos/Enviar fundos\". takeOffer.paymentInfo=Informações de pagamento takeOffer.setAmountPrice=Definir quantia @@ -600,29 +624,29 @@ portfolio.pending.step1.openForDispute=A transação de depósito ainda não foi # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Transfira com a sua carteira {0} externa\n{1} para o vendedor de BTC.\n\n +portfolio.pending.step2_buyer.crypto=Transfira com a sua carteira {0} externa\n{1} para o vendedor de XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Vá ao banco e pague {0} ao vendedor de BTC.\n\n -portfolio.pending.step2_buyer.cash.extra=IMPORTANTE:\nApós executar o pagamento, escreva no comprovante de depósito: SEM REEMBOLSO\nEntão rasgue-o em 2 partes, tire uma foto e envie-a para o e-mail do vendedor de BTC. +portfolio.pending.step2_buyer.cash=Vá ao banco e pague {0} ao vendedor de XMR.\n\n +portfolio.pending.step2_buyer.cash.extra=IMPORTANTE:\nApós executar o pagamento, escreva no comprovante de depósito: SEM REEMBOLSO\nEntão rasgue-o em 2 partes, tire uma foto e envie-a para o e-mail do vendedor de XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Pague {0} ao vendedor de BTC usando MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=IMPORTANTE:\nApós ter feito o pagamento, envie o número de autorização e uma foto do comprovante por e-mail para o vendedor de BTC.\nO comprovante deve exibir claramente o nome completo, o país e o estado do vendedor, assim como a quantia. O e-mail do vendedor é: {0}. +portfolio.pending.step2_buyer.moneyGram=Pague {0} ao vendedor de XMR usando MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=IMPORTANTE:\nApós ter feito o pagamento, envie o número de autorização e uma foto do comprovante por e-mail para o vendedor de XMR.\nO comprovante deve exibir claramente o nome completo, o país e o estado do vendedor, assim como a quantia. O e-mail do vendedor é: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Pague {0} ao vendedor de BTC usando Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=IMPORTANTE:\nApós ter feito o pagamento, envie o número de rastreamento (MTCN) e uma foto do comprovante por e-mail para o vendedor de BTC.\nO comprovante deve exibir claramente o nome completo, o país e o estado do vendedor, assim como a quantia. O e-mail do vendedor é: {0}. +portfolio.pending.step2_buyer.westernUnion=Pague {0} ao vendedor de XMR usando Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=IMPORTANTE:\nApós ter feito o pagamento, envie o número de rastreamento (MTCN) e uma foto do comprovante por e-mail para o vendedor de XMR.\nO comprovante deve exibir claramente o nome completo, o país e o estado do vendedor, assim como a quantia. O e-mail do vendedor é: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Envie {0} através de \"US Postal Money Order\" para o vendedor de BTC.\n\n +portfolio.pending.step2_buyer.postal=Envie {0} através de \"US Postal Money Order\" para o vendedor de XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Por favor, entre em contato com o vendedor de BTC através do contato fornecido e combine um encontro para pagá-lo {0}.\n\n +portfolio.pending.step2_buyer.f2f=Por favor, entre em contato com o vendedor de XMR através do contato fornecido e combine um encontro para pagá-lo {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Iniciar pagamento usando {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=Quantia a ser transferida @@ -631,27 +655,27 @@ portfolio.pending.step2_buyer.buyerAccount=A sua conta de pagamento a ser usada portfolio.pending.step2_buyer.paymentSent=Pagamento iniciado portfolio.pending.step2_buyer.warn=Você ainda não realizou seu pagamento de {0}!\nEssa negociação deve ser completada até {1}. portfolio.pending.step2_buyer.openForDispute=Você ainda não completou o seu pagamento!\nO período máximo para a negociação já passou. Entre em contato com o mediador para pedir assistência. -portfolio.pending.step2_buyer.paperReceipt.headline=Você enviou o comprovante de depósito para o vendedor de BTC? -portfolio.pending.step2_buyer.paperReceipt.msg=Lembre-se:\nVocê deve escrever no comprovante de depósito: SEM REEMBOLSO\nA seguir, rasgue-o em duas partes, tire uma foto e envie-a para o e-mail do vendedor de BTC. +portfolio.pending.step2_buyer.paperReceipt.headline=Você enviou o comprovante de depósito para o vendedor de XMR? +portfolio.pending.step2_buyer.paperReceipt.msg=Lembre-se:\nVocê deve escrever no comprovante de depósito: SEM REEMBOLSO\nA seguir, rasgue-o em duas partes, tire uma foto e envie-a para o e-mail do vendedor de XMR. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Enviar o número de autorização e o comprovante de depósito -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Você previsa enviar por-email para o vendedor BTC o número de autorização e uma foto com o comprovante de depósito.\nO comprovante deve mostrar claramente o nome completo, o país e o estado do vendedor, assim como a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o número de autorização e o contrato ao vendedor? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Você previsa enviar por-email para o vendedor XMR o número de autorização e uma foto com o comprovante de depósito.\nO comprovante deve mostrar claramente o nome completo, o país e o estado do vendedor, assim como a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o número de autorização e o contrato ao vendedor? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Enviar MTCN e comprovante -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Você precisa enviar o MTCN (número de rastreamento) e uma foto do recibo por e-mail para o vendedor de BTC.\nO recibo deve mostrar claramente o nome completo do vendedor, a cidade, o país e a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o MTCN e o contrato para o vendedor? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Você precisa enviar o MTCN (número de rastreamento) e uma foto do recibo por e-mail para o vendedor de XMR.\nO recibo deve mostrar claramente o nome completo do vendedor, a cidade, o país e a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o MTCN e o contrato para o vendedor? portfolio.pending.step2_buyer.halCashInfo.headline=Enviar código HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=Você precisa enviar uma mensagem de texto com o código HalCash, bem como o ID da negociação ({0}) para o vendedor BTC.\nO nº do telefone do vendedor é {1}.\n\nVocê enviou o código para o vendedor? +portfolio.pending.step2_buyer.halCashInfo.msg=Você precisa enviar uma mensagem de texto com o código HalCash, bem como o ID da negociação ({0}) para o vendedor XMR.\nO nº do telefone do vendedor é {1}.\n\nVocê enviou o código para o vendedor? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Alguns bancos podem verificar o nome do destinatário. Contas de pagamento rápido criadas numa versão antiga da Haveno não fornecem o nome do destinatário, então, por favor, use o chat de negociação pra obtê-lo (caso necessário). portfolio.pending.step2_buyer.confirmStart.headline=Confirme que você iniciou o pagamento portfolio.pending.step2_buyer.confirmStart.msg=Você iniciou o pagamento {0} para o seu parceiro de negociação? portfolio.pending.step2_buyer.confirmStart.yes=Sim, iniciei o pagamento portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=Aguardar pagamento portfolio.pending.step2_seller.f2fInfo.headline=Informações de contato do comprador -portfolio.pending.step2_seller.waitPayment.msg=A transação de depósito tem pelo menos uma confirmação blockchain do protocolo.\nVocê precisa aguardar até que o comprador de BTC inicie o pagamento de {0}. -portfolio.pending.step2_seller.warn=O comprador de BTC ainda não fez o pagamento de {0}.\nVocê precisa esperar até que ele inicie o pagamento.\nCaso a negociação não conclua em {1}, o árbitro irá investigar. -portfolio.pending.step2_seller.openForDispute=O comprador de BTC ainda não iniciou o pagamento!\nO período máximo permitido para a negociação expirou.\nVocê pode aguardar mais um pouco, dando mais tempo para o seu parceiro de negociação, ou você pode entrar em contato com o mediador para pedir assistência. +portfolio.pending.step2_seller.waitPayment.msg=A transação de depósito tem pelo menos uma confirmação blockchain do protocolo.\nVocê precisa aguardar até que o comprador de XMR inicie o pagamento de {0}. +portfolio.pending.step2_seller.warn=O comprador de XMR ainda não fez o pagamento de {0}.\nVocê precisa esperar até que ele inicie o pagamento.\nCaso a negociação não conclua em {1}, o árbitro irá investigar. +portfolio.pending.step2_seller.openForDispute=O comprador de XMR ainda não iniciou o pagamento!\nO período máximo permitido para a negociação expirou.\nVocê pode aguardar mais um pouco, dando mais tempo para o seu parceiro de negociação, ou você pode entrar em contato com o mediador para pedir assistência. tradeChat.chatWindowTitle=Abrir janela de conversa para a negociação com ID "{0}" tradeChat.openChat=Abrir janela de conversa tradeChat.rules=Você pode conversar com seu par da negociação para resolver potenciais problemas desta negociação.\nNão é obrigatório responder no chat.\nSe um negociante violar qualquer das regras abaixo, abra uma disputa e reporte o caso ao mediador ou árbitro.\n\nRegras do chat:\n\t● Não envie nenhum link (risco de malware). Você pode enviar a ID de transação e o nome de um explorador de blocos.\n\t● Não envie suas palavras-semente, chaves privadas, senhas ou outras informações sensíveis!\n\t● Não encoraje negociações fora da Haveno (sem segurança).\n\t● Não tente aplicar golpes por meio de qualquer forma de engenharia social.\n\t● Se o par não responder e preferir não se comunicar pelo chat, respeite essa decisão.\n\t● Mantenha o escopo da conversa limitado à negociação. Este chat não é um substituto de aplicativos de mensagens ou local para trolagens.\n\t● Mantenha a conversa amigável e respeitosa. @@ -669,26 +693,26 @@ message.state.ACKNOWLEDGED=O destinário confirmou o recebimento da mensagem # suppress inspection "UnusedProperty" message.state.FAILED=Erro ao enviar a mensagem -portfolio.pending.step3_buyer.wait.headline=Aguarde confirmação de pagamento do vendedor de BTC. -portfolio.pending.step3_buyer.wait.info=Aguardando o vendedor de BTC confirmar o recebimento do pagamento de {0}. +portfolio.pending.step3_buyer.wait.headline=Aguarde confirmação de pagamento do vendedor de XMR. +portfolio.pending.step3_buyer.wait.info=Aguardando o vendedor de XMR confirmar o recebimento do pagamento de {0}. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Status da mensagem de pagamento iniciado portfolio.pending.step3_buyer.warn.part1a=na blockchain {0} portfolio.pending.step3_buyer.warn.part1b=no seu provedor de pagamentos (ex: seu banco) -portfolio.pending.step3_buyer.warn.part2=O vendedor de BTC ainda não confirmou o seu pagamento. Por favor, verifique em {0} se o pagamento foi enviado com sucesso. -portfolio.pending.step3_buyer.openForDispute=O vendedor de BTC não confirmou o seu pagamento! O período máximo para essa negociação expirou. Você pode aguardar mais um pouco, dando mais tempo para o seu parceiro de negociação, ou você pode pedir a assistência de um mediador. +portfolio.pending.step3_buyer.warn.part2=O vendedor de XMR ainda não confirmou o seu pagamento. Por favor, verifique em {0} se o pagamento foi enviado com sucesso. +portfolio.pending.step3_buyer.openForDispute=O vendedor de XMR não confirmou o seu pagamento! O período máximo para essa negociação expirou. Você pode aguardar mais um pouco, dando mais tempo para o seu parceiro de negociação, ou você pode pedir a assistência de um mediador. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Seu parceiro de negociação confirmou que iniciou o pagamento de {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=no seu explorador da blockchain {0} preferido portfolio.pending.step3_seller.crypto.wallet=em sua carteira {0} portfolio.pending.step3_seller.crypto={0}Verifique em {1} se a transação para o seu endereço de recebimento\n{2}\njá tem confirmações suficientes na blockchain.\nA quantia do pagamento deve ser {3}\n\nVocê pode copiar e colar seu endereço {4} na janela principal, após fechar esse popup. -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=Como o pagamento é realizado através de depósito de dinheiro em espécie, o comprador de BTC obrigatoriamente deve escrever \"SEM REEMBOLSO\" no comprovante de depósito, rasgá-lo em duas partes e enviar uma foto do comprovante para você por e-mail.\n\nPara reduzir a chance de um reembolso (restituição do valor depositado para o comprador), confirme apenas se você tiver recebido o e-mail e tiver certeza de que o comprovante de depósito é autêntico.\nSe você não tiver certeza, {0} -portfolio.pending.step3_seller.moneyGram=O comprador deve enviar o Número de Autorização e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente o seu nome completo, país, estado e a quantia. Por favor verifique seu e-mail se recebeu o Número de Autorização.\n\nDepois de fechar esse pop-up, verá o nome e o endereço do comprador do BTC para retirar o dinheiro da MoneyGram.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! -portfolio.pending.step3_seller.westernUnion=O comprador deve enviar-lhe o MTCN (número de rastreamento) e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente seu nome completo, cidade, país e a quantia Por favor verifique no seu e-mail se você recebeu o MTCN.\n\nDepois de fechar esse pop-up, você verá o nome e endereço do comprador de BTC para receber o dinheiro da Western Union.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=Como o pagamento é realizado através de depósito de dinheiro em espécie, o comprador de XMR obrigatoriamente deve escrever \"SEM REEMBOLSO\" no comprovante de depósito, rasgá-lo em duas partes e enviar uma foto do comprovante para você por e-mail.\n\nPara reduzir a chance de um reembolso (restituição do valor depositado para o comprador), confirme apenas se você tiver recebido o e-mail e tiver certeza de que o comprovante de depósito é autêntico.\nSe você não tiver certeza, {0} +portfolio.pending.step3_seller.moneyGram=O comprador deve enviar o Número de Autorização e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente o seu nome completo, país, estado e a quantia. Por favor verifique seu e-mail se recebeu o Número de Autorização.\n\nDepois de fechar esse pop-up, verá o nome e o endereço do comprador do XMR para retirar o dinheiro da MoneyGram.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! +portfolio.pending.step3_seller.westernUnion=O comprador deve enviar-lhe o MTCN (número de rastreamento) e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente seu nome completo, cidade, país e a quantia Por favor verifique no seu e-mail se você recebeu o MTCN.\n\nDepois de fechar esse pop-up, você verá o nome e endereço do comprador de XMR para receber o dinheiro da Western Union.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! portfolio.pending.step3_seller.halCash=O comprador deve-lhe enviar o código HalCash como mensagem de texto. Além disso, você receberá uma mensagem do HalCash com as informações necessárias para sacar o EUR de uma ATM que suporte o HalCash.\n\nDepois de retirar o dinheiro na ATM, confirme aqui o recibo do pagamento! portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. @@ -704,7 +728,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID da Transação portfolio.pending.step3_seller.xmrTxKey=Transaction key portfolio.pending.step3_seller.buyersAccount=Buyers account data portfolio.pending.step3_seller.confirmReceipt=Confirmar recebimento do pagamento -portfolio.pending.step3_seller.buyerStartedPayment=O comprador de BTC iniciou o pagamento {0}.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=O comprador de XMR iniciou o pagamento {0}.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Verifique as confirmações de transação em sua carteira crypto ou explorador de blockchain e confirme o pagamento quando houver confirmações suficientes. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Verifique em sua conta de negociação (ex: sua conta bancária) e confirme que recebeu o pagamento. portfolio.pending.step3_seller.warn.part1a=na blockchain {0} @@ -716,7 +740,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Você recebeu o pagamento # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Verifique também se o nome de quem envia o pagamento no contrato de negociação é o mesmo que aparece em seu extrato bancário:\nNome do pagante, pelo contrato de negociação: {0}\n\nSe os nomes não forem exatamente iguais, não confirme o recebimento do pagamento. Em vez disso, abra uma disputa pressionando \"alt + o\" or \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Assim que você confirmar o recebimento do pagamento, o valor da transação será liberado para o comprador de BTC e o depósito de segurança será devolvido.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Assim que você confirmar o recebimento do pagamento, o valor da transação será liberado para o comprador de XMR e o depósito de segurança será devolvido.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Confirmar recebimento do pagamento portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Sim, eu recebi o pagamento portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANTE: Ao confirmar o recebimento do pagamento, você também estará verificando a conta do seu par e a assinando. Como a conta do seu par ainda não foi assinada, você deve segurar a confirmação do pagamento o máximo de tempo possível para reduzir o risco de estorno. @@ -726,7 +750,7 @@ portfolio.pending.step5_buyer.tradeFee=Taxa de negociação portfolio.pending.step5_buyer.makersMiningFee=Taxa de mineração portfolio.pending.step5_buyer.takersMiningFee=Total em taxas de mineração portfolio.pending.step5_buyer.refunded=Depósito de segurança devolvido -portfolio.pending.step5_buyer.withdrawBTC=Retirar seus bitcoins +portfolio.pending.step5_buyer.withdrawXMR=Retirar seus moneros portfolio.pending.step5_buyer.amount=Quantia a ser retirada portfolio.pending.step5_buyer.withdrawToAddress=Enviar para o endereço portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet @@ -735,7 +759,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Seus fundos já foram retirados.\ portfolio.pending.step5_buyer.confirmWithdrawal=Confirmar solicitação de retirada portfolio.pending.step5_buyer.amountTooLow=A quantia a ser transferida é inferior à taxa de transação e o valor mínimo de transação (poeira). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Retirada concluída -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Suas negociações concluídas estão salvas em \"Portfolio/Histórico\".\nVocê pode rever todas as suas transações bitcoin em \"Fundos/Transações\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Suas negociações concluídas estão salvas em \"Portfolio/Histórico\".\nVocê pode rever todas as suas transações monero em \"Fundos/Transações\" portfolio.pending.step5_buyer.bought=Você comprou portfolio.pending.step5_buyer.paid=Você pagou @@ -797,7 +821,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Você já aceitou portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -836,7 +860,7 @@ funds.deposit.fundHavenoWallet=Financiar carteira Haveno funds.deposit.noAddresses=Nenhum endereço de depósito foi gerado ainda funds.deposit.fundWallet=Financiar sua carteira funds.deposit.withdrawFromWallet=Enviar fundos da carteira -funds.deposit.amount=Quantia em BTC (opcional) +funds.deposit.amount=Quantia em XMR (opcional) funds.deposit.generateAddress=Gerar um endereço novo funds.deposit.generateAddressSegwit=Native segwit format (Bech32) funds.deposit.selectUnused=Selecione um endereço não utilizado da tabela acima ao invés de gerar um novo. @@ -893,7 +917,7 @@ funds.tx.revert=Reverter funds.tx.txSent=Transação enviada com sucesso para um novo endereço em sua carteira Haveno local. funds.tx.direction.self=Enviar para você mesmo funds.tx.dustAttackTx=Poeira recebida -funds.tx.dustAttackTx.popup=Esta transação está enviando uma quantia muito pequena de BTC para a sua carteira e pode ser uma tentativa das empresas de análise da blockchain para espionar a sua carteira.\n\nSe você usar esse output em uma transação eles decobrirão que você provavelmente também é o proprietário de outros endereços (mistura de moedas).\n\nPara proteger sua privacidade a carteira Haveno ignora tais outputs de poeira para fins de consumo e na tela de saldo. Você pode definir a quantia limite a partir da qual um output é considerado poeira nas configurações." +funds.tx.dustAttackTx.popup=Esta transação está enviando uma quantia muito pequena de XMR para a sua carteira e pode ser uma tentativa das empresas de análise da blockchain para espionar a sua carteira.\n\nSe você usar esse output em uma transação eles decobrirão que você provavelmente também é o proprietário de outros endereços (mistura de moedas).\n\nPara proteger sua privacidade a carteira Haveno ignora tais outputs de poeira para fins de consumo e na tela de saldo. Você pode definir a quantia limite a partir da qual um output é considerado poeira nas configurações." #################################################################### # Support @@ -907,7 +931,6 @@ support.filter=Search disputes support.filter.prompt=Insira ID da negociação. data. endereço onion ou dados da conta support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -943,8 +966,8 @@ support.savedInMailbox=Mensagem guardada na caixa de correio do destinatário. support.arrived=Mensagem chegou no destinatário support.acknowledged=O destinatário confirmou a chegada da mensagem support.error=O destinatário não pôde processar a mensagem. Erro: {0} -support.buyerAddress=Endereço do comprador de BTC -support.sellerAddress=Endereço do vendedor de BTC +support.buyerAddress=Endereço do comprador de XMR +support.sellerAddress=Endereço do vendedor de XMR support.role=Função support.agent=Support agent support.state=Estado @@ -952,13 +975,13 @@ support.chat=Chat support.closed=Fechado support.open=Aberto support.process=Process -support.buyerMaker=Comprador de BTC / Ofetante -support.sellerMaker=Vendedor de BTC / Ofertante -support.buyerTaker=Comprador de BTC / Aceitador da oferta -support.sellerTaker=Vendedor de BTC / Aceitador da oferta +support.buyerMaker=Comprador de XMR / Ofetante +support.sellerMaker=Vendedor de XMR / Ofertante +support.buyerTaker=Comprador de XMR / Aceitador da oferta +support.sellerTaker=Vendedor de XMR / Aceitador da oferta -support.backgroundInfo=Haveno não é uma empresa, então ela lida com disputas de uma forma diferente.\n\nComerciantes podem se comunicar dentro do aplicativo usando um chat seguro na tela de negociações em aberto para tentar resolver conflitos entre eles mesmos. Se isto não for o suficiente, um mediador pode intervir para ajudar. O mediador irá avaliar a situação e sugerir um pagamento. Se ambos comerciantes aceitarem essa sugestão, a transação de pagamento é finalizada e a negociação é fechada. Se um or ambos os comerciantes não concordarem com o pagamento sugerido pelo mediador, eles podem solicitar arbitragem. O árbitro irá reavaliar a situação e, se justificado, pagará pessoalmente o comerciante e então solicitará reembolso deste pagamento à DAO Haveno. -support.initialInfo=Por favor, entre a descrição do seu problema no campo de texto abaixo. Informe o máximo de informações que puder para agilizar a resolução da disputa.\n\nSegue uma lista com as informações que você deve fornecer:\n\t● Se você está comprando BTC: Você fez a transferência do dinheiro ou crypto? Caso afirmativo, você clicou no botão 'pagamento iniciado' no aplicativo?\n\t● Se você está vendendo BTC: Você recebeu o pagamento em dinheiro ou em crypto? Caso afirmativo, você clicou no botão 'pagamento recebido' no aplicativo?\n\t● Qual versão da Haveno você está usando?\n\t● Qual sistema operacional você está usando?\n\t● Se seu problema é com falhas em transações, por favor considere usar um novo diretório de dados.\n\t Às vezes, o diretório de dados pode ficar corrompido, causando bugs estranhos.\n\t Veja mais: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPor favor, familiarize-se com as regras básicas do processo de disputa:\n\t● Você precisa responder às solicitações de {0}' dentro do prazo de 2 dias.\n\t● Mediadores respondem dentro de 2 dias. Ábitros respondem dentro de 5 dias úteis.\n\t● O período máximo para uma disputa é de 14 dias.\n\t● Você deve cooperar com o {1} e providenciar as informações requisitadas para comprovar o seu caso.\n\t● Você aceitou as regras estipuladas nos termos de acordo do usuário que foi exibido na primeira vez em que você iniciou o aplicativo. \nVocê pode saber mais sobre o processo de disputa em: {2} +support.backgroundInfo=Haveno não é uma empresa, portanto, trata as disputas de forma diferente.\n\nOs negociantes podem se comunicar dentro do aplicativo por meio de um chat seguro na tela de negociações em aberto para tentar resolver disputas por conta própria. Se isso não for suficiente, um árbitro avaliará a situação e decidirá o pagamento dos fundos da negociação. +support.initialInfo=Por favor, entre a descrição do seu problema no campo de texto abaixo. Informe o máximo de informações que puder para agilizar a resolução da disputa.\n\nSegue uma lista com as informações que você deve fornecer:\n\t● Se você está comprando XMR: Você fez a transferência do dinheiro ou crypto? Caso afirmativo, você clicou no botão 'pagamento iniciado' no aplicativo?\n\t● Se você está vendendo XMR: Você recebeu o pagamento em dinheiro ou em crypto? Caso afirmativo, você clicou no botão 'pagamento recebido' no aplicativo?\n\t● Qual versão da Haveno você está usando?\n\t● Qual sistema operacional você está usando?\n\t● Se seu problema é com falhas em transações, por favor considere usar um novo diretório de dados.\n\t Às vezes, o diretório de dados pode ficar corrompido, causando bugs estranhos.\n\t Veja mais: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPor favor, familiarize-se com as regras básicas do processo de disputa:\n\t● Você precisa responder às solicitações de {0}' dentro do prazo de 2 dias.\n\t● Mediadores respondem dentro de 2 dias. Ábitros respondem dentro de 5 dias úteis.\n\t● O período máximo para uma disputa é de 14 dias.\n\t● Você deve cooperar com o {1} e providenciar as informações requisitadas para comprovar o seu caso.\n\t● Você aceitou as regras estipuladas nos termos de acordo do usuário que foi exibido na primeira vez em que você iniciou o aplicativo. \nVocê pode saber mais sobre o processo de disputa em: {2} support.systemMsg=Mensagem do sistema: {0} support.youOpenedTicket=Você abriu um pedido de suporte.\n\n{0}\n\nHaveno versão: {1} support.youOpenedDispute=Você abriu um pedido para uma disputa.\n\n{0}\n\nHaveno versão: {1} @@ -982,13 +1005,14 @@ settings.tab.network=Informações da rede settings.tab.about=Sobre setting.preferences.general=Preferências gerais -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Desvio máx. do preço do mercado setting.preferences.avoidStandbyMode=Impedir modo de economia de energia +setting.preferences.useSoundForNotifications=Reproduzir sons para notificações setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Valores acima de {0}% não são permitidos. setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1025,29 +1049,31 @@ settings.preferences.editCustomExplorer.name=Nome settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=Rede Bitcoin +settings.net.xmrHeader=Rede Monero settings.net.p2pHeader=Rede Haveno settings.net.onionAddressLabel=Meu endereço onion settings.net.xmrNodesLabel=Usar nodos personalizados do Monero settings.net.moneroPeersLabel=Pares conectados +settings.net.connection=Conexão +settings.net.connected=Conectado settings.net.useTorForXmrJLabel=Usar Tor na rede Monero settings.net.moneroNodesLabel=Conexão a nodos do Monero -settings.net.useProvidedNodesRadio=Usar nodos do Bitcoin Core fornecidos -settings.net.usePublicNodesRadio=Usar rede pública do Bitcoin -settings.net.useCustomNodesRadio=Usar nodos personalizados do Bitcoin Core +settings.net.useProvidedNodesRadio=Usar nodos do Monero Core fornecidos +settings.net.usePublicNodesRadio=Usar rede pública do Monero +settings.net.useCustomNodesRadio=Usar nodos personalizados do Monero Core settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=Não, usar os nodos fornecidos settings.net.warn.usePublicNodes.usePublic=Sim, usar rede pública -settings.net.warn.useCustomNodes.B2XWarning=Certifique-se de que o seu nodo Bitcoin é um nodo Bitcoin Core confiável!\n\nAo se conectar a nodos que não estão seguindo as regras de consenso do Bitcoin Core, você pode corromper a sua carteira e causar problemas no processo de negociação.\n\nOs usuários que se conectam a nodos que violam as regras de consenso são responsáveis pelos danos que forem criados por isso. As disputas causadas por esse motivo serão decididas a favor do outro negociante. Nenhum suporte técnico será fornecido para os usuários que ignorarem esse aviso e os mecanismos de proteção! -settings.net.warn.invalidBtcConfig=A conexão com a rede Bitcoin falhou porque suas configurações são inválidas.\n\nSuas configurações foram resetadas para utilizar os nós fornecidos da rede Bitcoin. É necessário reiniciar o aplicativo. -settings.net.localhostXmrNodeInfo=Informações básicas: Haveno busca por um nó Bitcoin local na inicialização. Caso encontre, Haveno irá comunicar com a rede Bitcoin exclusivamente através deste nó. +settings.net.warn.useCustomNodes.B2XWarning=Certifique-se de que o seu nodo Monero é um nodo Monero Core confiável!\n\nAo se conectar a nodos que não estão seguindo as regras de consenso do Monero Core, você pode corromper a sua carteira e causar problemas no processo de negociação.\n\nOs usuários que se conectam a nodos que violam as regras de consenso são responsáveis pelos danos que forem criados por isso. As disputas causadas por esse motivo serão decididas a favor do outro negociante. Nenhum suporte técnico será fornecido para os usuários que ignorarem esse aviso e os mecanismos de proteção! +settings.net.warn.invalidXmrConfig=A conexão com a rede Monero falhou porque suas configurações são inválidas.\n\nSuas configurações foram resetadas para utilizar os nós fornecidos da rede Monero. É necessário reiniciar o aplicativo. +settings.net.localhostXmrNodeInfo=Informações básicas: Haveno busca por um nó Monero local na inicialização. Caso encontre, Haveno irá comunicar com a rede Monero exclusivamente através deste nó. settings.net.p2PPeersLabel=Pares conectados settings.net.onionAddressColumn=Endereço onion settings.net.creationDateColumn=Estabelecida settings.net.connectionTypeColumn=Entrada/Saída settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=Ping settings.net.sentBytesColumn=Enviado settings.net.receivedBytesColumn=Recebido @@ -1062,7 +1088,7 @@ settings.net.needRestart=Você precisa reiniciar o programa para aplicar esta al settings.net.notKnownYet=Ainda desconhecido... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[Endeço IP:porta | nome do host:porta | endereço onion:porta] (seperados por vírgulas). A porta pode ser omitida quando a porta padrão (8333) for usada. settings.net.seedNode=Nó semente settings.net.directPeer=Par (direto) @@ -1071,7 +1097,7 @@ settings.net.peer=Par settings.net.inbound=entrada settings.net.outbound=saída setting.about.aboutHaveno=Sobre Haveno -setting.about.about=Haveno é um software de código aberto que facilita a troca de Bitcoin por moedas nacionais (e outras criptomoedas) através de uma rede ponto-a-ponto descentralizada, protegendo a privacidade dos usuários. Descubra mais sobre o Haveno no site do projeto. +setting.about.about=Haveno é um software de código aberto que facilita a troca de Monero por moedas nacionais (e outras criptomoedas) através de uma rede ponto-a-ponto descentralizada, protegendo a privacidade dos usuários. Descubra mais sobre o Haveno no site do projeto. setting.about.web=Site do Haveno setting.about.code=Código fonte setting.about.agpl=Licença AGPL @@ -1108,7 +1134,7 @@ setting.about.shortcuts.openDispute.value=Selecione negociação pendente e cliq setting.about.shortcuts.walletDetails=Abrir janela de detalhes da carteira -setting.about.shortcuts.openEmergencyBtcWalletTool=Abrir ferramenta de emergência da carteira BTC +setting.about.shortcuts.openEmergencyXmrWalletTool=Abrir ferramenta de emergência da carteira XMR setting.about.shortcuts.showTorLogs=Ativar registro de logs para mensagens Tor de níveis entre DEBUG e WARN @@ -1134,7 +1160,7 @@ setting.about.shortcuts.sendPrivateNotification=Enviar notificação privada ao setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1143,7 +1169,7 @@ account.tab.mediatorRegistration=Registro de mediador account.tab.refundAgentRegistration=Registro de agente de reembolsos account.tab.signing=Signing account.info.headline=Bem vindo à sua conta Haveno -account.info.msg=Aqui você pode adicionar contas de negociação para moedas nacionais & cryptos e criar um backup da sua carteira e dados da sua conta.\n\nUma nova carteira Bitcoin foi criada na primeira vez em que você iniciou a Haveno.\nNós encorajamos fortemente que você anote as palavras semente da sua carteira Bitcoin (veja a aba no topo) e considere adicionar uma senha antes de depositar fundos. Depósitos e retiradas de Bitcoin são gerenciados na seção "Fundos".\n\nNota de privacidade & segurança: visto que a Haveno é uma exchange decentralizada, todos os seus dados são mantidos no seu computador. Não existem servidores, então não temos acesso às suas informações pessoais, seus fundos ou até mesmo ao seu endereço IP. Dados como número de conta bancária, endereços de Bitcoin & crypto, etc apenas são compartilhados com seu parceiro de negociação para completar as negociações iniciadas por você (em caso de disputa, o mediador ou árbitro verá as mesmas informações que seu parceiro de negociação). +account.info.msg=Aqui você pode adicionar contas de negociação para moedas nacionais & cryptos e criar um backup da sua carteira e dados da sua conta.\n\nUma nova carteira Monero foi criada na primeira vez em que você iniciou a Haveno.\nNós encorajamos fortemente que você anote as palavras semente da sua carteira Monero (veja a aba no topo) e considere adicionar uma senha antes de depositar fundos. Depósitos e retiradas de Monero são gerenciados na seção "Fundos".\n\nNota de privacidade & segurança: visto que a Haveno é uma exchange decentralizada, todos os seus dados são mantidos no seu computador. Não existem servidores, então não temos acesso às suas informações pessoais, seus fundos ou até mesmo ao seu endereço IP. Dados como número de conta bancária, endereços de Monero & crypto, etc apenas são compartilhados com seu parceiro de negociação para completar as negociações iniciadas por você (em caso de disputa, o mediador ou árbitro verá as mesmas informações que seu parceiro de negociação). account.menu.paymentAccount=Contas de moedas nacionais account.menu.altCoinsAccountView=Contas de cryptos @@ -1154,7 +1180,7 @@ account.menu.backup=Backup account.menu.notifications=Notificações account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1183,7 +1209,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Trading ARQ on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending ARQ, you need to use either the official ArQmA GUI wallet or ArQmA CLI wallet with the store-tx-info flag enabled (default in new versions). Please be sure you can access the tx key as that would be required in case of a dispute.\narqma-wallet-cli (use the command get_tx_key)\narqma-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nAt normal block explorers the transfer is not verifiable.\n\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The ARQ sender is responsible for providing verification of the ARQ transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process visit ArQmA discord channel (https://discord.gg/s9BQpJT) or the ArQmA forum (https://labs.arqma.com) to find more information. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Negociar MSR Haveno requer que você entenda e cumpra os seguintes requisitos:\n\nPara enviar MSR, você deve usar uma destas: carteira oficial GUI Masari, carteira CLI Masari com a opção store-tx-info habilitada (habilitada por padrão) ou a carteira web Masari (https://wallet.getmasari.org). Por favor, certifique-se que você tenha acesso à chave da transação pois esta seria necessária em caso de uma disputa.\nmasari-wallet-cli (use o comando get_tx_key)\nmasari-wallet-gui (vá até a aba histórico e clique no botão (P) para prova de pagamento)\n\nCarteira Web Masari (vá até Conta -> histórico de transações e veja os detalhes da sua transação enviada.)\n\nVerificação pode ser feita dentro da carteira.\nmasari-wallet-cli : usando um comando (check_tx_key).\nmasari-wallet-gui : na página Avançado > Comprovar/Verificar.\nVerificação pode ser feita via explorador de blocos.\nAbra o explorador de blocos (https://explorer.getmasari.org) e use a barra de busca para encontrar o hash da sua transação.\nAssim que a transação for encontrada, role até o final da seção 'Comprovar envio' e preencha os detalhes conforme necessário.\nVocê precisa fornecer os seguintes dados ao mediador ou árbitro em caso de uma disputa:\n- Chave privada da transação\n- Hash da transação\n- Endereço público do destinatário\n\nA impossibilidade de fornecer as informações acima ou uso de uma carteira incompatível resultará na perda do caso de disputa. Em caso de uma disputa, o remetente de MSR é responsável por providenciar, ao mediador ou árbitro, a verificação do envio de MSR.\n\nNão é necessário um ID de pagamento, apenas o endereço público convencional.\nCaso tenha dúvidas sobre este processo, solicite ajuda no Discord oficial Masari (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1211,7 +1237,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin on Haveno requires that you unde account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Para negociar com L-BTC na Haveno é preciso entender o seguinte:\n\nQuando se recebe L-BTC de uma negociação na Haveno, você não pode usar a carteira móvel Blockstream Green ou uma carteira de exchange. Você só pode receber L-BTC numa carteira Liquid Elements Core, ou outra carteira L-BTC que lhe permita obter a blinding key para o seu endereço blinded de L-BTC.\n\nNo caso de mediação ou se uma disputa acontecer, você precisa divulgar ao mediador, ou agente de reembolsos, a blinding key do seu endereço receptor de L-BTC para que ele possa verificar os detalhes da sua Transação Confidencial no node próprio deles.\n\nCaso essa informação não seja fornecida ao mediador ou agente de reembolsos você corre o risco de perder a disputa. Em todos os casos de disputa o recebedor de L-BTC tem 100% de responsabilidade em fornecer a prova criptográfica ao mediador ou agente de reembolsos.\n\nSe você não entendeu esses requisitos, por favor não negocie L-BTC na Haveno. +account.crypto.popup.liquidmonero.msg=Para negociar com L-XMR na Haveno é preciso entender o seguinte:\n\nQuando se recebe L-XMR de uma negociação na Haveno, você não pode usar a carteira móvel Blockstream Green ou uma carteira de exchange. Você só pode receber L-XMR numa carteira Liquid Elements Core, ou outra carteira L-XMR que lhe permita obter a blinding key para o seu endereço blinded de L-XMR.\n\nNo caso de mediação ou se uma disputa acontecer, você precisa divulgar ao mediador, ou agente de reembolsos, a blinding key do seu endereço receptor de L-XMR para que ele possa verificar os detalhes da sua Transação Confidencial no node próprio deles.\n\nCaso essa informação não seja fornecida ao mediador ou agente de reembolsos você corre o risco de perder a disputa. Em todos os casos de disputa o recebedor de L-XMR tem 100% de responsabilidade em fornecer a prova criptográfica ao mediador ou agente de reembolsos.\n\nSe você não entendeu esses requisitos, por favor não negocie L-XMR na Haveno. account.traditional.yourTraditionalAccounts=Suas contas de moeda nacional @@ -1231,13 +1257,13 @@ account.password.setPw.button=Definir senha account.password.setPw.headline=Definir proteção de senha da carteira account.password.info=Com a proteção por senha ativada, você precisará inserir sua senha ao iniciar o aplicativo, ao retirar monero de sua carteira e ao exibir suas palavras-semente. -account.seed.backup.title=Fazer backup das palavras-semente da carteira -account.seed.info=Por favor, anote em um papel a data e as palavras-semente da carteira! Com essas informações, você poderá recuperar sua carteira à qualquer momento.\nA semente exibida é usada tanto para a carteira BTC quanto para a carteira BSQ.\n\nVocê deve anotá-las em uma folha de papel. Jamais anote as palavras em um arquivo no seu computador ou em seu e-mail.\n\nNote que a semente da carteira NÃO substitui um backup.\nPara fazer isso, você precisa fazer backup da pasta do Haveno na seção \"Conta/Backup\".\nA importação da semente da carteira só é recomendada em casos de emergência. O programa não funcionará corretamente se você não recuperá-lo através de um backup! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Faça backup das palavras-chave da sua carteira. +account.seed.info=Por favor, anote tanto as palavras-chave da sua carteira quanto a data. Você pode recuperar sua carteira a qualquer momento com as palavras-chave e a data.\n\nVocê deve anotar as palavras-chave em uma folha de papel. Não as salve no computador.\n\nPor favor, observe que as palavras-chave não substituem uma cópia de segurança.\nVocê precisa criar uma cópia de segurança do diretório completo do aplicativo na tela "Conta/Backup" para recuperar o estado e os dados do aplicativo. +account.seed.backup.warning=Por favor, observe que as palavras-chave não substituem uma cópia de segurança.\nVocê precisa criar uma cópia de segurança de todo o diretório de aplicativos na tela "Conta/Backup" para recuperar o estado e os dados do aplicativo. account.seed.warn.noPw.msg=Você não definiu uma senha para carteira, que protegeria a exibição das palavras-semente.\n\nGostaria de exibir as palavras-semente? account.seed.warn.noPw.yes=Sim, e não me pergunte novamente account.seed.enterPw=Digite a senha para ver a semente da carteira -account.seed.restore.info=Faça um backup antes de aplicar a restauração a partir de palavras-semente. Esteja ciente de que a restauração da carteira é apenas para casos de emergência e pode causar problemas com a base de dados interna da carteira.\nNão é uma maneira de aplicar um backup! Por favor, use um backup do diretório de dados do programa para restaurar um estado anterior do programa.\n\nDepois de restaurado, o programa será desligado automaticamente. Após ser reiniciado, o programa será ressincronizado com a rede Bitcoin. Isso pode demorar um pouco e aumenta ro consumo de CPU, especialmente se a carteira for mais antiga e tiver muitas transações. Por favor, evite interromper esse processo, caso contrário, você pode precisar excluir o diretório da corrente SPV novamente ou repetir o processo de restauração. +account.seed.restore.info=Faça um backup antes de aplicar a restauração a partir de palavras-semente. Esteja ciente de que a restauração da carteira é apenas para casos de emergência e pode causar problemas com a base de dados interna da carteira.\nNão é uma maneira de aplicar um backup! Por favor, use um backup do diretório de dados do programa para restaurar um estado anterior do programa.\n\nDepois de restaurado, o programa será desligado automaticamente. Após ser reiniciado, o programa será ressincronizado com a rede Monero. Isso pode demorar um pouco e aumenta ro consumo de CPU, especialmente se a carteira for mais antiga e tiver muitas transações. Por favor, evite interromper esse processo, caso contrário, você pode precisar excluir o diretório da corrente SPV novamente ou repetir o processo de restauração. account.seed.restore.ok=Ok, restaurar e desligar o Haveno @@ -1262,13 +1288,13 @@ account.notifications.trade.label=Receber mensagens de negociação account.notifications.market.label=Receber alertas de oferta account.notifications.price.label=Receber alertas de preço account.notifications.priceAlert.title=Alertas de preço -account.notifications.priceAlert.high.label=Avisar se o preço do BTC estiver acima de -account.notifications.priceAlert.low.label=Avisar se o preço do BTC estiver abaixo de +account.notifications.priceAlert.high.label=Avisar se o preço do XMR estiver acima de +account.notifications.priceAlert.low.label=Avisar se o preço do XMR estiver abaixo de account.notifications.priceAlert.setButton=Definir alerta de preço account.notifications.priceAlert.removeButton=Remover alerta de preço account.notifications.trade.message.title=O estado da negociação mudou account.notifications.trade.message.msg.conf=A transação de depósito para a negociação com o ID {0} foi confirmada. Por favor, abra o seu aplicativo Haveno e realize o pagamento. -account.notifications.trade.message.msg.started=O comprador de BTC iniciou o pagarmento para a negociação com o ID {0}. +account.notifications.trade.message.msg.started=O comprador de XMR iniciou o pagarmento para a negociação com o ID {0}. account.notifications.trade.message.msg.completed=A negociação com o ID {0} foi completada. account.notifications.offer.message.title=A sua oferta foi aceita account.notifications.offer.message.msg=A sua oferta com o ID {0} foi aceita @@ -1278,10 +1304,10 @@ account.notifications.dispute.message.msg=Você recebeu uma mensagem de disputa account.notifications.marketAlert.title=Alertas de oferta account.notifications.marketAlert.selectPaymentAccount=Ofertas correspondendo à conta de pagamento account.notifications.marketAlert.offerType.label=Tenho interesse em -account.notifications.marketAlert.offerType.buy=Ofertas de compra (eu quero vender BTC) -account.notifications.marketAlert.offerType.sell=Ofertas de venda (eu quero comprar BTC) +account.notifications.marketAlert.offerType.buy=Ofertas de compra (eu quero vender XMR) +account.notifications.marketAlert.offerType.sell=Ofertas de venda (eu quero comprar XMR) account.notifications.marketAlert.trigger=Distância do preço da oferta (%) -account.notifications.marketAlert.trigger.info=Ao definir uma distância de preço, você só irá receber um alerta quando alguém publicar uma oferta que atinge (ou excede) os seus critérios. Por exemplo: você quer vender BTC, mas você só irá vender a um prêmio de 2% sobre o preço de mercado atual. Ao definir esse campo para 2%, você só irá receber alertas de ofertas cujos preços estão 2% (ou mais) acima do preço de mercado atual. +account.notifications.marketAlert.trigger.info=Ao definir uma distância de preço, você só irá receber um alerta quando alguém publicar uma oferta que atinge (ou excede) os seus critérios. Por exemplo: você quer vender XMR, mas você só irá vender a um prêmio de 2% sobre o preço de mercado atual. Ao definir esse campo para 2%, você só irá receber alertas de ofertas cujos preços estão 2% (ou mais) acima do preço de mercado atual. account.notifications.marketAlert.trigger.prompt=Distância percentual do preço do mercado (ex: 2.50%, -0.50%, etc.) account.notifications.marketAlert.addButton=Inserir alerta de oferta account.notifications.marketAlert.manageAlertsButton=Gerenciar alertas de oferta @@ -1309,10 +1335,10 @@ inputControlWindow.balanceLabel=Saldo disponível contractWindow.title=Detalhes da disputa contractWindow.dates=Data da oferta / Data da negociação -contractWindow.btcAddresses=Endereço bitcoin do comprador de BTC / vendedor de BTC -contractWindow.onions=Endereço de rede comprador de BTC / vendendor de BTC -contractWindow.accountAge=Idade da conta do comprador de BTC / vendedor de BTC -contractWindow.numDisputes=Nº de disputas comprador de BTC / vendedor de BTC: +contractWindow.xmrAddresses=Endereço monero do comprador de XMR / vendedor de XMR +contractWindow.onions=Endereço de rede comprador de XMR / vendendor de XMR +contractWindow.accountAge=Idade da conta do comprador de XMR / vendedor de XMR +contractWindow.numDisputes=Nº de disputas comprador de XMR / vendedor de XMR: contractWindow.contractHash=Hash do contrato displayAlertMessageWindow.headline=Informação importante! @@ -1338,8 +1364,8 @@ disputeSummaryWindow.title=Resumo disputeSummaryWindow.openDate=Data da abertura do ticket disputeSummaryWindow.role=Função do negociador disputeSummaryWindow.payout=Pagamento da quantia negociada -disputeSummaryWindow.payout.getsTradeAmount={0} BTC fica com o pagamento da negociação -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount={0} XMR fica com o pagamento da negociação +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=Pagamento personalizado disputeSummaryWindow.payoutAmount.buyer=Quantia do pagamento do comprador disputeSummaryWindow.payoutAmount.seller=Quantia de pagamento do vendedor @@ -1381,7 +1407,7 @@ disputeSummaryWindow.close.button=Fechar ticket # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1425,18 +1451,18 @@ filterWindow.mediators=Mediadores filtrados (endereços onion separados por vír filterWindow.refundAgents=Agentes de reembolso filtrados (endereços onion separados por vírgula) filterWindow.seedNode=Nós de semente filtrados (endereços onion sep. por vírgula) filterWindow.priceRelayNode=Nós de transmissão de preço filtrados (endereços onion sep. por vírgula) -filterWindow.xmrNode=Nós de Bitcoin filtrados (endereços + portas sep. por vírgula) -filterWindow.preventPublicXmrNetwork=Prevenir uso da rede de Bitcoin pública +filterWindow.xmrNode=Nós de Monero filtrados (endereços + portas sep. por vírgula) +filterWindow.preventPublicXmrNetwork=Prevenir uso da rede de Monero pública filterWindow.disableAutoConf=Disable auto-confirm filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) filterWindow.disableTradeBelowVersion=Versão mínima necessária para negociação filterWindow.add=Adicionar filtro filterWindow.remove=Remover filtro -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Quantia mín. em BTC +offerDetailsWindow.minXmrAmount=Quantia mín. em XMR offerDetailsWindow.min=(mín. {0}) offerDetailsWindow.distance=(distância do preço de mercado: {0}) offerDetailsWindow.myTradingAccount=Minha conta de negociação @@ -1451,6 +1477,7 @@ offerDetailsWindow.confirm.maker=Criar oferta para {0} monero offerDetailsWindow.confirm.taker=Confirmar: Aceitar oferta de {0} monero offerDetailsWindow.creationDate=Criada em offerDetailsWindow.makersOnion=Endereço onion do ofertante +offerDetailsWindow.challenge=Passphrase da oferta qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1479,7 +1506,7 @@ showWalletDataWindow.walletData=Dados da carteira showWalletDataWindow.includePrivKeys=Incluir chaves privadas setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1491,7 +1518,7 @@ tacWindow.disagree=Eu não concordo e desisto tacWindow.arbitrationSystem=Resolução de disputas tradeDetailsWindow.headline=Negociação -tradeDetailsWindow.disputedPayoutTxId=ID de transação do pagamento disputado: +tradeDetailsWindow.disputedPayoutTxId=ID de transação do pagamento disputado tradeDetailsWindow.tradeDate=Data da negociação tradeDetailsWindow.txFee=Taxa de mineração tradeDetailsWindow.tradePeersOnion=Endereço onion dos parceiros de negociação @@ -1501,8 +1528,10 @@ tradeDetailsWindow.agentAddresses=Árbitro/Mediador tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=Você enviou XMR. +txDetailsWindow.xmr.noteReceived=Você recebeu XMR. +txDetailsWindow.sentTo=Enviado para +txDetailsWindow.receivedWith=Recebido com txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1511,7 +1540,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Digite senha para abrir: @@ -1538,12 +1567,12 @@ torNetworkSettingWindow.bridges.header=O Tor está bloqueado? torNetworkSettingWindow.bridges.info=Se o Tor estiver bloqueado pelo seu provedor de internet ou em seu país, você pode tentar usar pontes do Tor.\nVisite a página do Tor em https://bridges.torproject.org/bridges para aprender mais sobre pontes e transportadores plugáveis. feeOptionWindow.headline=Escolha a moeda para pagar a taxa de negociação -feeOptionWindow.info=Você pode optar por pagar a taxa de negociação em BSQ ou BTC. As taxas de negociação são reduzidas quando pagas com BSQ. +feeOptionWindow.info=Você pode optar por pagar a taxa de negociação em BSQ ou XMR. As taxas de negociação são reduzidas quando pagas com BSQ. feeOptionWindow.optionsLabel=Escolha a moeda para pagar a taxa de negociação -feeOptionWindow.useBTC=Usar BTC +feeOptionWindow.useXMR=Usar XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1585,15 +1614,15 @@ popup.warning.noTradingAccountSetup.msg=Você precisa criar uma conta em moeda n popup.warning.noArbitratorsAvailable=Não há árbitros disponíveis. popup.warning.noMediatorsAvailable=Não há mediadores disponíveis. popup.warning.notFullyConnected=Você precisa aguardar até estar totalmente conectado à rede.\nIsto pode levar até 2 minutos na inicialização do programa. -popup.warning.notSufficientConnectionsToBtcNetwork=Você precisa esperar até ter pelo menos {0} conexões à rede Bitcoin. -popup.warning.downloadNotComplete=Você precisa aguardar até que termine o download dos blocos de Bitcoin restantes -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Você precisa esperar até ter pelo menos {0} conexões à rede Monero. +popup.warning.downloadNotComplete=Você precisa aguardar até que termine o download dos blocos de Monero restantes +popup.warning.walletNotSynced=A carteira Haveno não está sincronizada com a altura mais recente da blockchain. Por favor, aguarde até que a carteira seja sincronizada ou verifique sua conexão. popup.warning.removeOffer=Tem certeza que deseja remover essa oferta? popup.warning.tooLargePercentageValue=Você não pode definir uma porcentagem superior a 100%. popup.warning.examplePercentageValue=Digite um número percentual, como \"5.4\" para 5.4% popup.warning.noPriceFeedAvailable=Não há feed de preços disponível para essa moeda. Você não pode usar um preço porcentual.\nPor favor selecione um preço fixo. popup.warning.sendMsgFailed=O envio da mensagem para seu parceiro de negociação falhou.\nFavor tentar novamente, e se o erro persistir reportar o erro (bug report). -popup.warning.btcChangeBelowDustException=Esta transação cria um troco menor do que o limite poeira (546 Satoshi) e seria rejeitada pela rede Bitcoin.\nVocê precisa adicionar a quantia poeira ao montante de envio para evitar gerar uma saída de poeira.\nA saída de poeira é {0}. +popup.warning.btcChangeBelowDustException=Esta transação cria um troco menor do que o limite poeira (546 Satoshi) e seria rejeitada pela rede Monero.\nVocê precisa adicionar a quantia poeira ao montante de envio para evitar gerar uma saída de poeira.\nA saída de poeira é {0}. popup.warning.messageTooLong=Sua mensagem excede o tamanho máximo permitido. Favor enviá-la em várias partes ou utilizando um serviço como https://pastebin.com. popup.warning.lockedUpFunds=Você possui fundos travados em uma negociação com erro.\nSaldo travado: {0}\nEndereço da transação de depósito: {1}\nID da negociação: {2}.\n\nPor favor, abra um ticket de suporte selecionando a negociação na tela de negociações em aberto e depois pressionando "\alt+o\" ou \"option+o\". @@ -1608,14 +1637,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=transmissão de preço popup.warning.seed=semente popup.warning.mandatoryUpdate.trading=Faça o update para a última versão do Haveno. Um update obrigatório foi lançado e desabilita negociações em versões antigas. Por favor, veja o Fórum do Haveno para mais informações. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=Esta transação não é possível, pois as taxas de mineração de {0} excederiam o montante a transferir de {1}. Aguarde até que as taxas de mineração estejam novamente baixas ou até você ter acumulado mais BTC para transferir. +popup.warning.burnXMR=Esta transação não é possível, pois as taxas de mineração de {0} excederiam o montante a transferir de {1}. Aguarde até que as taxas de mineração estejam novamente baixas ou até você ter acumulado mais XMR para transferir. -popup.warning.openOffer.makerFeeTxRejected=A transação de taxa de ofertante para a oferta com ID {0} foi rejeitada pela rede Bitcoin.\nID da transação: {1}.\nA oferta foi removida para evitar problemas adicionais.\nPor favor, vá até "Configurações/Informações da rede" e ressincronize o arquivo SPV.\nPara mais informações, por favor acesse o canal #support do time da Haveno na Keybase. +popup.warning.openOffer.makerFeeTxRejected=A transação de taxa de ofertante para a oferta com ID {0} foi rejeitada pela rede Monero.\nID da transação: {1}.\nA oferta foi removida para evitar problemas adicionais.\nPor favor, vá até "Configurações/Informações da rede" e ressincronize o arquivo SPV.\nPara mais informações, por favor acesse o canal #support do time da Haveno na Keybase. popup.warning.trade.txRejected.tradeFee=taxa de negociação popup.warning.trade.txRejected.deposit=depósito -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=A transação de taxa de ofertante para a oferta com ID {0} é inválida.\nID da transação: {1}.\nPor favor, vá até "Configurações/Informações da rede" e ressincronize o arquivo SPV.\nPara mais informações, por favor acesse o canal #support do time da Haveno na Keybase. @@ -1624,13 +1652,13 @@ popup.info.securityDepositInfo=Para garantir que ambas as partes sigam o protoco popup.info.cashDepositInfo=Certifique-se de que você possui uma agência bancária em sua região para poder fazer o depósito em dinheiro.\nO ID (BIC/SWIFT) do banco do vendedor é: {0}. popup.info.cashDepositInfo.confirm=Eu confirmo que posso fazer o depósito popup.info.shutDownWithOpenOffers=O Haveno está desligando, mas há ofertas abertas.\n\nEstas ofertas não ficarão disponíveis na rede P2P enquanto o Haveno estiver desligado, mas elas serão republicadas na rede assim que você reiniciar o programa.\n\nPara manter suas ofertas online, mantenha o Haveno aberto e certifique-se de que o seu computador continua online (ex: certifique-se de que o computador não está entrando em modo de hibernação). -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=Notificação privada importante! popup.securityRecommendation.headline=Recomendação de segurança importante -popup.securityRecommendation.msg=Lembre-se de proteger a sua carteira com uma senha, caso você já não tenha criado uma.\n\nRecomendamos que você escreva num papel as palavras da semente de sua carteira. Essas palavras funcionam como uma senha mestra para recuperar a sua carteira Bitcoin, caso o seu computador apresente algum problema.\nVocê irá encontrar mais informações na seção \"Semente da carteira\".\n\nTambém aconselhamos que você faça um backup completo da pasta de dados do programa na seção \"Backup\". +popup.securityRecommendation.msg=Lembre-se de proteger a sua carteira com uma senha, caso você já não tenha criado uma.\n\nRecomendamos que você escreva num papel as palavras da semente de sua carteira. Essas palavras funcionam como uma senha mestra para recuperar a sua carteira Monero, caso o seu computador apresente algum problema.\nVocê irá encontrar mais informações na seção \"Semente da carteira\".\n\nTambém aconselhamos que você faça um backup completo da pasta de dados do programa na seção \"Backup\". popup.shutDownInProgress.headline=Desligando popup.shutDownInProgress.msg=O desligamento do programa pode levar alguns segundos.\nPor favor, não interrompa este processo. @@ -1676,6 +1704,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=Nenhum depósito exigido do comprador +popup.info.buyerAsTakerWithoutDeposit=Sua oferta não exigirá um depósito de segurança ou taxa do comprador de XMR.\n\nPara aceitar sua oferta, você deve compartilhar uma senha com seu parceiro de negociação fora do Haveno.\n\nA senha é gerada automaticamente e exibida nos detalhes da oferta após a criação. + #################################################################### # Notifications #################################################################### @@ -1685,7 +1716,7 @@ notification.ticket.headline=Ticket de suporte para a oferta com ID {0} notification.trade.completed=A negociação foi concluída e você já pode retirar seus fundos. notification.trade.accepted=Sua oferta foi aceita por um {0}. notification.trade.unlocked=Sua negociação tem pelo menos uma confirmação da blockchain.\nVocê já pode iniciar o pagamento. -notification.trade.paymentSent=O comprador BTC iniciou o pagamento +notification.trade.paymentSent=O comprador XMR iniciou o pagamento notification.trade.selectTrade=Selecionar negociação notification.trade.peerOpenedDispute=Seu parceiro de negociação abriu um {0}. notification.trade.disputeClosed=A {0} foi fechada. @@ -1704,7 +1735,7 @@ systemTray.show=Mostrar janela do applicativo systemTray.hide=Esconder janela do applicativo systemTray.info=Informações sobre Haveno systemTray.exit=Sair -systemTray.tooltip=Haveno: a rede de exchange decentralizada de bitcoin +systemTray.tooltip=Haveno: a rede de exchange decentralizada de monero #################################################################### @@ -1755,7 +1786,7 @@ tooltip.openBlockchainForTx=Abrir um explorer de blockchain externo para a trans confidence.unknown=Transação com estado desconhecido confidence.seen=Visto por {0} par(es) / 0 confirmações -confidence.confirmed=Confirmado em {0} bloco(s) +confidence.confirmed={0} confirmação(ões) confidence.invalid=A transação é inválida peerInfo.title=Informação do par @@ -1766,10 +1797,10 @@ peerInfo.age.noRisk=Idade da conta de pagamento peerInfo.age.chargeBackRisk=Tempo desde a assinatura peerInfo.unknownAge=Idade desconhecida -addressTextField.openWallet=Abrir a sua carteira Bitcoin padrão +addressTextField.openWallet=Abrir a sua carteira Monero padrão addressTextField.copyToClipboard=Copiar endereço para área de transferência addressTextField.addressCopiedToClipboard=Endereço copiado para área de transferência -addressTextField.openWallet.failed=Erro ao abrir a carteira padrão Bitcoin. Talvez você não possua uma instalada. +addressTextField.openWallet.failed=Erro ao abrir a carteira padrão Monero. Talvez você não possua uma instalada. peerInfoIcon.tooltip={0}\nRótulo: {1} @@ -1801,6 +1832,7 @@ navigation.support=\"Suporte\" formatter.formatVolumeLabel={0} quantia{1} formatter.makerTaker=Ofertante: {1} de {0} / Aceitador: {3} de {2} +formatter.makerTakerLocked=Ofertante: {1} de {0} / Aceitador: {3} de {2} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Você está {0} {1} ({2} {3}) @@ -1846,7 +1878,6 @@ password.deriveKey=Derivando chave a partir da senha password.walletDecrypted=A carteira foi decifrada com sucesso e a proteção por senha removida password.wrongPw=Você digitou a senha incorreta.\n\nFavor tentar novamente, verificando com cuidado erros de digitação ou ortografia. password.walletEncrypted=A carteira foi encriptada e a proteção por senha foi ativada com sucesso. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=As 2 senhas inseridas não são iguais. password.forgotPassword=Esqueceu a senha? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1860,7 +1891,7 @@ seed.date=Data da carteira seed.restore.title=Recuperar carteira a partir das palavras semente seed.restore=Recuperar carteira seed.creationDate=Criada em -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Desejo recuperar mesmo assim seed.warn.walletNotEmpty.emptyWallet=Esvaziarei as carteiras primeiro seed.warn.notEncryptedAnymore=Suas carteiras estão encriptadas.\n\nApós a restauração, as carteiras não estarão mais encriptadas e você deverá definir uma nova senha.\n\nDeseja continuar? @@ -1877,7 +1908,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=Conta payment.account.no=Nº da conta payment.account.name=Nome da conta -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=Nome completo do titular da conta payment.account.fullName=Nome completo (nome e sobrenome) @@ -1909,7 +1940,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=Nome de usuário, e-mail ou nº de telefone payment.moneyBeam.accountId=E-mail ou nº de telefone -payment.venmo.venmoUserName=Nome do usuário do Venmo payment.popmoney.accountId=E-mail ou nº de telefone payment.promptPay.promptPayId=ID de cidadão/ID de impostos ou nº de telefone payment.supportedCurrencies=Moedas disponíveis @@ -1951,28 +1981,28 @@ payment.checking=Conta Corrente payment.savings=Poupança payment.personalId=Identificação pessoal payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Haveno to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=Ao usar o HalCash, o comprador de BTC precisa enviar ao vendedor de BTC o código HalCash através de uma mensagem de texto do seu telefone.\n\nPor favor, certifique-se de não exceder a quantia máxima que seu banco lhe permite enviar com o HalCash. O valor mínimo de saque é de 10 euros e valor máximo é de 600 EUR. Para saques repetidos é de 3000 euros por destinatário por dia e 6000 euros por destinatário por mês. Por favor confirme esses limites com seu banco para ter certeza de que eles usam os mesmos limites mencionados aqui.\n\nO valor de saque deve ser um múltiplo de 10 euros, pois você não pode sacar notas diferentes de uma ATM. Esse valor em BTC será ajustado na telas de criar e aceitar ofertas para que a quantia de EUR esteja correta. Você não pode usar o preço com base no mercado, pois o valor do EUR estaria mudando com a variação dos preços.\n\nEm caso de disputa, o comprador de BTC precisa fornecer a prova de que enviou o EUR. +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=Ao usar o HalCash, o comprador de XMR precisa enviar ao vendedor de XMR o código HalCash através de uma mensagem de texto do seu telefone.\n\nPor favor, certifique-se de não exceder a quantia máxima que seu banco lhe permite enviar com o HalCash. O valor mínimo de saque é de 10 euros e valor máximo é de 600 EUR. Para saques repetidos é de 3000 euros por destinatário por dia e 6000 euros por destinatário por mês. Por favor confirme esses limites com seu banco para ter certeza de que eles usam os mesmos limites mencionados aqui.\n\nO valor de saque deve ser um múltiplo de 10 euros, pois você não pode sacar notas diferentes de uma ATM. Esse valor em XMR será ajustado na telas de criar e aceitar ofertas para que a quantia de EUR esteja correta. Você não pode usar o preço com base no mercado, pois o valor do EUR estaria mudando com a variação dos preços.\n\nEm caso de disputa, o comprador de XMR precisa fornecer a prova de que enviou o EUR. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Certifique-se de que o seu banco permite a realização de depósitos em espécie na conta de terceiros. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=Informações para contato payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1983,7 +2013,7 @@ payment.f2f.city.prompt=A cidade será exibida na oferta payment.shared.optionalExtra=Informações adicionais opcionais payment.shared.extraInfo=Informações adicionais payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Abrir site payment.f2f.offerbook.tooltip.countryAndCity=País e cidade: {0} / {1} payment.f2f.offerbook.tooltip.extra=Informações adicionais: {0} @@ -1995,7 +2025,7 @@ payment.japan.recipient=Nome payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2153,7 +2183,7 @@ validation.zero=Número 0 não é permitido validation.negative=Valores negativos não são permitidos. validation.traditional.tooSmall=Quantia menor do que a mínima permitida. validation.traditional.tooLarge=Quantia maior do que a máxima permitida. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=Quantia máx. permitida: {0} validation.xmr.tooSmall=Quantia mín. permitida: {0} validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2163,10 +2193,10 @@ validation.sortCodeChars={0} deve consistir de {1} caracteres. validation.bankIdNumber={0} deve consistir de {1} números. validation.accountNr=O número de conta deve conter {0} números. validation.accountNrChars=O número da conta deve conter {0} caracteres. -validation.btc.invalidAddress=O endereço está incorreto. Por favor, verifique o formato do endereço. +validation.xmr.invalidAddress=O endereço está incorreto. Por favor, verifique o formato do endereço. validation.integerOnly=Por favor, insira apesar números inteiros validation.inputError=Os dados inseridos causaram um erro:\n{0} -validation.btc.exceedsMaxTradeLimit=Seu limite de negociação é {0}. +validation.xmr.exceedsMaxTradeLimit=Seu limite de negociação é {0}. validation.nationalAccountId={0} deve consistir de {1} números. #new diff --git a/core/src/main/resources/i18n/displayStrings_pt.properties b/core/src/main/resources/i18n/displayStrings_pt.properties index 23a3c3fa63..cd016e3aff 100644 --- a/core/src/main/resources/i18n/displayStrings_pt.properties +++ b/core/src/main/resources/i18n/displayStrings_pt.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Eu compreendo shared.na=N/D shared.shutDown=Desligar shared.reportBug=Reportar erro no GitHub -shared.buyBitcoin=Comprar bitcoin -shared.sellBitcoin=Vender bitcoin +shared.buyMonero=Comprar monero +shared.sellMonero=Vender monero shared.buyCurrency=Comprar {0} shared.sellCurrency=Vender {0} -shared.buyingBTCWith=comprando BTC com {0} -shared.sellingBTCFor=vendendo BTC por {0} -shared.buyingCurrency=comprando {0} (vendendo BTC) -shared.sellingCurrency=vendendo {0} (comprando BTC) +shared.buyCurrencyLocked=Comprar {0} 🔒 +shared.sellCurrencyLocked=Vender {0} 🔒 +shared.buyingXMRWith=comprando XMR com {0} +shared.sellingXMRFor=vendendo XMR por {0} +shared.buyingCurrency=comprando {0} (vendendo XMR) +shared.sellingCurrency=vendendo {0} (comprando XMR) shared.buy=comprar shared.sell=vender shared.buying=comprando @@ -93,7 +95,7 @@ shared.amountMinMax=Quantia (mín - máx) shared.amountHelp=Se a oferta tem uma quantia mínima ou máxima definida, poderá negociar qualquer quantia dentro deste intervalo. shared.remove=Remover shared.goTo=Ir para {0} -shared.BTCMinMax=BTC (mín - máx) +shared.XMRMinMax=XMR (mín - máx) shared.removeOffer=Remover oferta shared.dontRemoveOffer=Não remover a oferta shared.editOffer=Editar oferta @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=Sim, cancelar shared.nextStep=Próximo passo shared.selectTradingAccount=Selecionar conta de negociação -shared.fundFromSavingsWalletButton=Transferir fundos da carteira Haveno +shared.fundFromSavingsWalletButton=Aplicar fundos da carteira Haveno shared.fundFromExternalWalletButton=Abrir sua carteira externa para o financiamento -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=Abaixo % do preço de mercado shared.aboveInPercent=Acima % do preço de mercado shared.enterPercentageValue=Insira % do valor shared.OR=OU shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=Esperando pelos fundos... -shared.TheBTCBuyer=O comprador de BTC +shared.TheXMRBuyer=O comprador de XMR shared.You=Você shared.sendingConfirmation=Enviando confirmação... shared.sendingConfirmationAgain=Por favor envia a confirmação de novo @@ -123,9 +125,8 @@ shared.noDateAvailable=Sem dada disponível shared.noDetailsAvailable=Sem detalhes disponíveis shared.notUsedYet=Ainda não usado shared.date=Data -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=Copiar para área de transferência shared.language=Idioma shared.country=País @@ -140,6 +141,7 @@ shared.addNewAccount=Adicionar uma nova conta shared.ExportAccounts=Exportar Contas shared.importAccounts=Importar Contas shared.createNewAccount=Criar nova conta +shared.createNewAccountDescription=Os detalhes da sua conta são armazenados localmente no seu dispositivo e compartilhados apenas com seu parceiro de negociação e o árbitro, caso uma disputa seja aberta. shared.saveNewAccount=Guardar nova conta shared.selectedAccount=Conta selecionada shared.deleteAccount=Apagar conta @@ -169,7 +171,7 @@ shared.payoutTxId=ID de transação de pagamento shared.contractAsJson=Contrato em formato JSON shared.viewContractAsJson=Ver contrato em formato JSON shared.contract.title=Contrato para negócio com ID: {0} -shared.paymentDetails=Detalhes do pagamento do {0} de BTC +shared.paymentDetails=Detalhes do pagamento do {0} de XMR shared.securityDeposit=Depósito de segurança shared.yourSecurityDeposit=O seu depósito de segurança shared.contract=Contrato @@ -179,19 +181,21 @@ shared.messageSendingFailed=Falha no envio da mensagem. Erro: {0} shared.unlock=Desbloquear shared.toReceive=a receber shared.toSpend=a enviar -shared.btcAmount=Quantia de BTC +shared.xmrAmount=Quantia de XMR shared.yourLanguage=Os seus idiomas shared.addLanguage=Adicionar idioma shared.total=Total shared.totalsNeeded=Fundos necessários shared.tradeWalletAddress=Endereço da carteira do negócio shared.tradeWalletBalance=Saldo da carteira de negócio +shared.reserveExactAmount=Reserve apenas os fundos necessários. Requer uma taxa de mineração e ~20 minutos antes que sua oferta seja publicada. shared.makerTxFee=Ofertante: {0} shared.takerTxFee=Aceitador: {0} shared.iConfirm=Eu confirmo shared.openURL=Abrir {0} shared.fiat=Moeda fiduciária shared.crypto=Cripto +shared.preciousMetals=Metais Preciosos shared.all=Tudo shared.edit=Editar shared.advancedOptions=Opções avançadas @@ -226,8 +230,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=Mercado -mainView.menu.buyBtc=Comprar BTC -mainView.menu.sellBtc=Vender BTC +mainView.menu.buyXmr=Comprar XMR +mainView.menu.sellXmr=Vender XMR mainView.menu.portfolio=Portefólio mainView.menu.funds=Fundos mainView.menu.support=Apoio @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Reservado mainView.balance.pending.short=Bloqueado mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(localhost) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Conectando à rede Bitcoin -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=Conectando à rede Haveno +mainView.footer.xmrInfo.synchronizingWith=Sincronizando com {0} no bloco: {1} / {2} +mainView.footer.xmrInfo.connectedTo=Conectado a {0} no bloco {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Sincronizando a carteira com {0} no bloco: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Sincronizado com {0} no bloco {1} mainView.footer.xmrInfo.connectingTo=Conectando à mainView.footer.xmrInfo.connectionFailed=Connection failed to mainView.footer.xmrPeers=Monero network peers: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=O bootstrap para a rede do Ha mainView.p2pNetworkWarnMsg.noNodesAvailable=Não há nós de semente ou pares persistentes disponíveis para solicitar dados.\nPor favor, verifique a sua conexão de Internet ou tente reiniciar o programa. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=A conexão com a rede do Haveno falhou (erro reportado: {0}).\nPor favor, verifique sua conexão com a Internet ou tente reiniciar o programa. -mainView.walletServiceErrorMsg.timeout=A conexão com a rede Bitcoin falhou por causa de tempo esgotado. -mainView.walletServiceErrorMsg.connectionError=A conexão com a rede Bitcoin falhou devido ao erro: {0} +mainView.walletServiceErrorMsg.timeout=A conexão com a rede Monero falhou por causa de tempo esgotado. +mainView.walletServiceErrorMsg.connectionError=A conexão com a rede Monero falhou devido ao erro: {0} mainView.walletServiceErrorMsg.rejectedTxException=Uma transação foi rejeitada pela rede.\n\n{0} mainView.networkWarning.allConnectionsLost=Você perdeu a conexão com todos os pares de rede de {0} .\nTalvez você tenha perdido sua conexão de internet ou o seu computador estivesse no modo de espera. -mainView.networkWarning.localhostBitcoinLost=Perdeu a conexão ao nó Bitcoin do localhost.\nPor favor recomeçar o programa do Haveno para conectar à outros nós Bitcoin ou recomeçar o nó Bitcoin do localhost. +mainView.networkWarning.localhostMoneroLost=Perdeu a conexão ao nó Monero do localhost.\nPor favor recomeçar o programa do Haveno para conectar à outros nós Monero ou recomeçar o nó Monero do localhost. mainView.version.update=(Atualização disponível) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=Comprar {0} market.offerBook.sellWithTraditional=Vender {0} market.offerBook.sellOffersHeaderLabel=Vender {0} para market.offerBook.buyOffersHeaderLabel=Comprar {0} de -market.offerBook.buy=Eu quero comprar bitcoin -market.offerBook.sell=Eu quero vender bitcoin +market.offerBook.buy=Eu quero comprar monero +market.offerBook.sell=Eu quero vender monero # SpreadView market.spread.numberOfOffersColumn=Todas as ofertas ({0}) -market.spread.numberOfBuyOffersColumn=Comprar BTC ({0}) -market.spread.numberOfSellOffersColumn=Vender BTC ({0}) -market.spread.totalAmountColumn=Total de BTC ({0}) +market.spread.numberOfBuyOffersColumn=Comprar XMR ({0}) +market.spread.numberOfSellOffersColumn=Vender XMR ({0}) +market.spread.totalAmountColumn=Total de XMR ({0}) market.spread.spreadColumn=Spread market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=Criar oferta offerbook.takeOffer=Aceitar oferta offerbook.takeOfferToBuy=Aceitar oferta para comprar {0} offerbook.takeOfferToSell=Aceitar oferta para vender {0} +offerbook.takeOffer.enterChallenge=Digite a senha da oferta offerbook.trader=Negociador offerbook.offerersBankId=ID do banco do ofertante (BIC/SWIFT): {0} offerbook.offerersBankName=Nome do banco do ofertante: {0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=Sede do banco aceite (aceitador):\n {0} offerbook.availableOffers=Ofertas disponíveis offerbook.filterByCurrency=Filtrar por moeda offerbook.filterByPaymentMethod=Filtrar por método de pagamento -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=Ofertas que correspondem às minhas contas +offerbook.filterNoDeposit=Sem depósito +offerbook.noDepositOffers=Ofertas sem depósito (senha necessária) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=Esta conta foi verificada e {0} offerbook.timeSinceSigning.info.arbitrator=assinada pelo árbitro e pode assinar contas de pares @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=account was banned offerbook.timeSinceSigning.daysSinceSigning={0} dias offerbook.timeSinceSigning.daysSinceSigning.long={0} desde a assinatura offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=Compre XMR com: +offerbook.sellXmrFor=Venda XMR por: offerbook.timeSinceSigning.help=Quando você completa com sucesso um negócio com um par que tenha uma conta de pagamento assinada, a sua conta de pagamento é assinada .\n{0} dias depois, o limite inicial de {1} é aumentado e a sua conta pode assinar contas de pagamento de outros pares. offerbook.timeSinceSigning.notSigned=Ainda não assinada @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=Nº de ofertas: {0} offerbook.volume={0} (mín - máx) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=Criar oferta para {0} {1} offerbook.createOfferToBuy=Criar nova oferta para comprar {0} offerbook.createOfferToSell=Criar nova oferta para vender {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=A quantia de negócio é limitada à {0} devido à restrições de segurança baseadas nos seguinte critérios:\n- A conta do comprador não foi assinada por um árbitro ou um par\n- O tempo decorrido desde a assinatura da conta do comprador não é de pelo menos 30 dias\n- O método de pagamento para esta oferta é considerado arriscado para estornos bancários\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=A quantia de negócio é limitada à {0} devido à restrições de segurança baseadas nos seguinte critérios:\n- A sua conta não foi assinada por um árbitro ou um par\n- O tempo decorrido desde a assinatura da sua conta não é de pelo menos 30 dias\n- O método de pagamento para esta oferta é considerado arriscado para estornos bancários\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Este método de pagamento está temporariamente limitado a {0} até {1} porque todos os compradores têm novas contas.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Sua oferta será limitada a compradores com contas assinadas e antigas porque excede {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Essa oferta requer uma versão de protocolo diferente da usada na sua versão do software.\n\nPor favor, verifique se você tem a versão mais recente instalada, caso contrário, o usuário que criou a oferta usou uma versão mais antiga.\n\nOs utilizadores não podem negociar com uma versão de protocolo de negócio incompatível. offerbook.warning.userIgnored=Você adicionou o endereço onion daquele utilizador à sua lista de endereços ignorados. @@ -394,7 +409,6 @@ offerbook.warning.offerBlocked=Essa oferta foi bloqueada pelos desenvolvedores d offerbook.warning.currencyBanned=A moeda usada nessa oferta foi bloqueada pelos desenvolvedores do Haveno.\nPor favor, visite o Fórum Haveno para mais informações. offerbook.warning.paymentMethodBanned=O método de pagamento usado nessa oferta foi bloqueado pelos desenvolvedores do Haveno.\nPor favor, visite o Fórum Haveno para mais informações. offerbook.warning.nodeBlocked=O endereço onion desse negociador foi bloqueado pelos desenvolvedores do Haveno.\nProvavelmente, há um erro não tratado causando problemas ao aceitar ofertas desse negociador. -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=Venderá ao preço de mercado (atualizado à cada minuto). @@ -412,13 +426,13 @@ offerbook.info.roundedFiatVolume=A quantia foi arredondada para aumentar a priva # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Escreva a quantia em BTC +createOffer.amount.prompt=Escreva a quantia em XMR createOffer.price.prompt=Escreva o preço createOffer.volume.prompt=Escreva a quantia em {0} -createOffer.amountPriceBox.amountDescription=Quantia de BTC para {0} +createOffer.amountPriceBox.amountDescription=Quantia de XMR para {0} createOffer.amountPriceBox.buy.volumeDescription=Quantia em {0} a ser gasto createOffer.amountPriceBox.sell.volumeDescription=Quantia em {0} a ser recebido -createOffer.amountPriceBox.minAmountDescription=Quantia mínima de BTC +createOffer.amountPriceBox.minAmountDescription=Quantia mínima de XMR createOffer.securityDeposit.prompt=Depósito de segurança createOffer.fundsBox.title=Financiar sua oferta createOffer.fundsBox.offerFee=Taxa de negócio @@ -434,7 +448,7 @@ createOffer.info.sellAboveMarketPrice=Receberá sempre mais {0}% do que o atual createOffer.info.buyBelowMarketPrice=Pagará sempre menos {0}% do que o atual preço de mercado pois o preço da sua oferta será atualizado continuamente. createOffer.warning.sellBelowMarketPrice=Receberá sempre menos {0}% do que o atual preço de mercado pois o preço da sua oferta será atualizado continuamente. createOffer.warning.buyAboveMarketPrice=Pagará sempre mais {0}% do que o atual preço de mercado pois o preço da sua oferta será atualizado continuamente. -createOffer.tradeFee.descriptionBTCOnly=taxa de negócio +createOffer.tradeFee.descriptionXMROnly=taxa de negócio createOffer.tradeFee.descriptionBSQEnabled=Selecione a moeda da taxa de negócio createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +462,12 @@ createOffer.placeOfferButton=Rever: Colocar oferta para {0} monero createOffer.createOfferFundWalletInfo.headline=Financiar sua oferta # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Quantia de negócio: {0} \n -createOffer.createOfferFundWalletInfo.msg=Você precisa depositar {0} para esta oferta.\n\nEsses fundos estão reservados na sua carteira local e serão bloqueados no endereço de depósito multi-assinatura assim que alguém aceitar a sua oferta.\n\nA quantia é a soma de:\n{1} - Seu depósito de segurança: {2}\n- Taxa de negociação: {3}\n- Taxa de mineração: {4}\n\nVocê pode escolher entre duas opções ao financiar o seu negócio:\n- Use sua carteira Haveno (conveniente, mas as transações podem ser conectadas) OU\n- Transferência de uma carteira externa (potencialmente mais privada)\n\nVocê verá todas as opções de financiamento e detalhes depois de fechar este popup. +createOffer.createOfferFundWalletInfo.msg=Você precisa depositar {0} para esta oferta.\n\n\ + Esses fundos são reservados em sua carteira local e serão bloqueados em uma carteira multisig assim que alguém aceitar sua oferta.\n\n\ + O valor é a soma de:\n\ + {1}\ + - Seu depósito de segurança: {2}\n\ + - Taxa de negociação: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Ocorreu um erro ao colocar a oferta:\n\n{0}\n\nAinda nenhuns fundos saíram da sua carteira.\nPor favor, reinicie seu programa e verifique sua conexão de rede. @@ -470,30 +489,35 @@ createOffer.setDepositAsBuyer=Definir o meu depósito de segurança enquanto com createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=O depósito de segurança do seu comprador será {0} createOffer.securityDepositInfoAsBuyer=O seu depósito de segurança enquanto comprador será {0} -createOffer.minSecurityDepositUsed=O mín. depósito de segurança para o comprador é utilizado +createOffer.minSecurityDepositUsed=O depósito de segurança mínimo é utilizado +createOffer.buyerAsTakerWithoutDeposit=Nenhum depósito exigido do comprador (protegido por frase secreta) +createOffer.myDeposit=Meu depósito de segurança (%) +createOffer.myDepositInfo=Seu depósito de segurança será {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Insira a quantia de BTC -takeOffer.amountPriceBox.buy.amountDescription=Quantia de BTC a vender -takeOffer.amountPriceBox.sell.amountDescription=Quantia de BTC a comprar -takeOffer.amountPriceBox.priceDescription=Preço por bitcoin em {0} +takeOffer.amount.prompt=Insira a quantia de XMR +takeOffer.amountPriceBox.buy.amountDescription=Quantia de XMR a vender +takeOffer.amountPriceBox.sell.amountDescription=Quantia de XMR a comprar +takeOffer.amountPriceBox.priceDescription=Preço por monero em {0} takeOffer.amountPriceBox.amountRangeDescription=Intervalo de quantia possível -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=A quantia introduzida excede o número de casas décimas permitido.\nA quantia foi ajustada para 4 casas decimais. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=A quantia introduzida excede o número de casas décimas permitido.\nA quantia foi ajustada para 4 casas decimais. takeOffer.validation.amountSmallerThanMinAmount=A quantia não pode ser inferior à quantia mínima definida na oferta. takeOffer.validation.amountLargerThanOfferAmount=A quantia inserida não pode ser superior à quantia definida na oferta. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Essa quantia inseria criaria troco poeira para o vendedor de BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Essa quantia inseria criaria troco poeira para o vendedor de XMR. takeOffer.fundsBox.title=Financiar o seu negócio takeOffer.fundsBox.isOfferAvailable=Verificar se a oferta está disponível ... takeOffer.fundsBox.tradeAmount=Quantia para vender takeOffer.fundsBox.offerFee=Taxa de negócio takeOffer.fundsBox.networkFee=Total de taxas de mineração -takeOffer.fundsBox.takeOfferSpinnerInfo=Aceitação da oferta em progresso ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Aceitando a oferta: {0} takeOffer.fundsBox.paymentLabel=negócio do Haveno com ID {0} takeOffer.fundsBox.fundsStructure=({0} depósito de segurança, {1} taxa de negócio, {2} taxa de mineração) +takeOffer.fundsBox.noFundingRequiredTitle=Nenhum financiamento necessário +takeOffer.fundsBox.noFundingRequiredDescription=Obtenha a senha da oferta com o vendedor fora do Haveno para aceitar esta oferta. takeOffer.success.headline=Você aceitou uma oferta com sucesso. takeOffer.success.info=Você pode ver o estado de seu negócio em \"Portefólio/Negócios abertos\". takeOffer.error.message=Ocorreu um erro ao aceitar a oferta .\n\n{0} @@ -504,7 +528,7 @@ takeOffer.noPriceFeedAvailable=Você não pode aceitar aquela oferta pois ela ut takeOffer.takeOfferFundWalletInfo.headline=Financiar seu negócio # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Quantia de negócio: {0} \n -takeOffer.takeOfferFundWalletInfo.msg=Você precisa depositar {0} para aceitar esta oferta.\n\nA quantia é a soma de:\n{1} - Seu depósito de segurança: {2}\n- Taxa de negociação: {3}\n- Total das taxas de mineração: {4}\n\nVocê pode escolher entre duas opções ao financiar o seu negócio:\n- Use sua carteira Haveno (conveniente, mas as transações podem ser conectas) OU\n- Transferência de uma carteira externa (potencialmente mais privada)\n\nVocê verá todas as opções de financiamento e detalhes depois de fechar este popup. +takeOffer.takeOfferFundWalletInfo.msg=Você precisa depositar {0} para aceitar esta oferta.\n\nO valor é a soma de:\n{1}- Seu depósito de segurança: {2}\n- Taxa de negociação: {3} takeOffer.alreadyPaidInFunds=Se você já pagou com seus fundos você pode levantá-los na janela \"Fundos/Enviar fundos\". takeOffer.paymentInfo=Informações de pagamento takeOffer.setAmountPrice=Definir quantia @@ -597,29 +621,29 @@ portfolio.pending.step1.openForDispute=A transação de depósito ainda não foi # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.crypto=Por favor transfira da sua carteira externa {0}\n{1} para o vendedor de.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Por favor vá à um banco e pague{0} ao vendedor de BTC.\n\n -portfolio.pending.step2_buyer.cash.extra=REQUERIMENTO IMPORTANTE:\nDepois de ter feito o pagamento escreva no recibo de papel: SEM REEMBOLSOS.\nEm seguida, rasgue-o em 2 partes, tire uma foto e envie-a para o endereço de e-mail do vendedor de BTC. +portfolio.pending.step2_buyer.cash=Por favor vá à um banco e pague{0} ao vendedor de XMR.\n\n +portfolio.pending.step2_buyer.cash.extra=REQUERIMENTO IMPORTANTE:\nDepois de ter feito o pagamento escreva no recibo de papel: SEM REEMBOLSOS.\nEm seguida, rasgue-o em 2 partes, tire uma foto e envie-a para o endereço de e-mail do vendedor de XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Por favor pague {0} ao vendedor de BTC usando MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=REQUERIMENTO IMPORTANTE:\nDepois de ter feito o pagamento envie o Número de autorização e uma foto do recibo por email para o vendedor de BTC\nO recibo deve mostrar claramente o nome completo do vendedor, o país, o estado e a quantia. O email do vendedor é: {0}. +portfolio.pending.step2_buyer.moneyGram=Por favor pague {0} ao vendedor de XMR usando MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=REQUERIMENTO IMPORTANTE:\nDepois de ter feito o pagamento envie o Número de autorização e uma foto do recibo por email para o vendedor de XMR\nO recibo deve mostrar claramente o nome completo do vendedor, o país, o estado e a quantia. O email do vendedor é: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Por favor pague {0} ao vendedor de BTC usando Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=REQUISITO IMPORTANTE:\nDepois de ter feito o pagamento, envie o MTCN (número de rastreamento) e uma foto do recibo por e-mail para o vendedor de BTC.\nO recibo deve mostrar claramente o nome completo do vendedor, a cidade, o país e a quantia. O e-mail do vendedor é: {0}. +portfolio.pending.step2_buyer.westernUnion=Por favor pague {0} ao vendedor de XMR usando Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=REQUISITO IMPORTANTE:\nDepois de ter feito o pagamento, envie o MTCN (número de rastreamento) e uma foto do recibo por e-mail para o vendedor de XMR.\nO recibo deve mostrar claramente o nome completo do vendedor, a cidade, o país e a quantia. O e-mail do vendedor é: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Por favor envie {0} por \"US Postal Money Order\" para o vendedor de BTC.\n\n +portfolio.pending.step2_buyer.postal=Por favor envie {0} por \"US Postal Money Order\" para o vendedor de XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Por favor contacte o vendedor de BTC pelo contacto fornecido e marque um encontro para pagar {0}.\n\n +portfolio.pending.step2_buyer.f2f=Por favor contacte o vendedor de XMR pelo contacto fornecido e marque um encontro para pagar {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Iniciar pagamento usando {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=Quantia a transferir @@ -628,27 +652,27 @@ portfolio.pending.step2_buyer.buyerAccount=A sua conta de pagamento a ser usada portfolio.pending.step2_buyer.paymentSent=Pagamento iniciado portfolio.pending.step2_buyer.warn=Você ainda não fez o seu pagamento de {0}!\nSaiba que o negócio tem de ser concluído até {1}. portfolio.pending.step2_buyer.openForDispute=Você não completou o seu pagamento!\nO período máx. para o negócio acabou. Por favor entre em contacto com o mediador para assistência. -portfolio.pending.step2_buyer.paperReceipt.headline=Você enviou o recibo de papel para o vendedor de BTC? -portfolio.pending.step2_buyer.paperReceipt.msg=Lembre-se:\nPrecisa escrever no recibo de papel: SEM REEMBOLSOS.\nEm seguida, rasgue-o em 2 partes, tire uma foto e envie-a para o endereço de e-mail do vendedor de BTC. +portfolio.pending.step2_buyer.paperReceipt.headline=Você enviou o recibo de papel para o vendedor de XMR? +portfolio.pending.step2_buyer.paperReceipt.msg=Lembre-se:\nPrecisa escrever no recibo de papel: SEM REEMBOLSOS.\nEm seguida, rasgue-o em 2 partes, tire uma foto e envie-a para o endereço de e-mail do vendedor de XMR. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Enviar Número de autorização e recibo -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Você precisa enviar o Número de Autorização e uma foto do recibo por e-mail para o vendedor de BTC.\nO recibo deve mostrar claramente o nome completo do vendedor, o país, o estado e a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o Número de Autorização e o contrato para o vendedor? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Você precisa enviar o Número de Autorização e uma foto do recibo por e-mail para o vendedor de XMR.\nO recibo deve mostrar claramente o nome completo do vendedor, o país, o estado e a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o Número de Autorização e o contrato para o vendedor? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Enviar MTCN e recibo -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Você precisa enviar o MTCN (número de rastreamento) e uma foto do recibo por e-mail para o vendedor de BTC.\nO recibo deve mostrar claramente o nome completo do vendedor, a cidade, o país e a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o MTCN e o contrato para o vendedor? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Você precisa enviar o MTCN (número de rastreamento) e uma foto do recibo por e-mail para o vendedor de XMR.\nO recibo deve mostrar claramente o nome completo do vendedor, a cidade, o país e a quantia. O e-mail do vendedor é: {0}.\n\nVocê enviou o MTCN e o contrato para o vendedor? portfolio.pending.step2_buyer.halCashInfo.headline=Enviar o código HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=Você precisa enviar uma mensagem de texto com o código HalCash, bem como o ID da negociação ({0}) para o vendedor BTC.\nO nº do telemóvel do vendedor é {1}.\n\nVocê enviou o código para o vendedor? +portfolio.pending.step2_buyer.halCashInfo.msg=Você precisa enviar uma mensagem de texto com o código HalCash, bem como o ID da negociação ({0}) para o vendedor XMR.\nO nº do telemóvel do vendedor é {1}.\n\nVocê enviou o código para o vendedor? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Some banks might verify the receiver's name. Faster Payments accounts created in old Haveno clients do not provide the receiver's name, so please use trade chat to obtain it (if needed). portfolio.pending.step2_buyer.confirmStart.headline=Confirme que você iniciou o pagamento portfolio.pending.step2_buyer.confirmStart.msg=Você iniciou o pagamento de {0} para o seu parceiro de negociação? portfolio.pending.step2_buyer.confirmStart.yes=Sim, iniciei o pagamento portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=Aguardar o pagamento portfolio.pending.step2_seller.f2fInfo.headline=Informação do contacto do comprador -portfolio.pending.step2_seller.waitPayment.msg=A transação de depósito tem pelo menos uma confirmação da blockchain.\nVocê precisa esperar até que o comprador de BTC inicie o pagamento {0}. -portfolio.pending.step2_seller.warn=O comprador do BTC ainda não efetuou o pagamento de {0}.\nVocê precisa esperar até que eles tenham iniciado o pagamento.\nSe o negócio não for concluído em {1}, o árbitro irá investigar. -portfolio.pending.step2_seller.openForDispute=O comprador de BTC não iniciou o seu pagamento!\nO período máx. permitido para o negócio acabou.\nVocê pode esperar e dar mais tempo ao seu par de negociação ou entrar em contacto com o mediador para assistência. +portfolio.pending.step2_seller.waitPayment.msg=A transação de depósito tem pelo menos uma confirmação da blockchain.\nVocê precisa esperar até que o comprador de XMR inicie o pagamento {0}. +portfolio.pending.step2_seller.warn=O comprador do XMR ainda não efetuou o pagamento de {0}.\nVocê precisa esperar até que eles tenham iniciado o pagamento.\nSe o negócio não for concluído em {1}, o árbitro irá investigar. +portfolio.pending.step2_seller.openForDispute=O comprador de XMR não iniciou o seu pagamento!\nO período máx. permitido para o negócio acabou.\nVocê pode esperar e dar mais tempo ao seu par de negociação ou entrar em contacto com o mediador para assistência. tradeChat.chatWindowTitle=Janela de chat para o negócio com o ID ''{0}'' tradeChat.openChat=Abrir janela de chat tradeChat.rules=Você pode comunicar com o seu par de negociação para resolver problemas com este negócio.\nNão é obrigatório responder no chat.\nSe algum negociante infringir alguma das regras abaixo, abra uma disputa e reporte-o ao mediador ou ao árbitro.\n\nRegras do chat:\n\t● Não envie nenhum link (risco de malware). Você pode enviar o ID da transação e o nome de um explorador de blocos.\n\t● Não envie as suas palavras-semente, chaves privadas, senhas ou outra informação sensitiva!\n\t● Não encoraje negócios fora do Haveno (sem segurança).\n\t● Não engaje em nenhuma forma de scams de engenharia social.\n\t● Se um par não responde e prefere não comunicar pelo chat, respeite a sua decisão.\n\t● Mantenha o âmbito da conversa limitado ao negócio. Este chat não é um substituto para o messenger ou uma caixa para trolls.\n\t● Mantenha a conversa amigável e respeitosa. @@ -666,26 +690,26 @@ message.state.ACKNOWLEDGED=O par confirmou a recepção da mensagem # suppress inspection "UnusedProperty" message.state.FAILED=Falha de envio de mensagem -portfolio.pending.step3_buyer.wait.headline=Aguarde confirmação de pagamento do vendedor de BTC. -portfolio.pending.step3_buyer.wait.info=Aguardando confirmação do vendedor de BTC para o recibo do pagamento de {0}. +portfolio.pending.step3_buyer.wait.headline=Aguarde confirmação de pagamento do vendedor de XMR. +portfolio.pending.step3_buyer.wait.info=Aguardando confirmação do vendedor de XMR para o recibo do pagamento de {0}. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Pagamento iniciado mensagem de estado portfolio.pending.step3_buyer.warn.part1a=na blockchain {0} portfolio.pending.step3_buyer.warn.part1b=no seu provedor de pagamentos (ex: banco) -portfolio.pending.step3_buyer.warn.part2=O vendedor de BTC ainda não confirmou o seu pagamento. Por favor confirme se o envio do pagamento de {0} foi bem-sucedido. +portfolio.pending.step3_buyer.warn.part2=O vendedor de XMR ainda não confirmou o seu pagamento. Por favor confirme se o envio do pagamento de {0} foi bem-sucedido. portfolio.pending.step3_buyer.openForDispute=O vendedor de Haveno não confirmou o seu pagamento! O período máx. para o negócio acabou. Você pode esperar e dar mais tempo ao seu par de negociação or pedir assistência de um mediador. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=O seu parceiro de negociação confirmou que começou o pagamento de {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=no seu explorador de blockchain de {0} favorito portfolio.pending.step3_seller.crypto.wallet=na sua carteira de {0} portfolio.pending.step3_seller.crypto={0} Por favor verifique {1} se a transação para o seu endereço recipiente\n{2}\njá possui confirmações suficientes da blockchain.\nA quantia de pagamento deve ser {3}\n\nVocê pode copiar e colar o seu endereço {4} do ecrã principal depois de fechar o pop-up. -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=Como o pagamento é feito via Depósito em Dinheiro, o comprador do BTC deve escrever "SEM REEMBOLSO" no recibo de papel, rasgá-lo em 2 partes e enviar uma foto por e-mail.\n\nPara evitar o risco de estorno, confirme apenas se você recebeu o e-mail e se tiver certeza de que o recibo de papel é válido.\nSe você não tiver certeza, {0} -portfolio.pending.step3_seller.moneyGram=O comprador deve enviar o Número de Autorização e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente o seu nome completo, país, estado e a quantia. Por favor verifique seu e-mail se recebeu o Número de Autorização.\n\nDepois de fechar esse pop-up, verá o nome e o endereço do comprador do BTC para levantar o dinheiro da MoneyGram.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! -portfolio.pending.step3_seller.westernUnion=O comprador deve enviar-lhe o MTCN (número de rastreamento) e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente seu nome completo, cidade, país e a quantia Por favor verifique no seu e-mail se você recebeu o MTCN.\n\nDepois de fechar esse pop-up, você verá o nome e endereço do comprador de BTC para levantar o dinheiro da Western Union.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=Como o pagamento é feito via Depósito em Dinheiro, o comprador do XMR deve escrever "SEM REEMBOLSO" no recibo de papel, rasgá-lo em 2 partes e enviar uma foto por e-mail.\n\nPara evitar o risco de estorno, confirme apenas se você recebeu o e-mail e se tiver certeza de que o recibo de papel é válido.\nSe você não tiver certeza, {0} +portfolio.pending.step3_seller.moneyGram=O comprador deve enviar o Número de Autorização e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente o seu nome completo, país, estado e a quantia. Por favor verifique seu e-mail se recebeu o Número de Autorização.\n\nDepois de fechar esse pop-up, verá o nome e o endereço do comprador do XMR para levantar o dinheiro da MoneyGram.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! +portfolio.pending.step3_seller.westernUnion=O comprador deve enviar-lhe o MTCN (número de rastreamento) e uma foto do recibo por e-mail.\nO recibo deve mostrar claramente seu nome completo, cidade, país e a quantia Por favor verifique no seu e-mail se você recebeu o MTCN.\n\nDepois de fechar esse pop-up, você verá o nome e endereço do comprador de XMR para levantar o dinheiro da Western Union.\n\nConfirme apenas o recebimento depois de ter conseguido o dinheiro com sucesso! portfolio.pending.step3_seller.halCash=O comprador deve-lhe enviar o código HalCash como mensagem de texto. Além disso, você receberá uma mensagem do HalCash com as informações necessárias para retirar o EUR de uma ATM que suporte o HalCash.\n\nDepois de levantar o dinheiro na ATM, confirme aqui o recibo do pagamento! portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. @@ -701,7 +725,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID de transação portfolio.pending.step3_seller.xmrTxKey=Transaction key portfolio.pending.step3_seller.buyersAccount=Buyers account data portfolio.pending.step3_seller.confirmReceipt=Confirmar recibo de pagamento -portfolio.pending.step3_seller.buyerStartedPayment=O comprador de BTC começou o pagamento de {0}.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=O comprador de XMR começou o pagamento de {0}.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Verifique as confirmações da blockchain na sua carteira crypto ou explorador de blocos e confirme o pagamento quando houverem confirmações da blockchain suficientes. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Verifique em sua conta de negociação (por exemplo, sua conta bancária) e confirme que recebeu o pagamento. portfolio.pending.step3_seller.warn.part1a=na blockchain {0} @@ -713,7 +737,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Você recebeu o pagamento # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Verifique também se o nome do remetente especificado no contrato de negócio corresponde ao nome que aparece no seu extrato bancário:\nNome do remetente, por contrato de negócio: {0}\n\nSe os nomes não forem exatamente iguais, não confirme a recepção do pagamento. Em vez disso, abra uma disputa pressionando \"alt + o\" ou \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Observe que, assim que você confirmar a recepção, o valor da transação bloqueada será liberado para o comprador de BTC e o depósito de segurança será reembolsado.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Observe que, assim que você confirmar a recepção, o valor da transação bloqueada será liberado para o comprador de XMR e o depósito de segurança será reembolsado.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Confirme que recebeu o pagamento portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Sim, eu recebi o pagamento portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANTE: Ao confirmar a recepção do pagamento, você também está verificando a conta da contraparte e assinando-a. Como a conta da contraparte ainda não foi assinada, você deve adiar a confirmação do pagamento o máximo possível para reduzir o risco de estorno. @@ -723,7 +747,7 @@ portfolio.pending.step5_buyer.tradeFee=Taxa de negócio portfolio.pending.step5_buyer.makersMiningFee=Taxa de mineração portfolio.pending.step5_buyer.takersMiningFee=Total das taxas de mineração portfolio.pending.step5_buyer.refunded=Depósito de segurança reembolsado -portfolio.pending.step5_buyer.withdrawBTC=Levantar seus bitcoins +portfolio.pending.step5_buyer.withdrawXMR=Levantar seus moneros portfolio.pending.step5_buyer.amount=Quantia a levantar portfolio.pending.step5_buyer.withdrawToAddress=Levantar para o endereço portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet @@ -732,7 +756,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Seus fundos já foram levantados. portfolio.pending.step5_buyer.confirmWithdrawal=Confirmar solicitação de levantamento portfolio.pending.step5_buyer.amountTooLow=A quantia a ser transferida é inferior à taxa de transação e o mín. valor de transação possível (poeira). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Levantamento completado -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Os seus negócios concluídos são armazenadas em \ "Portefólio/Histórico\".\nVocê pode analisar todas as suas transações de bitcoin em \"Fundos/Transações\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Os seus negócios concluídos são armazenadas em \ "Portefólio/Histórico\".\nVocê pode analisar todas as suas transações de monero em \"Fundos/Transações\" portfolio.pending.step5_buyer.bought=Você comprou portfolio.pending.step5_buyer.paid=Você pagou @@ -794,7 +818,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=Você já aceitou portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +857,7 @@ funds.deposit.fundHavenoWallet=Financiar carteira Haveno funds.deposit.noAddresses=Ainda não foi gerado um endereço de depósito funds.deposit.fundWallet=Financiar sua carteira funds.deposit.withdrawFromWallet=Enviar fundos da carteira -funds.deposit.amount=Quantia em BTC (opcional) +funds.deposit.amount=Quantia em XMR (opcional) funds.deposit.generateAddress=Gerar um endereço novo funds.deposit.generateAddressSegwit=Native segwit format (Bech32) funds.deposit.selectUnused=Favor selecione um endereço não utilizado da tabela acima ao invés de gerar um novo. @@ -890,7 +914,7 @@ funds.tx.revert=Reverter funds.tx.txSent=Transação enviada com sucesso para um novo endereço em sua carteira Haveno local. funds.tx.direction.self=Enviado à você mesmo funds.tx.dustAttackTx=Poeira recebida -funds.tx.dustAttackTx.popup=Esta transação está enviando uma quantia muito pequena de BTC para a sua carteira e pode ser uma tentativa das empresas de análise da blockchain para espionar a sua carteira.\n\nSe você usar esse output em uma transação eles decobrirão que você provavelmente também é o proprietário de outros endereços (mistura de moedas).\n\nPara proteger sua privacidade a carteira Haveno ignora tais outputs de poeira para fins de consumo e no ecrã de saldo. Você pode definir a quantia limite a partir da qual um output é considerado poeira nas definições." +funds.tx.dustAttackTx.popup=Esta transação está enviando uma quantia muito pequena de XMR para a sua carteira e pode ser uma tentativa das empresas de análise da blockchain para espionar a sua carteira.\n\nSe você usar esse output em uma transação eles decobrirão que você provavelmente também é o proprietário de outros endereços (mistura de moedas).\n\nPara proteger sua privacidade a carteira Haveno ignora tais outputs de poeira para fins de consumo e no ecrã de saldo. Você pode definir a quantia limite a partir da qual um output é considerado poeira nas definições." #################################################################### # Support @@ -904,7 +928,6 @@ support.filter=Search disputes support.filter.prompt=Insira o ID do negócio, data, endereço onion ou dados da conta support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -940,8 +963,8 @@ support.savedInMailbox=Mensagem guardada na caixa de correio do recipiente. support.arrived=Mensagem chegou em seu destino. support.acknowledged=Chegada de mensagem confirmada pelo recipiente support.error=O recipiente não pode processar a mensagem. Erro: {0} -support.buyerAddress=Endereço do comprador de BTC -support.sellerAddress=Endereço do vendedor de BTC +support.buyerAddress=Endereço do comprador de XMR +support.sellerAddress=Endereço do vendedor de XMR support.role=Cargo support.agent=Support agent support.state=Estado @@ -949,13 +972,13 @@ support.chat=Chat support.closed=Fechado support.open=Aberto support.process=Process -support.buyerMaker=Comprador de BTC/Ofertante -support.sellerMaker=Vendedor de BTC/Ofertante -support.buyerTaker=Comprador de BTC/Aceitador -support.sellerTaker=Vendedor de BTC/Aceitador +support.buyerMaker=Comprador de XMR/Ofertante +support.sellerMaker=Vendedor de XMR/Ofertante +support.buyerTaker=Comprador de XMR/Aceitador +support.sellerTaker=Vendedor de XMR/Aceitador -support.backgroundInfo=O Haveno não é uma empresa, por isso as disputas são tratadas diferentemente.\n\nOs negociadores podem se comunicar dentro do programa via chat seguro no ecrã de negócios abertos para tentar resolver disputas por conta própria. Se isso não for suficiente, um mediador pode ajudar. O mediador avaliará a situação e sugerirá um pagamento dos fundos de negócio. Se ambos os negociadores aceitarem essa sugestão, a transação de pagamento será concluída e o negócio será encerrado. Se um ou ambos os negociadores não concordarem com o pagamento sugerido pelo mediador, eles podem solicitar a arbitragem. O árbitro reavaliará a situação e, se justificado, pagará pessoalmente o comerciante de volta e solicitará reembolso à OAD do Haveno. -support.initialInfo=Digite uma descrição do seu problema no campo de texto abaixo. Adicione o máximo de informações possível para acelerar o tempo de resolução da disputa.\n\nAqui está uma lista do que você deve fornecer:\n● Se você é o comprador de BTC: Você fez a transferência da Fiat ou Crypto? Se sim, você clicou no botão 'pagamento iniciado' no programa?\n● Se você é o vendedor de BTC: Você recebeu o pagamento da Fiat ou Crypto? Se sim, você clicou no botão 'pagamento recebido' no programa?\n\t● Qual versão do Haveno você está usando?\n\t● Qual sistema operacional você está usando?\n\t ● Se você encontrou um problema com transações com falha, considere mudar para um novo diretório de dados.\n\t Às vezes, o diretório de dados é corrompido e leva a erros estranhos.\n\t Consulte: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nFamiliarize-se com as regras básicas do processo de disputa:\n\t● Você precisa responder às solicitações do {0} dentro de 2 dias.\n\t● Os mediadores respondem entre 2 dias. Os árbitros respondem dentro de 5 dias úteis.\n\t ● O período máximo para uma disputa é de 14 dias.\n\t ● Você precisa cooperar com o {1} e fornecer as informações solicitadas para justificar o seu caso.\n\t● Você aceitou as regras descritas no documento de disputa no contrato do usuário quando iniciou o programa.\n\nVocê pode ler mais sobre o processo de disputa em: {2} +support.backgroundInfo=Haveno não é uma empresa, portanto, lida com disputas de forma diferente.\n\nOs traders podem se comunicar dentro do aplicativo por meio de um chat seguro na tela de negociações abertas para tentar resolver as disputas por conta própria. Se isso não for suficiente, um árbitro avaliará a situação e decidirá um pagamento dos fundos da negociação. +support.initialInfo=Digite uma descrição do seu problema no campo de texto abaixo. Adicione o máximo de informações possível para acelerar o tempo de resolução da disputa.\n\nAqui está uma lista do que você deve fornecer:\n● Se você é o comprador de XMR: Você fez a transferência da Fiat ou Crypto? Se sim, você clicou no botão 'pagamento iniciado' no programa?\n● Se você é o vendedor de XMR: Você recebeu o pagamento da Fiat ou Crypto? Se sim, você clicou no botão 'pagamento recebido' no programa?\n\t● Qual versão do Haveno você está usando?\n\t● Qual sistema operacional você está usando?\n\t ● Se você encontrou um problema com transações com falha, considere mudar para um novo diretório de dados.\n\t Às vezes, o diretório de dados é corrompido e leva a erros estranhos.\n\t Consulte: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nFamiliarize-se com as regras básicas do processo de disputa:\n\t● Você precisa responder às solicitações do {0} dentro de 2 dias.\n\t● Os mediadores respondem entre 2 dias. Os árbitros respondem dentro de 5 dias úteis.\n\t ● O período máximo para uma disputa é de 14 dias.\n\t ● Você precisa cooperar com o {1} e fornecer as informações solicitadas para justificar o seu caso.\n\t● Você aceitou as regras descritas no documento de disputa no contrato do usuário quando iniciou o programa.\n\nVocê pode ler mais sobre o processo de disputa em: {2} support.systemMsg=Mensagem do sistema: {0} support.youOpenedTicket=Você abriu um pedido para apoio.\n\n{0}\n\nHaveno versão: {1} support.youOpenedDispute=Você abriu um pedido para uma disputa.\n\n{0}\n\nHaveno versão: {1} @@ -979,13 +1002,14 @@ settings.tab.network=Informação da rede settings.tab.about=Sobre setting.preferences.general=Preferências gerais -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Máx. desvio do preço de mercado setting.preferences.avoidStandbyMode=Evite o modo espera +setting.preferences.useSoundForNotifications=Reproduzir sons para notificações setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Valores acima de {0}% não são permitidos. setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1022,29 +1046,31 @@ settings.preferences.editCustomExplorer.name=Nome settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=Rede Bitcoin +settings.net.xmrHeader=Rede Monero settings.net.p2pHeader=Rede do Haveno settings.net.onionAddressLabel=O meu endereço onion settings.net.xmrNodesLabel=Usar nós de Monero personalizados settings.net.moneroPeersLabel=Pares conectados +settings.net.connection=Conexão +settings.net.connected=Conectado settings.net.useTorForXmrJLabel=Usar Tor para a rede de Monero settings.net.moneroNodesLabel=Nós de Monero para conectar -settings.net.useProvidedNodesRadio=Usar nós de Bitcoin Core providenciados -settings.net.usePublicNodesRadio=Usar rede de Bitcoin pública -settings.net.useCustomNodesRadio=Usar nós de Bitcoin Core personalizados +settings.net.useProvidedNodesRadio=Usar nós de Monero Core providenciados +settings.net.usePublicNodesRadio=Usar rede de Monero pública +settings.net.useCustomNodesRadio=Usar nós de Monero Core personalizados settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=Não, usar nós providenciados settings.net.warn.usePublicNodes.usePublic=Sim, usar a rede pública -settings.net.warn.useCustomNodes.B2XWarning=Por favor, certifique-se de que seu nó Bitcoin é um nó confiável do Bitcoin Core!\n\nConectar-se a nós que não seguem as regras de consenso do Bitcoin Core pode corromper a sua carteira e causar problemas no processo de negócio.\n\nOs usuários que se conectam a nós que violam regras de consenso são responsáveis por qualquer dano resultante. Quaisquer disputas resultantes serão decididas em favor do outro par. Nenhum suporte técnico será dado aos usuários que ignorarem esses alertas e mecanismos de proteção! -settings.net.warn.invalidBtcConfig=A conexão à rede Bitcoin falhou porque sua configuração é inválida.\n\nA sua configuração foi redefinida para usar os nós de Bitcoin fornecidos. Você precisará reiniciar o programa. -settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Bitcoin node when starting. If it is found, Haveno will communicate with the Bitcoin network exclusively through it. +settings.net.warn.useCustomNodes.B2XWarning=Por favor, certifique-se de que seu nó Monero é um nó confiável do Monero Core!\n\nConectar-se a nós que não seguem as regras de consenso do Monero Core pode corromper a sua carteira e causar problemas no processo de negócio.\n\nOs usuários que se conectam a nós que violam regras de consenso são responsáveis por qualquer dano resultante. Quaisquer disputas resultantes serão decididas em favor do outro par. Nenhum suporte técnico será dado aos usuários que ignorarem esses alertas e mecanismos de proteção! +settings.net.warn.invalidXmrConfig=A conexão à rede Monero falhou porque sua configuração é inválida.\n\nA sua configuração foi redefinida para usar os nós de Monero fornecidos. Você precisará reiniciar o programa. +settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Monero node when starting. If it is found, Haveno will communicate with the Monero network exclusively through it. settings.net.p2PPeersLabel=Pares conectados settings.net.onionAddressColumn=Endereço onion settings.net.creationDateColumn=Estabelecida settings.net.connectionTypeColumn=Entrando/Saindo settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=Ida-e-volta settings.net.sentBytesColumn=Enviado settings.net.receivedBytesColumn=Recebido @@ -1059,7 +1085,7 @@ settings.net.needRestart=Você precisa reiniciar o programa para aplicar essa al settings.net.notKnownYet=Ainda desconhecido... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[endereço IP:porta | nome de host:porta | endereço onion:porta] (separado por vírgula). A porta pode ser omitida se a padrão for usada (8333). settings.net.seedNode=Nó semente settings.net.directPeer=Par (direto) @@ -1068,7 +1094,7 @@ settings.net.peer=Par settings.net.inbound=entrante settings.net.outbound=sainte setting.about.aboutHaveno=Sobre Haveno -setting.about.about=O Haveno é um software de código aberto que facilita a troca de bitcoins com moedas nacionais (e outras criptomoedas) por meio de uma rede par-à-par descentralizada, de uma maneira que protege fortemente a privacidade do utilizador. Saiba mais sobre o Haveno na nossa página web do projeto. +setting.about.about=O Haveno é um software de código aberto que facilita a troca de moneros com moedas nacionais (e outras criptomoedas) por meio de uma rede par-à-par descentralizada, de uma maneira que protege fortemente a privacidade do utilizador. Saiba mais sobre o Haveno na nossa página web do projeto. setting.about.web=página da web do Haveno setting.about.code=Código fonte setting.about.agpl=Licença AGPL @@ -1105,7 +1131,7 @@ setting.about.shortcuts.openDispute.value=Selecionar negócio pendente e clicar: setting.about.shortcuts.walletDetails=Abrir janela de detalhes da carteira -setting.about.shortcuts.openEmergencyBtcWalletTool=Abrir ferramenta e emergência da carteira para a carteira de BTC +setting.about.shortcuts.openEmergencyXmrWalletTool=Abrir ferramenta e emergência da carteira para a carteira de XMR setting.about.shortcuts.showTorLogs=Escolher o nível de log para mensagens Tor entre DEBUG e WARN @@ -1131,7 +1157,7 @@ setting.about.shortcuts.sendPrivateNotification=Enviar notificação privada ao setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1166,7 @@ account.tab.mediatorRegistration=Registo do Mediador account.tab.refundAgentRegistration=Registro de agente de reembolso account.tab.signing=Signing account.info.headline=Bem vindo à sua conta Haveno -account.info.msg=Aqui você pode adicionar contas de negociação para moedas nacionais e cryptos e criar um backup da sua carteira e dos dados da conta.\n\nUma nova carteira de Bitcoin foi criada na primeira vez que você iniciou o Haveno.\n\nÉ altamente recomendável que você anote as sua palavras-semente da carteira do Bitcoin (consulte a guia na parte superior) e considere adicionar uma senha antes do financiamento. Depósitos e retiradas de Bitcoin são gerenciados na secção \"Fundos\".\n\nNota sobre privacidade e segurança: como o Haveno é uma exchange descentralizada, todos os seus dados são mantidos no seu computador. Como não há servidores, não temos acesso às suas informações pessoais, fundos ou mesmo seu endereço IP. Dados como números de contas bancárias, endereços de crypto e Bitcoin etc. são compartilhados apenas com seu par de negociação para realizar negociações iniciadas (no caso de uma disputa, o mediador ou o árbitro verá os mesmos dados que o seu parceiro de negociação). +account.info.msg=Aqui você pode adicionar contas de negociação para moedas nacionais e cryptos e criar um backup da sua carteira e dos dados da conta.\n\nUma nova carteira de Monero foi criada na primeira vez que você iniciou o Haveno.\n\nÉ altamente recomendável que você anote as sua palavras-semente da carteira do Monero (consulte a guia na parte superior) e considere adicionar uma senha antes do financiamento. Depósitos e retiradas de Monero são gerenciados na secção \"Fundos\".\n\nNota sobre privacidade e segurança: como o Haveno é uma exchange descentralizada, todos os seus dados são mantidos no seu computador. Como não há servidores, não temos acesso às suas informações pessoais, fundos ou mesmo seu endereço IP. Dados como números de contas bancárias, endereços de crypto e Monero etc. são compartilhados apenas com seu par de negociação para realizar negociações iniciadas (no caso de uma disputa, o mediador ou o árbitro verá os mesmos dados que o seu parceiro de negociação). account.menu.paymentAccount=Contas de moedas nacionais account.menu.altCoinsAccountView=Contas de cryptos @@ -1151,7 +1177,7 @@ account.menu.backup=Backup account.menu.notifications=Notificações account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1180,7 +1206,7 @@ account.crypto.popup.upx.msg=Negociar UPX no Haveno exige que você entenda e cu # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Negociar o ARQ no Haveno requer que você entenda e atenda aos seguintes requerimentos:\n\nPara enviar o ARQ, você precisa usar a wallet oficial do ArQmA GUI ou a carteira do ArQmA CLI com o marcador store-tx-info ativado (padrão em novas versões). Por favor, certifique-se que você pode acessar a chave da tx porque isso seria necessário em caso de uma disputa.\narqma-wallet-cli (use o comando get_tx_key)\narqma-wallet-gui (vá para a aba do histórico e clique no botão (P) para comprovar o pagamento)\n\nEm exploradores de blocos normais, a transferência não é verificável.\n\nVocê precisa fornecer ao mediador ou árbitro os seguintes dados em caso de disputa:\n- A chave privada da tx\n- O hash da transação\n- o endereço público do destinatário\n\nA falha em fornecer os dados acima, ou se você usou uma carteira incompatível, resultará na perda do caso de disputa. O remetente do ARQ é responsável por fornecer a verificação da transferência do ARQ ao mediador ou árbitro em caso de disputa.\n\nNão é necessário um código de pagamento, apenas o endereço público normal.\nSe você não tiver certeza sobre esse processo, visite o canal de discord do ArQmA (https://discord.gg/s9BQpJT) ou o fórum do ArQmA (https://labs.arqma.com) para obter mais informações. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Negociar MSR no Haveno requer que você entenda e cumpra os seguintes requerimentos:\n\nPara enviar MSR, você precisa usar a carteira GUI oficial do Masari ou a carteira CLI do Masari com o marcador store-tx-info ativado (ativado por padrão) ou a carteira web do Masari (https://wallet.getmasari.org). Por favor, certifique-se que você pode acessar a chave da tx porque isso seria necessário em caso de uma disputa.\nmasari-wallet-cli (use o comando get_tx_key)\nmasari-wallet-gui (vá para a aba do histórico e clique no botão (P) para comprovar o pagamento)\n\nMasari Web Wallet (vá para Account -> histórico de transação e veja os detalhes da sua transação enviada)\n\nA verificação pode ser realizada na carteira.\nmasari-wallet-cli: usando o comando (check_tx_key).\nmasari-wallet-gui: na aba Advanced > Prove/Check.\nA verificação pode ser realizada no eplorador de blocos\nExplorador de blocos aberto (https://explorer.getmasari.org), use a barra de procurar para encontrar o hash da transação.\nUma que vez que a transação for encontrada, desça até ao baixo da àrea 'Prove Sending' e preencha os detalhes necessários.\nVocê precisa fornecer ao mediador ou ao árbitro os seguintes dados em caso de disputa:\n- A chave privada da tx\n- O hash da transação\n- o endereço público do destinatário\n\nFalha em fornecer os dados acima, ou se você usou uma carteira incompatível, resultará na perda do caso de disputa. O remetente da XMR é responsável por fornecer a verificação da transferência da MSR para o mediador ou o árbitro no caso de uma disputa.\n\nNão é necessário um código de pagamento, apenas o endereço público normal.\nSe você não tem certeza sobre o processo, peça ajuda no Discord official do Masari (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1234,7 @@ account.crypto.popup.pars.msg=A negociação de ParsiCoin no Haveno exige que vo account.crypto.popup.blk-burnt.msg=Para negociar blackcoins queimados, você precisa saber o seguinte:\n\nBlackcoins queimados não podem ser gastos. Para os negociar no Haveno, os output scripts precisam estar na forma: OP_RETURN OP_PUSHDATA, seguido pelos data bytes que, após serem codificados em hex, constituem endereços. Por exemplo, blackcoins queimados com um endereço 666f6f (“foo” em UTF-8) terá o seguinte script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nPara criar blackcoins queimados, deve-se usar o comando RPC “burn” disponível em algumas carteiras.\n\nPara casos possíveis, confira https://ibo.laboratorium.ee .\n\nComo os blackcoins queimados não podem ser gastos, eles não podem voltar a ser vendidos. “Vender” blackcoins queimados significa queimar blackcoins comuns (com os dados associados iguais ao endereço de destino).\n\nEm caso de disputa, o vendedor de BLK precisa providenciar o hash da transação. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=A negociação de L-BTC no Haveno exige que você entenda o seguinte:\n\nAo receber L-BTC para um negócio no Haveno, você não pode usar a aplicação móvel Blockstream Green Wallet ou uma carteira de custódia / exchange. Você só deve receber o L-BTC na carteira Liquid Elements Core ou em outra carteira L-BTC que permita obter a chave ofuscante para o seu endereço L-BTC cego.\n\nNo caso de ser necessária mediação, ou se surgir uma disputa de negócio, você deve divulgar a chave ofuscante do seu endereço L-BTC de recebimento ao mediador ou agente de reembolso Haveno, para que eles possam verificar os detalhes da sua Transação Confidencial no seu próprio Elements Core full node.\n\nO não fornecimento das informações necessárias ao mediador ou ao agente de reembolso resultará na perda do caso de disputa. Em todos os casos de disputa, o recipiente de L-BTC suporta 100% da responsabilidade ao fornecer prova criptográfica ao mediador ou ao agente de reembolso.\n\nSe você não entender esses requerimentos, não negocie o L-BTC no Haveno. +account.crypto.popup.liquidmonero.msg=A negociação de L-XMR no Haveno exige que você entenda o seguinte:\n\nAo receber L-XMR para um negócio no Haveno, você não pode usar a aplicação móvel Blockstream Green Wallet ou uma carteira de custódia / exchange. Você só deve receber o L-XMR na carteira Liquid Elements Core ou em outra carteira L-XMR que permita obter a chave ofuscante para o seu endereço L-XMR cego.\n\nNo caso de ser necessária mediação, ou se surgir uma disputa de negócio, você deve divulgar a chave ofuscante do seu endereço L-XMR de recebimento ao mediador ou agente de reembolso Haveno, para que eles possam verificar os detalhes da sua Transação Confidencial no seu próprio Elements Core full node.\n\nO não fornecimento das informações necessárias ao mediador ou ao agente de reembolso resultará na perda do caso de disputa. Em todos os casos de disputa, o recipiente de L-XMR suporta 100% da responsabilidade ao fornecer prova criptográfica ao mediador ou ao agente de reembolso.\n\nSe você não entender esses requerimentos, não negocie o L-XMR no Haveno. account.traditional.yourTraditionalAccounts=A sua conta de moeda nacional @@ -1228,13 +1254,13 @@ account.password.setPw.button=Definir senha account.password.setPw.headline=Definir proteção de senha da carteira account.password.info=Com a proteção por senha habilitada, você precisará inserir sua senha ao iniciar o aplicativo, ao retirar monero de sua carteira e ao exibir suas palavras-semente. -account.seed.backup.title=Fazer backup das palavras semente da sua carteira -account.seed.info=Por favor, anote as palavras-semente da carteira e a data! Você pode recuperar sua carteira a qualquer momento com palavras-semente e a data.\nAs mesmas palavras-semente são usadas para a carteira BTC e BSQ.\n\nVocê deve anotar as palavras-semente numa folha de papel. Não as guarde no seu computador.\n\nPor favor, note que as palavras-semente não são um substituto para um backup.\nVocê precisa criar um backup de todo o diretório do programa a partir do ecrã \"Conta/Backup\" para recuperar o estado e os dados do programa.\nA importação de palavras-semente é recomendada apenas para casos de emergência. O programa não será funcional sem um backup adequado dos arquivos da base de dados e das chaves! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Faça backup das palavras-chave da sua carteira +account.seed.info=Por favor, anote tanto as palavras-chave da sua carteira quanto a data. Você pode recuperar sua carteira a qualquer momento com as palavras-chave e a data.\n\nVocê deve anotar as palavras-chave em uma folha de papel. Não as salve no computador.\n\nPor favor, observe que as palavras-chave não substituem uma cópia de segurança.\nVocê precisa criar uma cópia de segurança do diretório completo do aplicativo na tela "Conta/Backup" para recuperar o estado e os dados do aplicativo. +account.seed.backup.warning=Por favor, observe que as palavras-chave não substituem uma cópia de segurança.\nVocê precisa criar uma cópia de segurança do diretório completo do aplicativo na tela "Conta/Backup" para recuperar o estado e os dados do aplicativo. account.seed.warn.noPw.msg=Você não definiu uma senha da carteira que protegeria a exibição das palavras-semente.\n\nVocê quer exibir as palavras-semente? account.seed.warn.noPw.yes=Sim, e não me pergunte novamente account.seed.enterPw=Digite a senha para ver palavras-semente -account.seed.restore.info=Por favor, faça um backup antes de aplicar a restauração a partir de palavras-semente. Esteja ciente de que a restauração da carteira é apenas para casos de emergência e pode causar problemas com a base de dados interna da carteira.\nNão é uma maneira de aplicar um backup! Por favor, use um backup do diretório de dados do programa para restaurar um estado anterior do programa.\n\nDepois de restaurar o programa será desligado automaticamente. Depois de ter reiniciado o programa, ele será ressincronizado com a rede Bitcoin. Isso pode demorar um pouco e consumir muito do CPU, especialmente se a carteira for mais antiga e tiver muitas transações. Por favor, evite interromper esse processo, caso contrário, você pode precisar excluir o ficheiro da corrente do SPV novamente ou repetir o processo de restauração. +account.seed.restore.info=Por favor, faça um backup antes de aplicar a restauração a partir de palavras-semente. Esteja ciente de que a restauração da carteira é apenas para casos de emergência e pode causar problemas com a base de dados interna da carteira.\nNão é uma maneira de aplicar um backup! Por favor, use um backup do diretório de dados do programa para restaurar um estado anterior do programa.\n\nDepois de restaurar o programa será desligado automaticamente. Depois de ter reiniciado o programa, ele será ressincronizado com a rede Monero. Isso pode demorar um pouco e consumir muito do CPU, especialmente se a carteira for mais antiga e tiver muitas transações. Por favor, evite interromper esse processo, caso contrário, você pode precisar excluir o ficheiro da corrente do SPV novamente ou repetir o processo de restauração. account.seed.restore.ok=Ok, restaurar e desligar Haveno @@ -1259,13 +1285,13 @@ account.notifications.trade.label=Receber mensagens de negócio account.notifications.market.label=Receber alertas de oferta account.notifications.price.label=Receber alertas de preço account.notifications.priceAlert.title=Alertas de preço -account.notifications.priceAlert.high.label=Notificar se o preço de BTC está acima de -account.notifications.priceAlert.low.label=Notificar se o preço de BTC está abaixo de +account.notifications.priceAlert.high.label=Notificar se o preço de XMR está acima de +account.notifications.priceAlert.low.label=Notificar se o preço de XMR está abaixo de account.notifications.priceAlert.setButton=Definir alerta de preço account.notifications.priceAlert.removeButton=Remover alerta de preço account.notifications.trade.message.title=Estado do negócio mudou account.notifications.trade.message.msg.conf=A transação do depósito para o negócio com o ID {0} está confirmada. Por favor, abra seu programa Haveno e inicie o pagamento. -account.notifications.trade.message.msg.started=O comprador do BTC iniciou o pagamento para o negócio com o ID {0}. +account.notifications.trade.message.msg.started=O comprador do XMR iniciou o pagamento para o negócio com o ID {0}. account.notifications.trade.message.msg.completed=O negócio com o ID {0} está completo. account.notifications.offer.message.title=A sua oferta foi aceite account.notifications.offer.message.msg=A sua oferta com o ID {0} foi aceite @@ -1275,10 +1301,10 @@ account.notifications.dispute.message.msg=Recebeu uma menagem de disputa para o account.notifications.marketAlert.title=Alertas de ofertas account.notifications.marketAlert.selectPaymentAccount=Ofertas compatíveis com a conta de pagamento account.notifications.marketAlert.offerType.label=Tipo de oferta que me interessa -account.notifications.marketAlert.offerType.buy=Ofertas de compra (Eu quero vender BTC) -account.notifications.marketAlert.offerType.sell=Ofertas de venda (eu quero comprar BTC) +account.notifications.marketAlert.offerType.buy=Ofertas de compra (Eu quero vender XMR) +account.notifications.marketAlert.offerType.sell=Ofertas de venda (eu quero comprar XMR) account.notifications.marketAlert.trigger=Distância do preço da oferta (%) -account.notifications.marketAlert.trigger.info=Com uma distância de preço definida, você só receberá um alerta quando uma oferta que atenda (ou exceda) os seus requerimentos for publicada. Exemplo: você quer vender BTC, mas você só venderá à um ganho de 2% sobre o atual preço de mercado. Definir esse campo como 2% garantirá que você receba apenas alertas para ofertas com preços que estão 2% (ou mais) acima do atual preço de mercado. +account.notifications.marketAlert.trigger.info=Com uma distância de preço definida, você só receberá um alerta quando uma oferta que atenda (ou exceda) os seus requerimentos for publicada. Exemplo: você quer vender XMR, mas você só venderá à um ganho de 2% sobre o atual preço de mercado. Definir esse campo como 2% garantirá que você receba apenas alertas para ofertas com preços que estão 2% (ou mais) acima do atual preço de mercado. account.notifications.marketAlert.trigger.prompt=Distância da percentagem do preço de mercado (ex: 2.50%, -0.50%, etc) account.notifications.marketAlert.addButton=Adicionar alerta de oferta account.notifications.marketAlert.manageAlertsButton=Gerir alertas de oferta @@ -1305,10 +1331,10 @@ inputControlWindow.balanceLabel=Saldo disponível contractWindow.title=Detalhes da disputa contractWindow.dates=Data de oferta / Data de negócio -contractWindow.btcAddresses=Endereço bitcoin comprador BTC / vendendor BTC -contractWindow.onions=Endereço de rede comprador de BTC / vendendor de BTC -contractWindow.accountAge=Idade da conta do comprador de BTC / vendedor de BTC -contractWindow.numDisputes=Nº de disputas comprador de BTC / vendedor de BTC: +contractWindow.xmrAddresses=Endereço monero comprador XMR / vendendor XMR +contractWindow.onions=Endereço de rede comprador de XMR / vendendor de XMR +contractWindow.accountAge=Idade da conta do comprador de XMR / vendedor de XMR +contractWindow.numDisputes=Nº de disputas comprador de XMR / vendedor de XMR: contractWindow.contractHash=Hash do contrato displayAlertMessageWindow.headline=Informação importante! @@ -1334,8 +1360,8 @@ disputeSummaryWindow.title=Resumo disputeSummaryWindow.openDate=Data de abertura do bilhete disputeSummaryWindow.role=Função do negociador disputeSummaryWindow.payout=Pagamento da quantia de negócio -disputeSummaryWindow.payout.getsTradeAmount={0} de BTC fica com o pagamento da quantia de negócio -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount={0} de XMR fica com o pagamento da quantia de negócio +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=Pagamento personalizado disputeSummaryWindow.payoutAmount.buyer=Quantia de pagamento do comprador disputeSummaryWindow.payoutAmount.seller=Quantia de pagamento do vendedor @@ -1377,7 +1403,7 @@ disputeSummaryWindow.close.button=Fechar bilhete # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1420,18 +1446,18 @@ filterWindow.mediators=Mediadores filtrados (endereços onion separados por vír filterWindow.refundAgents=Agentes de reembolso filtrados (endereços onion sep. por virgula) filterWindow.seedNode=Nós de semente filtrados (endereços onion sep. por vírgula) filterWindow.priceRelayNode=Nós de transmissão de preço filtrados (endereços onion sep. por vírgula) -filterWindow.xmrNode=Nós de Bitcoin filtrados (endereços + portas sep. por vírgula) -filterWindow.preventPublicXmrNetwork=Prevenir uso da rede de Bitcoin pública +filterWindow.xmrNode=Nós de Monero filtrados (endereços + portas sep. por vírgula) +filterWindow.preventPublicXmrNetwork=Prevenir uso da rede de Monero pública filterWindow.disableAutoConf=Disable auto-confirm filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) filterWindow.disableTradeBelowVersion=Mín. versão necessária para negociação filterWindow.add=Adicionar filtro filterWindow.remove=Remover filtro -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Quantia mín. de BTC +offerDetailsWindow.minXmrAmount=Quantia mín. de XMR offerDetailsWindow.min=(mín. {0}) offerDetailsWindow.distance=(distância do preço de mercado: {0}) offerDetailsWindow.myTradingAccount=Minha conta de negociação @@ -1444,6 +1470,7 @@ offerDetailsWindow.confirm.maker=Confirmar: Criar oferta para {0} monero offerDetailsWindow.confirm.taker=Confirmar: Aceitar oferta de {0} monero offerDetailsWindow.creationDate=Data de criação offerDetailsWindow.makersOnion=Endereço onion do ofertante +offerDetailsWindow.challenge=Passphrase da oferta qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1472,7 +1499,7 @@ showWalletDataWindow.walletData=Dados da carteira showWalletDataWindow.includePrivKeys=Incluir chaves privadas setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1484,7 +1511,7 @@ tacWindow.disagree=Eu não concordo e desisto tacWindow.arbitrationSystem=Resolução da disputa tradeDetailsWindow.headline=Negócio -tradeDetailsWindow.disputedPayoutTxId=ID de transação do pagamento disputado: +tradeDetailsWindow.disputedPayoutTxId=ID de transação do pagamento disputado tradeDetailsWindow.tradeDate=Data de negócio tradeDetailsWindow.txFee=Taxa de mineração tradeDetailsWindow.tradePeersOnion=Endereço onion dos parceiros de negociação @@ -1494,8 +1521,10 @@ tradeDetailsWindow.agentAddresses=Árbitro/Mediador tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=Você enviou XMR. +txDetailsWindow.xmr.noteReceived=Você recebeu XMR. +txDetailsWindow.sentTo=Enviado para +txDetailsWindow.receivedWith=Recebido com txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1504,7 +1533,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Digite senha para abrir: @@ -1530,12 +1559,12 @@ torNetworkSettingWindow.bridges.header=O Tor está bloqueado? torNetworkSettingWindow.bridges.info=Se o Tor estiver bloqueado pelo seu fornecedor de internet ou pelo seu país, você pode tentar usar pontes Tor.\nVisite a página web do Tor em: https://bridges.torproject.org/bridges para saber mais sobre pontes e transportes conectáveis. feeOptionWindow.headline=Escolha a moeda para o pagamento da taxa de negócio -feeOptionWindow.info=Pode escolher pagar a taxa de negócio em BSQ ou em BTC. Se escolher BSQ tira proveito da taxa de negócio descontada. +feeOptionWindow.info=Pode escolher pagar a taxa de negócio em BSQ ou em XMR. Se escolher BSQ tira proveito da taxa de negócio descontada. feeOptionWindow.optionsLabel=Escolha a moeda para o pagamento da taxa de negócio -feeOptionWindow.useBTC=Usar BTC +feeOptionWindow.useXMR=Usar XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1577,9 +1606,9 @@ popup.warning.noTradingAccountSetup.msg=Você precisa configurar uma conta de mo popup.warning.noArbitratorsAvailable=Não há árbitros disponíveis. popup.warning.noMediatorsAvailable=Não há mediadores disponíveis. popup.warning.notFullyConnected=Você precisa esperar até estar totalmente conectado à rede.\nIsso pode levar cerca de 2 minutos na inicialização. -popup.warning.notSufficientConnectionsToBtcNetwork=Você precisa esperar até que você tenha pelo menos {0} conexões com a rede Bitcoin. -popup.warning.downloadNotComplete=Você precisa esperar até que o download dos blocos de Bitcoin ausentes esteja completo. -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Você precisa esperar até que você tenha pelo menos {0} conexões com a rede Monero. +popup.warning.downloadNotComplete=Você precisa esperar até que o download dos blocos de Monero ausentes esteja completo. +popup.warning.walletNotSynced=A carteira Haveno não está sincronizada com a altura mais recente da blockchain. Por favor, aguarde até que a carteira seja sincronizada ou verifique a sua conexão. popup.warning.removeOffer=Tem certeza de que deseja remover essa oferta? popup.warning.tooLargePercentageValue=Você não pode definir uma percentagem superior à 100%. popup.warning.examplePercentageValue=Por favor digitar um número percentual como \"5.4\" para 5.4% @@ -1598,14 +1627,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=transmissão de preço popup.warning.seed=semente popup.warning.mandatoryUpdate.trading=Por favor, atualize para a versão mais recente do Haveno. Uma atualização obrigatória que desativa negociação para versões antigas foi lançada. Por favor, confira o Fórum Haveno para mais informações. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=Esta transação não é possível, pois as taxas de mineração de {0} excederia o montante a transferir de {1}. Aguarde até que as taxas de mineração estejam novamente baixas ou até você ter acumulado mais BTC para transferir. +popup.warning.burnXMR=Esta transação não é possível, pois as taxas de mineração de {0} excederia o montante a transferir de {1}. Aguarde até que as taxas de mineração estejam novamente baixas ou até você ter acumulado mais XMR para transferir. -popup.warning.openOffer.makerFeeTxRejected=A transação da taxa de ofertante para a oferta com o ID {0} foi rejeitada pela rede do Bitcoin.\nID da transação={1}.\nA oferta foi removida para evitar futuros problemas.\nPor favor vá à \"Definições/Informação da Rede\" e re-sincronize o ficheiro SPV.\nPara mais ajuda por favor contacte o canal de apoio do Haveno na equipa Keybase do Haveno. +popup.warning.openOffer.makerFeeTxRejected=A transação da taxa de ofertante para a oferta com o ID {0} foi rejeitada pela rede do Monero.\nID da transação={1}.\nA oferta foi removida para evitar futuros problemas.\nPor favor vá à \"Definições/Informação da Rede\" e re-sincronize o ficheiro SPV.\nPara mais ajuda por favor contacte o canal de apoio do Haveno na equipa Keybase do Haveno. popup.warning.trade.txRejected.tradeFee=taxa de negócio popup.warning.trade.txRejected.deposit=depósito -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=A transação de taxa de ofertante para a oferta com o ID {0} é inválida\nID da transação={1}.\nPor favor vá à \"Definições/Informação da Rede\" e re-sincronize o ficheiro SPV.\nPara mais ajuda por favor contacte o canal de apoio do Haveno na equipa Keybase do Haveno. @@ -1614,13 +1642,13 @@ popup.info.securityDepositInfo=Para garantir que ambos os negociadores seguem o popup.info.cashDepositInfo=Por favor, certifique-se de que você tem uma agência bancária na sua área para poder fazer o depósito em dinheiro.\nO ID do banco (BIC/SWIFT) do vendedor é: {0}. popup.info.cashDepositInfo.confirm=Eu confirmo que eu posso fazer o depósito popup.info.shutDownWithOpenOffers=Haveno está sendo fechado, mas há ofertas abertas. \n\nEstas ofertas não estarão disponíveis na rede P2P enquanto o Haveno estiver desligado, mas elas serão publicadas novamente na rede P2P na próxima vez que você iniciar o Haveno.\n\nPara manter suas ofertas on-line, mantenha o Haveno em execução e certifique-se de que este computador também permaneça online (ou seja, certifique-se de que ele não entra no modo de espera... o modo de espera do monitor não causa problema). -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=Notificação privada importante! popup.securityRecommendation.headline=Recomendação de segurança importante -popup.securityRecommendation.msg=Gostaríamos de lembrá-lo de considerar a possibilidade de usar a proteção por senha para sua carteira, caso você ainda não tenha ativado isso.\n\nTambém é altamente recomendável anotar as palavras-semente da carteira. Essas palavras-semente são como uma senha mestre para recuperar sua carteira Bitcoin.\nNa secção \"Semente da Carteira\", você encontrará mais informações.\n\nAlém disso, você deve fazer o backup da pasta completa de dados do programa na secção \"Backup\". +popup.securityRecommendation.msg=Gostaríamos de lembrá-lo de considerar a possibilidade de usar a proteção por senha para sua carteira, caso você ainda não tenha ativado isso.\n\nTambém é altamente recomendável anotar as palavras-semente da carteira. Essas palavras-semente são como uma senha mestre para recuperar sua carteira Monero.\nNa secção \"Semente da Carteira\", você encontrará mais informações.\n\nAlém disso, você deve fazer o backup da pasta completa de dados do programa na secção \"Backup\". popup.shutDownInProgress.headline=Desligando popup.shutDownInProgress.msg=Desligar o programa pode demorar alguns segundos.\nPor favor não interrompa este processo. @@ -1666,6 +1694,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=Nenhum depósito exigido do comprador +popup.info.buyerAsTakerWithoutDeposit=Sua oferta não exigirá um depósito de segurança ou taxa do comprador de XMR.\n\nPara aceitar sua oferta, você deve compartilhar uma senha com seu parceiro comercial fora do Haveno.\n\nA senha é gerada automaticamente e exibida nos detalhes da oferta após a criação. + #################################################################### # Notifications #################################################################### @@ -1673,9 +1704,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign notification.trade.headline=Notificação para o oferta com ID {0} notification.ticket.headline=Bilhete de apoio para o negócio com ID {0} notification.trade.completed=O negócio completou e você já pode levantar seus fundos. -notification.trade.accepted=Sua oferta foi aceite por um {0} de BTC. +notification.trade.accepted=Sua oferta foi aceite por um {0} de XMR. notification.trade.unlocked=Seu negócio tem pelo menos uma confirmação da blockchain.\nVocê pode começar o pagamento agora. -notification.trade.paymentSent=O comprador de BTC iniciou o pagamento +notification.trade.paymentSent=O comprador de XMR iniciou o pagamento notification.trade.selectTrade=Selecionar negócio notification.trade.peerOpenedDispute=Seu par de negociação abriu um {0}. notification.trade.disputeClosed=A {0} foi fechada. @@ -1694,7 +1725,7 @@ systemTray.show=Mostrar janela do programa systemTray.hide=Esconder janela do programa systemTray.info=Informação sobre Haveno systemTray.exit=Sair -systemTray.tooltip=Haveno: Uma rede de echange de bitcoin descentralizada +systemTray.tooltip=Haveno: Uma rede de echange de monero descentralizada #################################################################### @@ -1745,7 +1776,7 @@ tooltip.openBlockchainForTx=Abrir um explorador de blockchain externo para trans confidence.unknown=Estado da transação desconhecido confidence.seen=Visto por {0} par(es) / 0 confirmações -confidence.confirmed=Confirmado em {0} bloco(s) +confidence.confirmed={0} confirmação(ões) confidence.invalid=A transação é inválida peerInfo.title=Informação do par @@ -1756,10 +1787,10 @@ peerInfo.age.noRisk=Idade da conta de pagamento peerInfo.age.chargeBackRisk=Tempo desde a assinatura peerInfo.unknownAge=Idade desconhecida -addressTextField.openWallet=Abrir sua carteira Bitcoin padrão +addressTextField.openWallet=Abrir sua carteira Monero padrão addressTextField.copyToClipboard=Copiar endereço para área de transferência addressTextField.addressCopiedToClipboard=Endereço copiado para área de transferência -addressTextField.openWallet.failed=Abrir a programa de carteira Bitcoin padrão falhou. Talvez você não tenha um instalado? +addressTextField.openWallet.failed=Abrir a programa de carteira Monero padrão falhou. Talvez você não tenha um instalado? peerInfoIcon.tooltip={0}\nRótulo: {1} @@ -1791,6 +1822,7 @@ navigation.support=\"Apoio\" formatter.formatVolumeLabel={0} quantia{1} formatter.makerTaker=Ofertante como {0} {1} / Aceitador como {2} {3} +formatter.makerTakerLocked=Ofertante como {0} {1} / Aceitador como {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Você é {0} {1} ({2} {3}) @@ -1836,7 +1868,6 @@ password.deriveKey=Derivar chave a partir da senha password.walletDecrypted=A carteira foi descriptografada com sucesso e a proteção por senha removida. password.wrongPw=Você digitou a senha errada.\n\nPor favor, tente digitar sua senha novamente, verificando com atenção se há erros de ortografia. password.walletEncrypted=Carteira encriptada com sucesso e proteção por senha ativada. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=As 2 senhas inseridas não são iguais. password.forgotPassword=Esqueceu a senha? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1850,7 +1881,7 @@ seed.date=Data da carteira seed.restore.title=Restaurar carteira a partir de palavras-semente seed.restore=Restaurar carteiras seed.creationDate=Data de criação -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Eu desejo restaurar de qualquer forma seed.warn.walletNotEmpty.emptyWallet=Eu esvaziarei as carteiras primeiro seed.warn.notEncryptedAnymore=Suas carteiras são encriptadas.\n\nApós a restauração, as carteiras não serão mais encriptadas e você deverá definir uma nova senha.\n\nVocê quer continuar? @@ -1867,7 +1898,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=Conta payment.account.no=Nº da conta payment.account.name=Nome da conta -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=Nome completo do titular da conta payment.account.fullName=Nome completo (primeiro, nome do meio, último) @@ -1899,7 +1930,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=Nome de utilizador, email ou nº de telemóvel payment.moneyBeam.accountId=Email ou nº de telemóvel -payment.venmo.venmoUserName=Nome de utilizador do Venmo payment.popmoney.accountId=Email ou nº de telemóvel payment.promptPay.promptPayId=ID de cidadão/ID de impostos ou nº de telemóvel payment.supportedCurrencies=Moedas suportadas @@ -1941,28 +1971,28 @@ payment.checking=Conta Corrente payment.savings=Poupança payment.personalId=ID pessoal payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Haveno to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=Ao usar o HalCash, o comprador de BTC precisa enviar ao vendedor de BTC o código HalCash através de uma mensagem de texto do seu telemóvel.\n\nPor favor, certifique-se de não exceder a quantia máxima que seu banco lhe permite enviar com o HalCash. A quantia mín. de levantamento é de 10 euros e a quantia máx. é de 600 EUR. Para levantamentos repetidos é de 3000 euros por recipiente por dia e 6000 euros por recipiente por mês. Por favor confirme esses limites com seu banco para ter certeza de que eles usam os mesmos limites mencionados aqui.\n\nA quantia de levantamento deve ser um múltiplo de 10 euros, pois você não pode levantar outras quantias de uma ATM. A interface do utilizador no ecrã para criar oferta e aceitar ofertas ajustará a quantia de BTC para que a quantia de EUR esteja correta. Você não pode usar o preço com base no mercado, pois o valor do EUR estaria mudando com a variação dos preços.\n\nEm caso de disputa, o comprador de BTC precisa fornecer a prova de que enviou o EUR. +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=Ao usar o HalCash, o comprador de XMR precisa enviar ao vendedor de XMR o código HalCash através de uma mensagem de texto do seu telemóvel.\n\nPor favor, certifique-se de não exceder a quantia máxima que seu banco lhe permite enviar com o HalCash. A quantia mín. de levantamento é de 10 euros e a quantia máx. é de 600 EUR. Para levantamentos repetidos é de 3000 euros por recipiente por dia e 6000 euros por recipiente por mês. Por favor confirme esses limites com seu banco para ter certeza de que eles usam os mesmos limites mencionados aqui.\n\nA quantia de levantamento deve ser um múltiplo de 10 euros, pois você não pode levantar outras quantias de uma ATM. A interface do utilizador no ecrã para criar oferta e aceitar ofertas ajustará a quantia de XMR para que a quantia de EUR esteja correta. Você não pode usar o preço com base no mercado, pois o valor do EUR estaria mudando com a variação dos preços.\n\nEm caso de disputa, o comprador de XMR precisa fornecer a prova de que enviou o EUR. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Por favor, confirme que seu banco permite-lhe enviar depósitos em dinheiro para contas de outras pessoas. Por exemplo, o Bank of America e o Wells Fargo não permitem mais esses depósitos. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=Informação de contacto payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1973,7 +2003,7 @@ payment.f2f.city.prompt=A cidade será exibida com a oferta payment.shared.optionalExtra=Informação adicional opcional payment.shared.extraInfo=Informação adicional payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Abrir página web payment.f2f.offerbook.tooltip.countryAndCity=País e cidade: {0} / {1} payment.f2f.offerbook.tooltip.extra=Informação adicional: {0} @@ -1985,7 +2015,7 @@ payment.japan.recipient=Nome payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2143,7 +2173,7 @@ validation.zero=Número 0 não é permitido validation.negative=Valores negativos não são permitidos. validation.traditional.tooSmall=Input menor do que a quantia mínima permitida. validation.traditional.tooLarge=Input maior do que a quantia máxima permitida. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=O input maior que {0} não é permitido. validation.xmr.tooSmall=Input menor que {0} não é permitido. validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2153,10 +2183,10 @@ validation.sortCodeChars={0} deve consistir de {1} caracteres. validation.bankIdNumber={0} deve consistir de {1 números. validation.accountNr=O número de conta deve conter {0} números. validation.accountNrChars=O número da conta deve conter {0} caracteres. -validation.btc.invalidAddress=O endereço está incorreto. Por favor verificar o formato do endereço. +validation.xmr.invalidAddress=O endereço está incorreto. Por favor verificar o formato do endereço. validation.integerOnly=Por favor, insira apenas números inteiros validation.inputError=O seu input causou um erro:\n{0} -validation.btc.exceedsMaxTradeLimit=O seu limite de negócio é de {0}. +validation.xmr.exceedsMaxTradeLimit=O seu limite de negócio é de {0}. validation.nationalAccountId={0} tem de ser constituído por {1} números #new diff --git a/core/src/main/resources/i18n/displayStrings_ru.properties b/core/src/main/resources/i18n/displayStrings_ru.properties index 3624b6c350..664aebdaf9 100644 --- a/core/src/main/resources/i18n/displayStrings_ru.properties +++ b/core/src/main/resources/i18n/displayStrings_ru.properties @@ -36,12 +36,14 @@ shared.iUnderstand=Я понимаю shared.na=Н/Д shared.shutDown=Закрыть shared.reportBug=Report bug on GitHub -shared.buyBitcoin=Купить биткойн -shared.sellBitcoin=Продать биткойн +shared.buyMonero=Купить биткойн +shared.sellMonero=Продать биткойн shared.buyCurrency=Купить {0} shared.sellCurrency=Продать {0} -shared.buyingBTCWith=покупка ВТС за {0} -shared.sellingBTCFor=продажа ВТС за {0} +shared.buyCurrencyLocked=Купить {0} 🔒 +shared.sellCurrencyLocked=Продать {0} 🔒 +shared.buyingXMRWith=покупка ВТС за {0} +shared.sellingXMRFor=продажа ВТС за {0} shared.buyingCurrency=покупка {0} (продажа ВТС) shared.sellingCurrency=продажа {0} (покупка ВТС) shared.buy=покупки @@ -93,7 +95,7 @@ shared.amountMinMax=Количество (мин. — макс.) shared.amountHelp=Если предложение включает диапазон сделки, вы можете обменять любую сумму в этом диапазоне. shared.remove=Удалить shared.goTo=Перейти к {0} -shared.BTCMinMax=ВТС (мин. — макс.) +shared.XMRMinMax=ВТС (мин. — макс.) shared.removeOffer=Удалить предложение shared.dontRemoveOffer=Не удалять предложение shared.editOffer=Изменить предложение @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=Да, отменить shared.nextStep=Далее shared.selectTradingAccount=Выбрать торговый счёт -shared.fundFromSavingsWalletButton=Перевести средства с кошелька Haveno +shared.fundFromSavingsWalletButton=Применить средства из кошелька Haveno shared.fundFromExternalWalletButton=Открыть внешний кошелёк для пополнения -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=% ниже рыночного курса shared.aboveInPercent=% выше рыночного курса shared.enterPercentageValue=Ввести величину в % shared.OR=ИЛИ shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=Ожидание средств... -shared.TheBTCBuyer=Покупатель ВТС +shared.TheXMRBuyer=Покупатель ВТС shared.You=Вы shared.sendingConfirmation=Отправка подтверждения... shared.sendingConfirmationAgain=Отправьте подтверждение повторно @@ -123,9 +125,8 @@ shared.noDateAvailable=Дата не указана shared.noDetailsAvailable=Подробности не указаны shared.notUsedYet=Ещё не использовано shared.date=Дата -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=Скопировать в буфер shared.language=Язык shared.country=Страна @@ -140,6 +141,7 @@ shared.addNewAccount=Добавить новый счёт shared.ExportAccounts=Экспортировать счета shared.importAccounts=Импортировать счета shared.createNewAccount=Создать новый счёт +shared.createNewAccountDescription=Данные вашей учетной записи хранятся локально на вашем устройстве и передаются только вашему торговому партнеру и арбитру, если открывается спор. shared.saveNewAccount=Сохранить новый счёт shared.selectedAccount=Выбранный счёт shared.deleteAccount=Удалить счёт @@ -179,19 +181,21 @@ shared.messageSendingFailed=Ошибка отправки сообщения: {0 shared.unlock=Разблокировать shared.toReceive=получить shared.toSpend=потратить -shared.btcAmount=Сумма ВТС +shared.xmrAmount=Сумма ВТС shared.yourLanguage=Ваши языки shared.addLanguage=Добавить язык shared.total=Всего shared.totalsNeeded=Требуемая сумма shared.tradeWalletAddress=Адрес кошелька сделки shared.tradeWalletBalance=Баланс кошелька сделки +shared.reserveExactAmount=Резервируйте только необходимые средства. Требуется комиссия за майнинг и ~20 минут, прежде чем ваше предложение станет активным. shared.makerTxFee=Мейкер: {0} shared.takerTxFee=Тейкер: {0} shared.iConfirm=Подтверждаю shared.openURL=Открыть {0} shared.fiat=Нац. валюта shared.crypto=Криптовалюта +shared.preciousMetals=Драгоценные металлы shared.all=Все shared.edit=Редактировать shared.advancedOptions=Дополнительные настройки @@ -226,8 +230,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=Рынок -mainView.menu.buyBtc=Купить BTC -mainView.menu.sellBtc=Продать BTC +mainView.menu.buyXmr=Купить XMR +mainView.menu.sellXmr=Продать XMR mainView.menu.portfolio=Сделки mainView.menu.funds=Средства mainView.menu.support=Поддержка @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Выделено mainView.balance.pending.short=В сделках mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(локальный узел) +mainView.footer.localhostMoneroNode=(локальный узел) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Подключение к сети Биткойн -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=Подключение к сети Haveno +mainView.footer.xmrInfo.synchronizingWith=Синхронизация с {0} на блоке: {1} / {2} +mainView.footer.xmrInfo.connectedTo=Подключено к {0} на блоке {1} +mainView.footer.xmrInfo.synchronizingWalletWith=Синхронизация кошелька с {0} на блоке: {1} / {2} +mainView.footer.xmrInfo.syncedWith=Синхронизировано с {0} на блоке {1} mainView.footer.xmrInfo.connectingTo=Подключение к mainView.footer.xmrInfo.connectionFailed=Connection failed to mainView.footer.xmrPeers=Monero network peers: {0} @@ -274,7 +281,7 @@ mainView.walletServiceErrorMsg.connectionError=Не удалось подклю mainView.walletServiceErrorMsg.rejectedTxException=A transaction was rejected from the network.\n\n{0} mainView.networkWarning.allConnectionsLost=Сбой соединения со всеми {0} узлами сети.\nВозможно, вы отключились от интернета, или Ваш компьютер перешел в режим ожидания. -mainView.networkWarning.localhostBitcoinLost=Сбой соединения с локальным узлом Биткойн.\nПерезапустите приложение для подключения к другим узлам Биткойн или перезапустите свой локальный узел Биткойн. +mainView.networkWarning.localhostMoneroLost=Сбой соединения с локальным узлом Биткойн.\nПерезапустите приложение для подключения к другим узлам Биткойн или перезапустите свой локальный узел Биткойн. mainView.version.update=(Имеется обновление) @@ -299,9 +306,9 @@ market.offerBook.sell=Хочу продать биткойн # SpreadView market.spread.numberOfOffersColumn=Все предложения ({0}) -market.spread.numberOfBuyOffersColumn=Купить BTC ({0}) -market.spread.numberOfSellOffersColumn=Продать BTC ({0}) -market.spread.totalAmountColumn=Итого BTC ({0}) +market.spread.numberOfBuyOffersColumn=Купить XMR ({0}) +market.spread.numberOfSellOffersColumn=Продать XMR ({0}) +market.spread.totalAmountColumn=Итого XMR ({0}) market.spread.spreadColumn=Спред market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=Создать предложение offerbook.takeOffer=Принять предложение offerbook.takeOfferToBuy=Принять предложение купить {0} offerbook.takeOfferToSell=Принять предложение продать {0} +offerbook.takeOffer.enterChallenge=Введите фразу-пароль предложения offerbook.trader=Трейдер offerbook.offerersBankId=Идент. банка (BIC/SWIFT) мейкера: {0} offerbook.offerersBankName=Название банка мейкера: {0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=Допустимые страны банка offerbook.availableOffers=Доступные предложения offerbook.filterByCurrency=Фильтровать по валюте offerbook.filterByPaymentMethod=Фильтровать по способу оплаты -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=Предложения, соответствующие моим аккаунтам +offerbook.filterNoDeposit=Нет депозита +offerbook.noDepositOffers=Предложения без депозита (требуется пароль) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=account was banned offerbook.timeSinceSigning.daysSinceSigning={0} дн. offerbook.timeSinceSigning.daysSinceSigning.long={0} since signing offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=Купить XMR с помощью: +offerbook.sellXmrFor=Продать XMR за: offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=Кол-во предложений: {0} offerbook.volume={0} (мин. — макс.) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=Создать предложение для {0} {1} offerbook.createOfferToBuy=Создать новое предложение на покупку {0} offerbook.createOfferToSell=Создать новое предложение на продажу {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- The buyer''s account has not been signed by an arbitrator or a peer\n- The time since signing of the buyer''s account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- Your account has not been signed by an arbitrator or a peer\n- The time since signing of your account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Этот способ оплаты временно ограничен до {0} до {1}, поскольку все покупатели имеют новые аккаунты.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Ваше предложение будет ограничено для покупателей с подписанными и старыми аккаунтами, потому что оно превышает {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Это предложение требует другой версии протокола, чем та, что используется в вашей версии приложения.\n\nПроверьте, установлена ли у вас новейшая версия приложения. Если да, то пользователь, создавший предложение, использовал старую версию.\n\nПри использовании несовместимой версии торгового протокола торговля невозможна. offerbook.warning.userIgnored=Onion-адрес данного пользователя добавлен в чёрный список. @@ -394,7 +409,6 @@ offerbook.warning.offerBlocked=Это предложение заблокиро offerbook.warning.currencyBanned=Валюта, используемая в этом предложении, заблокирована разработчиками Haveno.\nПодробности можно узнать на форуме Haveno. offerbook.warning.paymentMethodBanned=Метод платежа, использованный в этом предложении, заблокирован разработчиками Haveno.\nПодробности можно узнать на форуме Haveno. offerbook.warning.nodeBlocked=Onion-адрес этого трейдера заблокирован разработчиками Haveno.\nВероятно, принятие предложения от данного трейдера вызывает необрабатываемую ошибку. -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=Продажа по рыночному курсу (обновляется ежеминутно). @@ -415,7 +429,7 @@ offerbook.info.roundedFiatVolume=Сумма округлена, чтобы по createOffer.amount.prompt=Введите сумму в ВТС createOffer.price.prompt=Введите курс createOffer.volume.prompt=Введите сумму в {0} -createOffer.amountPriceBox.amountDescription=Количество BTC для {0} +createOffer.amountPriceBox.amountDescription=Количество XMR для {0} createOffer.amountPriceBox.buy.volumeDescription=Сумма затрат в {0} createOffer.amountPriceBox.sell.volumeDescription=Сумма в {0} к получению createOffer.amountPriceBox.minAmountDescription=Мин. количество ВТС @@ -434,7 +448,7 @@ createOffer.info.sellAboveMarketPrice=Вы всегда получите на {0 createOffer.info.buyBelowMarketPrice=Вы всегда заплатите на {0}% меньше текущего рыночного курса, так как курс вашего предложения будет постоянно обновляться. createOffer.warning.sellBelowMarketPrice=Вы всегда получите на {0}% меньше текущего рыночного курса, так как курс вашего предложения будет постоянно обновляться. createOffer.warning.buyAboveMarketPrice=Вы всегда заплатите на {0}% больше текущего рыночного курса, так как курс вашего предложения будет постоянно обновляться. -createOffer.tradeFee.descriptionBTCOnly=Комиссия за сделку +createOffer.tradeFee.descriptionXMROnly=Комиссия за сделку createOffer.tradeFee.descriptionBSQEnabled=Выбрать валюту комиссии за сделку createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +462,12 @@ createOffer.placeOfferButton=Проверка: разместить предло createOffer.createOfferFundWalletInfo.headline=Обеспечить своё предложение # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Сумма сделки: {0} \n -createOffer.createOfferFundWalletInfo.msg=Вы должны внести {0} для обеспечения этого предложения.\n\nЭти средства будут зарезервированы в вашем локальном кошельке, а когда кто-то примет ваше предложение — заблокированы на депозитном multisig-адресе.\n\nСумма состоит из:\n{1}- вашего залога: {2},\n- комиссии за сделку: {3},\n- комиссии майнера: {4}.\n\nВы можете выбрать один из двух вариантов финансирования сделки:\n - использовать свой кошелёк Haveno (удобно, но сделки можно отследить) ИЛИ\n - перевести из внешнего кошелька (потенциально более анонимно).\n\nВы увидите все варианты обеспечения предложения и их подробности после закрытия этого окна. +createOffer.createOfferFundWalletInfo.msg=Вам нужно внести депозит {0} для этого предложения.\n\n\ + Эти средства резервируются в вашем локальном кошельке и будут заблокированы в мультиподписном кошельке, как только кто-то примет ваше предложение.\n\n\ + Сумма состоит из:\n\ + {1}\ + - Ваш залог: {2}\n\ + - Торговая комиссия: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Ошибка при создании предложения:\n\n{0}\n\nВаши средства остались в кошельке.\nПерезагрузите приложение и проверьте сетевое соединение. @@ -470,7 +489,10 @@ createOffer.setDepositAsBuyer=Установить мой залог как по createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=Сумма залога покупателя: {0} createOffer.securityDepositInfoAsBuyer=Сумма вашего залога: {0} -createOffer.minSecurityDepositUsed=Min. buyer security deposit is used +createOffer.minSecurityDepositUsed=Минимальный залог используется +createOffer.buyerAsTakerWithoutDeposit=Залог от покупателя не требуется (защищено паролем) +createOffer.myDeposit=Мой залог (%) +createOffer.myDepositInfo=Ваш залог составит {0} #################################################################### @@ -478,22 +500,24 @@ createOffer.minSecurityDepositUsed=Min. buyer security deposit is used #################################################################### takeOffer.amount.prompt=Введите сумму в ВТС -takeOffer.amountPriceBox.buy.amountDescription=Сумма BTC для продажи -takeOffer.amountPriceBox.sell.amountDescription=Сумма BTC для покупки +takeOffer.amountPriceBox.buy.amountDescription=Сумма XMR для продажи +takeOffer.amountPriceBox.sell.amountDescription=Сумма XMR для покупки takeOffer.amountPriceBox.priceDescription=Цена за биткойн в {0} takeOffer.amountPriceBox.amountRangeDescription=Возможный диапазон суммы -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=Слишком много знаков после запятой.\nКоличество знаков скорректировано до 4. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=Слишком много знаков после запятой.\nКоличество знаков скорректировано до 4. takeOffer.validation.amountSmallerThanMinAmount=Сумма не может быть меньше минимальной суммы, указанной в предложении. takeOffer.validation.amountLargerThanOfferAmount=Введённая сумма не может превышать сумму, указанную в предложении. -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Указанная сумма придет к появлению «пыли» у продавца BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Указанная сумма придет к появлению «пыли» у продавца XMR. takeOffer.fundsBox.title=Обеспечьте свою сделку takeOffer.fundsBox.isOfferAvailable=Проверка доступности предложения... takeOffer.fundsBox.tradeAmount=Сумма для продажи takeOffer.fundsBox.offerFee=Комиссия за сделку takeOffer.fundsBox.networkFee=Oбщая комиссия майнера -takeOffer.fundsBox.takeOfferSpinnerInfo=Принятие предложения... +takeOffer.fundsBox.takeOfferSpinnerInfo=Принятие предложения: {0} takeOffer.fundsBox.paymentLabel=Сделка в Haveno с идентификатором {0} takeOffer.fundsBox.fundsStructure=({0} — залог, {1} — комиссия за сделку, {2} — комиссия майнера) +takeOffer.fundsBox.noFundingRequiredTitle=Не требуется финансирование +takeOffer.fundsBox.noFundingRequiredDescription=Получите пароль предложения от продавца вне Haveno, чтобы принять это предложение. takeOffer.success.headline=Вы успешно приняли предложение. takeOffer.success.info=Статус вашей сделки отображается в разделе \«Папка/Текущие сделки\». takeOffer.error.message=Ошибка при принятии предложения:\n\n{0} @@ -504,7 +528,7 @@ takeOffer.noPriceFeedAvailable=Нельзя принять это предлож takeOffer.takeOfferFundWalletInfo.headline=Обеспечьте свою сделку # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Сумма сделки: {0} \n -takeOffer.takeOfferFundWalletInfo.msg=Вы должны внести {0} для принятия этого предложения.\n\nСумма состоит из:\n{1}- вашего залога: {2},\n- комиссии за сделку: {3},\n- общей комиссии майнера: {4}.\n\nВы можете выбрать один из двух вариантов финансирования сделки:\n - использовать свой кошелёк Haveno (удобно, но сделки можно отследить) ИЛИ\n - перевести из внешнего кошелька (потенциально более анонимно).\n\nВы увидите все варианты обеспечения предложения и их подробности после закрытия этого окна. +takeOffer.takeOfferFundWalletInfo.msg=Вам нужно внести депозит в размере {0} для принятия этого предложения.\n\nСумма составляет:\n{1}- Ваш залог: {2}\n- Торговая комиссия: {3} takeOffer.alreadyPaidInFunds=Если вы уже внесли средства, их можно вывести в разделе \«Средства/Отправить средства\». takeOffer.paymentInfo=Информация о платеже takeOffer.setAmountPrice=Задайте сумму @@ -597,7 +621,7 @@ portfolio.pending.step1.openForDispute=The deposit transaction is still not conf # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" @@ -606,20 +630,20 @@ portfolio.pending.step2_buyer.crypto=Переведите {1} с внешнег portfolio.pending.step2_buyer.cash=Обратитесь в банк и заплатите {0} продавцу ВТС.\n\n portfolio.pending.step2_buyer.cash.extra=ВАЖНОЕ ТРЕБОВАНИЕ:\nПосле оплаты напишите на бумажной квитанции «ВОЗВРАТУ НЕ ПОДЛЕЖИТ».\nЗатем разорвите квитанцию на 2 части, сфотографируйте её и отошлите на электронный адрес продавца ВТС. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Заплатите {0} продавцу BTC через MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=ВАЖНОЕ ТРЕБОВАНИЕ:\nПосле оплаты отправьте продавцу BTC по электронной почте код подтверждения и фото квитанции.\nВ квитанции должно быть четко указано полное имя продавца, страна (штат) и сумма. Электронный адрес продавца: {0}. +portfolio.pending.step2_buyer.moneyGram=Заплатите {0} продавцу XMR через MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=ВАЖНОЕ ТРЕБОВАНИЕ:\nПосле оплаты отправьте продавцу XMR по электронной почте код подтверждения и фото квитанции.\nВ квитанции должно быть четко указано полное имя продавца, страна (штат) и сумма. Электронный адрес продавца: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Заплатите {0} продавцу BTC через Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=ВАЖНОЕ ТРЕБОВАНИЕ: \nПосле оплаты отправьте по электронной почте продавцу BTC контрольный номер MTCN и фото квитанции.\nВ квитанции должно быть четко указано полное имя продавца, город, страна и сумма. Электронный адрес продавца: {0}. +portfolio.pending.step2_buyer.westernUnion=Заплатите {0} продавцу XMR через Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=ВАЖНОЕ ТРЕБОВАНИЕ: \nПосле оплаты отправьте по электронной почте продавцу XMR контрольный номер MTCN и фото квитанции.\nВ квитанции должно быть четко указано полное имя продавца, город, страна и сумма. Электронный адрес продавца: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Отправьте {0} \«Почтовым денежным переводом США\» продавцу BTC.\n\n +portfolio.pending.step2_buyer.postal=Отправьте {0} \«Почтовым денежным переводом США\» продавцу XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Свяжитесь с продавцом BTC с помощью указанных контактных данных и договоритесь о встрече для оплаты {0}.\n\n +portfolio.pending.step2_buyer.f2f=Свяжитесь с продавцом XMR с помощью указанных контактных данных и договоритесь о встрече для оплаты {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Начать оплату, используя {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=Сумма для перевода @@ -631,24 +655,24 @@ portfolio.pending.step2_buyer.openForDispute=You have not completed your payment portfolio.pending.step2_buyer.paperReceipt.headline=Вы отослали бумажную квитанцию продавцу ВТС? portfolio.pending.step2_buyer.paperReceipt.msg=Помните:\nВам необходимо написать на бумажной квитанции «ВОЗВРАТУ НЕ ПОДЛЕЖИТ».\nЗатем разорвите её пополам, сфотографируйте и отошлите по электронной почте продавцу ВТС. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Отправить код подтверждения и квитанцию -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Вам необходимо отправить по электронной почте продавцу BTC код подтверждения и фото квитанции.\nВ квитанции должно быть четко указано полное имя продавца, страна (штат) и сумма. Электронный адрес продавца: {0}.\n\nВы отправили продавцу код подтверждения и квитанцию? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Вам необходимо отправить по электронной почте продавцу XMR код подтверждения и фото квитанции.\nВ квитанции должно быть четко указано полное имя продавца, страна (штат) и сумма. Электронный адрес продавца: {0}.\n\nВы отправили продавцу код подтверждения и квитанцию? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Отправить MTCN и квитанцию -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Вам необходимо отправить по электронной почте продавцу BTC контрольный номер MTCN и фотографию квитанции.\nВ квитанции должно быть четко указано полное имя продавца, город, страна и сумма. Адрес электронной почты продавца: {0}. \n\nВы отправили MTCN и контракт продавцу? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Вам необходимо отправить по электронной почте продавцу XMR контрольный номер MTCN и фотографию квитанции.\nВ квитанции должно быть четко указано полное имя продавца, город, страна и сумма. Адрес электронной почты продавца: {0}. \n\nВы отправили MTCN и контракт продавцу? portfolio.pending.step2_buyer.halCashInfo.headline=Отправить код HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=Вам необходимо отправить сообщение с кодом HalCash и идентификатором сделки ({0}) продавцу BTC.\nНомер моб. тел. продавца: {1}\n\nВы отправили код продавцу? +portfolio.pending.step2_buyer.halCashInfo.msg=Вам необходимо отправить сообщение с кодом HalCash и идентификатором сделки ({0}) продавцу XMR.\nНомер моб. тел. продавца: {1}\n\nВы отправили код продавцу? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Some banks might verify the receiver's name. Faster Payments accounts created in old Haveno clients do not provide the receiver's name, so please use trade chat to obtain it (if needed). portfolio.pending.step2_buyer.confirmStart.headline=Подтвердите начало платежа portfolio.pending.step2_buyer.confirmStart.msg=Вы начали платеж {0} своему контрагенту? portfolio.pending.step2_buyer.confirmStart.yes=Да portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=Ожидайте платеж portfolio.pending.step2_seller.f2fInfo.headline=Контактная информация покупателя -portfolio.pending.step2_seller.waitPayment.msg=Депозитная транзакция подтверждена в блокчейне не менее одного раза.\nДождитесь начала платежа в {0} покупателем BTC. -portfolio.pending.step2_seller.warn=Покупатель BTC все еще не завершил платеж в {0}.\nДождитесь начала оплаты.\nЕсли сделка не завершится {1}, арбитр начнет разбирательство. -portfolio.pending.step2_seller.openForDispute=The BTC buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. +portfolio.pending.step2_seller.waitPayment.msg=Депозитная транзакция подтверждена в блокчейне не менее одного раза.\nДождитесь начала платежа в {0} покупателем XMR. +portfolio.pending.step2_seller.warn=Покупатель XMR все еще не завершил платеж в {0}.\nДождитесь начала оплаты.\nЕсли сделка не завершится {1}, арбитр начнет разбирательство. +portfolio.pending.step2_seller.openForDispute=The XMR buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. tradeChat.chatWindowTitle=Chat window for trade with ID ''{0}'' tradeChat.openChat=Open chat window tradeChat.rules=You can communicate with your trade peer to resolve potential problems with this trade.\nIt is not mandatory to reply in the chat.\nIf a trader violates any of the rules below, open a dispute and report it to the mediator or arbitrator.\n\nChat rules:\n\t● Do not send any links (risk of malware). You can send the transaction ID and the name of a block explorer.\n\t● Do not send your seed words, private keys, passwords or other sensitive information!\n\t● Do not encourage trading outside of Haveno (no security).\n\t● Do not engage in any form of social engineering scam attempts.\n\t● If a peer is not responding and prefers to not communicate via chat, respect their decision.\n\t● Keep conversation scope limited to the trade. This chat is not a messenger replacement or troll-box.\n\t● Keep conversation friendly and respectful. @@ -671,21 +695,21 @@ portfolio.pending.step3_buyer.wait.info=Ожидание подтвержден portfolio.pending.step3_buyer.wait.msgStateInfo.label=Статус сообщения о начале платежа portfolio.pending.step3_buyer.warn.part1a=в блокчейне {0} portfolio.pending.step3_buyer.warn.part1b=у вашего поставщика платёжных услуг (напр., банка) -portfolio.pending.step3_buyer.warn.part2=The BTC seller still has not confirmed your payment. Please check {0} if the payment sending was successful. -portfolio.pending.step3_buyer.openForDispute=The BTC seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. +portfolio.pending.step3_buyer.warn.part2=The XMR seller still has not confirmed your payment. Please check {0} if the payment sending was successful. +portfolio.pending.step3_buyer.openForDispute=The XMR seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Ваш контрагент подтвердил начало оплаты в {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=в вашем любимом обозревателе блоков {0} portfolio.pending.step3_seller.crypto.wallet=в вашем кошельке {0} portfolio.pending.step3_seller.crypto={0}Проверьте {1}, была ли транзакция в ваш адрес\n{2}\nподтверждена достаточное количество раз.\nСумма платежа должна составлять {3}.\n\n Вы можете скопировать и вставить свой адрес {4} из главного окна после закрытия этого окна. -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=Так как оплата осуществляется наличными на счёт, покупатель BTC должен написать \«НЕ ПОДЛЕЖИТ ВОЗВРАТУ\» на квитанции, разорвать её на 2 части и отправить вам её фото по электронной почте.\n\nЧтобы избежать возврата платёжа, подтверждайте его получение только после получения этого фото, если вы не сомневаетесь в подлинности квитанции.\nЕсли вы не уверены, {0} -portfolio.pending.step3_seller.moneyGram=Покупатель обязан отправить вам по электронной почте код подтверждения и фото квитанции.\nВ квитанции должно быть четко указано ваше полное имя, страна (штат) и сумма. Убедитесь, что вы получили код подтверждения по электронной почте.\n\nПосле закрытия этого окна вы увидите имя и адрес покупателя BTC, которые необходимо указать для получения денег от MoneyGram.\n\nПодтвердите получение только после того, как вы успешно заберете деньги! -portfolio.pending.step3_seller.westernUnion=Покупатель обязан отправить вам по электронной почте контрольный номер MTCN и фото квитанции.\nВ квитанции должно быть четко указано ваше полное имя, город, страна и сумма. Убедитесь, что вы получили номер MTCN по электронной почте.\n\nПосле закрытия этого окна вы увидите имя и адрес покупателя BTC, которые необходимо указать для получения денег от Western Union. \n\nПодтвердите получение только после того, как вы успешно заберете деньги! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=Так как оплата осуществляется наличными на счёт, покупатель XMR должен написать \«НЕ ПОДЛЕЖИТ ВОЗВРАТУ\» на квитанции, разорвать её на 2 части и отправить вам её фото по электронной почте.\n\nЧтобы избежать возврата платёжа, подтверждайте его получение только после получения этого фото, если вы не сомневаетесь в подлинности квитанции.\nЕсли вы не уверены, {0} +portfolio.pending.step3_seller.moneyGram=Покупатель обязан отправить вам по электронной почте код подтверждения и фото квитанции.\nВ квитанции должно быть четко указано ваше полное имя, страна (штат) и сумма. Убедитесь, что вы получили код подтверждения по электронной почте.\n\nПосле закрытия этого окна вы увидите имя и адрес покупателя XMR, которые необходимо указать для получения денег от MoneyGram.\n\nПодтвердите получение только после того, как вы успешно заберете деньги! +portfolio.pending.step3_seller.westernUnion=Покупатель обязан отправить вам по электронной почте контрольный номер MTCN и фото квитанции.\nВ квитанции должно быть четко указано ваше полное имя, город, страна и сумма. Убедитесь, что вы получили номер MTCN по электронной почте.\n\nПосле закрытия этого окна вы увидите имя и адрес покупателя XMR, которые необходимо указать для получения денег от Western Union. \n\nПодтвердите получение только после того, как вы успешно заберете деньги! portfolio.pending.step3_seller.halCash=Покупатель должен отправить вам код HalCash в текстовом сообщении. Кроме того, вы получите сообщение от HalCash с информацией, необходимой для снятия EUR в банкомате, поддерживающем HalCash.\n\nПосле того, как вы заберете деньги из банкомата, подтвердите получение платежа в приложении! portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. @@ -713,7 +737,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Вы получили п # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Please also verify that the name of the sender specified on the trade contract matches the name that appears on your bank statement:\nSender''s name, per trade contract: {0}\n\nIf the names are not exactly the same, don''t confirm payment receipt. Instead, open a dispute by pressing \"alt + o\" or \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the BTC buyer and the security deposit will be refunded.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the XMR buyer and the security deposit will be refunded.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Подтвердите получение платежа portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Да, я получил (-а) платёж portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANT: By confirming receipt of payment, you are also verifying the account of the counterparty and signing it accordingly. Since the account of the counterparty hasn't been signed yet, you should delay confirmation of the payment as long as possible to reduce the risk of a chargeback. @@ -723,7 +747,7 @@ portfolio.pending.step5_buyer.tradeFee=Комиссия за сделку portfolio.pending.step5_buyer.makersMiningFee=Комиссия майнера portfolio.pending.step5_buyer.takersMiningFee=Oбщая комиссия майнера portfolio.pending.step5_buyer.refunded=Сумма возмещённого залога -portfolio.pending.step5_buyer.withdrawBTC=Вывести биткойны +portfolio.pending.step5_buyer.withdrawXMR=Вывести биткойны portfolio.pending.step5_buyer.amount=Сумма для вывода portfolio.pending.step5_buyer.withdrawToAddress=Вывести на адрес portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet @@ -794,7 +818,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -890,7 +914,7 @@ funds.tx.revert=Отменить funds.tx.txSent=Транзакция успешно отправлена на новый адрес локального кошелька Haveno. funds.tx.direction.self=Транзакция внутри кошелька funds.tx.dustAttackTx=Полученная «пыль» -funds.tx.dustAttackTx.popup=Вы получили очень маленькую сумму BTC, что может являться попыткой компаний, занимающихся анализом блокчейна, проследить за вашим кошельком.\n\nЕсли вы воспользуетесь этими средствами для совершения исходящей транзакции, они смогут узнать, что вы также являетесь вероятным владельцем другого адреса (т. н. «объединение монет»).\n\nДля защиты вашей конфиденциальности кошелёк Haveno игнорирует такую «пыль» при совершении исходящих транзакций и отображении баланса. Вы можете самостоятельно установить сумму, которая будет рассматриваться в качестве «пыли» в настройках. +funds.tx.dustAttackTx.popup=Вы получили очень маленькую сумму XMR, что может являться попыткой компаний, занимающихся анализом блокчейна, проследить за вашим кошельком.\n\nЕсли вы воспользуетесь этими средствами для совершения исходящей транзакции, они смогут узнать, что вы также являетесь вероятным владельцем другого адреса (т. н. «объединение монет»).\n\nДля защиты вашей конфиденциальности кошелёк Haveno игнорирует такую «пыль» при совершении исходящих транзакций и отображении баланса. Вы можете самостоятельно установить сумму, которая будет рассматриваться в качестве «пыли» в настройках. #################################################################### # Support @@ -904,7 +928,6 @@ support.filter=Search disputes support.filter.prompt=Введите идентификатор сделки, дату, onion-адрес или данные учётной записи support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -952,10 +975,9 @@ support.process=Process support.buyerMaker=Покупатель ВТС/мейкер support.sellerMaker=Продавец ВТС/мейкер support.buyerTaker=Покупатель ВТС/тейкер -support.sellerTaker=Продавец BTC/тейкер +support.sellerTaker=Продавец XMR/тейкер -support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\nTraders can communicate within the application via secure chat on the open trades screen to try solving disputes on their own. If that is not sufficient, a mediator can step in to help. The mediator will evaluate the situation and suggest a payout of trade funds. If both traders accept this suggestion, the payout transaction is completed and the trade is closed. If one or both traders do not agree to the mediator's suggested payout, they can request arbitration.The arbitrator will re-evaluate the situation and, if warranted, personally pay the trader back and request reimbursement for this payment from Haveno. -support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the BTC buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the BTC seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} +support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the XMR buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the XMR seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} support.systemMsg=Системное сообщение: {0} support.youOpenedTicket=Вы запросили поддержку.\n\n{0}\n\nВерсия Haveno: {1} support.youOpenedDispute=Вы начали спор.\n\n{0}\n\nВерсия Haveno: {1} @@ -979,13 +1001,14 @@ settings.tab.network=Информация о сети settings.tab.about=О проекте setting.preferences.general=Основные настройки -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Макс. отклонение от рыночного курса setting.preferences.avoidStandbyMode=Избегать режима ожидания +setting.preferences.useSoundForNotifications=Воспроизводить звуки для уведомлений setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Значения выше {0}% запрещены. setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1022,29 +1045,31 @@ settings.preferences.editCustomExplorer.name=Имя settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=Сеть Биткойн +settings.net.xmrHeader=Сеть Биткойн settings.net.p2pHeader=Haveno network settings.net.onionAddressLabel=Мой onion-адрес settings.net.xmrNodesLabel=Использовать особые узлы Monero settings.net.moneroPeersLabel=Подключенные пиры +settings.net.connection=Соединение +settings.net.connected=Подключено settings.net.useTorForXmrJLabel=Использовать Tor для сети Monero settings.net.moneroNodesLabel=Узлы Monero для подключения -settings.net.useProvidedNodesRadio=Использовать предоставленные узлы Bitcoin Core -settings.net.usePublicNodesRadio=Использовать общедоступную сеть Bitcoin -settings.net.useCustomNodesRadio=Использовать особые узлы Bitcoin Core +settings.net.useProvidedNodesRadio=Использовать предоставленные узлы Monero Core +settings.net.usePublicNodesRadio=Использовать общедоступную сеть Monero +settings.net.useCustomNodesRadio=Использовать особые узлы Monero Core settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=Нет, использовать предоставленные узлы settings.net.warn.usePublicNodes.usePublic=Да, использовать общедоступную сеть -settings.net.warn.useCustomNodes.B2XWarning=Убедитесь, что ваш узел Биткойн является доверенным узлом Bitcoin Core! \n\nПодключение к узлам, не следующим правилам консенсуса Bitcoin Core, может повредить ваш кошелек и вызвать проблемы в процессе торговли.\n\nПользователи, подключающиеся к узлам, нарушающим правила консенсуса, несут ответственность за любой причиненный ущерб. Любые споры в таком случае будут решаться в пользу вашего контрагента. Пользователям, игнорирующим это предупреждение и механизмы защиты, техническая поддержка предоставляться не будет! -settings.net.warn.invalidBtcConfig=Connection to the Bitcoin network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Bitcoin nodes instead. You will need to restart the application. -settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Bitcoin node when starting. If it is found, Haveno will communicate with the Bitcoin network exclusively through it. +settings.net.warn.useCustomNodes.B2XWarning=Убедитесь, что ваш узел Биткойн является доверенным узлом Monero Core! \n\nПодключение к узлам, не следующим правилам консенсуса Monero Core, может повредить ваш кошелек и вызвать проблемы в процессе торговли.\n\nПользователи, подключающиеся к узлам, нарушающим правила консенсуса, несут ответственность за любой причиненный ущерб. Любые споры в таком случае будут решаться в пользу вашего контрагента. Пользователям, игнорирующим это предупреждение и механизмы защиты, техническая поддержка предоставляться не будет! +settings.net.warn.invalidXmrConfig=Connection to the Monero network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Monero nodes instead. You will need to restart the application. +settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Monero node when starting. If it is found, Haveno will communicate with the Monero network exclusively through it. settings.net.p2PPeersLabel=Подключенные пиры settings.net.onionAddressColumn=Onion-адрес settings.net.creationDateColumn=Создано settings.net.connectionTypeColumn=Вх./Вых. settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=Задержка settings.net.sentBytesColumn=Отправлено settings.net.receivedBytesColumn=Получено @@ -1059,7 +1084,7 @@ settings.net.needRestart=Необходимо перезагрузить при settings.net.notKnownYet=Пока неизвестно... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[IP-адрес:порт | хост:порт | onion-адрес:порт] (через запятые). Порт можно не указывать, если используется порт по умолчанию (8333). settings.net.seedNode=Исходный узел settings.net.directPeer=Пир (прямой) @@ -1105,7 +1130,7 @@ setting.about.shortcuts.openDispute.value=Select pending trade and click: {0} setting.about.shortcuts.walletDetails=Open wallet details window -setting.about.shortcuts.openEmergencyBtcWalletTool=Open emergency wallet tool for BTC wallet +setting.about.shortcuts.openEmergencyXmrWalletTool=Open emergency wallet tool for XMR wallet setting.about.shortcuts.showTorLogs=Toggle log level for Tor messages between DEBUG and WARN @@ -1131,7 +1156,7 @@ setting.about.shortcuts.sendPrivateNotification=Send private notification to pee setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1165,7 @@ account.tab.mediatorRegistration=Mediator registration account.tab.refundAgentRegistration=Refund agent registration account.tab.signing=Signing account.info.headline=Добро пожаловать в ваш счёт Haveno -account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Bitcoin wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Bitcoin wallet seed words (see tab on the top) and consider adding a password before funding. Bitcoin deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Bitcoin addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). +account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Monero wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Monero wallet seed words (see tab on the top) and consider adding a password before funding. Monero deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Monero addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). account.menu.paymentAccount=Счета в нац. валюте account.menu.altCoinsAccountView=Альткойн-счета @@ -1151,7 +1176,7 @@ account.menu.backup=Резервное копирование account.menu.notifications=Уведомления account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1180,7 +1205,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Trading ARQ on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending ARQ, you need to use either the official ArQmA GUI wallet or ArQmA CLI wallet with the store-tx-info flag enabled (default in new versions). Please be sure you can access the tx key as that would be required in case of a dispute.\narqma-wallet-cli (use the command get_tx_key)\narqma-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nAt normal block explorers the transfer is not verifiable.\n\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The ARQ sender is responsible for providing verification of the ARQ transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process visit ArQmA discord channel (https://discord.gg/s9BQpJT) or the ArQmA forum (https://labs.arqma.com) to find more information. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1233,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin on Haveno requires that you unde account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Trading L-BTC on Haveno requires that you understand the following:\n\nWhen receiving L-BTC for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-BTC into the Liquid Elements Core wallet, or another L-BTC wallet which allows you to obtain the blinding key for your blinded L-BTC address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-BTC address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-BTC receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-BTC on Haveno. +account.crypto.popup.liquidmonero.msg=Trading L-XMR on Haveno requires that you understand the following:\n\nWhen receiving L-XMR for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-XMR into the Liquid Elements Core wallet, or another L-XMR wallet which allows you to obtain the blinding key for your blinded L-XMR address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-XMR address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-XMR receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-XMR on Haveno. account.traditional.yourTraditionalAccounts=Ваши счета в нац. валюте @@ -1228,9 +1253,9 @@ account.password.setPw.button=Установить пароль account.password.setPw.headline=Установить пароль для защиты кошелька account.password.info=При включенной защите паролем, вам потребуется вводить пароль при запуске приложения, при выводе монеро из вашего кошелька и при отображении ваших сидовых слов. -account.seed.backup.title=Сохраните мнемоническую фразу для вашего кошелька -account.seed.info=Запишите мнемоническую фразу для кошелька и дату создания его! Используя эти данные, вы сможете восстановить ваш кошелёк когда угодно.\nДля обоих кошельков, BTC и BSQ, используется одна и та же мнемоническая фраза.\n\nВам следует записать её на бумаге и не хранить на компьютере.\n\nМнемоническая фраза НЕ заменяет резервную копию.\nВам следует сделать резервную копию всего каталога приложения в разделе \«Счёт/Резервное копирование\» для восстановления состояния приложения и данных.\nИмпорт мнемонической фразы рекомендуется только в экстренных случаях. Приложение не будет функционировать должным образом без наличия резервной копии файлов базы данных и ключей! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Сделайте резервную копию семени вашего кошелька +account.seed.info=Пожалуйста, запишите как семена вашего кошелька, так и дату. Вы можете восстановить свой кошелек в любое время, используя семена и дату.\n\nВы должны записать семена на лист бумаги. Не сохраняйте их на компьютере.\n\nОбратите внимание, что семена не заменяют резервное копирование. Вам нужно создать резервную копию всего каталога приложения с экрана "Аккаунт/Резервное копирование", чтобы восстановить состояние и данные приложения. +account.seed.backup.warning=Пожалуйста, обратите внимание, что слова-семена НЕ являются заменой для резервной копии.\nНеобходимо создать резервную копию всего каталога приложения с экрана "Аккаунт/Резервное копирование" для восстановления состояния и данных приложения. account.seed.warn.noPw.msg=Вы не установили пароль от кошелька для защиты мнемонической фразы.\n\nОтобразить мнемоническую фразу на экране? account.seed.warn.noPw.yes=Да и не спрашивать снова account.seed.enterPw=Введите пароль, чтобы увидеть мнемоническую фразу @@ -1259,13 +1284,13 @@ account.notifications.trade.label=Получать сообщения по сд account.notifications.market.label=Получать оповещения о предложении account.notifications.price.label=Получать оповещения о курсе account.notifications.priceAlert.title=Оповещения о курсе -account.notifications.priceAlert.high.label=Уведомить, если курс BTC выше -account.notifications.priceAlert.low.label=Уведомить, если курс BTC ниже +account.notifications.priceAlert.high.label=Уведомить, если курс XMR выше +account.notifications.priceAlert.low.label=Уведомить, если курс XMR ниже account.notifications.priceAlert.setButton=Установить оповещение о курсе account.notifications.priceAlert.removeButton=Удалить оповещение о курсе account.notifications.trade.message.title=Состояние сделки изменилось account.notifications.trade.message.msg.conf=Депозит по сделке с идентификатором {0} внесен. Откройте приложение Haveno и начните платеж. -account.notifications.trade.message.msg.started=Покупатель BTC начал платеж по сделке с идентификатором {0}. +account.notifications.trade.message.msg.started=Покупатель XMR начал платеж по сделке с идентификатором {0}. account.notifications.trade.message.msg.completed=Сделка с идентификатором {0} завершена. account.notifications.offer.message.title=Ваше предложение было принято account.notifications.offer.message.msg=Ваше предложение с идентификатором {0} было принято @@ -1275,10 +1300,10 @@ account.notifications.dispute.message.msg=Получено сообщение п account.notifications.marketAlert.title=Оповещения о предложении account.notifications.marketAlert.selectPaymentAccount=Предложения, соответствующие платежному счету account.notifications.marketAlert.offerType.label=Интересующий тип предложения -account.notifications.marketAlert.offerType.buy=Предложения купить (хочу продать BTC) -account.notifications.marketAlert.offerType.sell=Предложения продать (хочу купить BTC) +account.notifications.marketAlert.offerType.buy=Предложения купить (хочу продать XMR) +account.notifications.marketAlert.offerType.sell=Предложения продать (хочу купить XMR) account.notifications.marketAlert.trigger=Отклонение предложения от курса (%) -account.notifications.marketAlert.trigger.info=Если задано отклонение от курса, вы получите оповещение только при публикации предложения, соответствующего вашим требованиям (или превышающего их). Например: вы хотите продать BTC, но только с надбавкой 2% к текущему рыночному курсу. Указав 2% в этом поле, вы получите оповещение только о предложениях с курсом, превышающим текущий рыночный курс на 2% (или более). +account.notifications.marketAlert.trigger.info=Если задано отклонение от курса, вы получите оповещение только при публикации предложения, соответствующего вашим требованиям (или превышающего их). Например: вы хотите продать XMR, но только с надбавкой 2% к текущему рыночному курсу. Указав 2% в этом поле, вы получите оповещение только о предложениях с курсом, превышающим текущий рыночный курс на 2% (или более). account.notifications.marketAlert.trigger.prompt=Отклонение в процентах от рыночного курса (напр., 2,50%, -0,50% и т. д.) account.notifications.marketAlert.addButton=Добавить оповещение о предложении account.notifications.marketAlert.manageAlertsButton=Управление оповещениями о предложениях @@ -1305,10 +1330,10 @@ inputControlWindow.balanceLabel=Доступный баланс contractWindow.title=Подробности спора contractWindow.dates=Дата предложения / Дата сделки -contractWindow.btcAddresses=Биткойн-адрес покупателя BTC / продавца BTC -contractWindow.onions=Сетевой адрес покупателя BTC / продавца BTC -contractWindow.accountAge=Возраст счёта (покупатель/продавец BTC) -contractWindow.numDisputes=Кол-во споров покупателя BTC / продавца BTC +contractWindow.xmrAddresses=Биткойн-адрес покупателя XMR / продавца XMR +contractWindow.onions=Сетевой адрес покупателя XMR / продавца XMR +contractWindow.accountAge=Возраст счёта (покупатель/продавец XMR) +contractWindow.numDisputes=Кол-во споров покупателя XMR / продавца XMR contractWindow.contractHash=Хеш контракта displayAlertMessageWindow.headline=Важная информация! @@ -1334,8 +1359,8 @@ disputeSummaryWindow.title=Сводка disputeSummaryWindow.openDate=Дата обращения за поддержкой disputeSummaryWindow.role=Роль трейдера disputeSummaryWindow.payout=Выплата суммы сделки -disputeSummaryWindow.payout.getsTradeAmount={0} BTC получит выплату суммы сделки -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount={0} XMR получит выплату суммы сделки +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=Пользовательская выплата disputeSummaryWindow.payoutAmount.buyer=Сумма выплаты покупателя disputeSummaryWindow.payoutAmount.seller=Сумма выплаты продавца @@ -1377,7 +1402,7 @@ disputeSummaryWindow.close.button=Закрыть обращение # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1427,11 +1452,11 @@ filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addre filterWindow.disableTradeBelowVersion=Мин. версия, необходимая для торговли filterWindow.add=Добавить фильтр filterWindow.remove=Удалить фильтр -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Мин. количество BTC +offerDetailsWindow.minXmrAmount=Мин. количество XMR offerDetailsWindow.min=(мин. {0}) offerDetailsWindow.distance=(отклонение от рыночного курса: {0}) offerDetailsWindow.myTradingAccount=Мой торговый счёт @@ -1446,6 +1471,7 @@ offerDetailsWindow.confirm.maker=Подтвердите: разместить п offerDetailsWindow.confirm.taker=Подтвердите: принять предложение {0} биткойн offerDetailsWindow.creationDate=Дата создания offerDetailsWindow.makersOnion=Onion-адрес мейкера +offerDetailsWindow.challenge=Пароль предложения qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1474,7 +1500,7 @@ showWalletDataWindow.walletData=Данные кошелька showWalletDataWindow.includePrivKeys=Добавить приватные ключи setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1496,8 +1522,10 @@ tradeDetailsWindow.agentAddresses=Arbitrator/Mediator tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=Вы отправили XMR. +txDetailsWindow.xmr.noteReceived=Вы получили XMR. +txDetailsWindow.sentTo=Отправлено в +txDetailsWindow.receivedWith=Получено с txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1506,7 +1534,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Введите пароль для разблокировки @@ -1532,12 +1560,12 @@ torNetworkSettingWindow.bridges.header=Tor сеть заблокирована? torNetworkSettingWindow.bridges.info=Если Tor заблокирован вашим интернет-провайдером или правительством, попробуйте использовать мосты Tor.\nПосетите веб-страницу Tor по адресу: https://bridges.torproject.org/bridges, чтобы узнать больше о мостах и подключаемых транспортных протоколах. feeOptionWindow.headline=Выберите валюту для оплаты торгового сбора -feeOptionWindow.info=Вы можете оплатить комиссию за сделку в BSQ или BTC. Если вы выберите BSQ, то сумма комиссии будет ниже. +feeOptionWindow.info=Вы можете оплатить комиссию за сделку в BSQ или XMR. Если вы выберите BSQ, то сумма комиссии будет ниже. feeOptionWindow.optionsLabel=Выберите валюту для оплаты комиссии за сделку -feeOptionWindow.useBTC=Использовать ВТС +feeOptionWindow.useXMR=Использовать ВТС feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1607,9 @@ popup.warning.noTradingAccountSetup.msg=Перед созданием предл popup.warning.noArbitratorsAvailable=Нет доступных арбитров. popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=Необходимо дождаться полного подключения к сети.\nОно может занять до 2 минут. -popup.warning.notSufficientConnectionsToBtcNetwork=Необходимо дождаться не менее {0} соединений с сетью Биткойн. +popup.warning.notSufficientConnectionsToXmrNetwork=Необходимо дождаться не менее {0} соединений с сетью Биткойн. popup.warning.downloadNotComplete=Необходимо дождаться завершения загрузки недостающих блоков сети Биткойн. -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.walletNotSynced=Кошелек Haveno не синхронизирован с последней высотой блокчейна. Пожалуйста, подождите, пока кошелек синхронизируется, или проверьте ваше соединение. popup.warning.removeOffer=Действительно хотите удалить это предложение? popup.warning.tooLargePercentageValue=Нельзя установить процент в размере 100% или выше. popup.warning.examplePercentageValue=Введите процент, например \«5,4\» для 5,4% @@ -1600,14 +1628,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=ретранслятор курса popup.warning.seed=мнемоническая фраза popup.warning.mandatoryUpdate.trading=Обновите Haveno до последней версии. Вышло обязательное обновление, которое делает невозможной торговлю в старых версиях приложения. Посетите форум Haveno, чтобы узнать подробности. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=Данную транзакцию невозможно завершить, так как плата за нее ({0}) превышает сумму перевода ({1}). Подождите, пока плата за транзакцию не снизится или пока у вас не появится больше BTC для завершения перевода. +popup.warning.burnXMR=Данную транзакцию невозможно завершить, так как плата за нее ({0}) превышает сумму перевода ({1}). Подождите, пока плата за транзакцию не снизится или пока у вас не появится больше XMR для завершения перевода. -popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Bitcoin network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Monero network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. @@ -1616,7 +1643,7 @@ popup.info.securityDepositInfo=Чтобы гарантировать соблю popup.info.cashDepositInfo=Убедитесь, что в вашем районе есть отделение банка, где можно произвести перевод наличных.\nИдентификатор (BIC/SWIFT) банка продавца: {0}. popup.info.cashDepositInfo.confirm=Я подтверждаю, что могу внести оплату popup.info.shutDownWithOpenOffers=Haveno закрывается, но у вас есть открытые предложения.\n\nЭти предложения будут недоступны в сети P2P, пока приложение Haveno закрыто, но будут повторно опубликованы в сети P2P при следующем запуске Haveno.\n\nЧтобы ваши предложения были доступны в сети, компьютер и приложение должны быть включены и подключены к сети (убедитесь, что компьютер не перешёл в режим ожидания; переход монитора в спящий режим не влияет на работу приложения). -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=Важное личное уведомление! @@ -1668,6 +1695,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=Депозит от покупателя не требуется +popup.info.buyerAsTakerWithoutDeposit=Ваше предложение не потребует залога или комиссии от покупателя XMR.\n\nЧтобы принять ваше предложение, вы должны поделиться парольной фразой с вашим торговым партнером вне Haveno.\n\nПарольная фраза генерируется автоматически и отображается в деталях предложения после его создания. + #################################################################### # Notifications #################################################################### @@ -1696,7 +1726,7 @@ systemTray.show=Показать окно приложения systemTray.hide=Скрыть окно приложения systemTray.info=Информация о Haveno systemTray.exit=Выход -systemTray.tooltip=Haveno: A decentralized bitcoin exchange network +systemTray.tooltip=Haveno: A decentralized monero exchange network #################################################################### @@ -1747,7 +1777,7 @@ tooltip.openBlockchainForTx=Открыть транзакцию {0} во вне confidence.unknown=Статус транзакции неизвестен confidence.seen=Замечена {0} пиром (-ами) / 0 подтверждений -confidence.confirmed=Подтверждена в {0} блоке (-ах) +confidence.confirmed={0} подтверждение(ий) confidence.invalid=Недействительная транзакция peerInfo.title=Данные трейдера @@ -1793,6 +1823,7 @@ navigation.support=\«Поддержка\» formatter.formatVolumeLabel={0} сумма {1} formatter.makerTaker=Мейкер как {0} {1} / Тейкер как {2} {3} +formatter.makerTakerLocked=Мейкер как {0} {1} / Тейкер как {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Вы {0} {1} ({2} {3}) @@ -1838,7 +1869,6 @@ password.deriveKey=Извлечь ключ из пароля password.walletDecrypted=Кошелёк успешно расшифрован, защита паролем удалена. password.wrongPw=Вы ввели неверный пароль.\n\nПопробуйте снова, обратив внимание на возможные ошибки ввода. password.walletEncrypted=Кошелёк успешно зашифрован, защита паролем включена. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=Введённые вами 2 пароля не совпадают. password.forgotPassword=Забыли пароль? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1852,7 +1882,7 @@ seed.date=Дата создания кошелька seed.restore.title=Восстановить кошельки с помощью мнемонической фразы seed.restore=Восстановить кошельки seed.creationDate=Дата создания -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Всё равно хочу восстановить seed.warn.walletNotEmpty.emptyWallet=Вывести все средства с моих кошельков seed.warn.notEncryptedAnymore=Ваши кошельки зашифрованы.\n\nПосле восстановления кошельки больше не будут зашифрованы, и вам потребуется установить новый пароль.\n\nПродолжить? @@ -1869,7 +1899,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=Счёт payment.account.no=Номер счёта payment.account.name=Название счёта -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=Полное имя владельца счёта payment.account.fullName=Полное имя (имя, отчество, фамилия) @@ -1901,7 +1931,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=Имя пользователя, эл. адрес или тел. номер payment.moneyBeam.accountId=Эл. адрес или тел. номер -payment.venmo.venmoUserName=Имя пользователя Venmo payment.popmoney.accountId=Эл. адрес или тел. номер payment.promptPay.promptPayId=Удостовер. личности / налог. номер или номер телефона payment.supportedCurrencies=Поддерживаемые валюты @@ -1943,28 +1972,28 @@ payment.checking=Текущий payment.savings=Сберегательный payment.personalId=Личный идентификатор payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Haveno to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=Используя HalCash, покупатель BTC обязуется отправить продавцу BTC код HalCash через СМС с мобильного телефона.\n\nУбедитесь, что не вы не превысили максимальную сумму, которую ваш банк позволяет отправить с HalCash. Минимальная сумма на вывод средств составляет 10 EUR, а и максимальная — 600 EUR. При повторном выводе средств лимит составляет 3000 EUR на получателя в день и 6000 EUR на получателя в месяц. Просьба сверить эти лимиты с вашим банком и убедиться, что лимиты банка соответствуют лимитам, указанным здесь.\n\nВыводимая сумма должна быть кратна 10 EUR, так как другие суммы снять из банкомата невозможно. Приложение само отрегулирует сумму BTC, чтобы она соответствовала сумме в EUR, во время создания или принятия предложения. Вы не сможете использовать текущий рыночный курс, так как сумма в EUR будет меняться с изменением курса.\n\nВ случае спора покупателю BTC необходимо предоставить доказательство отправки EUR. +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=Используя HalCash, покупатель XMR обязуется отправить продавцу XMR код HalCash через СМС с мобильного телефона.\n\nУбедитесь, что не вы не превысили максимальную сумму, которую ваш банк позволяет отправить с HalCash. Минимальная сумма на вывод средств составляет 10 EUR, а и максимальная — 600 EUR. При повторном выводе средств лимит составляет 3000 EUR на получателя в день и 6000 EUR на получателя в месяц. Просьба сверить эти лимиты с вашим банком и убедиться, что лимиты банка соответствуют лимитам, указанным здесь.\n\nВыводимая сумма должна быть кратна 10 EUR, так как другие суммы снять из банкомата невозможно. Приложение само отрегулирует сумму XMR, чтобы она соответствовала сумме в EUR, во время создания или принятия предложения. Вы не сможете использовать текущий рыночный курс, так как сумма в EUR будет меняться с изменением курса.\n\nВ случае спора покупателю XMR необходимо предоставить доказательство отправки EUR. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Убедитесь, что ваш банк позволяет отправлять денежные переводы на счета других лиц. Например, Bank of America и Wells Fargo больше не разрешают такие переводы. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=Контактная информация payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1975,7 +2004,7 @@ payment.f2f.city.prompt=Город будет указан в предложен payment.shared.optionalExtra=Дополнительная необязательная информация payment.shared.extraInfo=Дополнительная информация payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Открыть веб-страницу payment.f2f.offerbook.tooltip.countryAndCity=Country and city: {0} / {1} payment.f2f.offerbook.tooltip.extra=Дополнительная информация: {0} @@ -1987,7 +2016,7 @@ payment.japan.recipient=Имя payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2145,7 +2174,7 @@ validation.zero=Введённое значение не может быть р validation.negative=Отрицательное значение недопустимо. validation.traditional.tooSmall=Ввод значения меньше минимально возможного не допускается. validation.traditional.tooLarge=Ввод значения больше максимально возможного не допускается. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=Значение не может превышать {0}. validation.xmr.tooSmall=Значение не может быть меньше {0}. validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2155,10 +2184,10 @@ validation.sortCodeChars={0} должен состоять из {1} символ validation.bankIdNumber={0} должен состоять из {1} цифр. validation.accountNr=Номер счёта должен состоять из {0} цифр. validation.accountNrChars=Номер счёта должен состоять из {0} символов. -validation.btc.invalidAddress=Неправильный адрес. Проверьте формат адреса. +validation.xmr.invalidAddress=Неправильный адрес. Проверьте формат адреса. validation.integerOnly=Введите только целые числа. validation.inputError=Введённое значение вызвало ошибку:\n{0} -validation.btc.exceedsMaxTradeLimit=Ваш торговый лимит составляет {0}. +validation.xmr.exceedsMaxTradeLimit=Ваш торговый лимит составляет {0}. validation.nationalAccountId={0} должен состоять из {1} цифр. #new diff --git a/core/src/main/resources/i18n/displayStrings_th.properties b/core/src/main/resources/i18n/displayStrings_th.properties index a5f2730d6c..2688b08d91 100644 --- a/core/src/main/resources/i18n/displayStrings_th.properties +++ b/core/src/main/resources/i18n/displayStrings_th.properties @@ -36,14 +36,16 @@ shared.iUnderstand=ฉันเข้าใจ shared.na=ไม่พร้อมใช้งาน shared.shutDown=ปิดใช้งาน shared.reportBug=Report bug on GitHub -shared.buyBitcoin=ซื้อ bitcoin (บิตคอยน์) -shared.sellBitcoin=ขาย bitcoin (บิตคอยน์) +shared.buyMonero=ซื้อ monero (บิตคอยน์) +shared.sellMonero=ขาย monero (บิตคอยน์) shared.buyCurrency=ซื้อ {0} shared.sellCurrency=ขาย {0} -shared.buyingBTCWith=การซื้อ BTC กับ {0} -shared.sellingBTCFor=การขาย BTC แก่ {0} -shared.buyingCurrency=การซื้อ {0} (การขาย BTC) -shared.sellingCurrency=การขาย {0} (การซื้อ BTC) +shared.buyCurrencyLocked=ซื้อ {0} 🔒 +shared.sellCurrencyLocked=ขาย {0} 🔒 +shared.buyingXMRWith=การซื้อ XMR กับ {0} +shared.sellingXMRFor=การขาย XMR แก่ {0} +shared.buyingCurrency=การซื้อ {0} (การขาย XMR) +shared.sellingCurrency=การขาย {0} (การซื้อ XMR) shared.buy=ซื้อ shared.sell=ขาย shared.buying=การซื้อ @@ -93,7 +95,7 @@ shared.amountMinMax=ยอดจำนวน (ต่ำสุด-สูงสุ shared.amountHelp=หากข้อเสนอนั้นถูกจัดอยู่ในระดับเซ็ทขั้นต่ำและสูงสุด คุณสามารถซื้อขายได้ทุกช่วงระดับของจำนวนที่มีอยู่ shared.remove=ลบออก shared.goTo=ไปที่ {0} -shared.BTCMinMax=BTC (ต่ำสุด-สูงสุด) +shared.XMRMinMax=XMR (ต่ำสุด-สูงสุด) shared.removeOffer=ลบข้อเสนอ shared.dontRemoveOffer=ห้ามลบข้อเสนอ shared.editOffer=แก้ไขข้อเสนอ @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=ใช่ ยกเลิก shared.nextStep=ขั้นถัดไป shared.selectTradingAccount=เลือกบัญชีการซื้อขาย -shared.fundFromSavingsWalletButton=โอนเงินจาก Haveno wallet +shared.fundFromSavingsWalletButton=ใช้เงินจากกระเป๋าเงิน Haveno shared.fundFromExternalWalletButton=เริ่มทำการระดมเงินทุนหาแหล่งเงินจากกระเป๋าสตางค์ภายนอกของคุณ -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=ต่ำกว่า % จากราคาตลาด shared.aboveInPercent=สูงกว่า % จากราคาตาด shared.enterPercentageValue=เข้าสู่ % ตามมูลค่า shared.OR=หรือ shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=กำลังรอเงิน ... -shared.TheBTCBuyer=ผู้ซื้อ BTC +shared.TheXMRBuyer=ผู้ซื้อ XMR shared.You=คุณ shared.sendingConfirmation=กำลังส่งการยืนยัน ... shared.sendingConfirmationAgain=โปรดยืนยันการส่งอีกครั้ง @@ -123,9 +125,8 @@ shared.noDateAvailable=ไม่มีวันที่ให้แสดง shared.noDetailsAvailable=ไม่มีรายละเอียด shared.notUsedYet=ยังไม่ได้ใช้งาน shared.date=วันที่ -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=คัดลอกไปที่คลิปบอร์ด shared.language=ภาษา shared.country=ประเทศ @@ -140,6 +141,7 @@ shared.addNewAccount=เพิ่มบัญชีใหม่ shared.ExportAccounts=บัญชีส่งออก shared.importAccounts=บัญชีนำเข้า shared.createNewAccount=สร้างบัญชีใหม่ +shared.createNewAccountDescription=รายละเอียดบัญชีของคุณถูกจัดเก็บไว้ในอุปกรณ์ของคุณและจะแบ่งปันเฉพาะกับคู่ค้าของคุณและผู้ตัดสินหากมีการเปิดข้อพิพาท shared.saveNewAccount=บันทึกบัญชีใหม่ shared.selectedAccount=บัญชีที่เลือก shared.deleteAccount=ลบบัญชี @@ -169,7 +171,7 @@ shared.payoutTxId=ID ธุรกรรมการชำระเงิน shared.contractAsJson=สัญญาในรูปแบบ JSON shared.viewContractAsJson=ดูสัญญาในรูปแบบ JSON: shared.contract.title=สัญญาการซื้อขายด้วยรหัส ID: {0} -shared.paymentDetails=BTC {0} รายละเอียดการชำระเงิน +shared.paymentDetails=XMR {0} รายละเอียดการชำระเงิน shared.securityDeposit=เงินประกัน shared.yourSecurityDeposit=เงินประกันของคุณ shared.contract=สัญญา @@ -179,19 +181,21 @@ shared.messageSendingFailed=การส่งข้อความล้มเ shared.unlock=ปลดล็อค shared.toReceive=รับ shared.toSpend=จ่าย -shared.btcAmount=BTC ยอดจำนวน +shared.xmrAmount=XMR ยอดจำนวน shared.yourLanguage=ภาษาของคุณ shared.addLanguage=เพิ่มภาษา shared.total=ยอดทั้งหมด shared.totalsNeeded=เงินที่จำเป็น shared.tradeWalletAddress=ที่อยู่ Trade wallet shared.tradeWalletBalance=ยอดคงเหลือของ Trade wallet +shared.reserveExactAmount=สำรองเฉพาะเงินที่จำเป็น ต้องใช้ค่าธรรมเนียมการขุดและเวลาประมาณ 20 นาทีก่อนที่ข้อเสนอของคุณจะเผยแพร่ shared.makerTxFee=ผู้ทำ: {0} shared.takerTxFee=ผู้รับ: {0} shared.iConfirm=ฉันยืนยัน shared.openURL=เปิด {0} shared.fiat=คำสั่ง shared.crypto=คริปโต +shared.preciousMetals=โลหะมีค่า shared.all=ทั้งหมด shared.edit=แก้ไข shared.advancedOptions=ทางเลือกขั้นสูง @@ -226,8 +230,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=ตลาด -mainView.menu.buyBtc=ซื้อ BTC -mainView.menu.sellBtc=ขาย BTC +mainView.menu.buyXmr=ซื้อ XMR +mainView.menu.sellXmr=ขาย XMR mainView.menu.portfolio=แฟ้มผลงาน mainView.menu.funds=เงิน mainView.menu.support=สนับสนุน @@ -245,12 +249,15 @@ mainView.balance.reserved.short=จองแล้ว mainView.balance.pending.short=ถูกล็อคไว้ mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(แม่ข่ายเฉพาะที่) +mainView.footer.localhostMoneroNode=(แม่ข่ายเฉพาะที่) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Connecting to Bitcoin network -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=เชื่อมต่อกับเครือข่าย Haveno +mainView.footer.xmrInfo.synchronizingWith=กำลังซิงโครไนซ์กับ {0} ที่บล็อก: {1} / {2} +mainView.footer.xmrInfo.connectedTo=เชื่อมต่อไปยัง {0} ที่บล็อก {1} +mainView.footer.xmrInfo.synchronizingWalletWith=กำลังซิงโครไนซ์กระเป๋าสตางค์กับ {0} ที่บล็อก: {1} / {2} +mainView.footer.xmrInfo.syncedWith=ซิงค์กับ {0} ที่บล็อก {1} เสร็จสมบูรณ์ mainView.footer.xmrInfo.connectingTo=Connecting to mainView.footer.xmrInfo.connectionFailed=Connection failed to mainView.footer.xmrPeers=Monero network peers: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=Bootstrapping to Haveno netwo mainView.p2pNetworkWarnMsg.noNodesAvailable=ไม่มีแหล่งข้อมูลในโหนดเครือข่ายและ peers (ระบบเพียร์) พร้อมให้บริการสำหรับการขอข้อมูล\nโปรดตรวจสอบการเชื่อมต่ออินเทอร์เน็ตของคุณหรือลองรีสตาร์ทแอพพลิเคชัน mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Connecting to the Haveno network failed (reported error: {0}).\nPlease check your internet connection or try to restart the application. -mainView.walletServiceErrorMsg.timeout=การเชื่อมต่อกับเครือข่าย Bitcoin ล้มเหลวเนื่องจากหมดเวลา -mainView.walletServiceErrorMsg.connectionError=การเชื่อมต่อกับเครือข่าย Bitcoin ล้มเหลวเนื่องจากข้อผิดพลาด: {0} +mainView.walletServiceErrorMsg.timeout=การเชื่อมต่อกับเครือข่าย Monero ล้มเหลวเนื่องจากหมดเวลา +mainView.walletServiceErrorMsg.connectionError=การเชื่อมต่อกับเครือข่าย Monero ล้มเหลวเนื่องจากข้อผิดพลาด: {0} mainView.walletServiceErrorMsg.rejectedTxException=A transaction was rejected from the network.\n\n{0} mainView.networkWarning.allConnectionsLost=คุณสูญเสียการเชื่อมต่อกับ {0} เครือข่าย peers\nบางทีคุณอาจขาดการเชื่อมต่ออินเทอร์เน็ตหรืออาจเป็นเพราะคอมพิวเตอร์ของคุณอยู่ในโหมดสแตนด์บาย -mainView.networkWarning.localhostBitcoinLost=คุณสูญเสียการเชื่อมต่อไปยังโหนดเครือข่าย Bitcoin localhost (แม่ข่ายเฉพาะที่)\nโปรดรีสตาร์ทแอ็พพลิเคชัน Haveno เพื่อเชื่อมต่อโหนด Bitcoin อื่นหรือรีสตาร์ทโหนด Bitcoin localhost +mainView.networkWarning.localhostMoneroLost=คุณสูญเสียการเชื่อมต่อไปยังโหนดเครือข่าย Monero localhost (แม่ข่ายเฉพาะที่)\nโปรดรีสตาร์ทแอ็พพลิเคชัน Haveno เพื่อเชื่อมต่อโหนด Monero อื่นหรือรีสตาร์ทโหนด Monero localhost mainView.version.update=(การอัพเดตพร้อมใช้งาน) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=ซื้อ {0} market.offerBook.sellWithTraditional=ขาย {0} market.offerBook.sellOffersHeaderLabel=ขาย {0} ไปยัง market.offerBook.buyOffersHeaderLabel=ซื้อ {0} จาก -market.offerBook.buy=ฉันต้องการจะซื้อ bitcoin -market.offerBook.sell=ฉันต้องการจะขาย bitcoin +market.offerBook.buy=ฉันต้องการจะซื้อ monero +market.offerBook.sell=ฉันต้องการจะขาย monero # SpreadView market.spread.numberOfOffersColumn=ข้อเสนอทั้งหมด ({0}) -market.spread.numberOfBuyOffersColumn=ซื้อ BTC ({0}) -market.spread.numberOfSellOffersColumn=ขาย BTC ({0}) -market.spread.totalAmountColumn=ยอด BTC ทั้งหมด ({0}) +market.spread.numberOfBuyOffersColumn=ซื้อ XMR ({0}) +market.spread.numberOfSellOffersColumn=ขาย XMR ({0}) +market.spread.totalAmountColumn=ยอด XMR ทั้งหมด ({0}) market.spread.spreadColumn=กระจาย market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=สร้างข้อเสนอ offerbook.takeOffer=รับข้อเสนอ offerbook.takeOfferToBuy=Take offer to buy {0} offerbook.takeOfferToSell=Take offer to sell {0} +offerbook.takeOffer.enterChallenge=กรอกพาสเฟรสข้อเสนอ offerbook.trader=Trader (เทรดเดอร์) offerbook.offerersBankId=รหัสธนาคารของผู้สร้าง (BIC / SWIFT): {0} offerbook.offerersBankName=ชื่อธนาคารของผู้สร้าง: {0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=ยอมรับตำแหน่งป offerbook.availableOffers=ข้อเสนอที่พร้อมใช้งาน offerbook.filterByCurrency=กรองตามสกุลเงิน offerbook.filterByPaymentMethod=ตัวกรองตามวิธีการชำระเงิน -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=ข้อเสนอที่ตรงกับบัญชีของฉัน +offerbook.filterNoDeposit=ไม่มีเงินมัดจำ +offerbook.noDepositOffers=ข้อเสนอที่ไม่มีเงินมัดจำ (ต้องการรหัสผ่าน) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=account was banned offerbook.timeSinceSigning.daysSinceSigning={0} วัน offerbook.timeSinceSigning.daysSinceSigning.long={0} since signing offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=ซื้อ XMR ด้วย: +offerbook.sellXmrFor=ขาย XMR สำหรับ: offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=No. ของข้อเสนอ: {0} offerbook.volume={0} (ต่ำสุด - สูงสุด) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=สร้างข้อเสนอให้กับ {0} {1} offerbook.createOfferToBuy=Create new offer to buy {0} offerbook.createOfferToSell=Create new offer to sell {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- The buyer''s account has not been signed by an arbitrator or a peer\n- The time since signing of the buyer''s account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- Your account has not been signed by an arbitrator or a peer\n- The time since signing of your account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=วิธีการชำระเงินนี้ถูก จำกัด ชั่วคราวไปยัง {0} จนถึง {1} เนื่องจากผู้ซื้อทุกคนมีบัญชีใหม่\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=ข้อเสนอของคุณจะถูก จำกัด เฉพาะผู้ซื้อที่มีบัญชีที่ได้ลงนามและมีอายุ เนื่องจากมันเกิน {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=ข้อเสนอดังกล่าวต้องใช้โปรโตคอลเวอร์ชันอื่นเหมือนกับเวอร์ชันที่ใช้ในซอฟต์แวร์เวอร์ชันของคุณ\n\nโปรดตรวจสอบว่าคุณได้ติดตั้งเวอร์ชั่นล่าสุด อีกนัยหนึ่งผู้ใช้ที่สร้างข้อเสนอได้ใช้รุ่นที่เก่ากว่า\n\nผู้ใช้ไม่สามารถซื้อขายกับโปรโตคอลการค้าเวอร์ชั่นซอฟต์แวร์ที่แตกต่างกันได้ offerbook.warning.userIgnored=คุณได้เพิ่มที่อยู่ onion ของผู้ใช้ลงในรายการที่ไม่สนใจแล้ว @@ -394,7 +409,6 @@ offerbook.warning.offerBlocked=ข้อเสนอดังกล่าวถ offerbook.warning.currencyBanned=สกุลเงินที่ใช้ในข้อเสนอนั้นถูกบล็อกโดยนักพัฒนา Haveno\nสามารถอ่านข้อมูลเพิ่มเติมได้ที่ฟอรั่มของ Haveno offerbook.warning.paymentMethodBanned=วิธีการชำระเงินที่ใช้ในข้อเสนอนั้นถูกบล็อกโดยนักพัฒนา Haveno\nกรุณาเข้าไปอ่านที่ Forum ของ Haveno สำหรับข้อมูลเพิ่มเติม offerbook.warning.nodeBlocked=ที่อยู่ onion ของผู้ซื้อขายรายนั้นถูกบล็อกโดยนักพัฒนา Haveno\nอาจมีข้อบกพร่องที่ไม่ได้รับการจัดการ ซึ่งก่อให้เกิดปัญหาเมื่อรับข้อเสนอจากผู้ซื้อขายรายนั้น -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=คุณจะขายในราคาตลาด (อัปเดตทุกนาที) @@ -412,13 +426,13 @@ offerbook.info.roundedFiatVolume=จำนวนเงินจะปัดเ # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=ป้อนจำนวนเงินใน BTC +createOffer.amount.prompt=ป้อนจำนวนเงินใน XMR createOffer.price.prompt=ป้อนราคา createOffer.volume.prompt=ป้อนจำนวนเงินใน {0} -createOffer.amountPriceBox.amountDescription=ยอดจำนวน BTC ถึง {0} +createOffer.amountPriceBox.amountDescription=ยอดจำนวน XMR ถึง {0} createOffer.amountPriceBox.buy.volumeDescription=ยอดจำนวน {0} ที่ต้องจ่าย createOffer.amountPriceBox.sell.volumeDescription=จำนวนเงิน {0} ที่ได้รับ -createOffer.amountPriceBox.minAmountDescription=จำนวนเงินขั้นต่ำของ BTC +createOffer.amountPriceBox.minAmountDescription=จำนวนเงินขั้นต่ำของ XMR createOffer.securityDeposit.prompt=เงินประกัน createOffer.fundsBox.title=เงินทุนสำหรับข้อเสนอของคุณ createOffer.fundsBox.offerFee=ค่าธรรมเนียมการซื้อขาย @@ -434,7 +448,7 @@ createOffer.info.sellAboveMarketPrice=คุณจะได้รับ {0}% ม createOffer.info.buyBelowMarketPrice=คุณจะจ่าย {0}% น้อยกว่าราคาตลาดในปัจจุบันเนื่องจากราคาข้อเสนอของคุณจะได้รับการอัพเดตอย่างต่อเนื่อง createOffer.warning.sellBelowMarketPrice=คุณจะได้รับ {0}% น้อยกว่าราคาตลาดในปัจจุบันเนื่องจากราคาข้อเสนอของคุณจะได้รับการอัพเดตอย่างต่อเนื่อง createOffer.warning.buyAboveMarketPrice=คุณจะต้องจ่ายเงิน {0}% มากกว่าราคาตลาดในปัจจุบันเนื่องจากราคาข้อเสนอของคุณจะได้รับการอัพเดตอย่างต่อเนื่อง -createOffer.tradeFee.descriptionBTCOnly=ค่าธรรมเนียมการซื้อขาย +createOffer.tradeFee.descriptionXMROnly=ค่าธรรมเนียมการซื้อขาย createOffer.tradeFee.descriptionBSQEnabled=เลือกสกุลเงินค่าธรรมเนียมในการเทรด createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +462,12 @@ createOffer.placeOfferButton=รีวิว: ใส่ข้อเสนอไ createOffer.createOfferFundWalletInfo.headline=เงินทุนสำหรับข้อเสนอของคุณ # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- ปริมาณการซื้อขาย: {0} -createOffer.createOfferFundWalletInfo.msg=คุณต้องวางเงินมัดจำ {0} ข้อเสนอนี้\n\nเงินเหล่านั้นจะถูกสงวนไว้ใน wallet ภายในประเทศของคุณและจะถูกล็อคไว้ในที่อยู่ที่ฝากเงิน multisig เมื่อมีคนรับข้อเสนอของคุณ\n\nผลรวมของจำนวนของ: \n{1} - เงินประกันของคุณ: {2} \n- ค่าธรรมเนียมการซื้อขาย: {3} \n- ค่าขุด: {4} \n\nคุณสามารถเลือกระหว่างสองตัวเลือกเมื่อมีการระดุมทุนการซื้อขายของคุณ: \n- ใช้กระเป๋าสตางค์ Haveno ของคุณ (สะดวก แต่ธุรกรรมอาจเชื่อมโยงกันได้) หรือ\n- โอนเงินจากเงินภายนอกเข้ามา (อาจเป็นส่วนตัวมากขึ้น) \n\nคุณจะเห็นตัวเลือกและรายละเอียดการระดมทุนทั้งหมดหลังจากปิดป๊อปอัปนี้ +createOffer.createOfferFundWalletInfo.msg=คุณจำเป็นต้องฝากเงิน {0} เพื่อข้อเสนอนี้\n\n\ + เงินเหล่านี้จะถูกสงวนไว้ในกระเป๋าเงินในเครื่องของคุณ และจะถูกล็อกในกระเป๋าเงินมัลติซิกเมื่อมีคนรับข้อเสนอของคุณ\n\n\ + จำนวนเงินคือผลรวมของ:\n\ + {1}\ + - เงินประกันของคุณ: {2}\n\ + - ค่าธรรมเนียมการซื้อขาย: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=เกิดข้อผิดพลาดขณะใส่ข้อเสนอ: \n\n{0} \n\nยังไม่มีการโอนเงินจาก wallet ของคุณเลย\nโปรดเริ่มแอปพลิเคชันใหม่และตรวจสอบการเชื่อมต่อเครือข่ายของคุณ @@ -470,30 +489,35 @@ createOffer.setDepositAsBuyer=Set my security deposit as buyer (%) createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=Your buyer''s security deposit will be {0} createOffer.securityDepositInfoAsBuyer=Your security deposit as buyer will be {0} -createOffer.minSecurityDepositUsed=Min. buyer security deposit is used +createOffer.minSecurityDepositUsed=เงินประกันความปลอดภัยขั้นต่ำถูกใช้ +createOffer.buyerAsTakerWithoutDeposit=ไม่ต้องวางมัดจำจากผู้ซื้อ (ป้องกันด้วยรหัสผ่าน) +createOffer.myDeposit=เงินประกันความปลอดภัยของฉัน (%) +createOffer.myDepositInfo=เงินประกันความปลอดภัยของคุณจะเป็น {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=ป้อนจำนวนเงินใน BTC -takeOffer.amountPriceBox.buy.amountDescription=จำนวน BTC ที่จะขาย -takeOffer.amountPriceBox.sell.amountDescription=จำนวน BTC ที่จะซื้อ -takeOffer.amountPriceBox.priceDescription=ราคาต่อ bitcoin ใน {0} +takeOffer.amount.prompt=ป้อนจำนวนเงินใน XMR +takeOffer.amountPriceBox.buy.amountDescription=จำนวน XMR ที่จะขาย +takeOffer.amountPriceBox.sell.amountDescription=จำนวน XMR ที่จะซื้อ +takeOffer.amountPriceBox.priceDescription=ราคาต่อ monero ใน {0} takeOffer.amountPriceBox.amountRangeDescription=ช่วงจำนวนที่เป็นไปได้ -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=จำนวนเงินที่คุณป้อนเกินจำนวนตำแหน่งทศนิยมที่อนุญาต\nจำนวนเงินได้รับการปรับเป็นตำแหน่งทศนิยม 4 ตำแหน่ง +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=จำนวนเงินที่คุณป้อนเกินจำนวนตำแหน่งทศนิยมที่อนุญาต\nจำนวนเงินได้รับการปรับเป็นตำแหน่งทศนิยม 4 ตำแหน่ง takeOffer.validation.amountSmallerThanMinAmount=จำนวนเงินต้องไม่น้อยกว่าจำนวนเงินขั้นต่ำที่ระบุไว้ในข้อเสนอ takeOffer.validation.amountLargerThanOfferAmount=จำนวนเงินที่ป้อนต้องไม่สูงกว่าจำนวนที่กำหนดไว้ในข้อเสนอ -takeOffer.validation.amountLargerThanOfferAmountMinusFee=จำนวนเงินที่ป้อนจะสร้างการเปลี่ยนแปลง dust (Bitcoin ที่มีขนาดเล็กมาก) สำหรับผู้ขาย BTC +takeOffer.validation.amountLargerThanOfferAmountMinusFee=จำนวนเงินที่ป้อนจะสร้างการเปลี่ยนแปลง dust (Monero ที่มีขนาดเล็กมาก) สำหรับผู้ขาย XMR takeOffer.fundsBox.title=ทุนการซื้อขายของคุณ takeOffer.fundsBox.isOfferAvailable=ตรวจสอบว่ามีข้อเสนออื่นๆหรือไม่ ... takeOffer.fundsBox.tradeAmount=จำนวนที่จะขาย takeOffer.fundsBox.offerFee=ค่าธรรมเนียมการซื้อขาย takeOffer.fundsBox.networkFee=ยอดรวมค่าธรรมเนียมการขุด -takeOffer.fundsBox.takeOfferSpinnerInfo=การรับข้อเสนออยู่ระหว่างการดำเนินการ... +takeOffer.fundsBox.takeOfferSpinnerInfo=ยอมรับข้อเสนอ: {0} takeOffer.fundsBox.paymentLabel=การซื้อขาย Haveno ด้วย ID {0} takeOffer.fundsBox.fundsStructure=({0} เงินประกัน {1} ค่าธรรมเนียมการซื้อขาย {2} ค่าธรรมเนียมการขุด) +takeOffer.fundsBox.noFundingRequiredTitle=ไม่ต้องใช้เงินทุน +takeOffer.fundsBox.noFundingRequiredDescription=รับรหัสผ่านข้อเสนอจากผู้ขายภายนอก Haveno เพื่อรับข้อเสนอนี้ takeOffer.success.headline=คุณได้รับข้อเสนอเป็นที่เรีบยร้อยแล้ว takeOffer.success.info=คุณสามารถดูสถานะการค้าของคุณได้ที่ \ "Portfolio (แฟ้มผลงาน) / เปิดการซื้อขาย \" takeOffer.error.message=เกิดข้อผิดพลาดขณะรับข้อเสนอ\n\n{0} @@ -504,7 +528,7 @@ takeOffer.noPriceFeedAvailable=คุณไม่สามารถรับข takeOffer.takeOfferFundWalletInfo.headline=ทุนการซื้อขายของคุณ # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- ปริมาณการซื้อขาย: {0} -takeOffer.takeOfferFundWalletInfo.msg=คุณต้องวางเงินประกัน {0} เพื่อรับข้อเสนอนี้\n\nจำนวนเงินคือผลรวมของ: \n{1} - เงินประกันของคุณ: {2} \n- ค่าธรรมเนียมการซื้อขาย: {3} \n- ค่าธรรมเนียมการขุดทั้งหมด: {4} \n\nคุณสามารถเลือกระหว่างสองตัวเลือกเมื่อลงทุนการซื้อขายของคุณ: \n- ใช้กระเป๋าสตางค์ Haveno ของคุณ (สะดวก แต่ธุรกรรมอาจเชื่อมโยงกันได้) หรือ\n- โอนเงินจากแหล่งเงินภายนอก (อาจเป็นส่วนตัวมากขึ้น) \n\nคุณจะเห็นตัวเลือกและรายละเอียดการลงทุนทั้งหมดหลังจากปิดป๊อปอัปนี้ +takeOffer.takeOfferFundWalletInfo.msg=คุณต้องฝากเงิน {0} เพื่อรับข้อเสนอนี้。\n\nจำนวนเงินคือผลรวมของ:\n{1}- เงินมัดจำของคุณ: {2}\n- ค่าธรรมเนียมการซื้อขาย: {3} takeOffer.alreadyPaidInFunds=หากคุณได้ชำระเงินแล้วคุณสามารถถอนเงินออกได้ในหน้าจอ \"เงิน / ส่งเงิน \" takeOffer.paymentInfo=ข้อมูลการชำระเงิน takeOffer.setAmountPrice=ตั้งยอดจำนวน @@ -597,29 +621,29 @@ portfolio.pending.step1.openForDispute=The deposit transaction is still not conf # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=โปรดโอนจาก wallet {0} ภายนอก\n{1} ให้กับผู้ขาย BTC\n\n +portfolio.pending.step2_buyer.crypto=โปรดโอนจาก wallet {0} ภายนอก\n{1} ให้กับผู้ขาย XMR\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=โปรดไปที่ธนาคารและจ่ายเงิน {0} ให้กับผู้ขาย BTC\n -portfolio.pending.step2_buyer.cash.extra=ข้อกำหนดที่สำคัญ: \nหลังจากที่คุณได้ชำระเงินแล้วให้เขียนลงในใบเสร็จรับเงิน: NO REFUNDS (ไม่มีการคืนเงิน)\nจากนั้นแบ่งออกเป็น 2 ส่วนถ่ายรูปและส่งไปที่ที่อยู่อีเมลของผู้ขาย BTC +portfolio.pending.step2_buyer.cash=โปรดไปที่ธนาคารและจ่ายเงิน {0} ให้กับผู้ขาย XMR\n +portfolio.pending.step2_buyer.cash.extra=ข้อกำหนดที่สำคัญ: \nหลังจากที่คุณได้ชำระเงินแล้วให้เขียนลงในใบเสร็จรับเงิน: NO REFUNDS (ไม่มีการคืนเงิน)\nจากนั้นแบ่งออกเป็น 2 ส่วนถ่ายรูปและส่งไปที่ที่อยู่อีเมลของผู้ขาย XMR # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=โปรดชำระเงิน {0} ให้กับผู้ขาย BTC โดยใช้ MoneyGram\n -portfolio.pending.step2_buyer.moneyGram.extra=ข้อกำหนดที่สำคัญ: \nหลังจากที่คุณได้ชำระเงินแล้วให้ส่งหมายเลข Authorization (การอนุมัติ) และรูปใบเสร็จรับเงินไปยังผู้ขาย BTC ทางอีเมล\nใบเสร็จจะต้องแสดงชื่อเต็มของผู้ขาย ประเทศ รัฐ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0}. +portfolio.pending.step2_buyer.moneyGram=โปรดชำระเงิน {0} ให้กับผู้ขาย XMR โดยใช้ MoneyGram\n +portfolio.pending.step2_buyer.moneyGram.extra=ข้อกำหนดที่สำคัญ: \nหลังจากที่คุณได้ชำระเงินแล้วให้ส่งหมายเลข Authorization (การอนุมัติ) และรูปใบเสร็จรับเงินไปยังผู้ขาย XMR ทางอีเมล\nใบเสร็จจะต้องแสดงชื่อเต็มของผู้ขาย ประเทศ รัฐ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=โปรดชำระเงิน {0} ให้กับผู้ขาย BTC โดยใช้ Western Union -portfolio.pending.step2_buyer.westernUnion.extra=ข้อกำหนดที่สำคัญ: \nหลังจากที่คุณได้ชำระเงินแล้วให้ส่ง MTCN (หมายเลขติดตาม) และรูปใบเสร็จรับเงินไปยังผู้ขาย BTC ทางอีเมล\nใบเสร็จจะต้องแสดงชื่อเต็ม เมือง ประเทศ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0} +portfolio.pending.step2_buyer.westernUnion=โปรดชำระเงิน {0} ให้กับผู้ขาย XMR โดยใช้ Western Union +portfolio.pending.step2_buyer.westernUnion.extra=ข้อกำหนดที่สำคัญ: \nหลังจากที่คุณได้ชำระเงินแล้วให้ส่ง MTCN (หมายเลขติดตาม) และรูปใบเสร็จรับเงินไปยังผู้ขาย XMR ทางอีเมล\nใบเสร็จจะต้องแสดงชื่อเต็ม เมือง ประเทศ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0} # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=โปรดส่ง {0} โดยธนาณัติ \"US Postal Money Order \" ไปยังผู้ขาย BTC\n +portfolio.pending.step2_buyer.postal=โปรดส่ง {0} โดยธนาณัติ \"US Postal Money Order \" ไปยังผู้ขาย XMR\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=กรุณาติดต่อผู้ขายของ BTC ตามรายชื่อที่ได้รับและนัดประชุมเพื่อจ่ายเงิน {0}\n\n +portfolio.pending.step2_buyer.f2f=กรุณาติดต่อผู้ขายของ XMR ตามรายชื่อที่ได้รับและนัดประชุมเพื่อจ่ายเงิน {0}\n\n portfolio.pending.step2_buyer.startPaymentUsing=เริ่มต้นการชำระเงินโดยใช้ {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=จำนวนเงินที่จะโอน @@ -628,27 +652,27 @@ portfolio.pending.step2_buyer.buyerAccount=บัญชีการชำระ portfolio.pending.step2_buyer.paymentSent=การชำระเงินเริ่มต้นแล้ว portfolio.pending.step2_buyer.warn=You still have not done your {0} payment!\nPlease note that the trade has to be completed by {1}. portfolio.pending.step2_buyer.openForDispute=You have not completed your payment!\nThe max. period for the trade has elapsed.Please contact the mediator for assistance. -portfolio.pending.step2_buyer.paperReceipt.headline=คุณได้ส่งใบเสร็จรับเงินให้กับผู้ขาย BTC หรือไม่? -portfolio.pending.step2_buyer.paperReceipt.msg=ข้อควรจำ: \nคุณต้องเขียนลงในใบเสร็จรับเงิน: NO REFUNDS (ไม่มีการคืนเงิน)\nจากนั้นแบ่งออกเป็น 2 ส่วนถ่ายรูปและส่งไปที่ที่อยู่อีเมลของผู้ขาย BTC +portfolio.pending.step2_buyer.paperReceipt.headline=คุณได้ส่งใบเสร็จรับเงินให้กับผู้ขาย XMR หรือไม่? +portfolio.pending.step2_buyer.paperReceipt.msg=ข้อควรจำ: \nคุณต้องเขียนลงในใบเสร็จรับเงิน: NO REFUNDS (ไม่มีการคืนเงิน)\nจากนั้นแบ่งออกเป็น 2 ส่วนถ่ายรูปและส่งไปที่ที่อยู่อีเมลของผู้ขาย XMR portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=ส่งหมายเลขการอนุมัติและใบเสร็จรับเงิน -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=คุณต้องส่งหมายเลขการอนุมัติและรูปใบเสร็จรับเงินทางอีเมลไปยังผู้ขาย BTC \nใบเสร็จจะต้องแสดงชื่อเต็มของประเทศ รัฐ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0} .\n\nคุณได้ส่งหมายเลขการอนุมัติและทำสัญญากับผู้ขายหรือไม่?\n +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=คุณต้องส่งหมายเลขการอนุมัติและรูปใบเสร็จรับเงินทางอีเมลไปยังผู้ขาย XMR \nใบเสร็จจะต้องแสดงชื่อเต็มของประเทศ รัฐ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0} .\n\nคุณได้ส่งหมายเลขการอนุมัติและทำสัญญากับผู้ขายหรือไม่?\n portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=ส่ง MTCN (หมายเลขติดตาม) และใบเสร็จรับเงิน -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=คุณต้องส่ง MTCN (หมายเลขติดตาม) และรูปใบเสร็จรับเงินทางอีเมลไปยังผู้ขาย BTC \nใบเสร็จจะต้องแสดงชื่อเต็ม เมือง ประเทศ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0} .\n\nคุณได้ส่ง MTCN และทำสัญญากับผู้ขายหรือไม่ +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=คุณต้องส่ง MTCN (หมายเลขติดตาม) และรูปใบเสร็จรับเงินทางอีเมลไปยังผู้ขาย XMR \nใบเสร็จจะต้องแสดงชื่อเต็ม เมือง ประเทศ และจำนวนเงินทั้งหมดของผู้ขาย อีเมลของผู้ขายคือ: {0} .\n\nคุณได้ส่ง MTCN และทำสัญญากับผู้ขายหรือไม่ portfolio.pending.step2_buyer.halCashInfo.headline=ส่งรหัส HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=คุณต้องส่งข้อความที่มีรหัส HalCash พร้อมกับ IDการค้า ({0}) ไปยังผู้ขาย BTC \nเบอร์โทรศัพท์มือถือของผู้ขาย คือ {1}\n\nคุณได้ส่งรหัสให้กับผู้ขายหรือยัง? +portfolio.pending.step2_buyer.halCashInfo.msg=คุณต้องส่งข้อความที่มีรหัส HalCash พร้อมกับ IDการค้า ({0}) ไปยังผู้ขาย XMR \nเบอร์โทรศัพท์มือถือของผู้ขาย คือ {1}\n\nคุณได้ส่งรหัสให้กับผู้ขายหรือยัง? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Some banks might verify the receiver's name. Faster Payments accounts created in old Haveno clients do not provide the receiver's name, so please use trade chat to obtain it (if needed). portfolio.pending.step2_buyer.confirmStart.headline=ยืนยันว่าคุณได้เริ่มต้นการชำระเงินแล้ว portfolio.pending.step2_buyer.confirmStart.msg=คุณได้เริ่มต้นการ {0} การชำระเงินให้กับคู่ค้าของคุณแล้วหรือยัง portfolio.pending.step2_buyer.confirmStart.yes=ใช่ฉันได้เริ่มต้นการชำระเงินแล้ว portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=รอการชำระเงิน portfolio.pending.step2_seller.f2fInfo.headline=ข้อมูลการติดต่อของผู้ซื้อ -portfolio.pending.step2_seller.waitPayment.msg=ธุรกรรมการฝากเงินมีการยืนยันบล็อกเชนอย่างน้อยหนึ่งรายการ\nคุณต้องรอจนกว่าผู้ซื้อ BTC จะเริ่มการชำระเงิน {0} -portfolio.pending.step2_seller.warn=ผู้ซื้อ BTC ยังไม่ได้ทำ {0} การชำระเงิน\nคุณต้องรอจนกว่าผู้ซื้อจะเริ่มชำระเงิน\nหากการซื้อขายยังไม่เสร็จสิ้นในวันที่ {1} ผู้ไกล่เกลี่ยจะดำเนินการตรวจสอบ -portfolio.pending.step2_seller.openForDispute=The BTC buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. +portfolio.pending.step2_seller.waitPayment.msg=ธุรกรรมการฝากเงินมีการยืนยันบล็อกเชนอย่างน้อยหนึ่งรายการ\nคุณต้องรอจนกว่าผู้ซื้อ XMR จะเริ่มการชำระเงิน {0} +portfolio.pending.step2_seller.warn=ผู้ซื้อ XMR ยังไม่ได้ทำ {0} การชำระเงิน\nคุณต้องรอจนกว่าผู้ซื้อจะเริ่มชำระเงิน\nหากการซื้อขายยังไม่เสร็จสิ้นในวันที่ {1} ผู้ไกล่เกลี่ยจะดำเนินการตรวจสอบ +portfolio.pending.step2_seller.openForDispute=The XMR buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. tradeChat.chatWindowTitle=Chat window for trade with ID ''{0}'' tradeChat.openChat=Open chat window tradeChat.rules=You can communicate with your trade peer to resolve potential problems with this trade.\nIt is not mandatory to reply in the chat.\nIf a trader violates any of the rules below, open a dispute and report it to the mediator or arbitrator.\n\nChat rules:\n\t● Do not send any links (risk of malware). You can send the transaction ID and the name of a block explorer.\n\t● Do not send your seed words, private keys, passwords or other sensitive information!\n\t● Do not encourage trading outside of Haveno (no security).\n\t● Do not engage in any form of social engineering scam attempts.\n\t● If a peer is not responding and prefers to not communicate via chat, respect their decision.\n\t● Keep conversation scope limited to the trade. This chat is not a messenger replacement or troll-box.\n\t● Keep conversation friendly and respectful. @@ -666,26 +690,26 @@ message.state.ACKNOWLEDGED=เน็ตเวิร์ก peer ยืนยั # suppress inspection "UnusedProperty" message.state.FAILED=การส่งข้อความล้มเหลว -portfolio.pending.step3_buyer.wait.headline=รอการยืนยันการชำระเงินของผู้ขาย BTC -portfolio.pending.step3_buyer.wait.info=กำลังรอการยืนยันจากผู้ขาย BTC สำหรับการรับ {0} การชำระเงิน +portfolio.pending.step3_buyer.wait.headline=รอการยืนยันการชำระเงินของผู้ขาย XMR +portfolio.pending.step3_buyer.wait.info=กำลังรอการยืนยันจากผู้ขาย XMR สำหรับการรับ {0} การชำระเงิน portfolio.pending.step3_buyer.wait.msgStateInfo.label=เริ่มต้นสถานะการชำระเงิน portfolio.pending.step3_buyer.warn.part1a=ใน {0} บล็อกเชน portfolio.pending.step3_buyer.warn.part1b=ที่ผู้ให้บริการการชำระเงิน (เช่น ธนาคาร) -portfolio.pending.step3_buyer.warn.part2=The BTC seller still has not confirmed your payment. Please check {0} if the payment sending was successful. -portfolio.pending.step3_buyer.openForDispute=The BTC seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. +portfolio.pending.step3_buyer.warn.part2=The XMR seller still has not confirmed your payment. Please check {0} if the payment sending was successful. +portfolio.pending.step3_buyer.openForDispute=The XMR seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=พันธมิตรทางการค้าของคุณได้ยืนยันว่าพวกเขาได้เริ่มต้น {0} การชำระเงิน\n\n portfolio.pending.step3_seller.crypto.explorer=ผู้สำรวจบล็อกเชน {0} ที่ถูกใจของคุณ portfolio.pending.step3_seller.crypto.wallet=ณ กระเป๋าสตางค์ {0} ของคุณ portfolio.pending.step3_seller.crypto={0}โปรดตรวจสอบ {1} หากการทำธุรกรรมส่วนที่อยู่รับของคุณ\n{2}\nมีการยืนยันบล็อกเชนแล้วเรียบร้อย\nยอดการชำระเงินต้องเป็น {3}\n\nคุณสามารถคัดลอกและวาง {4} ข้อมูลที่อยู่ของคุณได้จากหน้าจอหลักหลังจากปิดหน้าต่างป๊อปอัพ -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=เนื่องจากการชำระเงินผ่าน Cash Deposit (ฝากเงินสด) ผู้ซื้อ BTC จะต้องเขียน \"NO REFUND \" ในใบเสร็จรับเงินและให้แบ่งออกเป็น 2 ส่วนและส่งรูปถ่ายทางอีเมล\n\nเพื่อหลีกเลี่ยงความเสี่ยงจากการปฏิเสธการชำระเงิน ให้ยืนยันเฉพาะถ้าคุณได้รับอีเมลและหากคุณแน่ใจว่าใบเสร็จถูกต้องแล้ว\nถ้าคุณไม่แน่ใจ {0} -portfolio.pending.step3_seller.moneyGram=ผู้ซื้อต้องส่งหมายเลขอนุมัติและรูปใบเสร็จรับเงินทางอีเมล\nใบเสร็จรับเงินต้องแสดงชื่อเต็มของคุณ ประเทศ รัฐ และจำนวนเงิน โปรดตรวจสอบอีเมลของคุณหากคุณได้รับหมายเลขการให้สิทธิ์\n\nหลังจากปิดป๊อปอัปคุณจะเห็นชื่อและที่อยู่ของผู้ซื้อ BTC เพื่อรับเงินจาก MoneyGram\n\nยืนยันเฉพาะใบเสร็จหลังจากที่คุณได้รับเงินเรียบร้อยแล้ว! -portfolio.pending.step3_seller.westernUnion=ผู้ซื้อต้องส่ง MTCN (หมายเลขติดตาม) และรูปใบเสร็จรับเงินทางอีเมล\nใบเสร็จรับเงินต้องแสดงชื่อ เมือง ประเทศ และจำนวนเงินทั้งหมดไว้อย่างชัดเจน โปรดตรวจสอบอีเมลของคุณหากคุณได้รับ MTCN\n\nหลังจากปิดป๊อปอัปคุณจะเห็นชื่อและที่อยู่ของผู้ซื้อ BTC สำหรับการขอรับเงินจาก Western Union \n\nยืนยันเฉพาะใบเสร็จหลังจากที่คุณได้รับเงินเรียบร้อยแล้ว! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=เนื่องจากการชำระเงินผ่าน Cash Deposit (ฝากเงินสด) ผู้ซื้อ XMR จะต้องเขียน \"NO REFUND \" ในใบเสร็จรับเงินและให้แบ่งออกเป็น 2 ส่วนและส่งรูปถ่ายทางอีเมล\n\nเพื่อหลีกเลี่ยงความเสี่ยงจากการปฏิเสธการชำระเงิน ให้ยืนยันเฉพาะถ้าคุณได้รับอีเมลและหากคุณแน่ใจว่าใบเสร็จถูกต้องแล้ว\nถ้าคุณไม่แน่ใจ {0} +portfolio.pending.step3_seller.moneyGram=ผู้ซื้อต้องส่งหมายเลขอนุมัติและรูปใบเสร็จรับเงินทางอีเมล\nใบเสร็จรับเงินต้องแสดงชื่อเต็มของคุณ ประเทศ รัฐ และจำนวนเงิน โปรดตรวจสอบอีเมลของคุณหากคุณได้รับหมายเลขการให้สิทธิ์\n\nหลังจากปิดป๊อปอัปคุณจะเห็นชื่อและที่อยู่ของผู้ซื้อ XMR เพื่อรับเงินจาก MoneyGram\n\nยืนยันเฉพาะใบเสร็จหลังจากที่คุณได้รับเงินเรียบร้อยแล้ว! +portfolio.pending.step3_seller.westernUnion=ผู้ซื้อต้องส่ง MTCN (หมายเลขติดตาม) และรูปใบเสร็จรับเงินทางอีเมล\nใบเสร็จรับเงินต้องแสดงชื่อ เมือง ประเทศ และจำนวนเงินทั้งหมดไว้อย่างชัดเจน โปรดตรวจสอบอีเมลของคุณหากคุณได้รับ MTCN\n\nหลังจากปิดป๊อปอัปคุณจะเห็นชื่อและที่อยู่ของผู้ซื้อ XMR สำหรับการขอรับเงินจาก Western Union \n\nยืนยันเฉพาะใบเสร็จหลังจากที่คุณได้รับเงินเรียบร้อยแล้ว! portfolio.pending.step3_seller.halCash=ผู้ซื้อต้องส่งข้อความรหัส HalCash ให้คุณ ในขณะเดียวกันคุณจะได้รับข้อความจาก HalCash พร้อมกับคำขอข้อมูลจำเป็นในการถอนเงินยูโรุจากตู้เอทีเอ็มที่รองรับ HalCash \n\n หลังจากที่คุณได้รับเงินจากตู้เอทีเอ็มโปรดยืนยันใบเสร็จรับเงินจากการชำระเงินที่นี่ ! portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. @@ -701,7 +725,7 @@ portfolio.pending.step3_seller.xmrTxHash=เลขอ้างอิงการ portfolio.pending.step3_seller.xmrTxKey=Transaction key portfolio.pending.step3_seller.buyersAccount=Buyers account data portfolio.pending.step3_seller.confirmReceipt=ใบเสร็จยืนยันการชำระเงิน -portfolio.pending.step3_seller.buyerStartedPayment=ผู้ซื้อ BTC ได้เริ่มการชำระเงิน {0}\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=ผู้ซื้อ XMR ได้เริ่มการชำระเงิน {0}\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=ตรวจสอบการยืนยันบล็อกเชนที่ crypto wallet ของคุณหรือบล็อก explorer และยืนยันการชำระเงินเมื่อคุณมีการยืนยันบล็อกเชนที่เพียงพอ portfolio.pending.step3_seller.buyerStartedPayment.traditional=ตรวจสอบบัญชีการซื้อขายของคุณ (เช่น บัญชีธนาคาร) และยืนยันเมื่อคุณได้รับการชำระเงิน portfolio.pending.step3_seller.warn.part1a=ใน {0} บล็อกเชน @@ -713,7 +737,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=คุณได้รั # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Please also verify that the name of the sender specified on the trade contract matches the name that appears on your bank statement:\nSender''s name, per trade contract: {0}\n\nIf the names are not exactly the same, don''t confirm payment receipt. Instead, open a dispute by pressing \"alt + o\" or \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the BTC buyer and the security deposit will be refunded.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the XMR buyer and the security deposit will be refunded.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=ยืนยันว่าคุณได้รับการชำระเงินแล้ว portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=ใช่ ฉันได้รับการชำระเงินแล้ว portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANT: By confirming receipt of payment, you are also verifying the account of the counterparty and signing it accordingly. Since the account of the counterparty hasn't been signed yet, you should delay confirmation of the payment as long as possible to reduce the risk of a chargeback. @@ -723,16 +747,16 @@ portfolio.pending.step5_buyer.tradeFee=ค่าธรรมเนียมก portfolio.pending.step5_buyer.makersMiningFee=ค่าธรรมเนียมการขุด portfolio.pending.step5_buyer.takersMiningFee=ยอดรวมค่าธรรมเนียมการขุด portfolio.pending.step5_buyer.refunded=เงินประกันความปลอดภัยที่ถูกคืน -portfolio.pending.step5_buyer.withdrawBTC=ถอนเงิน bitcoin ของคุณ +portfolio.pending.step5_buyer.withdrawXMR=ถอนเงิน monero ของคุณ portfolio.pending.step5_buyer.amount=จำนวนเงินที่จะถอน portfolio.pending.step5_buyer.withdrawToAddress=ถอนไปยังที่อยู่ portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet portfolio.pending.step5_buyer.withdrawExternal=ถอนไปยัง wallet ภายนอก portfolio.pending.step5_buyer.alreadyWithdrawn=เงินทุนของคุณถูกถอนออกไปแล้ว\nโปรดตรวจสอบประวัติการทำธุรกรรม portfolio.pending.step5_buyer.confirmWithdrawal=ยืนยันคำขอถอนเงิน -portfolio.pending.step5_buyer.amountTooLow=จำนวนเงินที่โอนจะต่ำกว่าค่าธรรมเนียมการทำธุรกรรมและมูลค่าต่ำกว่าที่น่าจะเป็น (dust หน่วยเล็กสุดของ bitcoin) +portfolio.pending.step5_buyer.amountTooLow=จำนวนเงินที่โอนจะต่ำกว่าค่าธรรมเนียมการทำธุรกรรมและมูลค่าต่ำกว่าที่น่าจะเป็น (dust หน่วยเล็กสุดของ monero) portfolio.pending.step5_buyer.withdrawalCompleted.headline=การถอนเสร็จสิ้น -portfolio.pending.step5_buyer.withdrawalCompleted.msg=การซื้อขายที่เสร็จสิ้นของคุณจะถูกเก็บไว้ภายใต้ \"Portfolio (แฟ้มผลงาน) / ประวัติ\" \nคุณสามารถตรวจสอบการทำธุรกรรม Bitcoin ทั้งหมดภายใต้ \"เงิน / ธุรกรรม \" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=การซื้อขายที่เสร็จสิ้นของคุณจะถูกเก็บไว้ภายใต้ \"Portfolio (แฟ้มผลงาน) / ประวัติ\" \nคุณสามารถตรวจสอบการทำธุรกรรม Monero ทั้งหมดภายใต้ \"เงิน / ธุรกรรม \" portfolio.pending.step5_buyer.bought=คุณได้ซื้อ portfolio.pending.step5_buyer.paid=คุณได้จ่าย @@ -794,7 +818,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +857,7 @@ funds.deposit.fundHavenoWallet=เติมเงิน Haveno wallet funds.deposit.noAddresses=ยังไม่มีการสร้างที่อยู่ของเงินฝาก funds.deposit.fundWallet=เติมเงินใน wallet ของคุณ funds.deposit.withdrawFromWallet=ส่งเงินทุนจากกระเป๋าสตางค์ของคุณ -funds.deposit.amount=จำนวนเงินใน BTC (ตัวเลือก) +funds.deposit.amount=จำนวนเงินใน XMR (ตัวเลือก) funds.deposit.generateAddress=สร้างที่อยู่ใหม่ funds.deposit.generateAddressSegwit=Native segwit format (Bech32) funds.deposit.selectUnused=โปรดเลือกที่อยู่ที่ไม่ได้ใช้จากตารางด้านบนแทนที่จะสร้างที่อยู่ใหม่ @@ -890,7 +914,7 @@ funds.tx.revert=กลับสู่สภาพเดิม funds.tx.txSent=ธุรกรรมถูกส่งสำเร็จไปยังที่อยู่ใหม่ใน Haveno wallet ท้องถิ่นแล้ว funds.tx.direction.self=ส่งถึงตัวคุณเอง funds.tx.dustAttackTx=Received dust -funds.tx.dustAttackTx.popup=This transaction is sending a very small BTC amount to your wallet and might be an attempt from chain analysis companies to spy on your wallet.\n\nIf you use that transaction output in a spending transaction they will learn that you are likely the owner of the other address as well (coin merge).\n\nTo protect your privacy the Haveno wallet ignores such dust outputs for spending purposes and in the balance display. You can set the threshold amount when an output is considered dust in the settings. +funds.tx.dustAttackTx.popup=This transaction is sending a very small XMR amount to your wallet and might be an attempt from chain analysis companies to spy on your wallet.\n\nIf you use that transaction output in a spending transaction they will learn that you are likely the owner of the other address as well (coin merge).\n\nTo protect your privacy the Haveno wallet ignores such dust outputs for spending purposes and in the balance display. You can set the threshold amount when an output is considered dust in the settings. #################################################################### # Support @@ -904,7 +928,6 @@ support.filter=Search disputes support.filter.prompt=Enter trade ID, date, onion address or account data support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -940,8 +963,8 @@ support.savedInMailbox=ข้อความถูกบันทึกไว้ support.arrived=ข้อความถึงผู้รับแล้ว support.acknowledged=ข้อความได้รับการยืนยันจากผู้รับแล้ว support.error=ผู้รับไม่สามารถประมวลผลข้อความได้ ข้อผิดพลาด: {0} -support.buyerAddress=ที่อยู่ของผู้ซื้อ BTC -support.sellerAddress=ที่อยู่ของผู้ขาย BTC +support.buyerAddress=ที่อยู่ของผู้ซื้อ XMR +support.sellerAddress=ที่อยู่ของผู้ขาย XMR support.role=บทบาท support.agent=Support agent support.state=สถานะ @@ -949,13 +972,12 @@ support.chat=Chat support.closed=ปิดแล้ว support.open=เปิด support.process=Process -support.buyerMaker=BTC ผู้ซื้อ / ผู้สร้าง -support.sellerMaker= BTC ผู้ขาย/ ผู้สร้าง -support.buyerTaker=BTC ผู้ซื้อ / ผู้รับ -support.sellerTaker=BTC ผู้ขาย / ผู้รับ +support.buyerMaker=XMR ผู้ซื้อ / ผู้สร้าง +support.sellerMaker= XMR ผู้ขาย/ ผู้สร้าง +support.buyerTaker=XMR ผู้ซื้อ / ผู้รับ +support.sellerTaker=XMR ผู้ขาย / ผู้รับ -support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\nTraders can communicate within the application via secure chat on the open trades screen to try solving disputes on their own. If that is not sufficient, a mediator can step in to help. The mediator will evaluate the situation and suggest a payout of trade funds. If both traders accept this suggestion, the payout transaction is completed and the trade is closed. If one or both traders do not agree to the mediator's suggested payout, they can request arbitration.The arbitrator will re-evaluate the situation and, if warranted, personally pay the trader back and request reimbursement for this payment from Haveno. -support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the BTC buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the BTC seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} +support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the XMR buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the XMR seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} support.systemMsg=ระบบข้อความ: {0} support.youOpenedTicket=You opened a request for support.\n\n{0}\n\nHaveno version: {1} support.youOpenedDispute=You opened a request for a dispute.\n\n{0}\n\nHaveno version: {1} @@ -979,13 +1001,14 @@ settings.tab.network=ข้อมูลเครือข่าย settings.tab.about=เกี่ยวกับ setting.preferences.general=การตั้งค่าทั่วไป -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=สูงสุด ส่วนเบี่ยงเบนจากราคาตลาด setting.preferences.avoidStandbyMode=หลีกเลี่ยงโหมดแสตนบายด์ +setting.preferences.useSoundForNotifications=เล่นเสียงสำหรับการแจ้งเตือน setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=ค่าที่สูงกว่า {0}% ไม่ได้รับอนุญาต setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1022,29 +1045,31 @@ settings.preferences.editCustomExplorer.name=ชื่อ settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=เครือข่าย Bitcoin +settings.net.xmrHeader=เครือข่าย Monero settings.net.p2pHeader=Haveno network settings.net.onionAddressLabel=ที่อยู่ onion ของฉัน settings.net.xmrNodesLabel=ใช้โหนดเครือข่าย Monero ที่กำหนดเอง settings.net.moneroPeersLabel=เชื่อมต่อกับเน็ตเวิร์ก peers แล้ว +settings.net.connection=การเชื่อมต่อ +settings.net.connected=เชื่อมต่อ settings.net.useTorForXmrJLabel=ใช้ Tor สำหรับเครือข่าย Monero settings.net.moneroNodesLabel=ใช้โหนดเครือข่าย Monero เพื่อเชื่อมต่อ -settings.net.useProvidedNodesRadio=ใช้โหนดเครือข่าย Bitcoin ที่ให้มา -settings.net.usePublicNodesRadio=ใช้เครือข่าย Bitcoin สาธารณะ -settings.net.useCustomNodesRadio=ใช้โหนดเครือข่าย Bitcoin Core ที่กำหนดเอง +settings.net.useProvidedNodesRadio=ใช้โหนดเครือข่าย Monero ที่ให้มา +settings.net.usePublicNodesRadio=ใช้เครือข่าย Monero สาธารณะ +settings.net.useCustomNodesRadio=ใช้โหนดเครือข่าย Monero Core ที่กำหนดเอง settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=ไม่ ใช้โหนดที่ให้มา settings.net.warn.usePublicNodes.usePublic=ใช่ ใช้เครือข่ายสาธารณะ -settings.net.warn.useCustomNodes.B2XWarning=โปรดตรวจสอบว่าโหนด Bitcoin ของคุณเป็นโหนด Bitcoin Core ที่เชื่อถือได้!\n\nการเชื่อมต่อกับโหนดที่ไม่ปฏิบัติตามกฎกติกาการยินยอมของ Bitcoin Core อาจทำให้ wallet ของคุณเกิดปัญหาในกระบวนการทางการซื้อขายได้\n\nผู้ใช้ที่เชื่อมต่อกับโหนดที่ละเมิดกฎเป็นเอกฉันท์นั้นจำเป็นต้องรับผิดชอบต่อความเสียหายที่สร้างขึ้น ข้อพิพาทที่เกิดจากการที่จะได้รับการตัดสินใจจาก เน็ตกเวิร์ก Peer คนอื่น ๆ จะไม่มีการสนับสนุนด้านเทคนิคแก่ผู้ใช้ที่ไม่สนใจคำเตือนและกลไกการป้องกันของเรา! -settings.net.warn.invalidBtcConfig=Connection to the Bitcoin network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Bitcoin nodes instead. You will need to restart the application. -settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Bitcoin node when starting. If it is found, Haveno will communicate with the Bitcoin network exclusively through it. +settings.net.warn.useCustomNodes.B2XWarning=โปรดตรวจสอบว่าโหนด Monero ของคุณเป็นโหนด Monero Core ที่เชื่อถือได้!\n\nการเชื่อมต่อกับโหนดที่ไม่ปฏิบัติตามกฎกติกาการยินยอมของ Monero Core อาจทำให้ wallet ของคุณเกิดปัญหาในกระบวนการทางการซื้อขายได้\n\nผู้ใช้ที่เชื่อมต่อกับโหนดที่ละเมิดกฎเป็นเอกฉันท์นั้นจำเป็นต้องรับผิดชอบต่อความเสียหายที่สร้างขึ้น ข้อพิพาทที่เกิดจากการที่จะได้รับการตัดสินใจจาก เน็ตกเวิร์ก Peer คนอื่น ๆ จะไม่มีการสนับสนุนด้านเทคนิคแก่ผู้ใช้ที่ไม่สนใจคำเตือนและกลไกการป้องกันของเรา! +settings.net.warn.invalidXmrConfig=Connection to the Monero network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Monero nodes instead. You will need to restart the application. +settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Monero node when starting. If it is found, Haveno will communicate with the Monero network exclusively through it. settings.net.p2PPeersLabel=เชื่อมต่อกับเน็ตเวิร์ก peers แล้ว settings.net.onionAddressColumn=ที่อยู่ Onion settings.net.creationDateColumn=ที่จัดตั้งขึ้น settings.net.connectionTypeColumn=เข้า/ออก settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=ไป - กลับ settings.net.sentBytesColumn=ส่งแล้ว settings.net.receivedBytesColumn=ได้รับแล้ว @@ -1059,7 +1084,7 @@ settings.net.needRestart=คุณต้องรีสตาร์ทแอ็ settings.net.notKnownYet=ยังไม่ทราบ ... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[ที่อยู่ IP: พอร์ต | ชื่อโฮสต์: พอร์ต | ที่อยู่ onion: พอร์ต] (คั่นด้วยเครื่องหมายจุลภาค) Port สามารถละเว้นได้ถ้าใช้ค่าเริ่มต้น (8333) settings.net.seedNode=แหล่งโหนดข้อมูล settings.net.directPeer=Peer (โดยตรง) @@ -1105,7 +1130,7 @@ setting.about.shortcuts.openDispute.value=Select pending trade and click: {0} setting.about.shortcuts.walletDetails=Open wallet details window -setting.about.shortcuts.openEmergencyBtcWalletTool=Open emergency wallet tool for BTC wallet +setting.about.shortcuts.openEmergencyXmrWalletTool=Open emergency wallet tool for XMR wallet setting.about.shortcuts.showTorLogs=Toggle log level for Tor messages between DEBUG and WARN @@ -1131,7 +1156,7 @@ setting.about.shortcuts.sendPrivateNotification=Send private notification to pee setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1140,7 +1165,7 @@ account.tab.mediatorRegistration=Mediator registration account.tab.refundAgentRegistration=Refund agent registration account.tab.signing=Signing account.info.headline=ยินดีต้อนรับสู่บัญชี Haveno ของคุณ -account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Bitcoin wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Bitcoin wallet seed words (see tab on the top) and consider adding a password before funding. Bitcoin deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Bitcoin addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). +account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Monero wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Monero wallet seed words (see tab on the top) and consider adding a password before funding. Monero deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Monero addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). account.menu.paymentAccount=บัญชีสกุลเงินของประเทศ account.menu.altCoinsAccountView=บัญชี Crypto (เหรียญทางเลือก) @@ -1151,7 +1176,7 @@ account.menu.backup=การสำรองข้อมูล account.menu.notifications=การแจ้งเตือน account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1180,7 +1205,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Trading ARQ on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending ARQ, you need to use either the official ArQmA GUI wallet or ArQmA CLI wallet with the store-tx-info flag enabled (default in new versions). Please be sure you can access the tx key as that would be required in case of a dispute.\narqma-wallet-cli (use the command get_tx_key)\narqma-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nAt normal block explorers the transfer is not verifiable.\n\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The ARQ sender is responsible for providing verification of the ARQ transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process visit ArQmA discord channel (https://discord.gg/s9BQpJT) or the ArQmA forum (https://labs.arqma.com) to find more information. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1208,7 +1233,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin on Haveno requires that you unde account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Trading L-BTC on Haveno requires that you understand the following:\n\nWhen receiving L-BTC for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-BTC into the Liquid Elements Core wallet, or another L-BTC wallet which allows you to obtain the blinding key for your blinded L-BTC address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-BTC address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-BTC receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-BTC on Haveno. +account.crypto.popup.liquidmonero.msg=Trading L-XMR on Haveno requires that you understand the following:\n\nWhen receiving L-XMR for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-XMR into the Liquid Elements Core wallet, or another L-XMR wallet which allows you to obtain the blinding key for your blinded L-XMR address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-XMR address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-XMR receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-XMR on Haveno. account.traditional.yourTraditionalAccounts=บัญชีสกุลเงินของคุณ @@ -1228,13 +1253,13 @@ account.password.setPw.button=ตั้งรหัสผ่าน account.password.setPw.headline=ตั้งรหัสผ่านการป้องกันสำหรับ wallet account.password.info=เมื่อเปิดใช้งานการป้องกันด้วยรหัสผ่าน คุณจะต้องป้อนรหัสผ่านของคุณที่จุดเริ่มต้นของแอปพลิเคชัน ขณะถอนเงินมอเนโรออกจากกระเป๋าของคุณ และเมื่อแสดง seed words ของคุณ -account.seed.backup.title=สำรองข้อมูล wallet โค้ดของคุณ -account.seed.info=โปรดเขียนรหัสสำรองข้อมูล wallet และวันที่! คุณสามารถกู้ข้อมูล wallet ของคุณได้ทุกเมื่อด้วย รหัสสำรองข้อมูล wallet และวันที่\nรหัสสำรองข้อมูล ใช้ทั้ง BTC และ BSQ wallet\n\nคุณควรเขียนรหัสสำรองข้อมูล wallet ลงบนแผ่นกระดาษและไม่บันทึกไว้ในคอมพิวเตอร์ของคุณ\n\nโปรดทราบว่า รหัสสำรองข้อมูล wallet ไม่ได้แทนการสำรองข้อมูล\nคุณจำเป็นต้องสำรองข้อมูลสารบบแอ็พพลิเคชั่นทั้งหมดที่หน้าจอ \"บัญชี / การสำรองข้อมูล \" เพื่อกู้คืนสถานะแอ็พพลิเคชั่นและข้อมูลที่ถูกต้อง\nการนำเข้ารหัสสำรองข้อมูล wallet เป็นคำแนะนำเฉพาะสำหรับกรณีฉุกเฉินเท่านั้น แอพพลิเคชั่นจะไม่สามารถใช้งานได้หากไม่มีไฟล์สำรองฐานข้อมูลและคีย์ที่ถูกต้อง! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=สำรองคำพูดเมล็ดกระเป๋าของคุณ +account.seed.info=โปรดบันทึกทั้งคำพูดเมล็ดกระเป๋าและวันที่ คุณสามารถกู้คืนกระเป๋าของคุณได้ทุกเมื่อด้วยคำพูดเมล็ดและวันที่นั้น\n\nคุณควรจะบันทึกคำพูดเมล็ดลงในกระดาษ อย่าบันทึกไว้ในคอมพิวเตอร์\n\nโปรดทราบว่าคำพูดเมล็ดนั้นไม่ใช่การแทนที่สำหรับการสำรองข้อมูล\nคุณต้องสร้างสำรองข้อมูลของไดเรกทอรีแอปพลิเคชันทั้งหมดจากหน้าจอ "บัญชี/สำรอง" เพื่อกู้คืนสถานะและข้อมูลของแอปพลิเคชัน +account.seed.backup.warning=โปรดทราบว่าคำพูดเมล็ดนั้นไม่ใช่การแทนที่สำหรับการสำรองข้อมูล\nคุณต้องสร้างสำรองข้อมูลของไดเรกทอรีแอปพลิเคชันทั้งหมดจากหน้าจอ "บัญชี/สำรอง" เพื่อกู้คืนสถานะและข้อมูลของแอปพลิเคชัน account.seed.warn.noPw.msg=คุณยังไม่ได้ตั้งรหัสผ่าน wallet ซึ่งจะช่วยป้องกันการแสดงผลของรหัสสำรองข้อมูล wallet \n\nคุณต้องการแสดงรหัสสำรองข้อมูล wallet หรือไม่ account.seed.warn.noPw.yes=ใช่ และไม่ต้องถามฉันอีก account.seed.enterPw=ป้อนรหัสผ่านเพื่อดูรหัสสำรองข้อมูล wallet -account.seed.restore.info=Please make a backup before applying restore from seed words. Be aware that wallet restore is only for emergency cases and might cause problems with the internal wallet database.\nIt is not a way for applying a backup! Please use a backup from the application data directory for restoring a previous application state.\n\nAfter restoring the application will shut down automatically. After you have restarted the application it will resync with the Bitcoin network. This can take a while and can consume a lot of CPU, especially if the wallet was older and had many transactions. Please avoid interrupting that process, otherwise you might need to delete the SPV chain file again or repeat the restore process. +account.seed.restore.info=Please make a backup before applying restore from seed words. Be aware that wallet restore is only for emergency cases and might cause problems with the internal wallet database.\nIt is not a way for applying a backup! Please use a backup from the application data directory for restoring a previous application state.\n\nAfter restoring the application will shut down automatically. After you have restarted the application it will resync with the Monero network. This can take a while and can consume a lot of CPU, especially if the wallet was older and had many transactions. Please avoid interrupting that process, otherwise you might need to delete the SPV chain file again or repeat the restore process. account.seed.restore.ok=Ok, do the restore and shut down Haveno @@ -1259,13 +1284,13 @@ account.notifications.trade.label=ได้รับข้อความทา account.notifications.market.label=ได้รับการแจ้งเตือนข้อเสนอ account.notifications.price.label=ได้รับการแจ้งเตือนราคา account.notifications.priceAlert.title=แจ้งเตือนราคา -account.notifications.priceAlert.high.label=แจ้งเตือนหากราคา BTC สูงกว่า -account.notifications.priceAlert.low.label=แจ้งเตือนหากราคา BTC ต่ำกว่า +account.notifications.priceAlert.high.label=แจ้งเตือนหากราคา XMR สูงกว่า +account.notifications.priceAlert.low.label=แจ้งเตือนหากราคา XMR ต่ำกว่า account.notifications.priceAlert.setButton=ตั้งค่าการเตือนราคา account.notifications.priceAlert.removeButton=ลบการเตือนราคา account.notifications.trade.message.title=การเปลี่ยนแปลงสถานะทางการค้า account.notifications.trade.message.msg.conf=ธุรกรรมทางการค้าจากผู้ค้า ID {0} ได้รับการยืนยันแล้ว โปรดเปิดแอปพลิเคชัน Haveno ของคุณและเริ่มการรับการชำระเงิน -account.notifications.trade.message.msg.started=ผู้ซื้อ BTC ได้เริ่มต้นการชำระเงินสำหรับผู้ค้าที่มี ID {0} +account.notifications.trade.message.msg.started=ผู้ซื้อ XMR ได้เริ่มต้นการชำระเงินสำหรับผู้ค้าที่มี ID {0} account.notifications.trade.message.msg.completed=การค้ากับ ID {0} เสร็จสมบูรณ์ account.notifications.offer.message.title=ข้อเสนอของคุณถูกยอมรับ account.notifications.offer.message.msg=ข้อเสนอของคุณที่มี ID {0} ถูกยอมรับ @@ -1275,10 +1300,10 @@ account.notifications.dispute.message.msg=คุณได้รับข้อ account.notifications.marketAlert.title=เสนอการแจ้งเตือน account.notifications.marketAlert.selectPaymentAccount=เสนอบัญชีการชำระเงินที่ตรงกัน account.notifications.marketAlert.offerType.label=ประเภทข้อเสนอพิเศษที่ฉันสนใจ -account.notifications.marketAlert.offerType.buy=ซื้อข้อเสนอพิเศษ (ฉันต้องการขาย BTC) -account.notifications.marketAlert.offerType.sell=ข้อเสนอพิเศษในการขาย (ฉันต้องการซื้อ BTC) +account.notifications.marketAlert.offerType.buy=ซื้อข้อเสนอพิเศษ (ฉันต้องการขาย XMR) +account.notifications.marketAlert.offerType.sell=ข้อเสนอพิเศษในการขาย (ฉันต้องการซื้อ XMR) account.notifications.marketAlert.trigger=ระดับของราคาที่เสนอ (%) -account.notifications.marketAlert.trigger.info=เมื่อตั้งระดับของราคา คุณจะได้รับการแจ้งเตือนเมื่อมีการเผยแพร่ข้อเสนอที่ตรงกับความต้องการของคุณ (หรือมากกว่า) \nตัวอย่าง: หากคุณต้องการขาย BTC แต่คุณจะขายในราคาที่สูงกว่า 2% จากราคาตลาดปัจจุบันเท่านั้น\n การตั้งค่าฟิลด์นี้เป็น 2% จะทำให้คุณมั่นใจได้ว่าจะได้รับการแจ้งเตือนสำหรับข้อเสนอเฉพาะในราคาที่สูงกว่าราคาตลาดปัจจุบันที่ 2% (หรือมากกว่า) +account.notifications.marketAlert.trigger.info=เมื่อตั้งระดับของราคา คุณจะได้รับการแจ้งเตือนเมื่อมีการเผยแพร่ข้อเสนอที่ตรงกับความต้องการของคุณ (หรือมากกว่า) \nตัวอย่าง: หากคุณต้องการขาย XMR แต่คุณจะขายในราคาที่สูงกว่า 2% จากราคาตลาดปัจจุบันเท่านั้น\n การตั้งค่าฟิลด์นี้เป็น 2% จะทำให้คุณมั่นใจได้ว่าจะได้รับการแจ้งเตือนสำหรับข้อเสนอเฉพาะในราคาที่สูงกว่าราคาตลาดปัจจุบันที่ 2% (หรือมากกว่า) account.notifications.marketAlert.trigger.prompt=เปอร์เซ็นต์ระดับราคาจากราคาตลาด (เช่น 2.50%, -0.50% ฯลฯ ) account.notifications.marketAlert.addButton=เพิ่มการแจ้งเตือนข้อเสนอพิเศษ account.notifications.marketAlert.manageAlertsButton=จัดการการแจ้งเตือนข้อเสนอพิเศษ @@ -1305,10 +1330,10 @@ inputControlWindow.balanceLabel=ยอดคงเหลือที่พร้ contractWindow.title=รายละเอียดข้อพิพาท contractWindow.dates=วันที่เสนอ / วันที่ซื้อขาย -contractWindow.btcAddresses=ที่อยู่ Bitcoin ผู้ซื้อ BTC / ผู้ขาย BTC -contractWindow.onions=ที่อยู่เครือข่ายผู้ซื้อ BTC / ผู้ขาย BTC -contractWindow.accountAge=Account age BTC buyer / BTC seller -contractWindow.numDisputes=เลขที่ข้อพิพาทผู้ซื้อ BTC / ผู้ขาย BTC +contractWindow.xmrAddresses=ที่อยู่ Monero ผู้ซื้อ XMR / ผู้ขาย XMR +contractWindow.onions=ที่อยู่เครือข่ายผู้ซื้อ XMR / ผู้ขาย XMR +contractWindow.accountAge=Account age XMR buyer / XMR seller +contractWindow.numDisputes=เลขที่ข้อพิพาทผู้ซื้อ XMR / ผู้ขาย XMR contractWindow.contractHash=สัญญา hash displayAlertMessageWindow.headline=ข้อมูลสำคัญ! @@ -1334,8 +1359,8 @@ disputeSummaryWindow.title=สรุป disputeSummaryWindow.openDate=วันที่ยื่นการเปิดคำขอและความช่วยเหลือ disputeSummaryWindow.role=บทบาทของผู้ค้า disputeSummaryWindow.payout=การจ่ายเงินของจำนวนการซื้อขาย -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} รับการจ่ายเงินของปริมาณการซื้อขาย: -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} รับการจ่ายเงินของปริมาณการซื้อขาย: +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=การชำระเงินที่กำหนดเอง disputeSummaryWindow.payoutAmount.buyer=จำนวนเงินที่จ่ายของผู้ซื้อ disputeSummaryWindow.payoutAmount.seller=จำนวนเงินที่จ่ายของผู้ขาย @@ -1377,7 +1402,7 @@ disputeSummaryWindow.close.button=ปิดการยื่นคำขอแ # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1420,18 +1445,18 @@ filterWindow.mediators=Filtered mediators (comma sep. onion addresses) filterWindow.refundAgents=Filtered refund agents (comma sep. onion addresses) filterWindow.seedNode=แหล่งข้อมูลในโหนดเครือข่ายที่ได้รับการกรอง (คั่นด้วยเครื่องหมายจุลภาค ที่อยู่ onion) filterWindow.priceRelayNode=โหนดผลัดเปลี่ยนราคาที่ได้รับการกรอง (คั่นด้วยเครื่องหมายจุลภาค ที่อยู่ onion) -filterWindow.xmrNode=โหนด Bitcoin ที่ได้รับการกรองแล้ว (คั่นด้วยเครื่องหมายจุลภาค ที่อยู่ + พอร์ต) -filterWindow.preventPublicXmrNetwork=ป้องกันการใช้เครือข่าย Bitcoin สาธารณะ +filterWindow.xmrNode=โหนด Monero ที่ได้รับการกรองแล้ว (คั่นด้วยเครื่องหมายจุลภาค ที่อยู่ + พอร์ต) +filterWindow.preventPublicXmrNetwork=ป้องกันการใช้เครือข่าย Monero สาธารณะ filterWindow.disableAutoConf=Disable auto-confirm filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) filterWindow.disableTradeBelowVersion=Min. version required for trading filterWindow.add=เพิ่มตัวกรอง filterWindow.remove=ลบตัวกรอง -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=จำนวน BTC ต่ำสุด +offerDetailsWindow.minXmrAmount=จำนวน XMR ต่ำสุด offerDetailsWindow.min=(ต่ำสุด. {0}) offerDetailsWindow.distance=(ระดับราคาจากราคาตลาด: {0}) offerDetailsWindow.myTradingAccount=บัญชีการซื้อขายของฉัน @@ -1446,6 +1471,7 @@ offerDetailsWindow.confirm.maker=ยืนยัน: ยื่นข้อเส offerDetailsWindow.confirm.taker=ยืนยัน: รับข้อเสนอไปยัง {0} บิทคอยน์ offerDetailsWindow.creationDate=วันที่สร้าง offerDetailsWindow.makersOnion=ที่อยู่ onion ของผู้สร้าง +offerDetailsWindow.challenge=รหัสผ่านสำหรับข้อเสนอ qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1474,7 +1500,7 @@ showWalletDataWindow.walletData=ข้อมูล Wallet showWalletDataWindow.includePrivKeys=รวมคีย์ส่วนตัว setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1486,7 +1512,7 @@ tacWindow.disagree=ฉันไม่เห็นด้วยและออก tacWindow.arbitrationSystem=Dispute resolution tradeDetailsWindow.headline=ซื้อขาย -tradeDetailsWindow.disputedPayoutTxId=รหัส ID ธุรกรรมการจ่ายเงินที่พิพาท: +tradeDetailsWindow.disputedPayoutTxId=รหัส ID ธุรกรรมการจ่ายเงินที่พิพาท tradeDetailsWindow.tradeDate=วันที่ซื้อขาย tradeDetailsWindow.txFee=ค่าธรรมเนียมการขุด tradeDetailsWindow.tradePeersOnion=ที่อยู่ของ onion คู่ค้า @@ -1496,8 +1522,10 @@ tradeDetailsWindow.agentAddresses=Arbitrator/Mediator tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=คุณได้ส่ง XMR แล้ว +txDetailsWindow.xmr.noteReceived=คุณได้รับ XMR แล้ว +txDetailsWindow.sentTo=ส่งไปยัง +txDetailsWindow.receivedWith=ได้รับด้วย txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1506,7 +1534,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=ป้อนรหัสผ่านเพื่อปลดล็อก @@ -1532,12 +1560,12 @@ torNetworkSettingWindow.bridges.header=Tor ถูกบล็อกหรือ torNetworkSettingWindow.bridges.info=ถ้า Tor ถูกปิดกั้นโดยผู้ให้บริการอินเทอร์เน็ตหรือประเทศของคุณ คุณสามารถลองใช้ Tor bridges\nไปที่หน้าเว็บของ Tor ที่ https://bridges.torproject.org/bridges เพื่อเรียนรู้เพิ่มเติมเกี่ยวกับสะพานและการขนส่งแบบ pluggable feeOptionWindow.headline=เลือกสกุลเงินสำหรับการชำระค่าธรรมเนียมการซื้อขาย -feeOptionWindow.info=คุณสามารถเลือกที่จะชำระค่าธรรมเนียมทางการค้าใน BSQ หรือใน BTC แต่ถ้าคุณเลือก BSQ คุณจะได้รับส่วนลดค่าธรรมเนียมการซื้อขาย +feeOptionWindow.info=คุณสามารถเลือกที่จะชำระค่าธรรมเนียมทางการค้าใน BSQ หรือใน XMR แต่ถ้าคุณเลือก BSQ คุณจะได้รับส่วนลดค่าธรรมเนียมการซื้อขาย feeOptionWindow.optionsLabel=เลือกสกุลเงินสำหรับการชำระค่าธรรมเนียมการซื้อขาย -feeOptionWindow.useBTC=ใช้ BTC +feeOptionWindow.useXMR=ใช้ XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1607,9 @@ popup.warning.noTradingAccountSetup.msg=คุณต้องตั้งค่ popup.warning.noArbitratorsAvailable=ไม่มีผู้ไกล่เกลี่ยสำหรับทำการ popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=คุณต้องรอจนกว่าคุณจะเชื่อมต่อกับเครือข่ายอย่างสมบูรณ์\nอาจใช้เวลาประมาณ 2 นาทีเมื่อเริ่มต้น -popup.warning.notSufficientConnectionsToBtcNetwork=คุณต้องรอจนกว่าจะมีการเชื่อมต่อกับเครือข่าย Bitcoin อย่างน้อย {0} รายการ -popup.warning.downloadNotComplete=คุณต้องรอจนกว่าการดาวน์โหลดบล็อค Bitcoin ที่ขาดหายไปจะเสร็จสมบูรณ์ -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=คุณต้องรอจนกว่าจะมีการเชื่อมต่อกับเครือข่าย Monero อย่างน้อย {0} รายการ +popup.warning.downloadNotComplete=คุณต้องรอจนกว่าการดาวน์โหลดบล็อค Monero ที่ขาดหายไปจะเสร็จสมบูรณ์ +popup.warning.walletNotSynced=กระเป๋า Haveno ไม่ได้ปรับข้อมูลกับความสูงของบล็อกเชนล่าสุด โปรดรอให้กระเป๋าปรับข้อมูลหรือตรวจสอบการเชื่อมต่อของคุณ popup.warning.removeOffer=คุณแน่ใจหรือไม่ว่าต้องการนำข้อเสนอนั้นออก popup.warning.tooLargePercentageValue=คุณไม่สามารถกำหนดเปอร์เซ็นต์เป็น 100% หรือมากกว่าได้ popup.warning.examplePercentageValue=โปรดป้อนตัวเลขเปอร์เซ็นต์เช่น \"5.4 \" เป็น 5.4% @@ -1600,14 +1628,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=ราคาผลัดเปลี่ยน popup.warning.seed=รหัสลับเพื่อกู้ข้อมูล popup.warning.mandatoryUpdate.trading=Please update to the latest Haveno version. A mandatory update was released which disables trading for old versions. Please check out the Haveno Forum for more information. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=This transaction is not possible, as the mining fees of {0} would exceed the amount to transfer of {1}. Please wait until the mining fees are low again or until you''ve accumulated more BTC to transfer. +popup.warning.burnXMR=This transaction is not possible, as the mining fees of {0} would exceed the amount to transfer of {1}. Please wait until the mining fees are low again or until you''ve accumulated more XMR to transfer. -popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Bitcoin network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Monero network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. @@ -1616,13 +1643,13 @@ popup.info.securityDepositInfo=เพื่อให้แน่ใจว่า popup.info.cashDepositInfo=โปรดตรวจสอบว่าคุณมีสาขาธนาคารในพื้นที่ของคุณเพื่อสามารถฝากเงินได้\nรหัสธนาคาร (BIC / SWIFT) ของธนาคารผู้ขายคือ: {0} popup.info.cashDepositInfo.confirm=ฉันยืนยันว่าฉันสามารถฝากเงินได้ popup.info.shutDownWithOpenOffers=Haveno คือกำลังจะปิดลง แต่ยังคงมีการเปิดขายข้อเสนอปกติ\nข้อเสนอเหล่านี้จะไม่ใข้งานได้บนเครือข่าย P2P network ในขณะที่ Haveno ปิดตัวลง แต่จะมีการเผยแพร่บนเครือข่าย P2P ครั้งถัดไปเมื่อคุณมีการเริ่มใช้งาน Haveno.\n\nในการคงสถานะข้อเสนอแบบออนไลน์ คือเปิดใข้งาน Haveno และทำให้มั่นใจว่าคอมพิวเตอร์เครื่องนี้กำลังออนไลน์อยู่ด้วยเช่นกัน (เช่น ตรวจสอบว่าคอมพิวเตอร์ไม่ได้อยู่ในโหมดแสตนบายด์...หน้าจอแสตนบายด์ไม่มีปัญหา) -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=การแจ้งเตือนส่วนตัวที่สำคัญ! popup.securityRecommendation.headline=ข้อเสนอแนะด้านความปลอดภัยที่สำคัญ -popup.securityRecommendation.msg=เราขอแจ้งเตือนให้คุณพิจารณาใช้การป้องกันด้วยรหัสผ่านสำหรับ wallet ของคุณ หากยังไม่ได้เปิดใช้งาน\n\nขอแนะนำให้เขียนรหัสลับป้องกัน wallet รหัสลับเหล่านี้เหมือนกับรหัสผ่านหลักสำหรับการกู้คืน Bitcoin wallet ของคุณ\nไปที่ \"กระเป๋าสตางค์ \" คุณจะพบข้อมูลเพิ่มเติม\n\nนอกจากนี้คุณควรสำรองโฟลเดอร์ข้อมูลแอ็พพลิเคชั่นทั้งหมดไว้ที่ส่วน \"สำรองข้อมูล \" +popup.securityRecommendation.msg=เราขอแจ้งเตือนให้คุณพิจารณาใช้การป้องกันด้วยรหัสผ่านสำหรับ wallet ของคุณ หากยังไม่ได้เปิดใช้งาน\n\nขอแนะนำให้เขียนรหัสลับป้องกัน wallet รหัสลับเหล่านี้เหมือนกับรหัสผ่านหลักสำหรับการกู้คืน Monero wallet ของคุณ\nไปที่ \"กระเป๋าสตางค์ \" คุณจะพบข้อมูลเพิ่มเติม\n\nนอกจากนี้คุณควรสำรองโฟลเดอร์ข้อมูลแอ็พพลิเคชั่นทั้งหมดไว้ที่ส่วน \"สำรองข้อมูล \" popup.shutDownInProgress.headline=การปิดระบบอยู่ระหว่างดำเนินการ popup.shutDownInProgress.msg=การปิดแอพพลิเคชั่นอาจใช้เวลาสักครู่\nโปรดอย่าขัดจังหวะกระบวนการนี้ @@ -1668,6 +1695,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=ไม่ต้องมีเงินมัดจำจากผู้ซื้อ +popup.info.buyerAsTakerWithoutDeposit=ข้อเสนอของคุณจะไม่ต้องการเงินมัดจำหรือค่าธรรมเนียมจากผู้ซื้อ XMR\n\nในการยอมรับข้อเสนอของคุณ คุณต้องแบ่งปันรหัสผ่านกับคู่ค้าการค้าของคุณภายนอก Haveno\n\nรหัสผ่านจะถูกสร้างโดยอัตโนมัติและแสดงในรายละเอียดข้อเสนอหลังจากการสร้าง + #################################################################### # Notifications #################################################################### @@ -1675,9 +1705,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign notification.trade.headline=การแจ้งเตือนการซื้อขายด้วย ID {0} notification.ticket.headline=ศูนย์ช่วยเหลือสนับสนุนการซื้อขายด้วย ID {0} notification.trade.completed=การค้าเสร็จสิ้นแล้วและคุณสามารถถอนเงินของคุณได้ -notification.trade.accepted=ข้อเสนอของคุณได้รับการยอมรับจาก BTC {0} แล้ว +notification.trade.accepted=ข้อเสนอของคุณได้รับการยอมรับจาก XMR {0} แล้ว notification.trade.unlocked=การซื้อขายของคุณมีการยืนยัน blockchain อย่างน้อยหนึ่งรายการ\nคุณสามารถเริ่มการชำระเงินได้เลย -notification.trade.paymentSent=ผู้ซื้อ BTC ได้เริ่มการชำระเงินแล้ว +notification.trade.paymentSent=ผู้ซื้อ XMR ได้เริ่มการชำระเงินแล้ว notification.trade.selectTrade=เลือกการซื้อขาย notification.trade.peerOpenedDispute=เครือข่ายทางการค้าของคุณได้เริ่มต้นเปิดที่ {0} notification.trade.disputeClosed={0} ถูกปิดแล้ว @@ -1696,7 +1726,7 @@ systemTray.show=แสดงหน้าต่างแอ็พพลิเค systemTray.hide=ซ่อนหน้าต่างแอ็พพลิเคชั่น systemTray.info=ข้อมูลเกี่ยวกับ Haveno systemTray.exit=ออก -systemTray.tooltip=Haveno: A decentralized bitcoin exchange network +systemTray.tooltip=Haveno: A decentralized monero exchange network #################################################################### @@ -1747,7 +1777,7 @@ tooltip.openBlockchainForTx=เปิดตัวสำรวจ blockchain ภ confidence.unknown=สถานะธุรกรรมที่ไม่รู้จัก confidence.seen=เห็นโดย {0} peer (s) / 0 การยืนยัน -confidence.confirmed=ยืนยันใน {0} บล็อก(หลายอัน) +confidence.confirmed={0} การยืนยัน confidence.invalid=ธุรกรรมไม่ถูกต้อง peerInfo.title=ข้อมูล Peer @@ -1758,10 +1788,10 @@ peerInfo.age.noRisk=อายุบัญชีการชำระเงิน peerInfo.age.chargeBackRisk=Time since signing peerInfo.unknownAge=อายุ ที่ไม่ที่รู้จัก -addressTextField.openWallet=เปิดกระเป๋าสตางค์ Bitcoin เริ่มต้นของคุณ +addressTextField.openWallet=เปิดกระเป๋าสตางค์ Monero เริ่มต้นของคุณ addressTextField.copyToClipboard=คัดลอกที่อยู่ไปยังคลิปบอร์ด addressTextField.addressCopiedToClipboard=ที่อยู่ถูกคัดลอกไปยังคลิปบอร์ดแล้ว -addressTextField.openWallet.failed=การเปิดแอปพลิเคชั่นเริ่มต้นกระเป๋าสตางค์ Bitcoin ล้มเหลว บางทีคุณอาจยังไม่ได้ติดตั้งไว้ +addressTextField.openWallet.failed=การเปิดแอปพลิเคชั่นเริ่มต้นกระเป๋าสตางค์ Monero ล้มเหลว บางทีคุณอาจยังไม่ได้ติดตั้งไว้ peerInfoIcon.tooltip={0} \nแท็ก: {1} @@ -1793,6 +1823,7 @@ navigation.support=\"ช่วยเหลือและสนับสนุ formatter.formatVolumeLabel={0} จำนวนยอด{1} formatter.makerTaker=ผู้สร้าง เป็น {0} {1} / ผู้รับเป็น {2} {3} +formatter.makerTakerLocked=ผู้สร้าง เป็น {0} {1} / ผู้รับเป็น {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=คุณคือ {0} {1} ({2} {3}) @@ -1838,7 +1869,6 @@ password.deriveKey=ดึงข้อมูลจากรหัสผ่าน password.walletDecrypted=กระเป๋าสตางค์ถูกถอดรหัสสำเร็จและการป้องกันรหัสผ่านได้มีการออกแล้ว password.wrongPw=คุณป้อนรหัสผ่านไม่ถูกต้อง\n\nโปรดลองป้อนรหัสผ่านอีกครั้งโดยละเอียด เพื่อตรวจสอบความผิดพลาดในการพิมพ์หรือสะกด password.walletEncrypted=เปิดใช้งานกระเป๋าสตางค์ที่เข้ารหัสแล้วและเปิดใช้งานการป้องกันด้วยรหัสผ่านแล้ว -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=รหัสผ่าน 2 รายการที่คุณป้อนไม่ตรงกัน password.forgotPassword=ลืมรหัสผ่านหรือเปล่า? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1852,7 +1882,7 @@ seed.date=วันที่ในกระเป๋าสตางค์ seed.restore.title=เรียกคืนกระเป๋าสตางค์จากรหัสลับ seed.restore=เรียกกระเป๋าสตางค์คืน seed.creationDate=วันที่สร้าง -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=ฉันต้องการเรียกคืนอีกครั้ง seed.warn.walletNotEmpty.emptyWallet=ฉันจะทำให้กระเป๋าสตางค์ของฉันว่างเปล่าก่อน seed.warn.notEncryptedAnymore=กระเป๋าสตางค์ของคุณได้รับการเข้ารหัสแล้ว\n\nหลังจากเรียกคืน wallets จะไม่ได้รับการเข้ารหัสและคุณต้องตั้งรหัสผ่านใหม่\n\nคุณต้องการดำเนินการต่อหรือไม่ @@ -1869,7 +1899,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=บัญชี payment.account.no=หมายเลขบัญชี payment.account.name=ชื่อบัญชี -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=ชื่อเต็มของเจ้าของบัญชี payment.account.fullName=ชื่อเต็ม (ชื่อจริง, ชื่อกลาง, นามสกุล) @@ -1901,7 +1931,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=ชื่อผู้ใช้ หรือ อีเมล หรือ หมายเลขโทรศัพท์ payment.moneyBeam.accountId=อีเมลหรือหมายเลขโทรศัพท์ -payment.venmo.venmoUserName=ชื่อผู้ใช้ Venmo payment.popmoney.accountId=อีเมลหรือหมายเลขโทรศัพท์ payment.promptPay.promptPayId=รหัสบัตรประชาชน/รหัสประจำตัวผู้เสียภาษี หรือเบอร์โทรศัพท์ payment.supportedCurrencies=สกุลเงินที่ได้รับการสนับสนุน @@ -1943,28 +1972,28 @@ payment.checking=การตรวจสอบ payment.savings=ออมทรัพย์ payment.personalId=รหัส ID ประจำตัวบุคคล payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Haveno to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=เมื่อมีการใช้งาน HalCash ผู้ซื้อ BTC จำเป็นต้องส่งรหัส Halcash ให้กับผู้ขายทางข้อความโทรศัพท์มือถือ\n\nโปรดตรวจสอบว่าไม่เกินจำนวนเงินสูงสุดที่ธนาคารของคุณอนุญาตให้คุณส่งด้วย HalCash จำนวนเงินขั้นต่ำในการเบิกถอนคือ 10 EUR และสูงสุดในจำนวนเงิน 600 EUR สำหรับการถอนซ้ำเป็น 3000 EUR ต่อผู้รับและต่อวัน และ 6000 EUR ต่อผู้รับและต่อเดือน โปรดตรวจสอบข้อจำกัดจากทางธนาคารคุณเพื่อให้มั่นใจได้ว่าทางธนาคารได้มีการใช้มาตรฐานข้อกำหนดเดียวกันกับดังที่ระบุไว้ ณ ที่นี่\n\nจำนวนเงินที่ถอนจะต้องเป็นจำนวนเงินหลาย 10 EUR เนื่องจากคุณไม่สามารถถอนเงินอื่น ๆ ออกจากตู้เอทีเอ็มได้ UI ในหน้าจอสร้างข้อเสนอและรับข้อเสนอจะปรับจำนวนเงิน BTC เพื่อให้จำนวนเงิน EUR ถูกต้อง คุณไม่สามารถใช้ราคาตลาดเป็นจำนวนเงิน EUR ซึ่งจะเปลี่ยนแปลงไปตามราคาที่มีการปรับเปลี่ยน\n\nในกรณีที่มีข้อพิพาทผู้ซื้อ BTC ต้องแสดงหลักฐานว่าได้ส่ง EUR แล้ว +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=เมื่อมีการใช้งาน HalCash ผู้ซื้อ XMR จำเป็นต้องส่งรหัส Halcash ให้กับผู้ขายทางข้อความโทรศัพท์มือถือ\n\nโปรดตรวจสอบว่าไม่เกินจำนวนเงินสูงสุดที่ธนาคารของคุณอนุญาตให้คุณส่งด้วย HalCash จำนวนเงินขั้นต่ำในการเบิกถอนคือ 10 EUR และสูงสุดในจำนวนเงิน 600 EUR สำหรับการถอนซ้ำเป็น 3000 EUR ต่อผู้รับและต่อวัน และ 6000 EUR ต่อผู้รับและต่อเดือน โปรดตรวจสอบข้อจำกัดจากทางธนาคารคุณเพื่อให้มั่นใจได้ว่าทางธนาคารได้มีการใช้มาตรฐานข้อกำหนดเดียวกันกับดังที่ระบุไว้ ณ ที่นี่\n\nจำนวนเงินที่ถอนจะต้องเป็นจำนวนเงินหลาย 10 EUR เนื่องจากคุณไม่สามารถถอนเงินอื่น ๆ ออกจากตู้เอทีเอ็มได้ UI ในหน้าจอสร้างข้อเสนอและรับข้อเสนอจะปรับจำนวนเงิน XMR เพื่อให้จำนวนเงิน EUR ถูกต้อง คุณไม่สามารถใช้ราคาตลาดเป็นจำนวนเงิน EUR ซึ่งจะเปลี่ยนแปลงไปตามราคาที่มีการปรับเปลี่ยน\n\nในกรณีที่มีข้อพิพาทผู้ซื้อ XMR ต้องแสดงหลักฐานว่าได้ส่ง EUR แล้ว # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=โปรดยืนยันว่าธนาคารของคุณได้อนุมัติให้คุณสามารถส่งเงินสดให้กับบัญชีบุคคลอื่นได้ ตัวอย่างเช่น บางธนาคารที่ไม่ได้มีการบริการถ่ายโอนเงินสดอย่าง Bank of America และ Wells Fargo -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=ข้อมูลติดต่อ payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1975,7 +2004,7 @@ payment.f2f.city.prompt=ชื่อเมืองจะแสดงพร้ payment.shared.optionalExtra=ข้อมูลตัวเลือกเพิ่มเติม payment.shared.extraInfo=ข้อมูลเพิ่มเติม payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=เปิดหน้าเว็บ payment.f2f.offerbook.tooltip.countryAndCity=Country and city: {0} / {1} payment.f2f.offerbook.tooltip.extra=ข้อมูลเพิ่มเติม: {0} @@ -1987,7 +2016,7 @@ payment.japan.recipient=ชื่อ payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2145,7 +2174,7 @@ validation.zero=ไม่อนุญาตให้ป้อนข้อมู validation.negative=ไม่อนุญาตให้ใช้ค่าลบ validation.traditional.tooSmall=ไม่อนุญาตให้ป้อนข้อมูลที่มีขนาดเล็กกว่าจำนวนเป็นไปได้ต่ำสุด validation.traditional.tooLarge=ไม่อนุญาตให้ป้อนข้อมูลที่มีขนาดใหญ่กว่าจำนวนสูงสุดที่เป็นไปได้ -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=ไม่อนุญาตให้ป้อนข้อมูลขนาดใหญ่กว่า {0} validation.xmr.tooSmall=ไม่อนุญาตให้ป้อนข้อมูลที่มีขนาดเล็กกว่า {0} validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2155,10 +2184,10 @@ validation.sortCodeChars={0} ต้องประกอบด้วย {1} ต validation.bankIdNumber={0} ต้องประกอบด้วย {1} ตัวเลข validation.accountNr=หมายเลขบัญชีต้องประกอบด้วย {0} ตัวเลข validation.accountNrChars=หมายเลขบัญชีต้องประกอบด้วย {0} ตัวอักษร -validation.btc.invalidAddress=ที่อยู่ไม่ถูกต้อง โปรดตรวจสอบแบบฟอร์มที่อยู่ +validation.xmr.invalidAddress=ที่อยู่ไม่ถูกต้อง โปรดตรวจสอบแบบฟอร์มที่อยู่ validation.integerOnly=โปรดป้อนตัวเลขจำนวนเต็มเท่านั้น validation.inputError=การป้อนข้อมูลของคุณเกิดข้อผิดพลาด: \n{0} -validation.btc.exceedsMaxTradeLimit=ขีดจำกัดการเทรดของคุณคือ {0} +validation.xmr.exceedsMaxTradeLimit=ขีดจำกัดการเทรดของคุณคือ {0} validation.nationalAccountId={0} ต้องประกอบด้วย {1} ตัวเลข #new diff --git a/core/src/main/resources/i18n/displayStrings_tr.properties b/core/src/main/resources/i18n/displayStrings_tr.properties new file mode 100644 index 0000000000..f3863027c7 --- /dev/null +++ b/core/src/main/resources/i18n/displayStrings_tr.properties @@ -0,0 +1,3368 @@ +# Keep display strings organized by domain +# Naming convention: We use camelCase and dot separated name spaces. +# Use as many sub spaces as required to make the structure clear, but as little as possible. +# E.g.: [main-view].[component].[description] +# In some cases we use enum values or constants to map to display strings + +# A annoying issue with property files is that we need to use 2 single quotes in display string +# containing variables (e.g. {0}), otherwise the variable will not be resolved. +# In display string which do not use a variable a single quote is ok. +# E.g. Don''t .... {1} + +# We use sometimes dynamic parts which are put together in the code and therefore sometimes use line breaks or spaces +# at the end of the string. Please never remove any line breaks or spaces. They are there with a purpose! +# To make longer strings with better readable you can make a line break with \ which does not result in a line break +# in the display but only in the editor. + +# Please use in all language files the exact same order of the entries, that way a comparison is easier. + +# Please try to keep the length of the translated string similar to English. If it is longer it might break layout or +# get truncated. We will need some adjustments in the UI code to support that but we want to keep effort at the minimum. + + +#################################################################### +# Shared +#################################################################### + +shared.readMore=Daha fazla oku +shared.openHelp=Yardımı Aç +shared.warning=Uyarı +shared.close=Kapat +shared.closeAnywayDanger=Yine de kapat (TEHLİKE!) +shared.okWait=Tamam, bekleyeceğim +shared.cancel=İptal +shared.ok=Tamam +shared.yes=Evet +shared.no=Hayır +shared.iUnderstand=Anladım +shared.continueAnyway=Yine de devam et +shared.na=Mevcut değil +shared.shutDown=Kapat +shared.reportBug=GitHub'da hata bildir +shared.buyMonero=Monero Satın Al +shared.sellMonero=Monero Sat +shared.buyCurrency={0} satın al +shared.sellCurrency={0} sat +shared.buyCurrencyLocked={0} satın al 🔒 +shared.sellCurrencyLocked={0} sat 🔒 +shared.buyingXMRWith={0} ile XMR satın alınıyor +shared.sellingXMRFor={0} karşılığında XMR satılıyor +shared.buyingCurrency={0} satın alınıyor (XMR satılıyor) +shared.sellingCurrency={0} satılıyor (XMR satın alınıyor) +shared.buy=satın al +shared.sell=sat +shared.buying=satın alınıyor +shared.selling=satılıyor +shared.P2P=Eşler Arası +shared.oneOffer=teklif +shared.multipleOffers=teklifler +shared.Offer=Teklif +shared.offerVolumeCode={0} Teklif Hacmi +shared.openOffers=açık teklifler +shared.trade=işlem +shared.trades=işlemler +shared.openTrades=açık işlemler +shared.dateTime=Tarih/Saat +shared.price=Fiyat +shared.priceWithCur={0} cinsinde +shared.priceInCurForCur={1} / {0} cinsinde +shared.fixedPriceInCurForCur={1} için sabit fiyat {0} cinsinden +shared.amount=Miktar +shared.txFee=İşlem Ücreti +shared.tradeFee=İşlem Ücreti +shared.buyerSecurityDeposit=Alıcı Depozitosu +shared.sellerSecurityDeposit=Satıcı Depozitosu +shared.amountWithCur={0} cinsinden miktar +shared.volumeWithCur={0} cinsinden hacim +shared.currency=Para Birimi +shared.market=Piyasa +shared.deviation=Sapma +shared.paymentMethod=Ödeme yöntemi +shared.tradeCurrency=İşlem para birimi +shared.offerType=Teklif türü +shared.details=Ayrıntılar +shared.address=Adres +shared.balanceWithCur={0} cinsinden bakiye +shared.utxo=Harcanmamış işlem çıktısı +shared.txId=İşlem ID +shared.confirmations=Onaylar +shared.revert=İşlemi Geri Al +shared.select=Seç +shared.usage=Kullanım +shared.state=Durum +shared.tradeId=İşlem ID +shared.offerId=Teklif ID +shared.traderId=Tacir ID +shared.bankName=Banka adı +shared.acceptedBanks=Kabul edilen bankalar +shared.amountMinMax=Miktar (min - max) +shared.amountHelp=Bir teklifin minimum ve maksimum miktarı ayarlanmışsa, bu aralıktaki herhangi bir miktarla işlem yapabilirsiniz. +shared.remove=Kaldır +shared.goTo={0}'e git +shared.XMRMinMax=XMR (min - max) +shared.removeOffer=Teklifi kaldır +shared.dontRemoveOffer=Teklifi kaldırma +shared.editOffer=Teklifi düzenle +shared.duplicateOffer=Teklifi çoğalt +shared.openLargeQRWindow=Büyük QR kodu penceresini aç +shared.chooseTradingAccount=İşlem hesabını seç +shared.faq=SSS sayfasını ziyaret et +shared.yesCancel=Evet, iptal et +shared.nextStep=Sonraki adım +shared.fundFromSavingsWalletButton=Haveno cüzdanından fonları uygula +shared.fundFromExternalWalletButton=Fonlama için harici cüzdanını aç +shared.openDefaultWalletFailed=Bir Monero cüzdan uygulaması açılamadı. Yüklü olduğundan emin misiniz? +shared.belowInPercent=Piyasa fiyatının altında % +shared.aboveInPercent=Piyasa fiyatının üzerinde % +shared.enterPercentageValue=% değeri gir +shared.OR=VEYA +shared.notEnoughFunds=Haveno cüzdanınızda bu işlem için yeterli fon yok—{0} gerekli ama sadece {1} mevcut.\n\nLütfen harici bir cüzdandan fon ekleyin veya Haveno cüzdanınıza Fonlar > Fon Al kısmından fon aktarın. +shared.waitingForFunds=Fonlar bekleniyor... +shared.yourDepositTransactionId=Depozito işlem ID'niz +shared.peerDepositTransactionId=Eşin depozito işlem ID'si +shared.makerDepositTransactionId=Yapıcı'nın depozito işlem ID'si +shared.takerDepositTransactionId=Alıcı'nın depozito işlem ID'si +shared.TheXMRBuyer=XMR alıcısı +shared.You=Sen +shared.preparingConfirmation=Onay hazırlanıyor... +shared.sendingConfirmation=Onay gönderiliyor... +shared.sendingConfirmationAgain=Lütfen tekrar onay gönderin +shared.exportCSV=CSV'ye Aktar +shared.exportJSON=JSON'a Aktar +shared.summary=Özeti Göster +shared.noDateAvailable=Geçerli tarih yok +shared.noDetailsAvailable=Geçerli detay yok +shared.notUsedYet=Henüz kullanılmadı +shared.date=Tarih +shared.sendFundsDetailsWithFee=Gönderiliyor: {0}\nAlıcı adresine: {1}.\nGerekli madencilik ücreti: {2}\n\nAlıcı alacak: {3}\n\nBu miktarı çekmek istediğinizden emin misiniz? +# suppress inspection "TrailingSpacesInProperty" +shared.sendFundsDetailsDust=Haveno, bu işlemin minimum toz eşiğinin altında bir değişim çıktısı oluşturacağını (ve bu nedenle Monero konsensüs kuralları tarafından izin verilmediğini) tespit etti. Bunun yerine, bu toz ({0} satoshi{1}) madencilik ücretine eklenecektir.\n\n\n +shared.copyToClipboard=Panoya kopyala +shared.copiedToClipboard=Panoya kopyalandı! +shared.language=Dil +shared.country=Ülke +shared.applyAndShutDown=Uygula ve kapat +shared.selectPaymentMethod=Ödeme yöntemini seç +shared.accountNameAlreadyUsed=Bu hesap adı başka bir kayıtlı hesap için zaten kullanılıyor.\nLütfen başka bir ad seçin. +shared.askConfirmDeleteAccount=Seçilen hesabı gerçekten silmek istiyor musunuz? +shared.cannotDeleteAccount=Bu hesabı silemezsiniz çünkü açık bir teklif (veya açık bir işlem) kullanılıyor. +shared.noAccountsSetupYet=Henüz hesap ayarlanmadı +shared.manageAccounts=Hesapları yönet +shared.addNewAccount=Yeni hesap ekle +shared.ExportAccounts=Hesapları Dışa Aktar +shared.importAccounts=Hesapları İçe Aktar +shared.createNewAccount=Yeni hesap oluştur +shared.createNewAccountDescription=Hesap bilgileriniz yerel olarak cihazınızda saklanır ve yalnızca ticaret ortağınızla ve bir anlaşmazlık açılırsa hakemle paylaşılır. +shared.saveNewAccount=Yeni hesabı kaydet +shared.selectedAccount=Seçilen hesap +shared.deleteAccount=Hesabı sil +shared.errorMessageInline=\nHata mesajı: {0} +shared.errorMessage=Hata mesajı +shared.information=Bilgi +shared.name=Ad +shared.id=Kimlik +shared.dashboard=Gösterge Paneli +shared.accept=Kabul et +shared.balance=Bakiye +shared.save=Kaydet +shared.onionAddress=Onion adresi +shared.supportTicket=destek bileti +shared.dispute=anlaşmazlık +shared.mediationCase=arabuluculuk vakası +shared.seller=satıcı +shared.buyer=alıcı +shared.allEuroCountries=Tüm Euro ülkeleri +shared.acceptedTakerCountries=Kabul edilen alıcı ülkeler +shared.tradePrice=İşlem fiyatı +shared.tradeAmount=İşlem miktarı +shared.tradeVolume=İşlem hacmi +shared.reservedAmount=Ayrılmış miktar +shared.invalidKey=Girdiğiniz anahtar doğru değil. +shared.enterPrivKey=Kilidi açmak için özel anahtar girin +shared.payoutTxId=Ödeme işlem ID'si +shared.contractAsJson=JSON formatında sözleşme +shared.viewContractAsJson=JSON formatında sözleşmeyi görüntüle +shared.contract.title=İşlem kimliği ile sözleşme: {0} +shared.paymentDetails=XMR {0} ödeme detayları +shared.securityDeposit=Güvenlik depozitosu +shared.yourSecurityDeposit=Sizin güvenlik depozitonuz +shared.contract=Sözleşme +shared.messageArrived=Mesaj geldi. +shared.messageStoredInMailbox=Mesaj posta kutusunda saklandı. +shared.messageSendingFailed=Mesaj gönderme başarısız oldu. Hata: {0} +shared.unlock=Kilidi aç +shared.toReceive=almak için +shared.toSpend=harcamak için +shared.xmrAmount=XMR miktarı +shared.yourLanguage=Dilleriniz +shared.addLanguage=Dil ekle +shared.total=Toplam +shared.totalsNeeded=Gereken fonlar +shared.tradeWalletAddress=İşlem cüzdan adresi +shared.tradeWalletBalance=İşlem cüzdan bakiyesi +shared.reserveExactAmount=Yalnızca gerekli fonları ayırın. Teklifinizin aktif hale gelmesi için bir madencilik ücreti ve yaklaşık 20 dakika gereklidir. +shared.makerTxFee=Yapıcı: {0} +shared.takerTxFee=Alıcı: {0} +shared.iConfirm=Onaylıyorum +shared.openURL={0}'i aç +shared.fiat=Fiat +shared.crypto=Kripto +shared.preciousMetals=Değerli Madenler +shared.traditional=Nakit +shared.otherAssets=diğer varlıklar +shared.other=Diğer +shared.all=Hepsi +shared.edit=Düzenle +shared.advancedOptions=Gelişmiş seçenekler +shared.interval=Aralık +shared.actions=Eylemler +shared.buyerUpperCase=Alıcı +shared.sellerUpperCase=Satıcı +shared.new=YENİ +shared.learnMore=Daha fazla bilgi edin +shared.dismiss=Kapat +shared.selectedArbitrator=Seçilen hakem +shared.selectedMediator=Seçilen arabulucu +shared.selectedRefundAgent=Seçilen hakem +shared.mediator=Arabulucu +shared.arbitrator=Hakem +shared.refundAgent=Hakem +shared.refundAgentForSupportStaff=İade temsilcisi +shared.delayedPayoutTxId=Gecikmiş ödeme işlem kimliği +shared.delayedPayoutTxReceiverAddress=Gecikmiş ödeme işlemi gönderildi +shared.unconfirmedTransactionsLimitReached=Şu anda çok fazla onaylanmamış işleminiz var. Lütfen daha sonra tekrar deneyin. +shared.numItemsLabel=Girdi sayısı: {0} +shared.filter=Filtrele +shared.enabled=Etkin +shared.pending=Beklemede +shared.me=Ben +shared.maker=Yapıcı +shared.taker=Alıcı + + +#################################################################### +# UI views +#################################################################### + +#################################################################### +# MainView +#################################################################### + +mainView.menu.market=Piyasa +mainView.menu.buyXmr=XMR Satın Al +mainView.menu.sellXmr=XMR Sat +mainView.menu.portfolio=Portföy +mainView.menu.funds=Fonlar +mainView.menu.support=Destek +mainView.menu.settings=Ayarlar +mainView.menu.account=Hesap + +mainView.marketPriceWithProvider.label=Fiyat {0} tarafından +mainView.marketPrice.havenoInternalPrice=Son Haveno işlem fiyatı +mainView.marketPrice.tooltip.havenoInternalPrice=Harici fiyat besleme sağlayıcılarından piyasa fiyatı yok.\n\ + Görüntülenen fiyat, o para birimi için en son Haveno işlem fiyatıdır. +mainView.marketPrice.tooltip={0}{1} Piyasası\nSon güncelleme: {2}\nSağlayıcı düğüm URL'si: {3} +mainView.balance.available=Bakiye +mainView.balance.reserved=Tekliflerde ayrılmış +mainView.balance.pending=Beklemedeki bakiye +mainView.balance.reserved.short=Ayrılmış +mainView.balance.pending.short=Beklemede + +mainView.footer.usingTor=(Tor üzerinden) +mainView.footer.localhostMoneroNode=(localhost) +mainView.footer.clearnet=(clearnet üzerinden) +mainView.footer.xmrInfo={0} {1} +mainView.footer.xmrFeeRate=/ Ücret oranı: {0} sat/vB +mainView.footer.xmrInfo.initializing=Haveno ağına bağlanıyor +mainView.footer.xmrInfo.synchronizingWith={0} ile senkronize ediliyor blok: {1} / {2} +mainView.footer.xmrInfo.connectedTo={0}'a bağlandı blok {1} +mainView.footer.xmrInfo.synchronizingWalletWith={0} ile cüzdan senkronize ediliyor blok: {1} / {2} +mainView.footer.xmrInfo.syncedWith={0} ile senkronize edildi blok {1} +mainView.footer.xmrInfo.connectingTo=Bağlanıyor +mainView.footer.xmrInfo.connectionFailed=Bağlantı başarısız oldu +mainView.footer.xmrPeers=Monero ağ eşleri: {0} +mainView.footer.p2pPeers=Haveno ağ eşleri: {0} + +mainView.bootstrapState.connectionToTorNetwork=(1/4) Tor ağına bağlanılıyor... +mainView.bootstrapState.torNodeCreated=(2/4) Tor düğümü oluşturuldu +mainView.bootstrapState.hiddenServicePublished=(3/4) Gizli Hizmet yayımlandı +mainView.bootstrapState.initialDataReceived=(4/4) İlk veri alındı + +mainView.bootstrapWarning.noSeedNodesAvailable=Köken düğümü yok +mainView.bootstrapWarning.noNodesAvailable=Köken düğümü ve eş yok +mainView.bootstrapWarning.bootstrappingToP2PFailed=Haveno ağına başlatma başarısız oldu + +mainView.p2pNetworkWarnMsg.noNodesAvailable=Veri isteği için köken düğümü veya kayıtlı eş yok.\nLütfen internet bağlantınızı kontrol edin veya uygulamayı yeniden başlatmayı deneyin. +mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Haveno ağına bağlanma başarısız oldu (rapor edilen hata: {0}).\nLütfen internet bağlantınızı kontrol edin veya uygulamayı yeniden başlatmayı deneyin. + +mainView.walletServiceErrorMsg.timeout=Zaman aşımından dolayı Monero ağına bağlanma başarısız oldu. +mainView.walletServiceErrorMsg.connectionError=Hata nedeniyle Monero ağına bağlanma başarısız oldu: {0} + +mainView.walletServiceErrorMsg.rejectedTxException=Bir işlem ağdan reddedildi.\n\n{0} + +mainView.networkWarning.allConnectionsLost=Tüm {0} ağ eşlerine bağlantınız kesildi.\nBelki internet bağlantınızı kaybettiniz ya da bilgisayarınız bekleme modundaydı. +mainView.networkWarning.localhostMoneroLost=Yerel Monero düğümüne bağlantınızı kaybettiniz.\nDiğer Monero düğümlerine bağlanmak için Haveno uygulamasını yeniden başlatın veya yerel Monero düğümünü yeniden başlatın. +mainView.version.update=(Güncelleme mevcut) +mainView.status.connections=Gelen bağlantılar: {0}\nGiden bağlantılar: {1} + + +#################################################################### +# MarketView +#################################################################### + +market.tabs.offerBook=Teklif kitabı +market.tabs.spreadCurrency=Para Birimine Göre Teklifler +market.tabs.spreadPayment=Ödeme Yöntemine Göre Teklifler +market.tabs.trades=İşlemler + +# OfferBookChartView +market.offerBook.sellOffersHeaderLabel={0} sat +market.offerBook.buyOffersHeaderLabel={0} al +market.offerBook.buy=Monero almak istiyorum +market.offerBook.sell=Monero satmak istiyorum + +# SpreadView +market.spread.numberOfOffersColumn=Tüm teklifler ({0}) +market.spread.numberOfBuyOffersColumn=XMR al ({0}) +market.spread.numberOfSellOffersColumn=XMR sat ({0}) +market.spread.totalAmountColumn=Toplam XMR ({0}) +market.spread.spreadColumn=Fark +market.spread.expanded=Genişletilmiş görünüm + +# TradesChartsView +market.trades.nrOfTrades=İşlemler: {0} +market.trades.tooltip.volumeBar=Hacim: {0} / {1}\nİşlem sayısı: {2}\nTarih: {3} +market.trades.tooltip.candle.open=Açılış: +market.trades.tooltip.candle.close=Kapanış: +market.trades.tooltip.candle.high=En Yüksek: +market.trades.tooltip.candle.low=En Düşük: +market.trades.tooltip.candle.average=Ortalama: +market.trades.tooltip.candle.median=Medyan: +market.trades.tooltip.candle.date=Tarih: +market.trades.showVolumeInUSD=Hacmi USD olarak göster + +#################################################################### +# OfferView +#################################################################### + +offerbook.createOffer=Teklif oluştur +offerbook.takeOffer=Teklif al +offerbook.takeOffer.createAccount=Hesap oluştur ve teklifi al +offerbook.takeOffer.enterChallenge=Teklif şifresini girin +offerbook.trader=Yatırımcı +offerbook.offerersBankId=Yapıcının banka kimliği (BIC/SWIFT): {0} +offerbook.offerersBankName=Yapıcının banka adı: {0} +offerbook.offerersBankSeat=Yapıcının banka ülke merkezi: {0} +offerbook.offerersAcceptedBankSeatsEuro=Kabul edilen banka ülkeleri (alıcı): Tüm Euro ülkeleri +offerbook.offerersAcceptedBankSeats=Kabul edilen banka ülkeleri (alıcı):\n {0} +offerbook.availableOffersToBuy={0} ile {1} satın al +offerbook.availableOffersToSell={0} için {1} sat +offerbook.filterByCurrency=Para birimini seç +offerbook.filterByPaymentMethod=Ödeme yöntemini seç +offerbook.matchingOffers=Uygun Teklif +offerbook.filterNoDeposit=Depozito yok +offerbook.noDepositOffers=Depozitosuz teklifler (şifre gereklidir) +offerbook.timeSinceSigning=Hesap bilgisi +offerbook.timeSinceSigning.info.arbitrator=bir hakem tarafından imzalandı ve eş hesaplarını imzalayabilir +offerbook.timeSinceSigning.info.peer=bir eş tarafından imzalandı, limitlerin kaldırılması için %d gün bekleniyor +offerbook.timeSinceSigning.info.peerLimitLifted=bir eş tarafından imzalandı ve limitler kaldırıldı +offerbook.timeSinceSigning.info.signer=bir eş tarafından imzalandı ve eş hesaplarını imzalayabilir (limitler kaldırıldı) +offerbook.timeSinceSigning.info.banned=hesap yasaklandı +offerbook.timeSinceSigning.daysSinceSigning={0} gün +offerbook.timeSinceSigning.daysSinceSigning.long=imzalandığından beri {0} gün +offerbook.timeSinceSigning.tooltip.accountLimit=Hesap limiti: {0} +offerbook.timeSinceSigning.tooltip.accountLimitLifted=Hesap limiti kaldırıldı +offerbook.timeSinceSigning.tooltip.info.unsigned=Bu hesap henüz imzalanmadı +offerbook.timeSinceSigning.tooltip.info.signed=Bu hesap imzalandı +offerbook.timeSinceSigning.tooltip.info.signedAndLifted=Bu hesap imzalandı ve eş hesaplarını imzalayabilir +offerbook.timeSinceSigning.tooltip.checkmark.buyXmr=imzalı bir hesaptan XMR al +offerbook.timeSinceSigning.tooltip.checkmark.wait=minimal {0} gün bekleyin +offerbook.timeSinceSigning.tooltip.learnMore=Daha fazla bilgi edin +offerbook.xmrAutoConf=Otomatik onay etkin mi +offerbook.buyXmrWith=XMR satın al: +offerbook.sellXmrFor=XMR'i şunlar için satın: + +offerbook.timeSinceSigning.help=Bir imzalı ödeme hesabı olan bir eş ile başarılı bir şekilde işlem yaptığınızda, ödeme hesabınız imzalanır.\n\ + {0} gün sonra, başlangıç limiti {1} kaldırılır ve hesabınız diğer eşlerin ödeme hesaplarını imzalayabilir. +offerbook.timeSinceSigning.notSigned=Henüz imzalanmadı +offerbook.timeSinceSigning.notSigned.ageDays={0} gün +offerbook.timeSinceSigning.notSigned.noNeed=Gerekli değil +shared.notSigned.noNeedDays=Bu hesap türü imzalama gerektirmez ve {0} gün önce oluşturulmuştur +shared.notSigned.noNeedAlts=Kripto para hesaplarında imzalama veya yaşlanma özelliği yoktur + +offerbook.nrOffers=Teklif sayısı: {0} +offerbook.volume={0} (min - maks) +offerbook.deposit=Mevduat XMR (%) +offerbook.deposit.help=Her yatırımcı tarafından işlemi garanti altına almak için ödenen mevduat. İşlem tamamlandığında geri verilecektir. + +offerbook.createNewOffer=Teklif oluştur {0} {1} +offerbook.createOfferDisabled.tooltip=Bir seferde sadece bir teklif oluşturabilirsiniz + +offerbook.takeOfferButton.tooltip=Teklifi al {0} +offerbook.setupNewAccount=Yeni bir ticaret hesabı kur +offerbook.removeOffer.success=Teklif kaldırma başarılı oldu. +offerbook.removeOffer.failed=Teklif kaldırma başarısız oldu:\n{0} +offerbook.deactivateOffer.failed=Teklifi devre dışı bırakma başarısız oldu:\n{0} +offerbook.activateOffer.failed=Teklifi yayınlama başarısız oldu:\n{0} +offerbook.withdrawFundsHint=Teklif kaldırıldı. Bu teklif için artık fonlar ayrılmadı. \ + Mevcut fonları {0} ekranında dış bir cüzdana gönderebilirsiniz. + +offerbook.warning.noTradingAccountForCurrency.headline=Seçilen para birimi için ödeme hesabı yok +offerbook.warning.noTradingAccountForCurrency.msg=Seçilen para birimi için bir ödeme hesabı kurmadınız. +offerbook.warning.noMatchingAccount.headline=Eşleşen ödeme hesabı yok. +offerbook.warning.noMatchingAccount.msg=Bu teklif, henüz kurmadığınız bir ödeme yöntemi kullanıyor. \n\nŞimdi yeni bir ödeme hesabı kurmak ister misiniz? + +offerbook.warning.counterpartyTradeRestrictions=Karşı taraf ticaret kısıtlamaları nedeniyle bu teklif alınamaz + +offerbook.warning.newVersionAnnouncement=Bu yazılım sürümü ile, ticaret yapan eşler birbirlerinin ödeme hesaplarını doğrulayabilir ve imzalayabilir, böylece güvenilir ödeme hesapları ağı oluşturulabilir.\n\n\ + Doğrulanmış ödeme hesabı olan bir eş ile başarılı bir şekilde ticaret yaptıktan sonra, ödeme hesabınız imzalanır ve ticaret limitleri belirli bir zaman aralığından sonra kaldırılır (bu aralığın uzunluğu doğrulama yöntemine bağlıdır).\n\n\ + Hesap imzalama hakkında daha fazla bilgi için, lütfen [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits/#account-signing] belgelere bakın. + +popup.warning.tradeLimitDueAccountAgeRestriction.seller=İzin verilen ticaret miktarı, aşağıdaki kriterlere dayanan güvenlik kısıtlamaları nedeniyle {0} ile sınırlıdır:\n\ + - Alıcının hesabı bir hakem veya eş tarafından imzalanmamış\n\ + - Alıcının hesabının imzalanmasından bu yana en az 30 gün geçmemiş\n\ + - Bu teklif için ödeme yöntemi, banka geri ödemeleri için riskli kabul edilir\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.buyer=İzin verilen ticaret miktarı, aşağıdaki kriterlere dayanan güvenlik kısıtlamaları nedeniyle {0} ile sınırlıdır:\n\ + - Hesabınız bir hakem veya eş tarafından imzalanmamış\n\ + - Hesabınızın imzalanmasından bu yana en az 30 gün geçmemiş\n\ + - Bu teklif için ödeme yöntemi, banka geri ödemeleri için riskli kabul edilir\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Bu ödeme yöntemi, tüm alıcıların yeni hesapları olduğu için geçici olarak {0} ile sınırlıdır {1} kadar.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Teklifiniz {0} aşan imzasız ve yaşlanmış hesaplara sahip alıcılara sınırlı olacak.\n\n{1} + +offerbook.warning.wrongTradeProtocol=Bu teklif, yazılımınızın sürümünde kullanılan protokol sürümünden farklı bir protokol sürümü gerektiriyor.\n\nLütfen en son sürümün yüklü olup olmadığını kontrol edin, aksi takdirde teklifi oluşturan kullanıcı eski bir sürüm kullanmıştır.\n\nKullanıcılar, uyumsuz bir ticaret protokol sürümü ile ticaret yapamaz. +offerbook.warning.userIgnored=Bu kullanıcının onion adresini engelleme listenize eklediniz. +offerbook.warning.offerBlocked=Bu teklif Haveno geliştiricileri tarafından engellendi.\nMuhtemelen, bu teklifi alırken sorunlara neden olan bir hata var. +offerbook.warning.currencyBanned=Bu teklifte kullanılan para birimi Haveno geliştiricileri tarafından engellendi.\nDaha fazla bilgi için Haveno Forum'u ziyaret edin. +offerbook.warning.paymentMethodBanned=Bu teklifte kullanılan ödeme yöntemi Haveno geliştiricileri tarafından engellendi.\nDaha fazla bilgi için Haveno Forum'u ziyaret edin. +offerbook.warning.nodeBlocked=Bu yatırımcının onion adresi Haveno geliştiricileri tarafından engellendi.\nMuhtemelen, bu yatırımcıdan teklifler alırken sorunlara neden olan bir hata var. +offerbook.warning.requireUpdateToNewVersion=Sizin Haveno sürümünüz artık ticaret için uyumlu değil.\n\ + Lütfen en son Haveno sürümüne güncelleyin. +offerbook.warning.offerWasAlreadyUsedInTrade=Bu teklifi alamazsınız çünkü daha önce aldınız. \ + Önceki teklif alma girişiminiz başarısız bir ticaretle sonuçlanmış olabilir. + +offerbook.warning.arbitratorNotValidated=Bu teklif, hakem geçersiz olduğu için alınamaz +offerbook.warning.signatureNotValidated=Bu teklif, hakemin imzası geçersiz olduğu için alınamaz + +offerbook.info.sellAtMarketPrice=Piyasa fiyatından satış yapacaksınız (her dakika güncellenir). +offerbook.info.buyAtMarketPrice=Piyasa fiyatından alım yapacaksınız (her dakika güncellenir). +offerbook.info.sellBelowMarketPrice=Geçerli piyasa fiyatından {0} daha az alacaksınız (her dakika güncellenir). +offerbook.info.buyAboveMarketPrice=Geçerli piyasa fiyatından {0} daha fazla ödeyeceksiniz (her dakika güncellenir). +offerbook.info.sellAboveMarketPrice=Geçerli piyasa fiyatından {0} daha fazla alacaksınız (her dakika güncellenir). +offerbook.info.buyBelowMarketPrice=Geçerli piyasa fiyatından {0} daha az ödeyeceksiniz (her dakika güncellenir). +offerbook.info.buyAtFixedPrice=Bu sabit fiyattan alım yapacaksınız. +offerbook.info.sellAtFixedPrice=Bu sabit fiyattan satış yapacaksınız. +offerbook.info.roundedFiatVolume=İşleminizin gizliliğini artırmak için miktar yuvarlandı. + +#################################################################### +# Offerbook / Create offer +#################################################################### + +createOffer.amount.prompt=XMR miktarını girin +createOffer.price.prompt=Fiyatı girin +createOffer.volume.prompt={0} cinsinden miktar girin +createOffer.amountPriceBox.amountDescription={0} XMR miktarı +createOffer.amountPriceBox.buy.amountDescriptionCrypto=Satılacak XMR miktarı +createOffer.amountPriceBox.sell.amountDescriptionCrypto=Satın alınacak XMR miktarı +createOffer.amountPriceBox.buy.volumeDescription=Harcanacak {0} miktarı +createOffer.amountPriceBox.sell.volumeDescription=Alınacak {0} miktarı +createOffer.amountPriceBox.buy.volumeDescriptionCrypto=Satılacak {0} miktarı +createOffer.amountPriceBox.sell.volumeDescriptionCrypto=Satın alınacak {0} miktarı +createOffer.amountPriceBox.minAmountDescription=Minimum XMR miktarı +createOffer.securityDeposit.prompt=Güvenlik teminatı +createOffer.fundsBox.title=Teklifinizi finanse edin +createOffer.fundsBox.offerFee=İşlem ücreti +createOffer.fundsBox.networkFee=Madencilik ücreti +createOffer.fundsBox.placeOfferSpinnerInfo=Teklif yayınlanıyor ... +createOffer.fundsBox.paymentLabel=Haveno ticareti ID {0} +createOffer.fundsBox.fundsStructure=({0} güvenlik teminatı, {1} işlem ücreti) +createOffer.success.headline=Teklifiniz oluşturuldu +createOffer.success.info=Açık tekliflerinizi \"Portföy/Açık tekliflerim\" bölümünde yönetebilirsiniz. +createOffer.info.sellAtMarketPrice=Teklifinizin fiyatı sürekli güncelleneceği için her zaman piyasa fiyatından satış yapacaksınız. +createOffer.info.buyAtMarketPrice=Teklifinizin fiyatı sürekli güncelleneceği için her zaman piyasa fiyatından alım yapacaksınız. +createOffer.info.sellAboveMarketPrice=Teklifinizin fiyatı sürekli güncelleneceği için her zaman geçerli piyasa fiyatından {0}% daha fazla alacaksınız. +createOffer.info.buyBelowMarketPrice=Teklifinizin fiyatı sürekli güncelleneceği için her zaman geçerli piyasa fiyatından {0}% daha az ödeyeceksiniz. +createOffer.warning.sellBelowMarketPrice=Teklifinizin fiyatı sürekli güncelleneceği için her zaman geçerli piyasa fiyatından {0}% daha az alacaksınız. +createOffer.warning.buyAboveMarketPrice=Teklifinizin fiyatı sürekli güncelleneceği için her zaman geçerli piyasa fiyatından {0}% daha fazla ödeyeceksiniz. +createOffer.tradeFee.descriptionXMROnly=İşlem ücreti +createOffer.tradeFee.description=İşlem ücreti + +createOffer.triggerPrice.prompt=tetikleyici fiyat ayarı +createOffer.triggerPrice.label=Teklif, piyasa fiyatı {0} olduğunda devre dışı bırakılacak +createOffer.triggerPrice.tooltip=Drastik fiyat hareketlerine karşı koruma olarak, piyasa fiyatı bu değere ulaştığında \ + teklifi devre dışı bırakacak bir tetikleyici fiyat ayarlayabilirsiniz. +createOffer.triggerPrice.invalid.tooLow=Değer {0}'den yüksek olmalıdır +createOffer.triggerPrice.invalid.tooHigh=Değer {0}'den düşük olmalıdır + +# new entries +createOffer.placeOfferButton=Gözden Geçir: Teklif ver {0} monero +createOffer.placeOfferButtonCrypto=Gözden Geçir: Teklif ver {0} {1} +createOffer.createOfferFundWalletInfo.headline=Teklifinizi finanse edin +# suppress inspection "TrailingSpacesInProperty" +createOffer.createOfferFundWalletInfo.tradeAmount=- Ticaret miktarı: {0} \n +createOffer.createOfferFundWalletInfo.msg=Bu teklife {0} yatırmanız gerekiyor.\n\n\ + Bu fonlar yerel cüzdanınızda rezerve edilir ve birisi teklifinizi kabul ettiğinde bir multisig cüzdanda kilitlenir.\n\n\ + Tutarın toplamı şudur:\n\ + {1}\ + - Güvenlik depozitonuz: {2}\n\ + - İşlem ücreti: {3} + +# only first part "Bir teklif verirken bir hata oluştu:" has been used before. We added now the rest (need update in existing translations!) +createOffer.amountPriceBox.error.message=Bir teklif verirken bir hata oluştu:\n\n{0}\n\n\ +Henüz cüzdanınızdan hiçbir fon çıkmadı.\n\ +Lütfen uygulamanızı yeniden başlatın ve ağ bağlantınızı kontrol edin. +createOffer.setAmountPrice=Miktar ve fiyat belirleyin +createOffer.warnCancelOffer=Bu teklifi zaten finanse ettiniz.\nŞimdi iptal ederseniz, fonlarınız yerel Haveno cüzdanınızda kalacak ve \"Fonlar/Fon gönder\" ekranında çekilebilir durumda olacaktır.\nİptal etmek istediğinizden emin misiniz? +createOffer.timeoutAtPublishing=Teklif yayınlanırken zaman aşımı oluştu. +createOffer.errorInfo=\n\nYapıcı ücreti zaten ödendi. En kötü durumda, o ücreti kaybetmiş olabilirsiniz.\nLütfen uygulamanızı yeniden başlatın ve ağ bağlantınızı kontrol edin. +createOffer.tooLowSecDeposit.warning=Güvenlik teminatını önerilen varsayılan değerden {0} daha düşük bir değere ayarladınız.\n\ + Daha düşük bir güvenlik teminatı kullanmak istediğinizden emin misiniz? +createOffer.tooLowSecDeposit.makerIsSeller=Ticaret ortağının ticaret protokolüne uymaması durumunda size daha az koruma sağlar. +createOffer.tooLowSecDeposit.makerIsBuyer=Ticaret ortağına, ticaret protokolüne uymanız için daha az güvence sağlar çünkü daha az depozito riski taşır. \ + Diğer kullanıcılar sizin teklifiniz yerine başka teklifleri tercih edebilir. +createOffer.resetToDefault=Hayır, varsayılan değere sıfırla +createOffer.useLowerValue=Evet, daha düşük değerimi kullan +createOffer.priceOutSideOfDeviation=Girdiğiniz fiyat, piyasa fiyatından izin verilen maksimum sapmanın dışındadır.\nİzin verilen maksimum sapma {0} ve tercihlerde ayarlanabilir. +createOffer.changePrice=Fiyat değiştir +createOffer.tac=Bu teklifi yayınlayarak, bu ekranda tanımlanan koşulları yerine getiren herhangi bir tüccarla ticaret yapmayı kabul ediyorum. +createOffer.setDeposit=Alıcının güvenlik teminatını ayarla (%) +createOffer.setDepositAsBuyer=Alıcı olarak benim güvenlik teminatımı ayarla (%) +createOffer.setDepositForBothTraders=Tüccarların güvenlik teminatı (%) +createOffer.securityDepositInfo=Alıcının güvenlik teminatı {0} olacak +createOffer.securityDepositInfoAsBuyer=Alıcı olarak güvenlik teminatınız {0} olacak +createOffer.minSecurityDepositUsed=Minimum güvenlik depozitosu kullanılır +createOffer.buyerAsTakerWithoutDeposit=Alıcıdan depozito gerekmez (şifre korumalı) +createOffer.myDeposit=Güvenlik depozitam (%) +createOffer.myDepositInfo=Güvenlik depozitonuz {0} olacaktır. + + +#################################################################### +# Offerbook / Take offer +#################################################################### + +takeOffer.amount.prompt=Miktarı girin XMR olarak +takeOffer.amountPriceBox.buy.amountDescription=Satılacak XMR miktarı +takeOffer.amountPriceBox.sell.amountDescription=Alınacak XMR miktarı +takeOffer.amountPriceBox.buy.amountDescriptionCrypto=Satılacak XMR miktarı +takeOffer.amountPriceBox.sell.amountDescriptionCrypto=Alınacak XMR miktarı +takeOffer.amountPriceBox.priceDescription={0} başına monero fiyatı +takeOffer.amountPriceBox.amountRangeDescription=Olası miktar aralığı +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=Girdiğiniz miktar izin verilen ondalık basamak sayısını aşıyor.\nMiktar 4 ondalık basamağa ayarlandı. +takeOffer.validation.amountSmallerThanMinAmount=Miktar, teklifte belirtilen minimum miktardan küçük olamaz. +takeOffer.validation.amountLargerThanOfferAmount=Girdi miktarı, teklifte belirtilen miktardan yüksek olamaz. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Bu girdi miktarı, XMR satıcısı için toz değişimi oluşturur. +takeOffer.fundsBox.title=İşleminizi finanse edin +takeOffer.fundsBox.isOfferAvailable=Teklifin hala mevcut olup olmadığını kontrol ediyor ... +takeOffer.fundsBox.tradeAmount=Satılacak miktar +takeOffer.fundsBox.offerFee=İşlem ücreti +takeOffer.fundsBox.networkFee=Toplam madencilik ücretleri +takeOffer.fundsBox.takeOfferSpinnerInfo=Teklif alınıyor: {0} +takeOffer.fundsBox.paymentLabel=ID {0} ile Haveno işlemi +takeOffer.fundsBox.fundsStructure=({0} güvenlik teminatı, {1} işlem ücreti) +takeOffer.fundsBox.noFundingRequiredTitle=Fonlama gerekmez +takeOffer.fundsBox.noFundingRequiredDescription=Bu teklifi almak için satıcıdan passphrase'i Haveno dışında alınız. +takeOffer.success.headline=Teklifi başarıyla aldınız. +takeOffer.success.info=İşleminizin durumunu \"Portföy/Açık işlemler\" kısmında görebilirsiniz. +takeOffer.error.message=Teklif alımı sırasında bir hata oluştu.\n\n{0} + +# new entries +takeOffer.takeOfferButton=İncele: {0} monero için teklifi al +takeOffer.takeOfferButtonCrypto=İncele: {0} {1} için teklifi al +takeOffer.noPriceFeedAvailable=Bu teklifi alamazsınız çünkü piyasa fiyatına dayalı yüzdelik bir fiyat kullanıyor ancak fiyat beslemesi mevcut değil. +takeOffer.takeOfferFundWalletInfo.headline=İşleminizi finanse edin +# suppress inspection "TrailingSpacesInProperty" +takeOffer.takeOfferFundWalletInfo.tradeAmount=- İşlem miktarı: {0} \n +takeOffer.takeOfferFundWalletInfo.msg=Bu teklifi kabul etmek için {0} yatırmanız gerekiyor.\n\nMiktar, şu kalemlerin toplamıdır:\n{1}- Güvenlik depozitonuz: {2}\n- İşlem ücreti: {3} +takeOffer.alreadyPaidInFunds=Eğer zaten fon yatırdıysanız, \"Fonlar/Fon gönder\" ekranında çekebilirsiniz. +takeOffer.setAmountPrice=Miktar ayarla +takeOffer.alreadyFunded.askCancel=Bu teklifi zaten finanse ettiniz.\nŞimdi iptal ederseniz, fonlarınız yerel Haveno cüzdanınızda kalacak ve \"Fonlar/Fon gönder\" ekranında çekilebilir olacaktır.\nİptal etmek istediğinizden emin misiniz? +takeOffer.failed.offerNotAvailable=Teklif artık mevcut olmadığı için teklif alma isteği başarısız oldu. Belki başka bir tüccar bu teklifi almıştır. +takeOffer.failed.offerTaken=Bu teklifi alamazsınız çünkü teklif başka bir tüccar tarafından zaten alınmış. +takeOffer.failed.offerInvalid=Bu teklifi alamazsınız çünkü yapıcı imzası geçersiz. +takeOffer.failed.offerRemoved=Bu teklifi alamazsınız çünkü teklif bu arada kaldırılmış. +takeOffer.failed.offererNotOnline=Teklif alımı isteği başarısız oldu çünkü yapıcı artık çevrimdışı. +takeOffer.failed.offererOffline=Bu teklifi alamazsınız çünkü yapıcı çevrimdışı. +takeOffer.warning.connectionToPeerLost=Yapıcıya olan bağlantıyı kaybettiniz.\nÇevrimdışına gitmiş olabilir veya çok fazla açık bağlantı nedeniyle bağlantıyı kapatmış olabilir.\n\nTeklifi teklif kitabında hala görebiliyorsanız, teklifi tekrar almaya çalışabilirsiniz. + +takeOffer.error.noFundsLost=\n\nHenüz cüzdanınızdan fon çıkmadı.\nUygulamanızı yeniden başlatmayı deneyin ve sorunu çözmek için ağ bağlantınızı kontrol edin. +# suppress inspection "TrailingSpacesInProperty" +takeOffer.error.feePaid=\n\n +takeOffer.error.depositPublished=\n\nGüvence işlemi zaten yayınlandı.\nUygulamanızı yeniden başlatmayı deneyin ve sorunu çözmek için ağ bağlantınızı kontrol edin.\nSorun devam ederse lütfen geliştiricilerle iletişime geçin. +takeOffer.error.payoutPublished=\n\nÖdeme işlemi zaten yayınlandı.\nUygulamanızı yeniden başlatmayı deneyin ve sorunu çözmek için ağ bağlantınızı kontrol edin.\nSorun devam ederse lütfen geliştiricilerle iletişime geçin. +takeOffer.tac=Bu teklifi alarak bu ekranda tanımlanan işlem koşullarını kabul ediyorum. + + +#################################################################### +# Offerbook / Edit offer +#################################################################### + +openOffer.header.triggerPrice=Tetikleme fiyatı +openOffer.triggerPrice=Tetikleme fiyatı {0} +openOffer.triggered=Piyasa fiyatı tetikleme fiyatınıza ulaştığı için teklif devre dışı bırakıldı.\n\ + Yeni bir tetikleme fiyatı tanımlamak için teklifi düzenleyin + +editOffer.setPrice=Fiyat ayarla +editOffer.confirmEdit=Onayla: Teklifi düzenle +editOffer.publishOffer=Teklifinizi yayınlıyor. +editOffer.failed=Teklif düzenleme başarısız:\n{0} +editOffer.success=Teklifiniz başarıyla düzenlendi. +editOffer.invalidDeposit=Alıcının güvenlik teminatı Haveno tarafından tanımlanan sınırlamalar içinde değil ve artık düzenlenemez. + +#################################################################### +# Portfolio +#################################################################### + +portfolio.tab.openOffers=Açık tekliflerim +portfolio.tab.pendingTrades=Açık işlemler +portfolio.tab.history=Tarihçe +portfolio.tab.failed=Başarısız +portfolio.tab.editOpenOffer=Teklifi düzenle +portfolio.tab.duplicateOffer=Teklifi kopyala +portfolio.context.offerLikeThis=Bunun gibi yeni bir teklif oluştur... +portfolio.context.notYourOffer=Yapıcı olduğunuz teklifleri yalnızca kopyalayabilirsiniz. + +portfolio.closedTrades.deviation.help=Piyasa fiyatından yüzdelik fiyat sapması + +portfolio.pending.invalidTx=Eksik veya geçersiz işlem ile ilgili bir sorun var.\n\n\ + Lütfen geleneksel veya kripto para birimi ödemesini GÖNDERMEYİN.\n\n\ + Yardım almak için bir Destek bileti açın.\n\n\ + Hata mesajı: {0} + +portfolio.pending.unconfirmedTooLong=İşlem {0} üzerindeki güvence işlemleri {1} saat sonra hala onaylanmamış durumda. \ + Güvence işlemlerini bir blok zinciri gezgini kullanarak kontrol edin; eğer onaylanmışlarsa ancak Haveno'da \ + onaylanmış olarak gösterilmiyorlarsa, Haveno'yu yeniden başlatmayı deneyin.\n\n\ + Sorun devam ederse, Haveno desteğiyle iletişime geçin [HYPERLINK:https://matrix.to/#/#haveno:monero.social]. + +portfolio.pending.step1.waitForConf=Blok zinciri onaylarını bekleyin +portfolio.pending.step2_buyer.startPayment=Ödemeyi başlat +portfolio.pending.step2_seller.waitPaymentSent=Ödeme gönderilene kadar bekle +portfolio.pending.step3_buyer.waitPaymentArrived=Ödeme gelene kadar bekle +portfolio.pending.step3_seller.confirmPaymentReceived=Ödemenin alındığını onayla +portfolio.pending.step5.completed=Tamamlandı + +portfolio.pending.step3_seller.autoConf.status.label=Otomatik onay durumu +portfolio.pending.autoConf=Otomatik onaylandı +portfolio.pending.autoConf.blocks=XMR onayları: {0} / Gerekli: {1} +portfolio.pending.autoConf.state.xmr.txKeyReused=İşlem anahtarı tekrar kullanıldı. Lütfen bir ihtilaf açın. +portfolio.pending.autoConf.state.confirmations=XMR onayları: {0}/{1} +portfolio.pending.autoConf.state.txNotFound=İşlem henüz bellek havuzunda görülmedi +portfolio.pending.autoConf.state.txKeyOrTxIdInvalid=Geçerli işlem kimliği / işlem anahtarı yok +portfolio.pending.autoConf.state.filterDisabledFeature=Geliştiriciler tarafından devre dışı bırakıldı. + +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.FEATURE_DISABLED=Otomatik onay özelliği devre dışı bırakıldı. {0} +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.TRADE_LIMIT_EXCEEDED=İşlem miktarı otomatik onay limitini aşıyor +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.INVALID_DATA=Karşı taraf geçersiz veri sağladı. {0} +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.PAYOUT_TX_ALREADY_PUBLISHED=Ödeme işlemi zaten yayımlandı. +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.DISPUTE_OPENED=Uyuşmazlık açıldı. Otomatik onay bu işlem için devre dışı bırakıldı. +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.REQUESTS_STARTED=İşlem kanıtı talepleri başlatıldı +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.PENDING=Başarılı sonuçlar: {0}/{1}; {2} +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.COMPLETED=Tüm hizmetlerde kanıt başarıyla tamamlandı +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.ERROR=Bir hizmet talebinde hata oluştu. Otomatik onay mümkün değil. +# suppress inspection "UnusedProperty" +portfolio.pending.autoConf.state.FAILED=Bir hizmet başarısızlıkla sonuçlandı. Otomatik onay mümkün değil. + +portfolio.pending.step1.info=Yatırım işlemi yayımlandı.\n{0} ödemeye başlamadan önce 10 onay (yaklaşık 20 dakika) beklemeniz gerekiyor. +portfolio.pending.step1.warn=Yatırım işlemi henüz onaylanmadı. Bu genellikle yaklaşık 20 dakika sürer, ancak ağ yoğunsa daha uzun sürebilir. +portfolio.pending.step1.openForDispute=Yatırım işlemi hala onaylanmadı. \ + 20 dakikadan çok daha uzun süre beklediyseniz, Haveno desteği ile iletişime geçin. + +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2.confReached=İşleminiz 10 onaya ulaştı.\n\n + +portfolio.pending.step2_buyer.refTextWarn=Önemli: ödeme yaparken, \"ödeme nedeni\" alanını boş bırakın. \ + İşlem ID'si veya 'monero', 'XMR' veya 'Haveno' gibi başka bir metin koymayın. \ + Eğer her iki taraf için de uygun olacak alternatif bir \"ödeme nedeni\" tartışmak isterseniz, trader sohbetini kullanabilirsiniz. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.fees=Bankanız transfer yapmak için sizden herhangi bir ücret alıyorsa, bu ücretleri ödemekten siz sorumlusunuz. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.fees.swift=SWIFT ödemesini göndermek için SHA (paylaşılan ücret modeli) kullanmanız gerekmektedir. \ + Daha fazla ayrıntı için [HYPERLINK:https://haveno.exchange/wiki/SWIFT#Use_the_correct_fee_option] adresine bakınız. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.crypto=Lütfen dış {0} cüzdanınızdan\n{1} XMR satıcısına transfer yapın.\n\n +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.cash=Lütfen bir bankaya gidin ve {0} tutarını XMR satıcısına ödeyin.\n\n +portfolio.pending.step2_buyer.cash.extra=ÖNEMLİ GEREKLİLİK:\nÖdeme yaptıktan sonra kağıt makbuzun üzerine: İADE YOK yazın. Ardından iki parçaya ayırın, bir fotoğraf çekin ve XMR satıcısının e-posta adresine gönderin. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.moneyGram=Lütfen MoneyGram kullanarak {0} tutarını XMR satıcısına ödeyin.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=ÖNEMLİ GEREKLİLİK:\nÖdeme yaptıktan sonra yetkilendirme numarasını ve makbuzun bir fotoğrafını e-posta ile XMR satıcısına gönderin.\n\ + Makbuz, satıcının tam adını, ülkesini, eyaletini ve miktarı açıkça göstermelidir. Satıcının e-postası: {0}. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.westernUnion=Lütfen Western Union kullanarak {0} tutarını XMR satıcısına ödeyin.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=ÖNEMLİ GEREKLİLİK:\nÖdeme yaptıktan sonra MTCN (izleme numarası) ve makbuzun bir fotoğrafını e-posta ile XMR satıcısına gönderin.\n\ + Makbuz, satıcının tam adını, şehrini, ülkesini ve miktarı açıkça göstermelidir. Satıcının e-postası: {0}. + +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.postal=Lütfen "US Postal Money Order" kullanarak {0} tutarını XMR satıcısına gönderin.\n\n +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.payByMail=Lütfen "Pay by Mail" kullanarak {0} tutarını XMR satıcısına gönderin. \ + Belirli talimatlar işlem sözleşmesinde bulunmaktadır, veya belirsizse trader sohbeti aracılığıyla sorular sorabilirsiniz. \ + Pay by Mail hakkında daha fazla ayrıntı için Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail] adresine bakın.\n\n +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.pay=Lütfen belirtilen ödeme yöntemini kullanarak {0} tutarını XMR satıcısına ödeyin. Satıcının hesap bilgilerini bir sonraki ekranda bulacaksınız.\n\n +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step2_buyer.f2f=Lütfen sağlanan iletişim bilgileriyle XMR satıcısıyla iletişime geçin ve {0} ödemesi için bir buluşma düzenleyin.\n\n +portfolio.pending.step2_buyer.startPaymentUsing={0} kullanarak ödemeye başlayın +portfolio.pending.step2_buyer.recipientsAccountData=Alıcının {0} +portfolio.pending.step2_buyer.amountToTransfer=Transfer edilecek miktar +portfolio.pending.step2_buyer.sellersAddress=Satıcının {0} adresi +portfolio.pending.step2_buyer.buyerAccount=Kullanılacak ödeme hesabınız +portfolio.pending.step2_buyer.paymentSent=Ödeme gönderildi +portfolio.pending.step2_buyer.warn=Hala {0} ödemenizi yapmadınız!\nLütfen işlemin {1} tarihine kadar tamamlanması gerektiğini unutmayın. +portfolio.pending.step2_buyer.openForDispute=Ödemenizi henüz tamamlamadınız\nİşlemin maksimum süresi doldu, ancak yine de ödemeyi tamamlayabilirsiniz.\n\ + Yardım gerekiyorsa bir arabulucu ile iletişime geçin. +portfolio.pending.step2_buyer.paperReceipt.headline=Kağıt makbuzu XMR satıcısına gönderdiniz mi? +portfolio.pending.step2_buyer.paperReceipt.msg=Unutmayın:\n\ + Kağıt makbuzun üzerine: İADE YOK yazmanız gerekiyor.\n\ + Ardından iki parçaya ayırın, bir fotoğraf çekin ve XMR satıcısının e-posta adresine gönderin. +portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Yetkilendirme numarası ve makbuz gönder +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Yetkilendirme numarasını ve makbuzun bir fotoğrafını e-posta ile XMR satıcısına göndermeniz gerekiyor.\n\ + Makbuz, satıcının tam adını, ülkesini, eyaletini ve miktarı açıkça göstermelidir. Satıcının e-postası: {0}.\n\n\ + Yetkilendirme numarasını ve sözleşmeyi satıcıya gönderdiniz mi? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=MTCN ve makbuz gönder +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=MTCN (izleme numarası) ve makbuzun bir fotoğrafını e-posta ile XMR satıcısına göndermeniz gerekiyor.\n\ + Makbuz, satıcının tam adını, şehrini, ülkesini ve miktarı açıkça göstermelidir. Satıcının e-postası: {0}.\n\n\ + MTCN ve sözleşmeyi satıcıya gönderdiniz mi? +portfolio.pending.step2_buyer.halCashInfo.headline=HalCash kodunu gönder +portfolio.pending.step2_buyer.halCashInfo.msg=HalCash kodunu ve işlem kimliğini ({0}) XMR satıcısına \ + kısa mesaj olarak göndermeniz gerekiyor. Satıcının cep telefonu numarası: {1}.\n\n\ + Kodu satıcıya gönderdiniz mi? +portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Bazı bankalar alıcının adını doğrulayabilir. \ + Eski Haveno istemcilerinde oluşturulan Faster Payments hesapları alıcının adını sağlamaz, \ + bu nedenle gerektiğinde işlem sohbeti aracılığıyla bu bilgiyi edinmek için kullanın. +portfolio.pending.step2_buyer.confirmStart.headline=Ödemeye başladığınızı onaylayın +portfolio.pending.step2_buyer.confirmStart.msg=İşlem ortağınıza {0} ödemesini başlattınız mı? +portfolio.pending.step2_buyer.confirmStart.yes=Evet, ödemeye başladım +portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=Ödeme kanıtı sağlamadınız +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=İşlem kimliğini ve işlem anahtarını girmediniz.\n\n\ + Bu verileri sağlamadan, karşı taraf XMR'yi aldığında otomatik onay özelliğini kullanamaz.\n\ + Ayrıca, Haveno, bir uyuşmazlık durumunda XMR işleminin göndericisinin bu bilgileri sağlayabilmesini gerektirir.\n\ + Daha fazla bilgi için Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] adresine bakın. +portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Girdi 32 baytlık bir onaltılık değer değil +portfolio.pending.step2_buyer.confirmStart.warningButton=Yoksay ve yine de devam et +portfolio.pending.step2_seller.waitPayment.headline=Ödeme bekleniyor +portfolio.pending.step2_seller.f2fInfo.headline=Alıcının iletişim bilgileri +portfolio.pending.step2_seller.waitPayment.msg=Yatırım işlemi kilidi açıldı.\nXMR alıcısının {0} ödemesini başlatmasını beklemeniz gerekiyor. +portfolio.pending.step2_seller.warn=XMR alıcısı hala {0} ödemesini yapmadı.\nÖdeme başlatılana kadar beklemeniz gerekiyor.\nİşlem {1} tarihinde tamamlanmadıysa, arabulucu durumu inceleyecektir. +portfolio.pending.step2_seller.openForDispute=XMR alıcısı ödemesine başlamadı!\nİşlem için izin verilen maksimum süre doldu.\nKarşı tarafa daha fazla zaman tanıyabilir veya arabulucu ile iletişime geçebilirsiniz. +disputeChat.chatWindowTitle=İşlem ID''si ile ilgili uyuşmazlık sohbet penceresi ''{0}'' +tradeChat.chatWindowTitle=İşlem ID''si ile ilgili trader sohbet penceresi ''{0}'' +tradeChat.openChat=Sohbet penceresini aç +tradeChat.rules=Bu işlemle ilgili olası sorunları çözmek için işlem ortağınızla iletişim kurabilirsiniz.\n\ + Sohbette yanıt vermek zorunlu değildir.\n\ + Bir trader aşağıdaki kurallardan herhangi birini ihlal ederse, uyuşmazlık açın ve durumu arabulucuya bildirin.\n\n\ + Sohbet kuralları:\n\ + \t● Bağlantı göndermeyin (zararlı yazılım riski). İşlem kimliğini ve bir blok gezgininin adını gönderebilirsiniz.\n\ + \t● Seed kelimelerinizi, özel anahtarlarınızı, şifrelerinizi veya diğer hassas bilgilerinizi göndermeyin!\n\ + \t● Haveno dışında işlem yapmaya teşvik etmeyin (güvenlik yok).\n\ + \t● Sosyal mühendislik dolandırıcılık girişimlerinde bulunmayın.\n\ + \t● Bir eş yanıt vermiyorsa ve sohbet yoluyla iletişim kurmak istemiyorsa, kararına saygı gösterin.\n\ + \t● Sohbeti işlemin kapsamı ile sınırlı tutun. Bu sohbet bir mesajlaşma uygulaması veya troll kutusu değildir.\n\ + \t● Sohbeti dostça ve saygılı tutun. + +# suppress inspection "UnusedProperty" +message.state.UNDEFINED=Tanımsız +# suppress inspection "UnusedProperty" +message.state.SENT=Mesaj gönderildi +# suppress inspection "UnusedProperty" +message.state.ARRIVED=Mesaj alıcıya ulaştı +# suppress inspection "UnusedProperty" +message.state.STORED_IN_MAILBOX=Ödeme mesajı gönderildi ancak alıcı tarafından henüz alınmadı +# suppress inspection "UnusedProperty" +message.state.ACKNOWLEDGED=Alıcı mesajı aldığını doğruladı +# suppress inspection "UnusedProperty" +message.state.FAILED=Mesaj gönderimi başarısız oldu + +portfolio.pending.step3_buyer.wait.headline=XMR satıcısının ödeme onayını bekleyin +portfolio.pending.step3_buyer.wait.info=XMR satıcısının {0} ödemesini aldığına dair onayı bekleniyor. +portfolio.pending.step3_buyer.wait.msgStateInfo.label=Ödeme başlatıldı mesaj durumu +portfolio.pending.step3_buyer.warn.part1a={0} blok zincirinde +portfolio.pending.step3_buyer.warn.part1b=ödeme sağlayıcınızda (örneğin, banka) +portfolio.pending.step3_buyer.warn.part2=XMR satıcısı hala ödemenizi onaylamadı. Lütfen {0} kontrol edin ve \ + ödemenin başarılı olup olmadığını doğrulayın. +portfolio.pending.step3_buyer.openForDispute=XMR satıcısı ödemenizi onaylamadı! Maksimum ticaret süresi doldu. \ + Daha uzun süre bekleyebilir ve ticaret partnerinize daha fazla zaman tanıyabilir veya hakemden yardım isteyebilirsiniz. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.part=Ticaret partneriniz {0} ödemesini başlattığını doğruladı.\n\n +portfolio.pending.step3_seller.crypto.explorer=favori {0} blok zinciri gezgininizde +portfolio.pending.step3_seller.crypto.wallet={0} cüzdanınızda +portfolio.pending.step3_seller.crypto={0}Lütfen alıcı adresinize yapılan işlemin\n\ +{2}\n\ +yeterli blok zinciri onayına sahip olup olmadığını kontrol edin.\nÖdeme tutarı {3} olmalıdır\n\n\ +Bu açılır pencereyi kapattıktan sonra ana ekrandan {4} adresinizi kopyalayıp yapıştırabilirsiniz. +portfolio.pending.step3_seller.postal={0}XMR alıcısından \"ABD Posta Para Havalesi\" ile {1} alıp almadığınızı kontrol edin. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.payByMail={0}XMR alıcısından \"Posta ile Öde\" ile {1} alıp almadığınızı kontrol edin. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.bank=Ticaret partneriniz {0} ödemesini başlattığını doğruladı.\n\n\ + Lütfen çevrimiçi bankacılık web sayfanıza gidin ve XMR alıcısından {1} alıp almadığınızı kontrol edin. +portfolio.pending.step3_seller.cash=Ödeme Nakit Depozito yoluyla yapıldığından, XMR alıcısı makbuzun üzerine \"İADE YOK\" yazmalı, iki parçaya ayırmalı ve size e-posta ile bir fotoğraf göndermelidir.\n\n\ +Geri ödeme riskini önlemek için, yalnızca e-postayı aldıysanız ve makbuzun geçerli olduğundan eminseniz onaylayın.\n\ +Emin değilseniz, {0} +portfolio.pending.step3_seller.moneyGram=Alıcı, yetkilendirme numarasını ve makbuzun fotoğrafını size e-posta ile göndermelidir.\n\ + Makbuz, tam adınızı, ülkenizi, eyaletinizi ve tutarı açıkça göstermelidir. Lütfen e-postanızı kontrol edin ve yetkilendirme numarasını aldığınızdan emin olun.\n\n\ + Bu açılır pencereyi kapattıktan sonra, XMR alıcısının adını ve adresini MoneyGram'dan parayı almak için göreceksiniz.\n\n\ + Parayı başarıyla aldıktan sonra alımı onaylayın! +portfolio.pending.step3_seller.westernUnion=Alıcı, MTCN (takip numarası) ve makbuzun fotoğrafını size e-posta ile göndermelidir.\n\ + Makbuz, tam adınızı, şehrinizi, ülkenizi ve tutarı açıkça göstermelidir. Lütfen e-postanızı kontrol edin ve MTCN'yi aldığınızdan emin olun.\n\n\ + Bu açılır pencereyi kapattıktan sonra, XMR alıcısının adını ve adresini Western Union'dan parayı almak için göreceksiniz.\n\n\ + Parayı başarıyla aldıktan sonra alımı onaylayın! +portfolio.pending.step3_seller.halCash=Alıcı, size HalCash kodunu kısa mesaj olarak göndermelidir. Bunun yanı sıra, HalCash destekleyen bir ATM'den EUR çekmek için gerekli bilgileri içeren bir mesaj alacaksınız.\n\n\ + ATM'den parayı aldıktan sonra burada ödemenin alındığını onaylayın! +portfolio.pending.step3_seller.amazonGiftCard=Alıcı, size Amazon eGift Kartı'nı e-posta veya cep telefonunuza \ + kısa mesaj olarak gönderdi. Lütfen şimdi Amazon hesabınızda Amazon eGift Kartı'nı kullanın ve kabul edildikten \ + sonra ödeme alımını onaylayın. + +portfolio.pending.step3_seller.bankCheck=\n\nLütfen ayrıca ticaret sözleşmesinde belirtilen gönderici adının banka ekstrenizde görünen adla eşleştiğini doğrulayın:\nTicaret sözleşmesine göre gönderici adı: {0}\n\n\ + İsimler tam olarak aynı değilse, {1} +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.openDispute=ödeme alımını onaylamayın. Bunun yerine, "alt + o" veya "option + o" tuşlarına basarak bir anlaşmazlık açın.\n\n +portfolio.pending.step3_seller.confirmPaymentReceipt=Ödeme alımını onayla +portfolio.pending.step3_seller.amountToReceive=Alınacak tutar +portfolio.pending.step3_seller.yourAddress=Sizin {0} adresiniz +portfolio.pending.step3_seller.buyersAddress=Alıcının {0} adresi +portfolio.pending.step3_seller.yourAccount=Ticaret hesabınız +portfolio.pending.step3_seller.xmrTxHash=İşlem Kimliği +portfolio.pending.step3_seller.xmrTxKey=İşlem anahtarı +portfolio.pending.step3_seller.buyersAccount=Alıcının hesap verileri +portfolio.pending.step3_seller.confirmReceipt=Ödeme alımını onayla +portfolio.pending.step3_seller.buyerStartedPayment=XMR alıcısı {0} ödemesini başlattı.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment.crypto=Kripto para cüzdanınızda veya blok gezgininde blok zinciri onaylarını kontrol edin ve yeterli blok zinciri onayına sahip olduğunuzda ödemeyi onaylayın. +portfolio.pending.step3_seller.buyerStartedPayment.traditional=Ticaret hesabınızda (örneğin banka hesabı) kontrol edin ve ödemeyi aldığınızda onaylayın. +portfolio.pending.step3_seller.warn.part1a={0} blok zincirinde +portfolio.pending.step3_seller.warn.part1b=ödeme sağlayıcınızda (örneğin, banka) +portfolio.pending.step3_seller.warn.part2=Ödeme alımını hala onaylamadınız. \ + Lütfen {0} kontrol edin ve ödemeyi aldığınızı doğrulayın. +portfolio.pending.step3_seller.openForDispute=Ödeme alımını henüz onaylamadınız.\n\ + Maksimum ticaret süresi doldu.\nLütfen onaylayın veya hakemden yardım isteyin. +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.onPaymentReceived.part1=Ticaret partnerinizden {0} ödemesini aldınız mı?\n\n +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.onPaymentReceived.name=Lütfen ayrıca ticaret sözleşmesinde belirtilen gönderici adının banka ekstrenizde görünen adla eşleştiğini doğrulayın:\nTicaret sözleşmesine göre gönderici adı: {0}\n\nİsimler tam olarak aynı değilse, ödeme alımını onaylamayın. Bunun yerine, "alt + o" veya "option + o" tuşlarına basarak bir anlaşmazlık açın.\n\n +# suppress inspection "TrailingSpacesInProperty" +portfolio.pending.step3_seller.onPaymentReceived.note=Lütfen unutmayın, ödeme alımını onayladığınız anda, kilitli ticaret tutarı XMR alıcısına serbest bırakılacak ve güvenlik depozitosu iade edilecektir.\n\n +portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Ödemeyi aldığınızı onaylayın +portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Evet, ödemeyi aldım +portfolio.pending.step3_seller.onPaymentReceived.signer=ÖNEMLİ: Ödeme alımını onaylayarak, karşı tarafın hesabını da \ + doğrulamış ve buna göre imzalamış olursunuz. Karşı tarafın hesabı henüz imzalanmadığından, geri ödeme riskini azaltmak için \ + ödeme onayını mümkün olduğunca geciktirmelisiniz. + +portfolio.pending.step5_buyer.groupTitle=Tamamlanan ticaret özeti +portfolio.pending.step5_buyer.groupTitle.mediated=Bu ticaret arabuluculukla çözüldü +portfolio.pending.step5_buyer.groupTitle.arbitrated=Bu ticaret hakemlikle çözüldü +portfolio.pending.step5_buyer.tradeFee=Ticaret ücreti +portfolio.pending.step5_buyer.makersMiningFee=Madencilik ücreti +portfolio.pending.step5_buyer.takersMiningFee=Toplam madencilik ücretleri +portfolio.pending.step5_buyer.refunded=İade edilen güvenlik depozitosu +portfolio.pending.step5_buyer.amountTooLow=Transfer edilecek tutar, işlem ücretinden ve mümkün olan minimum işlem değerinden (toz) daha düşük. +portfolio.pending.step5_buyer.tradeCompleted.headline=Ticaret tamamlandı +portfolio.pending.step5_buyer.tradeCompleted.msg=Tamamlanan ticaretleriniz \"Portföy/Tarihçe\" altında saklanır.\nTüm Monero işlemlerinizi \"Fonlar/İşlemler\" altında inceleyebilirsiniz. +portfolio.pending.step5_buyer.bought=Satın aldınız +portfolio.pending.step5_buyer.paid=Ödediniz + +portfolio.pending.step5_seller.sold=Satış yaptınız +portfolio.pending.step5_seller.received=Aldınız + +tradeFeedbackWindow.title=Ticaretiniz başarıyla tamamlandı! +tradeFeedbackWindow.msg.part1=Deneyiminiz hakkında geri bildirim almak isteriz. Yazılımı geliştirmemize ve pürüzleri gidermemize yardımcı olacaktır. +tradeFeedbackWindow.msg.part2=Herhangi bir sorunuz varsa veya herhangi bir sorun yaşadıysanız, diğer kullanıcılar ve katkıda bulunanlarla Matrix sohbet odamızda iletişime geçin: +tradeFeedbackWindow.msg.part3=Haveno'yu kullandığınız için teşekkürler! + +portfolio.pending.role=Rolüm +portfolio.pending.tradeInformation=Ticaret bilgileri +portfolio.pending.remainingTime=Kalan süre +portfolio.pending.remainingTimeDetail={0} (kadar {1}) +portfolio.pending.tradePeriodInfo=İlk blok zinciri onayından sonra ticaret süresi başlar. Kullanılan ödeme yöntemine bağlı olarak, farklı bir maksimum ticaret süresi uygulanır. +portfolio.pending.tradePeriodWarning=Süre aşılırsa her iki tüccar da bir anlaşmazlık açabilir. +portfolio.pending.tradeNotCompleted=Ticaret zamanında tamamlanmadı (kadar {0}) +portfolio.pending.tradeProcess=Ticaret süreci +portfolio.pending.stillNotResolved=Sorununuz çözülmezse, [Matrix sohbet odamızda](https://matrix.to/#/#haveno:monero.social) destek talep edebilirsiniz. + +portfolio.pending.openAgainDispute.msg=Hakeme gönderilen mesajın ulaştığından emin değilseniz (örneğin, 1 gün içinde yanıt almadıysanız), ekibe ulaşmaktan çekinmeyin. +portfolio.pending.openAgainDispute.button=Anlaşmazlığı tekrar aç +portfolio.pending.openSupportTicket.headline=Destek bileti aç +portfolio.pending.openSupportTicket.msg=Lütfen bu işlevi yalnızca acil durumlarda kullanın, eğer \ + \"Destek aç\" veya \"Anlaşmazlık aç\" butonlarını görmüyorsanız.\n\nDestek bileti açtığınızda ticaret kesintiye uğrar ve \ + bir hakem tarafından ele alınır. + +portfolio.pending.timeLockNotOver=Arabuluculuk anlaşmazlığı açmadan önce ≈{0} ({1} daha fazla blok) beklemeniz gerekiyor. +portfolio.pending.error.depositTxNull=Bir depozito işlemi null. Geçersiz bir depozito işlemiyle \ + anlaşmazlık açamazsınız.\n\n\ + Daha fazla yardım için, lütfen Matrix sohbet odamızda Haveno desteği ile iletişime geçin. +portfolio.pending.mediationResult.error.depositTxNull=Depozito işlemi null. Ticareti başarısız \ + işlemler olarak taşıyabilirsiniz. +portfolio.pending.mediationResult.error.delayedPayoutTxNull=Gecikmiş ödeme işlemi null. Ticareti başarısız \ + işlemler olarak taşıyabilirsiniz. +portfolio.pending.error.depositTxNotConfirmed=Depozito işlemleri onaylanmadı ve kullanılabilir değil. Bekleyen bir depozito işlemiyle \ + anlaşmazlık açamazsınız. Lütfen her iki depozito işlemi de onaylanana ve kullanılabilir olana kadar bekleyin.\n\n\ + Daha fazla yardım için, lütfen Matrix sohbet odamızda Haveno desteği ile iletişime geçin. + +portfolio.pending.support.headline.getHelp=Yardıma mı ihtiyacınız var? +portfolio.pending.support.button.getHelp=Tüccar Sohbetini Aç +portfolio.pending.support.headline.halfPeriodOver=Ödemeyi kontrol edin +portfolio.pending.support.headline.periodOver=Ticaret süresi doldu + +portfolio.pending.arbitrationRequested=Arabuluculuk talep edildi +portfolio.pending.mediationRequested=Arabuluculuk talep edildi +portfolio.pending.refundRequested=İade talep edildi +portfolio.pending.openSupport=Destek bileti aç +portfolio.pending.supportTicketOpened=Destek bileti açıldı +portfolio.pending.communicateWithArbitrator=Lütfen \"Destek\" ekranında hakemle iletişime geçin. +portfolio.pending.communicateWithMediator=Lütfen \"Destek\" ekranında arabulucu ile iletişime geçin. +portfolio.pending.disputeOpenedByUser=Zaten bir anlaşmazlık açtınız.\n{0} +portfolio.pending.disputeOpenedByPeer=Ticaret ortağınız bir anlaşmazlık açtı\n{0} +portfolio.pending.noReceiverAddressDefined=Alıcı adresi tanımlanmamış + +portfolio.pending.mediationResult.headline=Arabuluculuk sonucunda önerilen ödeme +portfolio.pending.mediationResult.info.noneAccepted=Arabulucunun ticaret ödemesi için önerisini kabul ederek ticareti tamamlayın. +portfolio.pending.mediationResult.info.selfAccepted=Arabulucunun önerisini kabul ettiniz. Karşı tarafın da kabul etmesini bekliyor. +portfolio.pending.mediationResult.info.peerAccepted=Ticaret ortağınız arabulucunun önerisini kabul etti. Siz de kabul ediyor musunuz? +portfolio.pending.mediationResult.button=Önerilen çözümü görüntüle +portfolio.pending.mediationResult.popup.headline=Ticaret Kimliği ile arabuluculuk sonucu: {0} +portfolio.pending.mediationResult.popup.headline.peerAccepted=Ticaret {0} için ticaret ortağınız arabulucunun önerisini kabul etti +portfolio.pending.mediationResult.popup.info=Arabulucu şu şekilde bir ödeme önermiştir:\n\ + Siz alıyorsunuz: {0}\n\ + Ticaret ortağınız alıyor: {1}\n\n\ + Bu önerilen ödemeyi kabul edebilir veya reddedebilirsiniz.\n\n\ + Kabul ederseniz, önerilen ödeme işlemini imzalarsınız. \ + Ticaret ortağınız da kabul eder ve imzalarsa, ödeme tamamlanır ve ticaret kapanır.\n\n\ + Bir veya ikiniz de öneriyi reddederseniz, {2} tarihine kadar (blok {3}) \ + hakemle ikinci anlaşmazlık için beklemek zorundasınız. Hakem, tekrar inceleyip bulgularına göre ödeme yapacaktır.\n\n\ + Hakem, çalışmaları için küçük bir ücret (maksimum ücret: tüccarın güvenlik depozitosu) talep edebilir. \ + Her iki tüccarın da arabulucunun önerisini kabul etmesi mutlu yoldur - hakem talep etmek, \ + arabulucunun adil bir ödeme önerisi yapmadığından emin olunması durumunda istisnai durumlar içindir \ + (veya diğer taraf yanıt vermiyorsa).\n\n\ + Yeni arabuluculuk modeli hakkında daha fazla ayrıntı: [HYPERLINK:https://haveno.exchange/wiki/Dispute_resolution#Level_3:_Arbitration] +portfolio.pending.mediationResult.popup.selfAccepted.lockTimeOver=Arabulucunun önerdiği ödemeyi kabul ettiniz \ + ancak ticaret ortağınızın kabul etmemiş gibi görünüyor.\n\n\ + Kilit süresi sona erdiğinde {0} (blok {1}), \ + hakemle ikinci tur anlaşmazlık açabilirsiniz. Hakem durumu tekrar inceleyip bulgularına göre ödeme yapacaktır.\n\n\ + Arabuluculuk modeli hakkında daha fazla ayrıntıyı şu adreste bulabilirsiniz:\ + [HYPERLINK:https://haveno.exchange/wiki/Dispute_resolution#Level_3:_Arbitration] +portfolio.pending.mediationResult.popup.openArbitration=Reddet ve hakem talep et +portfolio.pending.mediationResult.popup.alreadyAccepted=Zaten kabul ettiniz + +portfolio.pending.failedTrade.taker.missingTakerFeeTx=Alıcı ücret işlemi eksik.\n\n\ + Bu işlem olmadan, ticaret tamamlanamaz. Hiçbir fon kilitlenmedi ve ticaret ücreti ödenmedi. \ + Bu ticareti başarısız ticaretler arasına taşıyabilirsiniz. +portfolio.pending.failedTrade.maker.missingTakerFeeTx=Karşı tarafın alıcı ücret işlemi eksik.\n\n\ + Bu işlem olmadan, ticaret tamamlanamaz. Hiçbir fon kilitlenmedi. \ + Teklifiniz diğer tüccarlar için hala mevcut, bu yüzden üretici ücretini kaybetmediniz. \ + Bu ticareti başarısız ticaretler arasına taşıyabilirsiniz. +portfolio.pending.failedTrade.missingDepositTx=Para yatırma işlemi (2-of-2 multisig işlemi) eksik.\n\n\ + Bu işlem olmadan, ticaret tamamlanamaz. Hiçbir fon kilitlenmedi ancak ticaret ücretiniz ödendi. \ + Ticaret ücretinin geri ödenmesi için burada talepte bulunabilirsiniz: \ + [HYPERLINK:https://github.com/bisq-network/support/issues]\n\n\ + Bu ticareti başarısız ticaretler arasına taşımakta özgürsünüz. +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=Gecikmiş ödeme işlemi eksik, \ + ancak fonlar depozito işleminde kilitlendi.\n\n\ + Lütfen geleneksel veya kripto para ödemesini XMR satıcısına göndermeyin, çünkü gecikmiş ödeme işlemi olmadan arabuluculuk \ + açılamaz. Bunun yerine, Cmd/Ctrl+o ile bir arabuluculuk bileti açın. \ + Arabulucu, her iki tarafın da güvenlik mevduatlarının tamamını geri almasını önermelidir \ + (satıcı da tam ticaret miktarını geri alır). \ + Bu şekilde, güvenlik riski yoktur ve yalnızca ticaret ücretleri kaybedilir. \n\n\ + Kaybedilen ticaret ücretleri için burada geri ödeme talebinde bulunabilirsiniz: \ + [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=Gecikmiş ödeme işlemi eksik \ + ancak fonlar depozito işleminde kilitlendi.\n\n\ + Eğer alıcı da gecikmiş ödeme işlemini eksikse, onlara ödemeyi göndermemeleri ve \ + bir arabuluculuk bileti açmaları talimatı verilecektir. Siz de Cmd/Ctrl+o ile bir arabuluculuk bileti açmalısınız. \n\n\ + Eğer alıcı henüz ödeme yapmadıysa, arabulucu her iki tarafın da güvenlik mevduatlarının \ + tamamını geri almasını önermelidir (satıcı da tam ticaret miktarını geri alır). \ + Aksi takdirde ticaret miktarı alıcıya gitmelidir. \n\n\ + Kaybedilen ticaret ücretleri için burada geri ödeme talebinde bulunabilirsiniz: \ + [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.errorMsgSet=Ticaret protokolü yürütülürken bir hata oluştu.\n\n\ + Hata: {0}\n\n\ + Bu hata kritik olmayabilir ve ticaret normal şekilde tamamlanabilir. Emin değilseniz, \ + Haveno arabulucularından tavsiye almak için bir arabuluculuk bileti açın. \n\n\ + Eğer hata kritikse ve ticaret tamamlanamazsa, ticaret ücretinizi kaybetmiş olabilirsiniz. \ + Kaybedilen ticaret ücretleri için burada geri ödeme talebinde bulunun: \ + [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.missingContract=Ticaret sözleşmesi ayarlanmadı.\n\n\ + Ticaret tamamlanamaz ve ticaret ücretinizi kaybetmiş olabilirsiniz. \ + Eğer öyleyse, kaybedilen ticaret ücretleri için burada geri ödeme talebinde bulunun: \ + [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.info.popup=Ticaret protokolü bazı sorunlarla karşılaştı.\n\n{0} +portfolio.pending.failedTrade.txChainInvalid.moveToFailed=Ticaret protokolü ciddi bir sorunla karşılaştı.\n\n{0}\n\n\ + Ticareti başarısız ticaretler arasına taşımak ister misiniz?\n\n\ + Başarısız ticaretler görünümünden arabuluculuk veya tahkim açamazsınız, ancak başarısız bir ticareti istediğiniz zaman \ + açık ticaretler ekranına geri taşıyabilirsiniz. +portfolio.pending.failedTrade.txChainValid.moveToFailed=Ticaret protokolü bazı sorunlarla karşılaştı.\n\n{0}\n\n\ + Ticaret işlemleri yayınlandı ve fonlar kilitlendi. Ticareti başarısız ticaretler arasına yalnızca gerçekten emin \ + iseniz taşıyın. Sorunu çözme seçeneklerini engelleyebilir.\n\n\ + Ticareti başarısız ticaretler arasına taşımak ister misiniz?\n\n\ + Başarısız ticaretler görünümünden arabuluculuk veya tahkim açamazsınız, ancak başarısız bir ticareti istediğiniz zaman \ + açık ticaretler ekranına geri taşıyabilirsiniz. +portfolio.pending.failedTrade.moveTradeToFailedIcon.tooltip=Ticareti başarısız ticaretler arasına taşı +portfolio.pending.failedTrade.warningIcon.tooltip=Bu ticaretin sorunları hakkında ayrıntıları açmak için tıklayın +portfolio.failed.revertToPending.popup=Bu ticareti açık ticaretler arasına taşımak istiyor musunuz? +portfolio.failed.revertToPending.failed=Bu ticareti açık ticaretler arasına taşımak başarısız oldu. +portfolio.failed.revertToPending=Ticareti açık ticaretler arasına taşı +portfolio.closed.completed=Tamamlandı +portfolio.closed.ticketClosed=Hakem Kararıyla +portfolio.closed.mediationTicketClosed=Arabuluculukla +portfolio.closed.canceled=İptal Edildi +portfolio.failed.Failed=Başarısız +portfolio.failed.unfail=Devam etmeden önce, veri dizininizin bir yedeğine sahip olduğunuzdan emin olun!\n\ + Bu ticareti açık ticaretler arasına geri taşımak istiyor musunuz?\n\ + Bu, başarısız bir ticarette sıkışmış fonları açmanın bir yoludur. +portfolio.failed.cantUnfail=Bu ticaret şu anda açık ticaretler arasına taşınamaz. \n\ + {0} ticaret(lerinin) tamamlanmasından sonra tekrar deneyin. +portfolio.failed.depositTxNull=Ticaret açık bir ticarete geri dönüştürülemez. Para yatırma işlemi null. +portfolio.failed.delayedPayoutTxNull=Ticaret açık bir ticarete geri dönüştürülemez. Gecikmiş ödeme işlemi null. +portfolio.failed.penalty.msg=Bu, {0}/{1} bir ceza ücreti olarak {2} tutarında ücret tahsil edecek ve kalan ticaret \ + fonlarını cüzdanlarına geri gönderecek. Göndermek istediğinizden emin misiniz?\n\n\ + Diğer Bilgiler:\n\ + İşlem Ücreti: {3}\n\ + Rezerv Tx Hash: {4} +portfolio.failed.error.msg=Ticaret kaydı mevcut değil. + +#################################################################### +# Funds +#################################################################### + +funds.tab.deposit=Fon al +funds.tab.withdrawal=Fon gönder +funds.tab.reserved=Rezerve edilen fonlar +funds.tab.locked=Kilitli fonlar +funds.tab.transactions=İşlemler + +funds.deposit.unused=Kullanılmamış +funds.deposit.usedInTx={0} işlemde kullanıldı +funds.deposit.baseAddress=Temel adres +funds.deposit.offerFunding=Teklif finansmanı için rezerve ({0}) +funds.deposit.tradePayout=Ticaret ödemesi için rezerve ({0}) +funds.deposit.fundHavenoWallet=Haveno cüzdanını finanse et +funds.deposit.noAddresses=Henüz herhangi bir para yatırma adresi oluşturulmadı +funds.deposit.fundWallet=Cüzdanınızı finanse edin +funds.deposit.withdrawFromWallet=Cüzdandan fon gönder +funds.deposit.amount=XMR miktarı (isteğe bağlı) +funds.deposit.generateAddress=Yeni adres oluştur +funds.deposit.generateAddressSegwit=Yerli segwit formatı (Bech32) +funds.deposit.selectUnused=Lütfen yukarıdaki tablodan kullanılmamış bir adres seçin, yeni bir tane oluşturmaktansa. + +funds.withdrawal.arbitrationFee=Arabuluculuk ücreti +funds.withdrawal.inputs=Girdi seçimi +funds.withdrawal.useAllInputs=Mevcut tüm girdileri kullan +funds.withdrawal.useCustomInputs=Özel girdileri kullan +funds.withdrawal.receiverAmount=Alıcının miktarı +funds.withdrawal.senderAmount=Gönderenin miktarı +funds.withdrawal.feeExcluded=Miktar madenci ücretini içermez +funds.withdrawal.feeIncluded=Miktar madenci ücretini içerir +funds.withdrawal.fromLabel=Adresten çek +funds.withdrawal.toLabel=Adrese çek +funds.withdrawal.memoLabel=Çekme notu +funds.withdrawal.memo=İsteğe bağlı olarak not ekleyin +funds.withdrawal.withdrawButton=Seçilenleri çek +funds.withdrawal.noFundsAvailable=Çekmek için mevcut fon yok +funds.withdrawal.confirmWithdrawalRequest=Çekme talebini onayla +funds.withdrawal.withdrawMultipleAddresses=Birden fazla adresten çek ({0}) +funds.withdrawal.withdrawMultipleAddresses.tooltip=Birden fazla adresten çek:\n{0} +funds.withdrawal.notEnoughFunds=Cüzdanınızda yeterli fon yok. +funds.withdrawal.selectAddress=Tablodan bir kaynak adres seçin +funds.withdrawal.setAmount=Çekilecek miktarı belirleyin +funds.withdrawal.fillDestAddress=Hedef adresinizi doldurun +funds.withdrawal.warn.noSourceAddressSelected=Yukarıdaki tablodan bir kaynak adres seçmeniz gerekiyor. +funds.withdrawal.warn.amountExceeds=Seçilen adresten yeterli fon yok.\n\ + Yukarıdaki tablodan birden fazla adres seçmeyi düşünün veya madenci ücretini içerecek şekilde ücreti değiştirin. +funds.withdrawal.warn.amountMissing=Çekilecek bir miktar girin. +funds.withdrawal.txFee=Çekme işlem ücreti (satoshis/vbyte) +funds.withdrawal.useCustomFeeValueInfo=Özel bir işlem ücreti değeri girin +funds.withdrawal.useCustomFeeValue=Özel değeri kullan +funds.withdrawal.txFeeMin=İşlem ücreti en az {0} satoshis/vbyte olmalıdır +funds.withdrawal.txFeeTooLarge=Girdiğiniz değer makul değerin üzerinde (>5000 satoshis/vbyte). İşlem ücreti genellikle 50-400 satoshis/vbyte arasında olur. + +funds.reserved.noFunds=Açık tekliflerde rezerve edilmiş fon yok +funds.reserved.reserved=Teklif ID'si ile yerel cüzdanda rezerve: {0} + +funds.locked.noFunds=İşlemlerde kilitli fon yok +funds.locked.locked=Ticaret ID'si ile multisig'de kilitli: {0} + +funds.tx.direction.sentTo=Gönderildi: +funds.tx.direction.receivedWith=Alındı: +funds.tx.direction.genesisTx=Genesis işleminden: +funds.tx.createOfferFee=Üretici ve işlem ücreti: {0} +funds.tx.takeOfferFee=Alıcı ve işlem ücreti: {0} +funds.tx.multiSigDeposit=Multisig depozito: {0} +funds.tx.multiSigPayout=Multisig ödeme: {0} +funds.tx.disputePayout=Uyuşmazlık ödemesi: {0} +funds.tx.disputeLost=Uyuşmazlık kaybedildi: {0} +funds.tx.collateralForRefund=Teminat geri ödemesi: {0} +funds.tx.timeLockedPayoutTx=Zaman kilitli ödeme işlemi: {0} +funds.tx.refund=Arabuluculuktan geri ödeme: {0} +funds.tx.unknown=Bilinmeyen neden: {0} +funds.tx.noFundsFromDispute=Uyuşmazlıktan geri ödeme yok +funds.tx.receivedFunds=Alınan fonlar +funds.tx.withdrawnFromWallet=Cüzdandan çekildi +funds.tx.memo=Not +funds.tx.noTxAvailable=Mevcut işlem yok +funds.tx.revert=Geri al +funds.tx.txSent=İşlem yerel Haveno cüzdanında yeni bir adrese başarıyla gönderildi. +funds.tx.direction.self=Kendinize gönderildi +funds.tx.dustAttackTx=Toz alındı +funds.tx.dustAttackTx.popup=Bu işlem cüzdanınıza çok küçük bir XMR miktarı gönderiyor ve zincir analizi şirketlerinin \ + cüzdanınızı izlemeye çalışıyor olabileceği bir girişim olabilir.\n\n\ + Bu işlem çıktısını harcama işleminde kullanırsanız, diğer adresin de muhtemelen size ait olduğunu öğrenirler \ + (coin merge).\n\n\ + Gizliliğinizi korumak için Haveno cüzdanı bu tür toz çıktıları harcama amaçlı ve bakiye \ + görüntülemede görmezden gelir. Bir çıktının toz olarak kabul edildiği eşik miktarını ayarlarda belirleyebilirsiniz. + +#################################################################### +# Support +#################################################################### + +support.tab.mediation.support=Arabuluculuk +support.tab.refund.support=Geri Ödeme +support.tab.arbitration.support=Arbitraj +support.tab.legacyArbitration.support=Eski Arbitraj +support.tab.ArbitratorsSupportTickets={0}'nin biletleri +support.filter=Uyuşmazlıkları ara +support.filter.prompt=İşlem ID'si, tarih, onion adresi veya hesap verilerini girin +support.tab.SignedOffers=İmzalı Teklifler +support.prompt.signedOffer.penalty.msg=Bu, üreticiden bir ceza ücreti alacak ve kalan işlem fonlarını cüzdanına iade edecektir. Göndermek istediğinizden emin misiniz?\n\n\ + Teklif ID'si: {0}\n\ + Üretici Ceza Ücreti: {1}\n\ + Rezerv Tx Madenci Ücreti: {2}\n\ + Rezerv Tx Hash: {3}\n\ + Rezerv Tx Anahtar Görüntüleri: {4}\n\ + +support.contextmenu.penalize.msg=Rezerv işlemi yayımlayarak {0}'i cezalandır +support.prompt.signedOffer.error.msg=İmzalı Teklif kaydı mevcut değil; yöneticiyle iletişime geçin. +support.info.submitTxHex=Rezerv işlemi aşağıdaki sonuçla yayımlandı:\n +support.result.success=İşlem hex başarıyla gönderildi. + +support.sigCheck.button=İmzayı kontrol et +support.sigCheck.popup.info=Arbitraj sürecinin özet mesajını yapıştırın. Bu araçla, herhangi bir kullanıcı hakemin imzasının özet mesajla eşleşip eşleşmediğini kontrol edebilir. +support.sigCheck.popup.header=Uyuşmazlık sonucu imzasını doğrula +support.sigCheck.popup.msg.label=Özet mesaj +support.sigCheck.popup.msg.prompt=Uyuşmazlıktan özet mesajı kopyala ve yapıştır +support.sigCheck.popup.result=Doğrulama sonucu +support.sigCheck.popup.success=İmza geçerli +support.sigCheck.popup.failed=İmza doğrulaması başarısız oldu +support.sigCheck.popup.invalidFormat=Mesaj beklenen formatta değil. Uyuşmazlıktan özet mesajı kopyala ve yapıştır. + +support.reOpenByTrader.prompt=Uyuşmazlığı tekrar açmak istediğinizden emin misiniz? +support.reOpenByTrader.failed=Uyuşmazlığı tekrar açma başarısız oldu. +support.reOpenButton.label=Tekrar aç +support.sendNotificationButton.label=Özel bildirim +support.reportButton.label=Rapor et +support.fullReportButton.label=Tüm uyuşmazlıklar +support.noTickets=Açık bilet yok +support.sendingMessage=Mesaj Gönderiliyor... +support.receiverNotOnline=Alıcı çevrimdışı. Mesaj posta kutusuna kaydedildi. +support.sendMessageError=Mesaj gönderme başarısız oldu. Hata: {0} +support.receiverNotKnown=Alıcı bilinmiyor +support.wrongVersion=Bu uyuşmazlıktaki teklif Haveno'nun eski bir sürümü ile oluşturulmuş.\n\ +Bu uyuşmazlığı uygulamanızın sürümü ile kapatamazsınız.\n\n\ +Lütfen protokol sürümü {0} olan eski bir sürüm kullanın. +support.openFile=Eklenecek dosyayı aç (maks. dosya boyutu: {0} kb) +support.attachmentTooLarge=Eklerinizin toplam boyutu {0} kb ve izin verilen en fazla mesaj boyutunu {1} kB aşıyor. +support.maxSize=İzin verilen en fazla dosya boyutu {0} kB'dir. +support.attachment=Ek +support.tooManyAttachments=Bir mesajda 3'ten fazla ek gönderemezsiniz. +support.save=Dosyayı diske kaydet +support.messages=Mesajlar +support.input.prompt=Mesaj girin... +support.send=Gönder +support.addAttachments=Ekleri ekle +support.closeTicket=Bileti kapat +support.attachments=Ekler: +support.savedInMailbox=Mesaj alıcının posta kutusuna kaydedildi +support.arrived=Mesaj alıcıya ulaştı +support.transient=Mesaj alıcıya doğru yolda +support.acknowledged=Mesajın alıcı tarafından alındığı teyit edildi +support.error=Alıcı mesajı işleyemedi. Hata: {0} +support.errorTimeout=zamanaşımı. Mesajı tekrar göndermeyi deneyin. +support.buyerAddress=XMR alıcı adresi +support.sellerAddress=XMR satıcı adresi +support.role=Rol +support.agent=Destek temsilcisi +support.state=Durum +support.chat=Sohbet +support.requested=Talep edildi +support.closed=Kapalı +support.open=Açık +support.moreButton=DAHA FAZLA... +support.sendLogFiles=Günlük Dosyalarını Gönder +support.uploadTraderChat=Tüccar Sohbetini Yükle +support.process=Süreç +support.buyerMaker=XMR Alıcı/Üretici +support.sellerMaker=XMR Satıcı/Üretici +support.buyerTaker=XMR Alıcı/Alıcı +support.sellerTaker=XMR Satıcı/Alıcı +support.sendLogs.title=Günlük Dosyalarını Gönder +support.sendLogs.backgroundInfo=Bir hata ile karşılaştığınızda, hakemler ve destek personeli genellikle sorunu teşhis etmek için günlük dosyalarınızın kopyalarını ister.\n\n\ + 'Gönder' düğmesine bastığınızda, günlük dosyalarınız sıkıştırılacak ve doğrudan hakeme iletilecektir. +support.sendLogs.step1=Günlük Dosyalarının Zip Arşivini Oluştur +support.sendLogs.step2=Hakeme Bağlantı İsteği +support.sendLogs.step3=Arşivlenmiş Günlük Verilerini Yükle +support.sendLogs.send=Gönder +support.sendLogs.cancel=İptal +support.sendLogs.init=Başlatılıyor +support.sendLogs.retry=Göndermeyi yeniden deniyor +support.sendLogs.stopped=Transfer durduruldu +support.sendLogs.progress=Transfer ilerlemesi: %.0f%% +support.sendLogs.finished=Transfer tamamlandı! +support.sendLogs.command=Yeniden denemek için 'Gönder' düğmesine basın veya iptal etmek için 'Durdur' düğmesine basın +support.txKeyImages=Anahtar Görüntüleri +support.txHash=İşlem Hash +support.txHex=İşlem Hex +support.signature=İmza +support.maker.penalty.fee=Üretici Ceza Ücreti +support.tx.miner.fee=Madenci Ücreti + +support.backgroundInfo=Haveno bir şirket değildir, bu yüzden uyuşmazlıkları farklı şekilde ele alır.\n\n\ +Tüccarlar, açık işlemler ekranında güvenli sohbet üzerinden iletişim kurarak uyuşmazlıkları kendi başlarına çözmeye çalışabilirler. \ + Eğer bu yeterli olmazsa, bir hakem durumu değerlendirecek ve işlem fonlarının \ + ödemesine karar verecektir. +support.initialInfo=Lütfen aşağıdaki metin alanına sorununuzun bir açıklamasını girin. \ + Uyuşmazlık çözüm süresini hızlandırmak için mümkün olduğunca fazla bilgi ekleyin.\n\n\ + Sağlamanız gereken bilgiler için bir kontrol listesi:\n\ + \t● XMR alıcısıysanız: Geleneksel veya Kripto para transferi yaptınız mı? Eğer öyleyse, uygulamada 'ödeme başlatıldı' \ + düğmesine tıkladınız mı?\n\ + \t● XMR satıcısıysanız: Geleneksel veya Kripto para ödemesini aldınız mı? Eğer öyleyse, uygulamada 'ödeme alındı' \ + düğmesine tıkladınız mı?\n\ + \t● Hangi Haveno sürümünü kullanıyorsunuz?\n\ + \t● Hangi işletim sistemini kullanıyorsunuz?\n\ + \t● Başarısız işlemlerle ilgili bir sorunla karşılaştıysanız, yeni bir veri dizinine geçmeyi düşünün.\n\ + \t Bazen veri dizini bozulur ve garip hatalara yol açar.\n\ + \t Bkz: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n\ + Lütfen uyuşmazlık süreciyle ilgili temel kuralları öğrenin:\n\ +\t● {0}'nin taleplerine 2 gün içinde yanıt vermelisiniz.\n\ +\t● Arabulucular 2 gün içinde yanıt verir. Hakemler 5 iş günü içinde yanıt verir.\n\ +\t● Bir uyuşmazlık için maksimum süre 14 gündür.\n\ +\t● {1} ile işbirliği yapmalı ve davanızı oluşturmak için talep ettikleri bilgileri sağlamalısınız.\n\ +\t● Uygulamayı ilk başlattığınızda kullanıcı sözleşmesinde uyuşmazlık belgesinde belirtilen kuralları kabul ettiniz.\n\n\ +Uyuşmazlık süreci hakkında daha fazla bilgiyi şu adreste okuyabilirsiniz: {2} +support.systemMsg=Sistem mesajı: {0} +support.youOpenedTicket=Destek talebinde bulundunuz.\n\n{0}\n\nHaveno sürümü: {1} +support.youOpenedDispute=Uyuşmazlık talebinde bulundunuz.\n\n{0}\n\nHaveno sürümü: {1} +support.youOpenedDisputeForMediation=Arabuluculuk talebinde bulundunuz.\n\n{0}\n\nHaveno sürümü: {1} +support.peerOpenedTicket=İşlem eşiniz teknik sorunlar nedeniyle destek talebinde bulundu.\n\n{0}\n\nHaveno sürümü: {1} +support.peerOpenedDispute=İşlem eşiniz uyuşmazlık talebinde bulundu.\n\n{0}\n\nHaveno sürümü: {1} +support.peerOpenedDisputeForMediation=İşlem eşiniz arabuluculuk talebinde bulundu.\n\n{0}\n\nHaveno sürümü: {1} +support.mediatorsDisputeSummary=Sistem mesajı: Arabulucunun uyuşmazlık özeti:\n{0} +support.mediatorReceivedLogs=Sistem mesajı: Arabulucu günlükleri aldı: {0} +support.mediatorsAddress=Arabulucunun düğüm adresi: {0} +support.warning.disputesWithInvalidDonationAddress=Gecikmiş ödeme işlemi geçersiz bir alıcı adresi kullanmıştır. \ + Bu adres, geçerli bağış adresleri için DAO parametre değerlerinden hiçbiriyle eşleşmemektedir.\n\nBu bir dolandırıcılık girişimi olabilir. \ + Lütfen bu durumu geliştiricilere bildirin ve durum çözülmeden bu davayı kapatmayın!\n\n\ + Uyuşmazlıkta kullanılan adres: {0}\n\n\ + Tüm DAO parametre bağış adresleri: {1}\n\n\ + İşlem ID'si: {2}\ + {3} +support.warning.disputesWithInvalidDonationAddress.mediator=\n\nUyuşmazlığı yine de kapatmak istiyor musunuz? +support.warning.disputesWithInvalidDonationAddress.refundAgent=\n\nÖdemeyi yapmamalısınız. +support.warning.traderCloseOwnDisputeWarning=Tüccarlar destek biletlerini ancak işlem ödendikten sonra kendileri kapatabilirler. +support.info.disputeReOpened=Uyuşmazlık bileti tekrar açıldı. + +#################################################################### +# Settings +#################################################################### +settings.tab.preferences=Tercihler +settings.tab.network=Ağ bilgisi +settings.tab.about=Hakkında + +setting.preferences.general=Genel tercihler +setting.preferences.explorer=Monero Gezgini +setting.preferences.deviation=Piyasa fiyatından maksimum sapma +setting.preferences.avoidStandbyMode=Bekleme modundan kaçın +setting.preferences.useSoundForNotifications=Bildirimler için sesleri çal +setting.preferences.autoConfirmXMR=XMR otomatik onay +setting.preferences.autoConfirmEnabled=Etkin +setting.preferences.autoConfirmRequiredConfirmations=Gerekli onaylar +setting.preferences.autoConfirmMaxTradeSize=Maks. işlem miktarı (XMR) +setting.preferences.autoConfirmServiceAddresses=Monero Gezgini URL'leri (localhost, LAN IP adresleri ve *.local ana bilgisayar adları hariç Tor kullanır) +setting.preferences.deviationToLarge={0}% üzerindeki değerler izin verilmez. +setting.preferences.txFee=BSQ Çekme işlem ücreti (satoshi/vbyte) +setting.preferences.useCustomValue=Özel değeri kullan +setting.preferences.ignorePeers=Yok sayılan eşler [onion address:port] +setting.preferences.ignoreDustThreshold=Min. toz olmayan çıkış değeri +setting.preferences.currenciesInList=Piyasa fiyat listesinde para birimleri +setting.preferences.prefCurrency=Tercih edilen para birimi +setting.preferences.displayTraditional=Geleneksel para birimlerini göster +setting.preferences.noTraditional=Seçilmiş geleneksel para birimleri yok +setting.preferences.cannotRemovePrefCurrency=Seçtiğiniz tercih edilen görüntüleme para birimini kaldıramazsınız +setting.preferences.displayCryptos=Kripto paraları göster +setting.preferences.noCryptos=Seçilmiş kripto paralar yok +setting.preferences.addTraditional=Geleneksel para birimi ekle +setting.preferences.addCrypto=Kripto para ekle +setting.preferences.displayOptions=Görüntüleme seçenekleri +setting.preferences.showOwnOffers=Teklif defterinde kendi tekliflerini göster +setting.preferences.useAnimations=Animasyonları kullan +setting.preferences.useDarkMode=Karanlık modu kullan +setting.preferences.sortWithNumOffers=Piyasaları teklif sayısına göre sırala +setting.preferences.onlyShowPaymentMethodsFromAccount=Olmayan ödeme yöntemlerini gizle +setting.preferences.denyApiTaker=API kullanan alıcıları reddet +setting.preferences.notifyOnPreRelease=Ön sürüm bildirimlerini al +setting.preferences.resetAllFlags=Tüm \"Tekrar gösterme\" bayraklarını sıfırla +settings.preferences.languageChange=Dil değişikliğinin tüm ekranlarda uygulanması için yeniden başlatma gereklidir. +settings.preferences.supportLanguageWarning=Bir uyuşmazlık durumunda, hakemlik işlemleri {0} dilinde yapılır. +settings.preferences.editCustomExplorer.headline=Gezgin Ayarları +settings.preferences.editCustomExplorer.description=Soldaki listeden bir sistem tanımlı gezgini seçin ve/veya \ + kendi tercihlerinize göre özelleştirin. +settings.preferences.editCustomExplorer.available=Mevcut gezginler +settings.preferences.editCustomExplorer.chosen=Seçilmiş gezgin ayarları +settings.preferences.editCustomExplorer.name=İsim +settings.preferences.editCustomExplorer.txUrl=İşlem URL'si +settings.preferences.editCustomExplorer.addressUrl=Adres URL'si + +settings.net.xmrHeader=Monero ağı +settings.net.p2pHeader=Haveno ağı +settings.net.onionAddressLabel=Onion adresim +settings.net.xmrNodesLabel=Özel Monero düğümleri kullan +settings.net.moneroPeersLabel=Bağlı eşler +settings.net.connection=Bağlantı +settings.net.connected=Bağlı +settings.net.useTorForXmrJLabel=Monero ağı için Tor kullan +settings.net.useTorForXmrAfterSyncRadio=Cüzdan senkronize edildikten sonra +settings.net.useTorForXmrOffRadio=Asla +settings.net.useTorForXmrOnRadio=Her zaman +settings.net.moneroNodesLabel=Bağlanılacak Monero düğümleri +settings.net.useProvidedNodesRadio=Sağlanan Monero düğümlerini kullan +settings.net.usePublicNodesRadio=Genel Monero ağını kullan +settings.net.useCustomNodesRadio=Özel Monero düğümlerini kullan +settings.net.warn.usePublicNodes=Genel Monero düğümlerini kullanırsanız, güvenilmeyen uzak düğümleri kullanmanın getirdiği tüm risklere tabisiniz.\n\nDaha fazla ayrıntı için lütfen [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html] adresini okuyun.\n\nGenel düğümleri kullanmak istediğinizden emin misiniz? +settings.net.warn.usePublicNodes.useProvided=Hayır, sağlanan düğümleri kullan +settings.net.warn.usePublicNodes.usePublic=Evet, genel ağı kullan +settings.net.warn.useCustomNodes.B2XWarning=Lütfen Monero düğümünüzün güvenilir bir Monero düğümü olduğundan emin olun!\n\n\ + Monero konsensüs kurallarını takip etmeyen düğümlere bağlanmak cüzdanınızı bozabilir ve işlem sürecinde sorunlara yol açabilir.\n\n\ + Konsensüs kurallarını ihlal eden düğümlere bağlanan kullanıcılar, ortaya çıkan herhangi bir hasardan sorumludur. \ + Ortaya çıkan herhangi bir uyuşmazlık diğer taraf lehine karar verilecektir. \ + Bu uyarıyı ve koruma mekanizmalarını görmezden gelen kullanıcılara teknik destek verilmeyecektir! +settings.net.warn.invalidXmrConfig=Monero ağına bağlantı yapılandırmanız geçersiz olduğu için başarısız oldu.\n\nYapılandırmanız sağlanan Monero düğümlerini kullanacak şekilde sıfırlandı. Uygulamayı yeniden başlatmanız gerekecek. +settings.net.localhostXmrNodeInfo=Arka plan bilgisi: Haveno, başlatıldığında yerel bir Monero düğümü arar. Bulunursa, Haveno Monero ağıyla yalnızca bu düğüm aracılığıyla iletişim kuracaktır. +settings.net.p2PPeersLabel=Bağlı eşler +settings.net.onionAddressColumn=Onion adresi +settings.net.creationDateColumn=Kuruluş +settings.net.connectionTypeColumn=G/Ç +settings.net.sentDataLabel=Gönderilen veri istatistikleri +settings.net.receivedDataLabel=Alınan veri istatistikleri +settings.net.chainHeightLabel=Son XMR blok yüksekliği +settings.net.roundTripTimeColumn=Gidiş-dönüş süresi +settings.net.sentBytesColumn=Gönderilen +settings.net.receivedBytesColumn=Alınan +settings.net.peerTypeColumn=Eş türü +settings.net.openTorSettingsButton=Tor ayarlarını aç + +settings.net.versionColumn=Sürüm +settings.net.subVersionColumn=Alt sürüm +settings.net.heightColumn=Yükseklik + +settings.net.needRestart=Bu değişikliği uygulamak için uygulamayı yeniden başlatmanız gerekiyor.\nŞimdi yapmak istiyor musunuz? +settings.net.notKnownYet=Henüz bilinmiyor... +settings.net.sentData=Gönderilen veri: {0}, {1} mesaj, {2} mesaj/saniye +settings.net.receivedData=Alınan veri: {0}, {1} mesaj, {2} mesaj/saniye +settings.net.chainHeight=Monero Eşlerinin blok yüksekliği: {0} +settings.net.ips=[IP adresi:port | ana bilgisayar adı:port | onion adresi:port] (virgülle ayrılmış). Varsayılan kullanılıyorsa port belirtilebilir ({0}). +settings.net.seedNode=Tohum düğümü +settings.net.directPeer=Eş (doğrudan) +settings.net.initialDataExchange={0} [Başlatılıyor] +settings.net.peer=Eş +settings.net.inbound=gelen +settings.net.outbound=giden +settings.net.rescanOutputsLabel=Çıktıları Yeniden Tara +settings.net.rescanOutputsButton=Cüzdan Çıktılarını Yeniden Tara +settings.net.rescanOutputsSuccess=Cüzdan çıktılarını yeniden taramak istediğinize emin misiniz? +settings.net.rescanOutputsFailed=Cüzdan çıktılarını yeniden tarayamadı.\nHata: {0} +setting.about.aboutHaveno=Haveno Hakkında +setting.about.about=Haveno, kullanıcı gizliliğini güçlü bir şekilde koruyan merkezi olmayan bir eşler arası ağ aracılığıyla monero'nun ulusal para birimleri (ve diğer kripto para birimleri) ile değişimini kolaylaştıran açık kaynaklı bir yazılımdır. Haveno hakkında daha fazla bilgi edinmek için proje web sayfamızı ziyaret edin. +setting.about.web=Haveno web sayfası +setting.about.code=Kaynak kodu +setting.about.agpl=AGPL Lisansı +setting.about.support=Haveno'yu Destekleyin +setting.about.def=Haveno bir şirket değildir—topluluğa açık bir projedir. Haveno'yu desteklemek istiyorsanız lütfen aşağıdaki bağlantıları takip edin. +setting.about.contribute=Katkıda Bulunun +setting.about.providers=Veri sağlayıcılar +setting.about.apisWithFee=Haveno, Geleneksel ve Kripto Para piyasası fiyatları için fiyat endeksleri kullanır +setting.about.apis=Haveno, Geleneksel ve Kripto Para piyasası fiyatları için Fiyat Endeksleri kullanır. +setting.about.pricesProvided=Piyasa fiyatları tarafından sağlanır +setting.about.feeEstimation.label=Madencilik ücreti tahmini tarafından sağlanır +setting.about.versionDetails=Sürüm detayları +setting.about.version=Uygulama sürümü +setting.about.subsystems.label=Alt sistemlerin sürümleri +setting.about.subsystems.val=Ağ sürümü: {0}; P2P mesaj sürümü: {1}; Yerel DB sürümü: {2}; Ticaret protokolü sürümü: {3} + +setting.about.shortcuts=Kısayollar +setting.about.shortcuts.ctrlOrAltOrCmd=''Ctrl + {0}'' veya ''alt + {0}'' veya ''cmd + {0}'' + +setting.about.shortcuts.menuNav=Ana menüde gezin +setting.about.shortcuts.menuNav.value=Ana menüde gezinmek için şuna basın: 'Ctrl' veya 'alt' veya 'cmd' ve '1-9' arasındaki bir sayı tuşu + +setting.about.shortcuts.close=Haveno'yu kapat +setting.about.shortcuts.close.value=''Ctrl + {0}'' veya ''cmd + {0}'' veya ''Ctrl + {1}'' veya ''cmd + {1}'' + +setting.about.shortcuts.closePopup=Açılır pencereyi veya iletişim penceresini kapat +setting.about.shortcuts.closePopup.value='ESCAPE' tuşu + +setting.about.shortcuts.chatSendMsg=Trader sohbet mesajı gönder +setting.about.shortcuts.chatSendMsg.value=''Ctrl + ENTER'' veya ''alt + ENTER'' veya ''cmd + ENTER'' + +setting.about.shortcuts.openDispute=Uyuşmazlık aç +setting.about.shortcuts.openDispute.value=Bekleyen işlemi seçin ve tıklayın: {0} + +setting.about.shortcuts.walletDetails=Cüzdan detayları penceresini aç + +setting.about.shortcuts.openEmergencyXmrWalletTool=Acil durum cüzdan aracı penceresini aç + +setting.about.shortcuts.showTorLogs=Tor mesajları için log seviyesini DEBUG ve WARN arasında değiştir + +setting.about.shortcuts.manualPayoutTxWindow=2of2 Multisig depozit işleminden manuel ödeme penceresini aç + +setting.about.shortcuts.removeStuckTrade=Başarısız işlemi tekrar açık işlemler sekmesine taşımak için açılır pencereyi aç +setting.about.shortcuts.removeStuckTrade.value=Başarısız işlemi seçin ve basın: {0} + +setting.about.shortcuts.registerArbitrator=Arabulucu kaydettir (arabulucu/hakem sadece) +setting.about.shortcuts.registerArbitrator.value=Hesaba gidin ve basın: {0} + +setting.about.shortcuts.registerMediator=Arabulucu kaydettir (arabulucu/hakem sadece) +setting.about.shortcuts.registerMediator.value=Hesaba gidin ve basın: {0} + +setting.about.shortcuts.openSignPaymentAccountsWindow=Hesap yaşı imzalama penceresini aç (eski hakemler sadece) +setting.about.shortcuts.openSignPaymentAccountsWindow.value=Eski hakem görünümüne gidin ve basın: {0} + +setting.about.shortcuts.sendAlertMsg=Uyarı veya güncelleme mesajı gönder (ayrıcalıklı etkinlik) + +setting.about.shortcuts.sendFilter=Filtre Ayarla (ayrıcalıklı etkinlik) + +setting.about.shortcuts.sendPrivateNotification=Eşe özel bildirim gönder (ayrıcalıklı etkinlik) +setting.about.shortcuts.sendPrivateNotification.value=Eş bilgilerini avatar üzerinde açın ve basın: {0} + +#################################################################### +# Account +#################################################################### + +account.tab.arbitratorRegistration=Hakem kaydı +account.tab.mediatorRegistration=Arabulucu kaydı +account.tab.refundAgentRegistration=İade temsilcisi kaydı +account.tab.signing=İmzalama + +account.menu.paymentAccount=Geleneksel para hesapları +account.menu.altCoinsAccountView=Kripto para hesapları +account.menu.password=Cüzdan şifresi +account.menu.seedWords=Cüzdan kelimeleri +account.menu.walletInfo=Cüzdan bilgileri +account.menu.backup=Yedekleme +account.menu.notifications=Bildirimler + +account.menu.walletInfo.balance.headLine=Cüzdan bakiyeleri +account.menu.walletInfo.balance.info=Bu, onaylanmamış işlemler de dahil olmak üzere iç cüzdan bakiyesini gösterir.\n\ + XMR için, aşağıda gösterilen iç cüzdan bakiyesi, bu pencerenin sağ üst köşesinde gösterilen 'Kullanılabilir' ve 'Ayrılmış' bakiyelerin toplamına eşit olmalıdır. +account.menu.walletInfo.xpub.headLine=İzleme anahtarları (xpub anahtarları) +account.menu.walletInfo.walletSelector={0} {1} cüzdan +account.menu.walletInfo.path.headLine=HD anahtar zinciri yolları +account.menu.walletInfo.path.info=Eğer seed kelimelerini başka bir cüzdana (örneğin Electrum) aktarırsanız, \ + yolu tanımlamanız gerekecek. Bu sadece acil durumlarda Haveno cüzdanına ve veri dizinine erişimi kaybettiğinizde yapılmalıdır.\n\ + Unutmayın ki, Haveno dışındaki bir cüzdandan fon harcamak, cüzdan verileriyle ilişkili Haveno iç veri \ + yapılarını bozabilir, bu da başarısız ticaretlere yol açabilir.\n\n\ + BSQ'yu Haveno dışındaki bir cüzdandan ASLA göndermeyin, çünkü bu muhtemelen geçersiz bir BSQ işlemi ve BSQ kaybına yol açar. + +account.menu.walletInfo.openDetails=Ham cüzdan detaylarını ve özel anahtarları göster + +## TODO genel bir isimle yeniden adlandırmalı mıyız? +account.arbitratorRegistration.pubKey=Genel anahtar + +account.arbitratorRegistration.register=Kaydol +account.arbitratorRegistration.registration={0} kaydı +account.arbitratorRegistration.revoke=İptal et +account.arbitratorRegistration.info.msg=Lütfen kaydınızı iptal ettikten sonra 15 gün boyunca ulaşılabilir kalmanız gerektiğini unutmayın, çünkü {0} olarak sizi kullanan ticaretler olabilir. Maksimum izin verilen ticaret süresi 8 gündür ve anlaşmazlık süreci 7 güne kadar sürebilir. +account.arbitratorRegistration.warn.min1Language=En az 1 dil ayarlamanız gerekmektedir.\nSizin için varsayılan dili ekledik. +account.arbitratorRegistration.removedSuccess=Kayıt işleminizi Haveno ağından başarıyla kaldırdınız. +account.arbitratorRegistration.removedFailed=Kaydı kaldıramadı.{0} +account.arbitratorRegistration.registerSuccess=Haveno ağına başarıyla kaydoldunuz. +account.arbitratorRegistration.registerFailed=Kaydı tamamlayamadı.{0} + +account.crypto.yourCryptoAccounts=Kripto para hesaplarınız +account.crypto.popup.wallet.msg=Lütfen {0} cüzdanlarının kullanım gereksinimlerini {1} web sayfasında \ +açıklanan şekilde takip ettiğinizden emin olun.\nAnahtarlarını kontrol etmediğiniz merkezi borsalardan cüzdan kullanmak veya \ +uyumlu cüzdan yazılımı kullanmayan cüzdanlar kullanmak risklidir: ticaret fonlarının kaybına yol açabilir!\nArabulucu veya hakem \ +{2} uzmanı değildir ve bu tür durumlarda yardımcı olamaz. +account.crypto.popup.wallet.confirm=Hangi cüzdanı kullanmam gerektiğini anladığımı ve onayladığımı kabul ediyorum. +# suppress inspection "UnusedProperty" +account.crypto.popup.upx.msg=Haveno'da UPX ticareti yapmak için aşağıdaki gereksinimleri \ +anladığınızı ve yerine getirdiğinizi kabul etmeniz gerekmektedir:\n\n\ +UPX gönderimi için, ya resmi uPlexa GUI cüzdanını ya da store-tx-info bayrağı etkin olan uPlexa CLI cüzdanını \ +kullanmanız gerekmektedir (yeni sürümlerde varsayılan). Lütfen işlem anahtarına erişebildiğinizden emin olun, \ +çünkü bir anlaşmazlık durumunda bu gerekecektir.\n\ +uplexa-wallet-cli (get_tx_key komutunu kullanın)\n\ +uplexa-wallet-gui (geçmiş sekmesine gidin ve ödeme kanıtı için (P) butonuna tıklayın)\n\n\ +Normal blok kaşiflerinde transfer doğrulanamaz.\n\n\ +Bir anlaşmazlık durumunda hakeme aşağıdaki verileri sağlamanız gerekmektedir:\n\ +- İşlem özel anahtarı\n\ +- İşlem hash'i\n\ +- Alıcının genel adresi\n\n\ +Yukarıdaki verileri sağlayamamak veya uyumsuz bir cüzdan kullanmak, anlaşmazlık durumunda kaybetmenize yol açacaktır. \ +Anlaşmazlık durumunda hakeme UPX transferinin doğrulanmasını sağlamak UPX göndericisinin sorumluluğundadır.\n\n\ +Sadece normal genel adres gereklidir, ödeme kimliği gerekli değildir.\n\ +Bu süreç hakkında emin değilseniz uPlexa discord kanalını (https://discord.gg/vhdNSrV) \ +veya uPlexa Telegram Sohbetini (https://t.me/uplexaOfficial) ziyaret ederek daha fazla bilgi bulabilirsiniz. +# suppress inspection "UnusedProperty" +account.crypto.popup.arq.msg=Haveno'da ARQ ticareti yapmak için aşağıdaki gereksinimleri \ +anladığınızı ve yerine getirdiğinizi kabul etmeniz gerekmektedir:\n\n\ +ARQ gönderimi için, ya resmi ArQmA GUI cüzdanını ya da store-tx-info bayrağı etkin olan ArQmA CLI cüzdanını \ +kullanmanız gerekmektedir (yeni sürümlerde varsayılan). \ +Lütfen işlem anahtarına erişebildiğinizden emin olun, \ +çünkü bir anlaşmazlık durumunda bu gerekecektir.\n\ +arqma-wallet-cli (get_tx_key komutunu kullanın)\n\ +arqma-wallet-gui (geçmiş sekmesine gidin ve ödeme kanıtı için (P) butonuna tıklayın)\n\n\ +Normal blok kaşiflerinde transfer doğrulanamaz.\n\n\ +Bir anlaşmazlık durumunda hakeme aşağıdaki verileri sağlamanız gerekmektedir:\n\ +- İşlem özel anahtarı\n\ +- İşlem hash'i\n\ +- Alıcının genel adresi\n\n\ +Yukarıdaki verileri sağlayamamak veya uyumsuz bir cüzdan kullanmak, anlaşmazlık durumunda kaybetmenize yol açacaktır. \ +Anlaşmazlık durumunda hakeme ARQ transferinin doğrulanmasını \ +sağlamak ARQ göndericisinin sorumluluğundadır.\n\n\ +Sadece normal genel adres gereklidir, ödeme kimliği gerekli değildir.\n\ +Bu süreç hakkında emin değilseniz ArQmA discord kanalını (https://discord.gg/s9BQpJT) \ +veya ArQmA forumunu (https://labs.arqma.com) ziyaret ederek daha fazla bilgi bulabilirsiniz. +# suppress inspection "UnusedProperty" +account.crypto.popup.xmr.msg=Haveno'da XMR ticareti yapmak için aşağıdaki gereksinimi anlamanız gerekmektedir.\n\n\ +XMR satıyorsanız, bir anlaşmazlık durumunda arabulucuya veya \ +hakeme aşağıdaki bilgileri sağlayabilmeniz gerekmektedir:\n\ +- İşlem anahtarı (Tx Anahtarı, Tx Gizli Anahtarı veya Tx Özel Anahtarı)\n\ +- İşlem kimliği (Tx Kimliği veya Tx Hash)\n\ +- Hedef adres (alıcının adresi)\n\n\ +Popüler Monero cüzdanlarında bu bilgilerin nerede bulunacağını öğrenmek için wiki'yi inceleyin [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\n\ +Gerekli işlem verilerini sağlayamamak anlaşmazlıkları kaybetmenize yol açar.\n\n\ +Ayrıca Haveno'nun artık XMR işlemlerini otomatik onaylama özelliği sunduğunu, ancak bu özelliği Ayarlar'dan etkinleştirmeniz gerektiğini unutmayın.\n\n\ +Otomatik onaylama özelliği hakkında daha fazla bilgi için wiki'yi inceleyin: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. +# suppress inspection "UnusedProperty" +account.crypto.popup.msr.msg=Haveno'da MSR ticareti yapmak, aşağıdaki gereksinimleri anladığınızı \ +ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +MSR göndermek için resmi Masari GUI cüzdanını, store-tx-info bayrağı etkin olan (varsayılan olarak etkin) \ +Masari CLI cüzdanını veya Masari web cüzdanını (https://wallet.getmasari.org) kullanmanız gerekir. Bir anlaşmazlık durumunda gerekli olacağı \ +için tx anahtarına erişebildiğinizden emin olun.\n\ +masari-wallet-cli (get_tx_key komutunu kullanın)\n\ +masari-wallet-gui (geçmiş sekmesine gidin ve ödeme kanıtı için (P) düğmesine tıklayın)\n\n\ +Masari Web Cüzdan (Hesap -> işlem geçmişine gidin ve gönderdiğiniz işlemin detaylarını görüntüleyin)\n\n\ +Doğrulama cüzdan içinde yapılabilir.\n\ +masari-wallet-cli : check_tx_key komutunu kullanarak.\n\ +masari-wallet-gui : Gelişmiş > Kanıtla/Kontrol et sayfasında.\n\ +Doğrulama blok kaşifinde yapılabilir \n\ +Blok kaşifini açın (https://explorer.getmasari.org), işlem hash'inizi bulmak için arama çubuğunu kullanın.\n\ +İşlem bulunduğunda, 'Gönderim Kanıtı' alanına gidin ve gerekli bilgileri doldurun.\n\ +Bir anlaşmazlık durumunda arabulucuya veya hakeme aşağıdaki verileri sağlamanız gerekecektir:\n\ +- Tx özel anahtarı\n\ +- İşlem hash'i\n\ +- Alıcının genel adresi\n\n\ +Yukarıdaki verileri sağlamamak veya uyumsuz bir cüzdan kullanmak, anlaşmazlık durumunu kaybetmenize \ +neden olacaktır. MSR göndericisi, bir anlaşmazlık durumunda arabulucuya veya hakeme MSR \ +transferinin doğrulamasını sağlama sorumluluğunu taşır.\n\n\ +Ödeme kimliği gerekli değildir, sadece normal genel adres gereklidir.\n\ +Bu süreç hakkında emin değilseniz, Resmi Masari Discord'da (https://discord.gg/sMCwMqs) yardım isteyin. +# suppress inspection "UnusedProperty" +account.crypto.popup.blur.msg=Haveno'da BLUR ticareti yapmak, aşağıdaki gereksinimleri anladığınızı \ +ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +BLUR göndermek için Blur Network CLI veya GUI Cüzdanını kullanmalısınız.\n\n\ +CLI cüzdanını kullanıyorsanız, bir transfer gönderildikten sonra bir işlem hash'i (tx ID) görüntülenecektir. Bu bilgiyi \ +kaydetmelisiniz. Transferi gönderdikten hemen sonra, işlem özel anahtarını almak için 'get_tx_key' komutunu \ +kullanmalısınız. Bu adımı gerçekleştirmezseniz, anahtarı daha sonra almanız mümkün olmayabilir.\n\n\ +Blur Network GUI Cüzdanını kullanıyorsanız, işlem özel anahtarı ve işlem ID'si "Geçmiş" sekmesinde kolayca bulunabilir.\ +Gönderdikten hemen sonra, ilgili işlemi bulun. İşlemi içeren kutunun sağ alt \ +köşesindeki "?" simgesine tıklayın. Bu bilgiyi kaydetmelisiniz.\n\n\ +Arabuluculuk gerekli olduğunda, arabulucuya veya hakeme şu bilgileri sunmanız gerekecektir: 1.) işlem ID'si, \ +2.) işlem özel anahtarı ve 3.) alıcının adresi. Arabulucu veya hakem, Blur İşlem Görüntüleyicisini \ +(https://blur.cash/#tx-viewer) kullanarak BLUR transferini doğrulayacaktır.\n\n\ +Gerekli bilgileri arabulucuya veya hakeme sağlamamak, anlaşmazlık durumunu kaybetmenize neden olacaktır. Tüm anlaşmazlık durumlarında, \ +BLUR göndericisi, işlemleri arabulucuya veya hakeme doğrulama sorumluluğunu %100 oranında taşır.\n\n\ +Bu gereksinimleri anlamıyorsanız, Haveno'da ticaret yapmayın. Öncelikle Blur Network Discord'da (https://discord.gg/dMWaqVW) yardım isteyin. +# suppress inspection "UnusedProperty" +account.crypto.popup.solo.msg=Haveno'da Solo ticareti yapmak, aşağıdaki gereksinimleri \ +anladığınızı ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +Solo göndermek için Solo Network CLI Cüzdanını kullanmalısınız. \n\n\ +CLI cüzdanını kullanıyorsanız, bir transfer gönderildikten sonra bir işlem hash'i (tx ID) görüntülenecektir. \ +Bu bilgiyi kaydetmelisiniz. Transferi gönderdikten hemen sonra, işlem özel anahtarını almak için 'get_tx_key' \ +komutunu kullanmalısınız. Bu adımı gerçekleştirmezseniz, anahtarı daha sonra almanız mümkün olmayabilir. \n\n\ +Arabuluculuk gerekli olduğunda, arabulucuya veya hakeme şu bilgileri sunmanız gerekecektir: 1) işlem ID'si, \ +2) işlem özel anahtarı ve 3) alıcının adresi. Arabulucu veya hakem, Solo transferini Solo Blok Kaşifi'ni kullanarak \ +işlemi aratarak ve ardından "Gönderim kanıtı" işlevini kullanarak doğrulayacaktır (https://explorer.minesolo.com/).\n\n\ +Gerekli bilgileri arabulucuya veya hakeme sağlamamak, anlaşmazlık durumunu kaybetmenize neden olacaktır. Tüm anlaşmazlık durumlarında, \ +Solo göndericisi, işlemleri arabulucuya veya hakeme doğrulama sorumluluğunu %100 oranında taşır. \n\n\ +Bu gereksinimleri anlamıyorsanız, Haveno'da ticaret yapmayın. Öncelikle Solo Network Discord'da (https://discord.minesolo.com/) yardım isteyin. +# suppress inspection "UnusedProperty" +account.crypto.popup.cash2.msg=Haveno'da CASH2 ticareti yapmak, aşağıdaki gereksinimleri anladığınızı \ +ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +CASH2 göndermek için Cash2 Cüzdan sürüm 3 veya daha yüksek bir sürümünü kullanmalısınız. \n\n\ +Bir işlem gönderildikten sonra, işlem ID'si görüntülenecektir. Bu bilgiyi kaydetmelisiniz. Transferi \ +gönderdikten hemen sonra, işlem gizli anahtarını almak için simplewallet'te 'getTxKey' \ +komutunu kullanmalısınız. \n\n\ +Arabuluculuk gerekli olduğunda, arabulucuya veya hakeme şu bilgileri sunmanız gerekecektir: 1) işlem ID'si, \ +2) işlem gizli anahtarı ve 3) alıcının Cash2 adresi. Arabulucu veya hakem, CASH2 transferini Cash2 Blok Kaşifi'ni \ +kullanarak doğrulayacaktır (https://blocks.cash2.org).\n\n\ +Gerekli bilgileri arabulucuya veya hakeme sağlamamak, anlaşmazlık durumunu kaybetmenize neden olacaktır. Tüm anlaşmazlık durumlarında, \ +CASH2 göndericisi, işlemleri arabulucuya veya hakeme doğrulama sorumluluğunu %100 oranında taşır. \n\n\ +Bu gereksinimleri anlamıyorsanız, Haveno'da ticaret yapmayın. Öncelikle Cash2 Discord'da (https://discord.gg/FGfXAYN) yardım isteyin. +# suppress inspection "UnusedProperty" +account.crypto.popup.qwertycoin.msg=Haveno'da Qwertycoin ticareti yapmak, aşağıdaki gereksinimleri anladığınızı \ +ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +QWC göndermek için resmi QWC Cüzdan sürüm 5.1.3 veya daha yüksek bir sürümünü kullanmalısınız. \n\n\ +Bir işlem gönderildikten sonra, işlem ID'si görüntülenecektir. Bu bilgiyi kaydetmelisiniz. Transferi \ +gönderdikten hemen sonra, işlem gizli anahtarını almak için simplewallet'te 'get_Tx_Key' \ +komutunu kullanmalısınız. \n\n\ +Arabuluculuk gerekli olduğunda, arabulucuya veya hakeme şu bilgileri sunmanız gerekecektir: 1) işlem ID'si, \ +2) işlem gizli anahtarı ve 3) alıcının QWC adresi. Arabulucu veya hakem, QWC transferini QWC Blok Kaşifi'ni \ +kullanarak doğrulayacaktır (https://explorer.qwertycoin.org).\n\n\ +Gerekli bilgileri arabulucuya veya hakeme sağlamamak, anlaşmazlık durumunu kaybetmenize neden olacaktır. Tüm anlaşmazlık durumlarında, \ +QWC göndericisi, işlemleri arabulucuya veya hakeme doğrulama sorumluluğunu %100 oranında taşır. \n\n\ +Bu gereksinimleri anlamıyorsanız, Haveno'da ticaret yapmayın. Öncelikle QWC Discord'da (https://discord.gg/rUkfnpC) yardım isteyin. +# suppress inspection "UnusedProperty" +account.crypto.popup.drgl.msg=Haveno'da Dragonglass ticareti yapmak, aşağıdaki gereksinimleri anladığınızı \ +ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +Dragonglass'ın sağladığı gizlilik nedeniyle, bir işlem genel blockchain üzerinde doğrulanamaz. Gerektiğinde, ödemenizi \ +TXN-Private-Key'inizi kullanarak kanıtlayabilirsiniz.\n\ +TXN-Private Key, her işlem için otomatik olarak oluşturulan ve yalnızca DRGL cüzdanınızdan \ +erişilebilen tek seferlik bir anahtardır.\n\ +DRGL-cüzdan GUI'si (işlem detayları diyalogu içinde) veya Dragonglass CLI simplewallet'i (get_tx_key komutunu kullanarak) ile erişilebilir.\n\n\ +Her ikisi için de 'Oathkeeper' ve daha yüksek sürüm DRGL gereklidir.\n\n\ +Bir anlaşmazlık durumunda, arabulucuya veya hakeme şu verileri sağlamanız gerekecektir:\n\ +- TXN-Private key\n\ +- İşlem hash'i\n\ +- Alıcının genel adresi\n\n\ +Ödeme doğrulaması, yukarıdaki veriler kullanılarak (http://drgl.info/#check_txn) adresinde yapılabilir.\n\n\ +Yukarıdaki verileri sağlamamak veya uyumsuz bir cüzdan kullanmak, anlaşmazlık durumunu kaybetmenize \ +neden olacaktır. Bir anlaşmazlık durumunda, Dragonglass göndericisi DRGL transferinin doğrulamasını \ +arabulucuya veya hakeme sağlamakla sorumludur. PaymentID kullanımı gerekli değildir.\n\n\ +Bu sürecin herhangi bir bölümünden emin değilseniz, yardım için Dragonglass Discord'da (http://discord.drgl.info) ziyaret edin. +# suppress inspection "UnusedProperty" +account.crypto.popup.ZEC.msg=Zcash kullanırken sadece şeffaf adresleri (t ile başlayan) kullanabilirsiniz, \ +z-adreslerini (özel) kullanamazsınız, çünkü arabulucu veya hakem z-adresleri ile işlemi doğrulayamaz. +# suppress inspection "UnusedProperty" +account.crypto.popup.XZC.msg=Zcoin kullanırken sadece şeffaf (izlenebilir) adresleri kullanabilirsiniz, \ +izlenemez adresleri kullanamazsınız, çünkü arabulucu veya hakem blok kaşifinde izlenemez adreslerle işlemi doğrulayamaz. +# suppress inspection "UnusedProperty" +account.crypto.popup.grin.msg=GRIN, işlemi oluşturmak için gönderen ve alıcı arasında etkileşimli bir süreç gerektirir. \ + GRIN göndermek ve almak için GRIN proje web sayfasındaki talimatları takip ettiğinizden emin olun \ + (alıcı çevrimiçi olmalı veya en azından belirli bir zaman diliminde çevrimiçi olmalıdır). \n\n\ + Haveno sadece Grinbox (Wallet713) cüzdan URL formatını destekler. \n\n\ + GRIN göndericisi, GRIN'i başarıyla gönderdiklerine dair kanıt sağlamakla yükümlüdür. Eğer cüzdan bu kanıtı sağlayamıyorsa, \ + olası bir anlaşmazlık GRIN alıcısı lehine çözülecektir. \ + Lütfen işlem kanıtını destekleyen en son Grinbox yazılımını kullandığınızdan ve GRIN transferi ve alım sürecini nasıl \ + gerçekleştireceğinizi ve kanıt oluşturma sürecini anladığınızdan emin olun. \n\n\ + Daha fazla bilgi için https://github.com/vault713/wallet713/blob/master/docs/usage.md#transaction-proofs-grinbox-only \ + adresindeki Grinbox kanıt aracı belgelerine bakın. +# suppress inspection "UnusedProperty" +account.crypto.popup.beam.msg=BEAM, işlemi oluşturmak için gönderen ve alıcı arasında etkileşimli \ + bir süreç gerektirir. \n\n\ + BEAM göndermek ve almak için BEAM proje web sayfasındaki talimatları takip ettiğinizden emin olun \ + (alıcı çevrimiçi olmalı veya en azından belirli bir zaman diliminde çevrimiçi olmalıdır). \n\n\ + BEAM göndericisi, BEAM'i başarıyla gönderdiklerine dair kanıt sağlamakla yükümlüdür. \ + Böyle bir kanıt üretebilen cüzdan yazılımını kullandığınızdan emin olun. Cüzdan kanıt sağlayamıyorsa, olası \ + bir anlaşmazlık BEAM alıcısı lehine çözülecektir. +# suppress inspection "UnusedProperty" +account.crypto.popup.pars.msg=Haveno'da ParsiCoin ticareti yapmak, aşağıdaki gereksinimleri \ +anladığınızı ve yerine getirdiğinizi kabul etmenizi gerektirir:\n\n\ +PARS göndermek için resmi ParsiCoin Cüzdanı sürüm 3.0.0 veya daha yüksek bir sürüm kullanmalısınız. \n\n\ +İşlem Hash'inizi ve İşlem Anahtarınızı GUI Cüzdanınızdaki (ParsiPay) İşlemler bölümünden kontrol edebilirsiniz. \ +İşlem üzerine sağ tıklayıp detayları göster'e tıklamanız gerekmektedir. \n\n\ +Bir anlaşmazlık durumunda, arabulucuya veya hakeme şu bilgileri sağlamanız gerekecektir: 1) İşlem Hash'i, \ +2) İşlem Anahtarı ve 3) alıcının PARS adresi. Arabulucu veya hakem, ParsiCoin transferini ParsiCoin Blok Kaşifi'ni \ +(http://explorer.parsicoin.net/#check_payment) kullanarak doğrulayacaktır.\n\n\ +Gerekli bilgileri arabulucuya veya hakeme sağlayamamak, anlaşmazlık durumunu kaybetmenize neden olacaktır. Anlaşmazlık durumlarında, \ +ParsiCoin göndericisi, işlemleri arabulucuya veya hakeme doğrulama sorumluluğunun %100'ünü taşır. \n\n\ +Bu gereksinimleri anlamıyorsanız, Haveno'da ticaret yapmayın. İlk olarak, ParsiCoin Discord'da yardım arayın (https://discord.gg/c7qmFNh). + +# suppress inspection "UnusedProperty" +account.crypto.popup.blk-burnt.msg=Yakılmış blackcoin'leri ticaret yapmak için, aşağıdaki bilgileri bilmeniz gerekmektedir:\n\n\ +Yakılmış blackcoin'ler harcanamaz. Haveno'da bunları ticaret yapmak için, çıktı betikleri şu formda olmalıdır: \ +OP_RETURN OP_PUSHDATA, ardından hex kodlaması yapıldıktan sonra adresleri oluşturan ilişkili veri baytları.\n\ +Örneğin, adresi 666f6f (“foo” UTF-8'de) olan yakılmış blackcoin'ler şu betiğe sahip olacaktır:\n\n\ +OP_RETURN OP_PUSHDATA 666f6f\n\n\ +Yakılmış blackcoin'ler oluşturmak için, bazı cüzdanlarda bulunan “burn” RPC komutunu kullanabilirsiniz.\n\n\ +Olası kullanım durumları için, https://ibo.laboratorium.ee adresine bakabilirsiniz.\n\n\ +Yakılmış blackcoin'ler harcanamaz olduğundan, yeniden satılamazlar. “Yakılmış” blackcoin'ler satmak, \ +normal blackcoin'leri (ilişkili veriler hedef adresle eşit olacak şekilde) yakmak anlamına gelir.\n\n\ +Bir anlaşmazlık durumunda, BLK satıcısının işlem hash'ini sağlaması gerekmektedir. + +# suppress inspection "UnusedProperty" +account.crypto.popup.liquidmonero.msg=Haveno'da L-XMR ticareti yapmak, aşağıdakileri anlamanızı gerektirir:\n\n\ +Haveno'da bir ticaret için L-XMR alırken, mobil Blockstream Green Wallet uygulamasını veya \ +bir saklama/cüzdan borsası cüzdanını kullanamazsınız. L-XMR'yi yalnızca Liquid Elements Core cüzdanına veya \ +kör L-XMR adresiniz için körleme anahtarını elde etmenize izin veren başka bir L-XMR cüzdanına almanız gerekmektedir.\n\n\ +Arabuluculuk gerekli olursa veya bir ticaret anlaşmazlığı ortaya çıkarsa, arabulucuya veya geri ödeme \ +ajanına alıcı L-XMR adresinizin körleme anahtarını açıklamanız gerekecektir, böylece \ +kendi Elements Core full node'larında Gizli İşleminizin ayrıntılarını doğrulayabilirler.\n\n\ +Gerekli bilgileri arabulucuya veya geri ödeme ajana sağlayamamak, anlaşmazlık durumunu kaybetmenize \ +neden olacaktır. Tüm anlaşmazlık durumlarında, L-XMR alıcısı, arabulucuya veya geri ödeme \ +ajana kriptografik kanıt sağlama sorumluluğunun %100'ünü taşır.\n\n\ +Bu gereksinimleri anlamıyorsanız, Haveno'da L-XMR ticareti yapmayın. + +account.traditional.yourTraditionalAccounts=Ulusal para birimi hesaplarınız + +account.backup.title=Cüzdan yedeği +account.backup.location=Yedekleme konumu +account.backup.selectLocation=Yedekleme konumunu seçin +account.backup.backupNow=Şimdi yedekleyin (yedekleme şifrelenmemiştir!) +account.backup.appDir=Uygulama veri dizini +account.backup.openDirectory=Dizini aç +account.backup.openLogFile=Günlük dosyasını aç +account.backup.success=Yedekleme başarıyla kaydedildi:\n{0} +account.backup.directoryNotAccessible=Seçtiğiniz dizin erişilebilir değil. {0} + +account.password.removePw.button=Şifreyi kaldır +account.password.removePw.headline=Cüzdan şifre korumasını kaldır +account.password.setPw.button=Şifre ayarla +account.password.setPw.headline=Cüzdan için şifre koruması ayarla +account.password.info=Şifre koruması etkinleştirildiğinde, uygulama başlatıldığında, cüzdanınızdan monero çekilirken ve anahtar kelimelerinizi görüntülerken şifrenizi girmeniz gerekecek. +account.seed.backup.title=Cüzdan anahtar kelimelerinizi yedekleyin +account.seed.info=Lütfen hem cüzdan anahtar kelimelerini hem de tarihi not edin. Anahtar kelimeler ve tarih ile cüzdanınızı istediğiniz zaman kurtarabilirsiniz.\n\nAnahtar kelimeleri bir kağıt parçasına yazmalısınız. Bilgisayarda kaydetmeyin.\n\nLütfen anahtar kelimelerin bir yedekleme yerine geçmediğini unutmayın.\nUygulama durumunu ve verilerini kurtarmak için "Hesap/Yedekleme" ekranından tüm uygulama dizininin bir yedeğini oluşturmanız gerekmektedir. +account.seed.backup.warning=Lütfen anahtar kelimelerin bir yedekleme yerine geçmediğini unutmayın.\nUygulama durumunu ve verilerini kurtarmak için "Hesap/Yedekleme" ekranından tüm uygulama dizininin bir yedeğini oluşturmanız gerekmektedir. +account.seed.warn.noPw.msg=Cüzdan anahtar kelimelerinin görüntülenmesini koruyacak bir şifre ayarlamadınız.\n\n\ +Anahtar kelimeleri görüntülemek istiyor musunuz? +account.seed.warn.noPw.yes=Evet, ve bir daha sorma +account.seed.enterPw=Anahtar kelimeleri görüntülemek için şifreyi girin +account.seed.restore.info=Anahtar kelimelerden geri yükleme uygulamadan önce bir yedekleme yapmanız gerekmektedir. Cüzdan geri yüklemenin \ + yalnızca acil durumlar için olduğunu ve iç cüzdan veritabanında sorunlara neden olabileceğini unutmayın.\n\ + Bir yedekleme uygulamak için bir yol değildir! Önceki uygulama durumunu geri yüklemek için uygulama \ + veri dizininden bir yedekleme kullanın.\n\n\ + Geri yüklemeden sonra uygulama otomatik olarak kapanacaktır. Uygulamayı yeniden başlattıktan sonra Monero ağı ile yeniden \ + senkronize olacaktır. Bu biraz zaman alabilir ve özellikle eski bir cüzdansa ve birçok işlem varsa çok fazla \ + CPU tüketebilir. Bu süreci kesintiye uğratmaktan kaçının, aksi takdirde SPV zincir dosyasını \ + tekrar silmeniz veya geri yükleme sürecini tekrarlamanız gerekebilir. +account.seed.restore.ok=Tamam, geri yükle ve Haveno'yu kapat +account.keys.clipboard.warning=Cüzdan özel anahtarlarının son derece hassas finansal veriler olduğunu unutmayın.\n\n\ + ● Özel anahtarlarınızı isteyen herhangi bir kişiye vermemelisiniz, paranızı kullanma konusunda tamamen güvenilir olmadıklarından emin değilseniz! \n\n\ + ● Özel anahtar verilerini panoya kopyalamamalısınız, tamamen güvenli bir bilgisayar ortamı çalıştırdığınızdan emin olmadıkça, kötü amaçlı yazılım riskleri olmadığından emin olun. \n\n\ + Pek çok kişi bu şekilde Monero'sunu kaybetti. Herhangi bir şüpheniz varsa, bu diyaloğu hemen kapatın ve bilgili birinden yardım isteyin. + +#################################################################### +# Mobile notifications +#################################################################### + +account.notifications.setup.title=Kurulum +account.notifications.download.label=Mobil uygulamayı indir +account.notifications.waitingForWebCam=Web kamerası bekleniyor... +account.notifications.webCamWindow.headline=Telefondan QR kodu tarayın +account.notifications.webcam.label=Web kamerası kullan +account.notifications.webcam.button=QR kodu tara +account.notifications.noWebcam.button=Web kameram yok +account.notifications.erase.label=Telefondaki bildirimleri temizle +account.notifications.erase.title=Bildirimleri temizle +account.notifications.email.label=Eşleştirme kodu +account.notifications.email.prompt=E-posta ile aldığınız eşleştirme kodunu girin +account.notifications.settings.title=Ayarlar +account.notifications.useSound.label=Telefonda bildirim sesi çal +account.notifications.trade.label=Ticaret mesajlarını al +account.notifications.market.label=Teklif uyarılarını al +account.notifications.price.label=Fiyat uyarılarını al +account.notifications.priceAlert.title=Fiyat uyarıları +account.notifications.priceAlert.high.label=XMR fiyatı üstündeyse bildir +account.notifications.priceAlert.low.label=XMR fiyatı altındaysa bildir +account.notifications.priceAlert.setButton=Fiyat uyarısını ayarla +account.notifications.priceAlert.removeButton=Fiyat uyarısını kaldır +account.notifications.trade.message.title=Ticaret durumu değişti +account.notifications.trade.message.msg.conf=ID {0} olan ticaretin depozito işlemi onaylandı. \ + Lütfen Haveno uygulamanızı açın ve ödemeyi başlatın. +account.notifications.trade.message.msg.started=ID {0} olan ticaret için XMR alıcısı ödemeyi başlattı. +account.notifications.trade.message.msg.completed=ID {0} olan ticaret tamamlandı. +account.notifications.offer.message.title=Teklifiniz alındı +account.notifications.offer.message.msg=ID {0} olan teklifiniz alındı +account.notifications.dispute.message.title=Yeni uyuşmazlık mesajı +account.notifications.dispute.message.msg=ID {0} olan ticaret için bir uyuşmazlık mesajı aldınız + +account.notifications.marketAlert.title=Teklif uyarıları +account.notifications.marketAlert.selectPaymentAccount=Ödeme hesabına uyan teklifler +account.notifications.marketAlert.offerType.label=İlgilendiğim teklif türü +account.notifications.marketAlert.offerType.buy=Alım teklifleri (XMR satmak istiyorum) +account.notifications.marketAlert.offerType.sell=Satış teklifleri (XMR almak istiyorum) +account.notifications.marketAlert.trigger=Teklif fiyat mesafesi (%) +account.notifications.marketAlert.trigger.info=Bir fiyat mesafesi ayarlandığında, yalnızca gereksinimlerinizi karşılayan \ + (veya aşan) bir teklif yayınlandığında uyarı alırsınız. Örnek: XMR satmak istiyorsunuz, ancak yalnızca mevcut \ + piyasa fiyatına %2 primle satacaksınız. Bu alanı %2 olarak ayarlamak, yalnızca fiyatları mevcut piyasa fiyatının \ + %2 (veya daha fazla) üzerinde olan teklifler için uyarı almanızı sağlar. +account.notifications.marketAlert.trigger.prompt=Piyasa fiyatından yüzdelik mesafe (örneğin %2.50, -%0.50, vb.) +account.notifications.marketAlert.addButton=Teklif uyarısı ekle +account.notifications.marketAlert.manageAlertsButton=Teklif uyarılarını yönet +account.notifications.marketAlert.manageAlerts.title=Teklif uyarılarını yönet +account.notifications.marketAlert.manageAlerts.header.paymentAccount=Ödeme hesabı +account.notifications.marketAlert.manageAlerts.header.trigger=Tetikleyici fiyat +account.notifications.marketAlert.manageAlerts.header.offerType=Teklif türü +account.notifications.marketAlert.message.title=Teklif uyarısı +account.notifications.marketAlert.message.msg.below=altında +account.notifications.marketAlert.message.msg.above=üstünde +account.notifications.marketAlert.message.msg=Haveno teklif defterine {2} ({3} {4} piyasa fiyatı) fiyatıyla \ + ve ödeme yöntemi ''{5}'' olan yeni bir ''{0} {1}'' teklifi yayınlandı.\n\ + Teklif ID: {6}. +account.notifications.priceAlert.message.title={0} için fiyat uyarısı +account.notifications.priceAlert.message.msg=Fiyat uyarınız tetiklendi. Mevcut {0} fiyatı {1} {2} +account.notifications.noWebCamFound.warning=Web kamerası bulunamadı.\n\n\ + Lütfen eşleştirme kodunu ve şifreleme anahtarını mobil telefonunuzdan Haveno uygulamasına göndermek için e-posta seçeneğini kullanın. +account.notifications.priceAlert.warning.highPriceTooLow=Yüksek fiyat, düşük fiyattan büyük olmalıdır. +account.notifications.priceAlert.warning.lowerPriceTooHigh=Düşük fiyat, yüksek fiyattan düşük olmalıdır. + +#################################################################### +# Windows +#################################################################### + +inputControlWindow.headline=İşlem için girdileri seçin +inputControlWindow.balanceLabel=Bakiye + +contractWindow.title=Uyuşmazlık detayları +contractWindow.dates=Teklif tarihi / Ticaret tarihi +contractWindow.xmrAddresses=Monero adresi XMR alıcı / XMR satıcı +contractWindow.onions=Ağ adresi XMR alıcı / XMR satıcı +contractWindow.accountAge=Hesap yaşı XMR alıcı / XMR satıcı +contractWindow.numDisputes=Uyuşmazlık sayısı XMR alıcı / XMR satıcı +contractWindow.contractHash=Sözleşme hash + +displayAlertMessageWindow.headline=Önemli bilgi! +displayAlertMessageWindow.update.headline=Önemli güncelleme bilgisi! +displayAlertMessageWindow.update.download=İndir: +displayUpdateDownloadWindow.downloadedFiles=Dosyalar: +displayUpdateDownloadWindow.downloadingFile=İndiriliyor: {0} +displayUpdateDownloadWindow.verifiedSigs=Anahtarlarla doğrulanan imza: +displayUpdateDownloadWindow.status.downloading=Dosyalar indiriliyor... +displayUpdateDownloadWindow.status.verifying=İmza doğrulanıyor... +displayUpdateDownloadWindow.button.label=Yükleyiciyi indir ve imzayı doğrula +displayUpdateDownloadWindow.button.downloadLater=Daha sonra indir +displayUpdateDownloadWindow.button.ignoreDownload=Bu sürümü yok say +displayUpdateDownloadWindow.headline=Yeni bir Haveno güncellemesi mevcut! +displayUpdateDownloadWindow.download.failed.headline=İndirme başarısız +displayUpdateDownloadWindow.download.failed=İndirme başarısız oldu.\n\ + Lütfen manuel olarak indirip doğrulayın: [HYPERLINK:https://haveno.exchange/downloads] +displayUpdateDownloadWindow.installer.failed=Doğru yükleyici belirlenemedi. Lütfen manuel olarak indirip doğrulayın: \ + [HYPERLINK:https://haveno.exchange/downloads] +displayUpdateDownloadWindow.verify.failed=Doğrulama başarısız oldu.\n\ + Lütfen manuel olarak indirip doğrulayın: [HYPERLINK:https://haveno.exchange/downloads] +displayUpdateDownloadWindow.success=Yeni sürüm başarıyla indirildi ve imza doğrulandı.\n\n\ +Lütfen indirme dizinini açın, uygulamayı kapatın ve yeni sürümü yükleyin. +displayUpdateDownloadWindow.download.openDir=İndirme dizinini aç + +disputeSummaryWindow.title=Özet +disputeSummaryWindow.openDate=Ticket açılma tarihi +disputeSummaryWindow.role=Açan kişinin rolü +disputeSummaryWindow.payout=Ticaret miktarı ödemesi +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} ticaret miktarı ödemesi alır +disputeSummaryWindow.payout.getsAll=Maks. ödeme XMR {0} +disputeSummaryWindow.payout.custom=Özel ödeme +disputeSummaryWindow.payoutAmount.buyer=Alıcının ödeme miktarı +disputeSummaryWindow.payoutAmount.seller=Satıcının ödeme miktarı +disputeSummaryWindow.payoutAmount.invert=Kaybedeni yayıncı olarak kullan +disputeSummaryWindow.reason=Uyuşmazlık nedeni +disputeSummaryWindow.tradePeriodEnd=Ticaret dönemi sonu +disputeSummaryWindow.extraInfo=Ek bilgi +disputeSummaryWindow.delayedPayoutStatus=Gecikmeli Ödeme Durumu + +# IntelliJ tarafından tanınmayan dinamik değerler +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.BUG=Hata +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.USABILITY=Kullanılabilirlik +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.PROTOCOL_VIOLATION=Protokol ihlali +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.NO_REPLY=Cevap yok +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.SCAM=Dolandırıcılık +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.OTHER=Diğer +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.BANK_PROBLEMS=Banka sorunları +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.OPTION_TRADE=Opsiyon ticareti +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.SELLER_NOT_RESPONDING=Satıcı yanıt vermiyor +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.WRONG_SENDER_ACCOUNT=Yanlış gönderen hesabı +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.PEER_WAS_LATE=Karşı taraf geç kaldı +# inspection "UnusedProperty" uyarısını bastır +disputeSummaryWindow.reason.TRADE_ALREADY_SETTLED=Ticaret zaten tamamlandı + +disputeSummaryWindow.summaryNotes=Özet notlar +disputeSummaryWindow.addSummaryNotes=Özet notlar ekle +disputeSummaryWindow.close.button=Bileti kapat + +# Satır sonu veya token sırasını değiştirmeyin, yapı imza doğrulama için kullanılıyor +# inspection "TrailingSpacesInProperty" uyarısını bastır +disputeSummaryWindow.close.msg=Bilet {0} tarihinde kapatıldı\n\ + {1} düğüm adresi: {2}\n\n\ + Özet:\n\ + Ticaret ID: {3}\n\ + Para birimi: {4}\n\ + Uyuşmazlık nedeni: {5}\n\ + Ticaret miktarı: {6}\n\ + XMR alıcı için ödeme miktarı: {7}\n\ + XMR satıcı için ödeme miktarı: {8}\n\n\ + Özet notlar:\n{9}\n + +# Satır sonu veya token sırasını değiştirmeyin, yapı imza doğrulama için kullanılıyor +disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} + +disputeSummaryWindow.close.nextStepsForMediation=\nSonraki adımlar:\n\ +Ticareti açın ve arabulucudan gelen öneriyi kabul edin veya reddedin +disputeSummaryWindow.close.nextStepsForRefundAgentArbitration=\nSonraki adımlar:\n\ +Bir hakemle uyuşmazlık açıldı. Uyuşmazlığı çözmek için "Destek" sekmesinde hakemle sohbet edebilirsiniz. +disputeSummaryWindow.close.closePeer=Alım-satım taraflarının biletini de kapatmanız gerekiyor! +disputeSummaryWindow.close.txDetails.headline=Geri ödeme işlemini yayınla +# inspection "TrailingSpacesInProperty" uyarısını bastır +disputeSummaryWindow.close.txDetails.buyer=Alıcı {0} adresine {1} alır\n +# inspection "TrailingSpacesInProperty" uyarısını bastır +disputeSummaryWindow.close.txDetails.seller=Satıcı {0} adresine {1} alır\n +disputeSummaryWindow.close.txDetails=Harcanıyor: {0}\n\ + {1}{2}\ + İşlem ücreti: {3}\n\n\ + Bu işlemi yayınlamak istediğinizden emin misiniz? + +disputeSummaryWindow.close.noPayout.headline=Ödeme yapmadan kapat +disputeSummaryWindow.close.noPayout.text=Herhangi bir ödeme yapmadan kapatmak istiyor musunuz? + +disputeSummaryWindow.close.alreadyPaid.headline=Ödeme zaten yapıldı +disputeSummaryWindow.close.alreadyPaid.text=Bu uyuşmazlık için başka bir ödeme yapmak üzere istemciyi yeniden başlatın + +emptyWalletWindow.headline={0} acil durum cüzdan aracı +emptyWalletWindow.info=Bunu yalnızca arayüzden fonlarınıza erişemiyorsanız acil durumlarda kullanın.\n\n\ +Bu aracı kullanırken, tüm açık teklifler otomatik olarak kapatılacaktır.\n\n\ +Bu aracı kullanmadan önce, veri dizininizi yedekleyin. \ +Bunu "Hesap/Yedekleme" altında yapabilirsiniz.\n\n\ +Lütfen sorunuzu bildirin ve GitHub'da veya Haveno forumunda bir hata raporu oluşturun ki sorunun ne olduğunu araştırabilelim. +emptyWalletWindow.balance=Mevcut cüzdan bakiyeniz +emptyWalletWindow.address=Hedef adresiniz +emptyWalletWindow.button=Tüm fonları gönder +emptyWalletWindow.openOffers.warn=Açık teklifleriniz var ve cüzdanı boşaltırsanız bu teklifler kaldırılacaktır.\nCüzdanınızı boşaltmak istediğinizden emin misiniz? +emptyWalletWindow.openOffers.yes=Evet, eminim +emptyWalletWindow.sent.success=Cüzdan bakiyeniz başarıyla transfer edildi. + +enterPrivKeyWindow.headline=Kayıt için özel anahtar girin + +filterWindow.headline=Filtre listesini düzenle +filterWindow.offers=Filtrelenmiş teklifler (virgülle ayrılmış) +filterWindow.onions=Alışverişten yasaklanan adresler (virgülle ayrılmış) +filterWindow.bannedFromNetwork=Ağdan yasaklanan adresler (virgülle ayrılmış) +filterWindow.accounts=Filtrelenmiş alışveriş hesabı verileri:\nFormat: virgülle ayrılmış [ödeme yöntemi id | veri alanı | değer] listesi +filterWindow.bannedCurrencies=Filtrelenmiş para birimi kodları (virgülle ayrılmış) +filterWindow.bannedPaymentMethods=Filtrelenmiş ödeme yöntemi kimlikleri (virgülle ayrılmış) +filterWindow.bannedAccountWitnessSignerPubKeys=Filtrelenmiş hesap tanık imzalayıcı açık anahtarları (virgülle ayrılmış açık anahtarların hex kodları) +filterWindow.bannedPrivilegedDevPubKeys=Filtrelenmiş ayrıcalıklı geliştirici açık anahtarları (virgülle ayrılmış açık anahtarların hex kodları) +filterWindow.arbitrators=Filtrelenmiş hakemler (virgülle ayrılmış onion adresleri) +filterWindow.mediators=Filtrelenmiş arabulucular (virgülle ayrılmış onion adresleri) +filterWindow.refundAgents=Filtrelenmiş geri ödeme ajanları (virgülle ayrılmış onion adresleri) +filterWindow.seedNode=Filtrelenmiş seed düğümleri (virgülle ayrılmış onion adresleri) +filterWindow.priceRelayNode=Filtrelenmiş fiyat aktarma düğümleri (virgülle ayrılmış adresler) +filterWindow.xmrNode=Filtrelenmiş Monero düğümleri (virgülle ayrılmış adresler + port) +filterWindow.preventPublicXmrNetwork=Genel Monero ağının kullanımını engelle +filterWindow.disableAutoConf=Otomatik onayı devre dışı bırak +filterWindow.autoConfExplorers=Filtrelenmiş otomatik onay gezginleri (virgülle ayrılmış adresler) +filterWindow.disableTradeBelowVersion=Alım satım için gereken minimum sürüm +filterWindow.add=Filtre ekle +filterWindow.remove=Filtreyi kaldır +filterWindow.xmrFeeReceiverAddresses=XMR ücret alıcı adresleri +filterWindow.disableApi=API'yi devre dışı bırak +filterWindow.disableMempoolValidation=Mempool doğrulamasını devre dışı bırak + +offerDetailsWindow.minXmrAmount=Min. XMR miktarı +offerDetailsWindow.min=(min. {0}) +offerDetailsWindow.distance=(piyasa fiyatından uzaklık: {0}) +offerDetailsWindow.myTradingAccount=Alışveriş hesabım +offerDetailsWindow.bankId=Banka kimliği (ör. BIC veya SWIFT) +offerDetailsWindow.countryBank=Yapıcı'nın banka ülkesi +offerDetailsWindow.commitment=Taahhüt +offerDetailsWindow.agree=Kabul ediyorum +offerDetailsWindow.tac=Şartlar ve koşullar +offerDetailsWindow.confirm.maker=Onayla: {0} monero teklifi yerleştir +offerDetailsWindow.confirm.makerCrypto=Onayla: {0} {1} teklifi yerleştir +offerDetailsWindow.confirm.taker=Onayla: {0} monero teklifi al +offerDetailsWindow.confirm.takerCrypto=Onayla: {0} {1} teklifi al +offerDetailsWindow.creationDate=Oluşturma tarihi +offerDetailsWindow.makersOnion=Yapıcı'nın onion adresi +offerDetailsWindow.challenge=Teklif şifresi + +qRCodeWindow.headline=QR Kodu +qRCodeWindow.msg=Harici cüzdanınızdan Haveno cüzdanınızı finanse etmek için bu QR kodunu kullanın. +qRCodeWindow.request=Ödeme talebi:\n{0} + +selectDepositTxWindow.headline=Uyuşmazlık için yatırma işlemini seçin +selectDepositTxWindow.msg=Yatırma işlemi ticarette saklanmadı.\n\ +Lütfen cüzdanınızdaki mevcut çoklu imza işlemlerinden birini seçin ve \ +başarısız ticarette kullanılan yatırma işlemi olarak işaretleyin.\n\n\ +Doğru işlemi, ticaret detayları penceresini açarak (listeden ticaret kimliğine tıklayın) \ +ve ticaret ücreti ödeme işlem çıktısını, çoklu imza yatırma işlemini (adres 3 ile başlar) \ +gördüğünüz sonraki işleme kadar takip ederek bulabilirsiniz. Bu işlem kimliği burada sunulan listede görünmelidir. \ +Doğru işlemi bulduğunuzda, burada o işlemi seçin ve devam edin.\n\n\ +Bu rahatsızlık için özür dileriz, ancak bu hata durumu çok nadiren gerçekleşmelidir \ +ve gelecekte bunu çözmek için daha iyi yollar bulmaya çalışacağız. +selectDepositTxWindow.select=Yatırma işlemini seçin + +sendAlertMessageWindow.headline=Global bildirim gönder +sendAlertMessageWindow.alertMsg=Uyarı mesajı +sendAlertMessageWindow.enterMsg=Mesajı girin +sendAlertMessageWindow.isSoftwareUpdate=Yazılım güncelleme bildirimi +sendAlertMessageWindow.isUpdate=Tam sürüm +sendAlertMessageWindow.isPreRelease=Ön sürüm +sendAlertMessageWindow.version=Yeni sürüm no. +sendAlertMessageWindow.send=Bildirimi gönder +sendAlertMessageWindow.remove=Bildirimi kaldır + +sendPrivateNotificationWindow.headline=Özel mesaj gönder +sendPrivateNotificationWindow.privateNotification=Özel bildirim +sendPrivateNotificationWindow.enterNotification=Bildirim girin +sendPrivateNotificationWindow.send=Özel bildirimi gönder + +showWalletDataWindow.walletData=Cüzdan verileri +showWalletDataWindow.includePrivKeys=Özel anahtarları dahil et + +setXMRTxKeyWindow.headline=XMR gönderimini kanıtla +setXMRTxKeyWindow.note=Aşağıdaki işlem bilgisini eklemek, daha hızlı ticaret için otomatik onayı etkinleştirir. Daha fazlasını görün: https://haveno.exchange/wiki/Trading_Monero +setXMRTxKeyWindow.txHash=İşlem Kimliği (isteğe bağlı) +setXMRTxKeyWindow.txKey=İşlem anahtarı (isteğe bağlı) + +# Yasal nedenlerden dolayı tac'ı çevirmiyoruz. Her dilde avukatlar tarafından kontrol edilmiş çevirilere ihtiyacımız var +# Ve bu şu anda çok maliyetli. +tacWindow.headline=Kullanıcı sözleşmesi +tacWindow.agree=Kabul ediyorum +tacWindow.disagree=Kabul etmiyorum ve çıkıyorum +tacWindow.arbitrationSystem=Uyuşmazlık çözümü + +tradeDetailsWindow.headline=Ticaret +tradeDetailsWindow.disputedPayoutTxId=Uyuşmazlık konusu olan ödeme işlem kimliği +tradeDetailsWindow.tradeDate=Ticaret tarihi +tradeDetailsWindow.txFee=Madencilik ücreti +tradeDetailsWindow.tradePeersOnion=Ticaret ortaklarının onion adresi +tradeDetailsWindow.tradePeersPubKeyHash=Ticaret ortaklarının açık anahtar hash'i +tradeDetailsWindow.tradeState=Ticaret durumu +tradeDetailsWindow.tradePhase=Ticaret aşaması +tradeDetailsWindow.agentAddresses=Hakem/Arabulucu +tradeDetailsWindow.detailData=Detay verileri + +txDetailsWindow.headline=İşlem Detayları +txDetailsWindow.xmr.noteSent=XMR gönderdiniz. +txDetailsWindow.xmr.noteReceived=XMR aldınız. +txDetailsWindow.sentTo=Gönderilen adres +txDetailsWindow.receivedWith=Alındı ile +txDetailsWindow.txId=İşlem Kimliği (TxId) + +closedTradesSummaryWindow.headline=Ticaret geçmişi özeti +closedTradesSummaryWindow.totalAmount.title=Toplam ticaret miktarı +closedTradesSummaryWindow.totalAmount.value={0} (mevcut piyasa fiyatıyla {1}) +closedTradesSummaryWindow.totalVolume.title={0} içinde toplam ticaret hacmi +closedTradesSummaryWindow.totalMinerFee.title=Tüm madenci ücretlerinin toplamı +closedTradesSummaryWindow.totalMinerFee.value={0} (toplam ticaret miktarının {1}'i) +closedTradesSummaryWindow.totalTradeFeeInXmr.title=XMR olarak ödenen tüm ticaret ücretlerinin toplamı +closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} (toplam ticaret miktarının {1}'i) +walletPasswordWindow.headline=Kilidi açmak için şifre girin + +torNetworkSettingWindow.header=Tor ağı ayarları +torNetworkSettingWindow.noBridges=Köprüleri kullanma +torNetworkSettingWindow.providedBridges=Sağlanan köprülerle bağlan +torNetworkSettingWindow.customBridges=Özel köprüleri girin +torNetworkSettingWindow.transportType=Taşıma türü +torNetworkSettingWindow.obfs3=obfs3 +torNetworkSettingWindow.obfs4=obfs4 (önerilen) +torNetworkSettingWindow.meekAmazon=meek-amazon +torNetworkSettingWindow.meekAzure=meek-azure +torNetworkSettingWindow.enterBridge=Bir veya daha fazla köprü rölesi girin (satır başına bir tane) +torNetworkSettingWindow.enterBridgePrompt=adres:port yazın +torNetworkSettingWindow.restartInfo=Değişikliklerin uygulanması için yeniden başlatmanız gerekiyor +torNetworkSettingWindow.openTorWebPage=Tor projesi web sayfasını aç +torNetworkSettingWindow.deleteFiles.header=Bağlantı sorunları mı? +torNetworkSettingWindow.deleteFiles.info=Başlangıçta tekrarlanan bağlantı sorunları yaşıyorsanız, eski Tor dosyalarını silmek yardımcı olabilir. Bunu yapmak için aşağıdaki düğmeye tıklayın ve ardından yeniden başlatın. +torNetworkSettingWindow.deleteFiles.button=Eski Tor dosyalarını sil ve kapat +torNetworkSettingWindow.deleteFiles.progress=Tor kapatma işlemi devam ediyor +torNetworkSettingWindow.deleteFiles.success=Eski Tor dosyaları başarıyla silindi. Lütfen yeniden başlatın. +torNetworkSettingWindow.bridges.header=Tor engellendi mi? +torNetworkSettingWindow.bridges.info=İnternet sağlayıcınız veya ülkeniz tarafından Tor engelleniyorsa, Tor köprülerini kullanmayı deneyebilirsiniz.\n\ + Köprüler ve takılabilir taşıma hakkında daha fazla bilgi edinmek için: + https://bridges.torproject.org/bridges web sayfasını ziyaret edin. + +feeOptionWindow.useXMR=XMR kullan +feeOptionWindow.fee={0} (≈ {1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) + + +#################################################################### +# Popups +#################################################################### + +popup.headline.notification=Bildirim +popup.headline.instruction=Lütfen dikkat: +popup.headline.attention=Dikkat +popup.headline.backgroundInfo=Arka plan bilgisi +popup.headline.feedback=Tamamlandı +popup.headline.confirmation=Onay +popup.headline.information=Bilgi +popup.headline.warning=Uyarı +popup.headline.error=Hata + +popup.doNotShowAgain=Tekrar gösterme +popup.reportError.log=Günlük dosyasını aç +popup.reportError.gitHub=GitHub hata izleyicisine bildir +popup.reportError={0}\n\nYazılımı geliştirmemize yardımcı olmak için lütfen bu hatayı https://github.com/haveno-dex/haveno/issues adresinde yeni bir sorun açarak bildirin.\n\ +Yukarıdaki hata mesajı, aşağıdaki düğmelerden birine tıkladığınızda panoya kopyalanacaktır.\n\ +Hata ayıklamayı kolaylaştırmak için \"Günlük dosyasını aç\" düğmesine basarak günlük dosyasını kaydedip hata raporunuza eklemeniz yararlı olacaktır. + +popup.error.tryRestart=Lütfen uygulamanızı yeniden başlatmayı ve ağ bağlantınızı kontrol etmeyi deneyin. +popup.error.takeOfferRequestFailed=Teklif alınırken bir hata oluştu:\n{0} + +error.spvFileCorrupted=SPV zincir dosyası okunurken bir hata oluştu.\nSPV zincir dosyası bozulmuş olabilir.\n\nHata mesajı: {0}\n\nSilip yeniden senkronize etmek istiyor musunuz? +error.deleteAddressEntryListFailed=AddressEntryList dosyası silinemedi.\nHata: {0} +error.closedTradeWithUnconfirmedDepositTx=Ticaret ID'si {0} olan kapalı ticaretin yatırma işlemi \ + hala onaylanmadı.\n\n\ + İşlemin geçerli olup olmadığını görmek için \"Ayarlar/Ağ bilgisi\" bölümünde bir SPV yeniden senkronizasyonu yapın. +error.closedTradeWithNoDepositTx=Ticaret ID'si {0} olan kapalı ticaretin yatırma işlemi null.\n\n\ + Kapalı ticaret listesini temizlemek için uygulamayı yeniden başlatın. + +popup.warning.walletNotInitialized=Cüzdan henüz başlatılmadı +popup.warning.wrongVersion=Muhtemelen bu bilgisayar için yanlış Haveno sürümünü kullanıyorsunuz.\n\ +Bilgisayarınızın mimarisi: {0}.\n\ +Yüklediğiniz Haveno ikilisi: {1}.\n\ +Lütfen kapatın ve doğru sürümü ({2}) yeniden yükleyin. +popup.warning.incompatibleDB=Uyumsuz veri tabanı dosyaları tespit ettik!\n\n\ +Bu veri tabanı dosyaları mevcut kod tabanımızla uyumlu değil:\n{0}\n\n\ +Bozuk dosyanın yedeğini aldık ve yeni bir veri tabanı sürümüne varsayılan değerleri uyguladık.\n\n\ +Yedek şu konumda bulunuyor:\n\ +{1}/db/backup_of_corrupted_data.\n\n\ +En son Haveno sürümünün yüklü olup olmadığını kontrol edin.\n\ +Bunu şu adresten indirebilirsiniz: [HYPERLINK:https://haveno.exchange/downloads].\n\n\ +Lütfen uygulamayı yeniden başlatın. +popup.warning.startupFailed.twoInstances=Haveno zaten çalışıyor. İki Haveno örneği çalıştıramazsınız. +popup.warning.tradePeriod.halfReached=Ticaret ID'si {0} olan ticaretiniz, izin verilen maksimum ticaret süresinin yarısına ulaştı ve hala tamamlanmadı.\n\nTicaret süresi {1} tarihinde sona eriyor\n\nDaha fazla bilgi için \"Portföy/Açık ticaretler\" bölümünde ticaret durumunuzu kontrol edin. +popup.warning.tradePeriod.ended=Ticaret ID'si {0} olan ticaretiniz, izin verilen maksimum ticaret süresine ulaştı ve tamamlanmadı.\n\n\ + Ticaret süresi {1} tarihinde sona erdi\n\n\ + Hakemle iletişime geçmek için \"Portföy/Açık ticaretler\" bölümünde ticaretinizi kontrol edin. +popup.warning.noTradingAccountSetup.headline=Bir ticaret hesabı kurmadınız +popup.warning.noTradingAccountSetup.msg=Bir teklif oluşturmadan önce bir ulusal para birimi veya kripto para hesabı kurmanız gerekmektedir.\nHesap kurmak istiyor musunuz? +popup.warning.noArbitratorsAvailable=Mevcut hakem yok. +popup.warning.noMediatorsAvailable=Mevcut arabulucu yok. +popup.warning.notFullyConnected=Ağa tamamen bağlanana kadar beklemeniz gerekiyor.\nBaşlangıçta yaklaşık 2 dakika sürebilir. +popup.warning.notSufficientConnectionsToXmrNetwork=Monero ağına en az {0} bağlantınız olana kadar beklemeniz gerekmektedir. +popup.warning.downloadNotComplete=Eksik Monero bloklarının indirilmesi tamamlanana kadar beklemeniz gerekmektedir. +popup.warning.walletNotSynced=Haveno cüzdanı en son blok zinciri yüksekliği ile senkronize değil. Lütfen cüzdanın senkronize olmasını bekleyin veya bağlantınızı kontrol edin. +popup.warning.removeOffer=Bu teklifi kaldırmak istediğinizden emin misiniz? +popup.warning.tooLargePercentageValue=%100 veya daha büyük bir yüzde değeri belirleyemezsiniz. +popup.warning.examplePercentageValue=Lütfen \"5.4\" gibi bir yüzde sayısı girin +popup.warning.noPriceFeedAvailable=Bu para birimi için fiyat beslemesi yok. Yüzde tabanlı fiyat kullanamazsınız.\nLütfen sabit fiyatı seçin. +popup.warning.sendMsgFailed=Ticaret ortağınıza mesaj gönderme başarısız oldu.\nLütfen tekrar deneyin ve başarısız olmaya devam ederse bir hata bildirin. +popup.warning.messageTooLong=Mesajınız izin verilen maksimum boyutu aşıyor. Lütfen birkaç parça halinde gönderin veya https://pastebin.com gibi bir servise yükleyin. +popup.warning.lockedUpFunds=Başarısız bir ticaretten kilitli fonlarınız var.\n\ + Kilitli bakiye: {0} \n\ + Yatırma tx adresi: {1}\n\ + Ticaret ID'si: {2}.\n\n\ + Lütfen açık ticaretler ekranında ticareti seçerek ve \"alt + o\" veya \"option + o\" tuşlarına basarak bir destek bileti açın. + +popup.warning.makerTxInvalid=Bu teklif geçerli değil. Lütfen farklı bir teklif seçin.\n\n +takeOffer.cancelButton=Teklifi iptal et +takeOffer.warningButton=Yine de yoksay ve devam et + +# suppress inspection "UnusedProperty" +popup.warning.nodeBanned={0} düğümlerinden biri yasaklandı. +# suppress inspection "UnusedProperty" +popup.warning.priceRelay=fiyat rölesi +popup.warning.seed=anahtar kelime +popup.warning.mandatoryUpdate.trading=Lütfen en son Haveno sürümüne güncelleyin. \ + Eski sürümler için ticareti devre dışı bırakan zorunlu bir güncelleme yayınlandı. \ + Daha fazla bilgi için lütfen Haveno Forumunu kontrol edin. +popup.warning.noFilter=Tohum düğümlerinden bir filtre nesnesi almadık. Lütfen Haveno ağ yöneticilerini bir filtre nesnesi kaydetmek için ctrl + f ile bilgilendirin. +popup.warning.burnXMR=Bu işlem mümkün değil, çünkü {0} tutarındaki madencilik ücretleri, transfer edilecek {1} tutarını aşacaktır. \ + Lütfen madencilik ücretleri tekrar düşük olana kadar bekleyin veya transfer etmek için daha fazla XMR biriktirin. + +popup.warning.openOffer.makerFeeTxRejected=Teklif ID'si {0} olan teklif için Monero ağı tarafından yapıcı ücret işlemi reddedildi.\n\ + İşlem ID'si={1}.\n\ + Daha fazla sorun yaşamamak için teklif kaldırıldı.\n\ + Lütfen \"Ayarlar/Ağ bilgisi\" bölümüne gidin ve bir SPV yeniden senkronizasyonu yapın.\n\ + Daha fazla yardım için lütfen Haveno destek kanalına Haveno Keybase takımında başvurun. + +popup.warning.trade.txRejected.tradeFee=işlem ücreti +popup.warning.trade.txRejected.deposit=yatırma +popup.warning.trade.txRejected=Ticaret ID'si {1} olan ticaret için {0} işlemi Monero ağı tarafından reddedildi.\n\ + İşlem ID'si={2}\n\ + Ticaret başarısız ticaretlere taşındı.\n\ + Lütfen \"Ayarlar/Ağ bilgisi\" bölümüne gidin ve bir SPV yeniden senkronizasyonu yapın.\n\ + Daha fazla yardım için lütfen Haveno destek kanalına Haveno Keybase takımında başvurun. + +popup.warning.openOfferWithInvalidMakerFeeTx=ID {0} olan teklif için yapıcı ücret işlemi geçersiz.\n\ + İşlem ID={1}.\n\ + Lütfen "Ayarlar/Ağ bilgisi" bölümüne gidin ve bir SPV yeniden senkronizasyonu yapın.\n\ + Daha fazla yardım için lütfen Haveno Keybase takımındaki Haveno destek kanalına başvurun. + +popup.info.cashDepositInfo=Nakit yatırma işlemini gerçekleştirebilmek için bölgenizde bir banka şubesinin olduğundan emin olun.\n\ + Satıcının bankasının banka ID'si (BIC/SWIFT) şudur: {0}. +popup.info.cashDepositInfo.confirm=Yatırma işlemini gerçekleştirebileceğimi onaylıyorum +popup.info.shutDownWithOpenOffers=Haveno kapatılıyor, ancak açık teklifler var. \n\n\ + Bu teklifler Haveno kapalıyken P2P ağında mevcut olmayacak, ancak Haveno'yu bir sonraki başlattığınızda tekrar P2P ağına yayınlanacaklar.\n\n\ + Tekliflerinizi çevrimiçi tutmak için Haveno'yu çalışır durumda tutun ve bu bilgisayarın da çevrimiçi kalmasını sağlayın \ + (yani, uyku moduna geçmemesini sağlayın... monitör bekleme modu sorun yaratmaz). +popup.info.shutDownWithTradeInit={0}\n\ + Bu ticaret henüz başlatmayı tamamlamadı; şimdi kapatmak muhtemelen onu bozacaktır. Lütfen bir dakika bekleyin ve tekrar deneyin. +popup.info.shutDownWithDisputeInit=Haveno kapatılıyor, ancak bekleyen bir Uyuşmazlık sistemi mesajı var.\n\ + Lütfen kapatmadan önce bir dakika bekleyin. +popup.info.shutDownQuery=Haveno'dan çıkmak istediğinize emin misiniz? +popup.info.qubesOSSetupInfo=Görünüşe göre Haveno'yu Qubes OS üzerinde çalıştırıyorsunuz. \n\n\ + Lütfen Haveno küpünüzün Kurulum Kılavuzumuza göre ayarlandığından emin olun [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. +popup.info.p2pStatusIndicator.red={0}\n\n\ + Düğümünüz P2P ağına bağlı değil. Haveno bu durumda çalışamaz. +popup.info.p2pStatusIndicator.yellow={0}\n\n\ + Düğümünüzün Tor giriş bağlantısı yok. Haveno çalışacaktır, ancak bu durum birkaç saat boyunca devam ederse bağlantı sorunlarına işaret edebilir. +popup.info.p2pStatusIndicator.green={0}\n\n\ + İyi haber, P2P bağlantı durumunuz sağlıklı görünüyor! +popup.info.firewallSetupInfo=Görünüşe göre bu makine gelen Tor bağlantılarını engelliyor. \ + Bu, Qubes/VirtualBox/Whonix gibi VM ortamlarında olabilir. \n\n\ + Ortamınızı gelen Tor bağlantılarını kabul edecek şekilde ayarlayın, aksi takdirde kimse tekliflerinizi alamaz. +popup.warn.downGradePrevention=Sürüm {0} den sürüm {1} e düşürme desteklenmiyor. Lütfen en son Haveno sürümünü kullanın. +popup.warn.daoRequiresRestart=DAO durumu senkronize edilirken bir sorun oluştu. Sorunu çözmek için uygulamayı yeniden başlatmalısınız. + +popup.privateNotification.headline=Önemli özel bildirim! + +popup.xmrLocalNode.msg=Haveno bu makinede (localhost'ta) çalışan bir Monero düğümü tespit etti.\n\n\ + Düğümün tamamen senkronize olduğundan emin olun Haveno'yu başlatmadan önce. +popup.shutDownInProgress.headline=Kapatma işlemi devam ediyor +popup.shutDownInProgress.msg=Uygulamayı kapatmak birkaç saniye sürebilir.\nLütfen bu işlemi kesmeyin. + +popup.attention.forTradeWithId=ID'si {0} olan ticaret için bildirim +popup.attention.welcome.stagenet=Haveno test sürümüne hoş geldiniz!\n\n\ +Bu platform Haveno'nun protokolünü test etmenizi sağlar. Talimatları izlediğinizden emin olun [HYPERLINK:https://github.com/haveno-dex/haveno/blob/master/docs/installing.md].\n\n\ +Herhangi bir sorunla karşılaşırsanız, lütfen bir sorun bildirerek bize bildirin [HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\ +Bu bir test sürümüdür. Gerçek para kullanmayın! +popup.attention.welcome.mainnet=Haveno'ya hoş geldiniz!\n\n\ +Bu platform, Monero'yu itibari para birimleri veya diğer kripto para birimleriyle merkezi olmayan bir şekilde ticaret yapmanızı sağlar.\n\n\ +Yeni bir ödeme hesabı oluşturarak ve ardından bir teklif yaparak veya teklif alarak başlayın.\n\n\ +Herhangi bir sorunla karşılaşırsanız, lütfen bir sorun bildirerek bize bildirin [HYPERLINK:https://github.com/haveno-dex/haveno/issues/new]. +popup.attention.welcome.mainnet.test=Haveno'ya hoş geldiniz!\n\n\ +Bu platform, Monero'yu itibari para birimleri veya diğer kripto para birimleriyle merkezi olmayan bir şekilde ticaret yapmanızı sağlar.\n\n\ +Yeni bir ödeme hesabı oluşturarak ve ardından bir teklif yaparak veya teklif alarak başlayın.\n\n\ +Herhangi bir sorunla karşılaşırsanız, lütfen bir sorun bildirerek bize bildirin [HYPERLINK:https://github.com/haveno-dex/haveno/issues/new].\n\n\ +Haveno kısa bir süre önce kamu testi için yayınlandı. Lütfen küçük miktarlar kullanın! + +popup.info.multiplePaymentAccounts.headline=Birden fazla ödeme hesabı mevcut +popup.info.multiplePaymentAccounts.msg=Bu teklif için birden fazla ödeme hesabınız var. Lütfen doğru olanı seçtiğinizden emin olun. + +popup.accountSigning.selectAccounts.headline=Ödeme hesaplarını seçin +popup.accountSigning.selectAccounts.description=Ödeme yöntemi ve zaman noktasına bağlı olarak, bir alıcıya ödeme yapılan bir uyuşmazlıkla bağlantılı tüm ödeme hesapları sizin için seçilecektir. +popup.accountSigning.selectAccounts.signAll=Tüm ödeme yöntemlerini imzala +popup.accountSigning.selectAccounts.datePicker=Hesapların imzalanacağı zamanı seçin + +popup.accountSigning.confirmSelectedAccounts.headline=Seçilen ödeme hesaplarını onaylayın +popup.accountSigning.confirmSelectedAccounts.description=Girdiğiniz bilgilere göre, {0} ödeme hesabı seçilecektir. +popup.accountSigning.confirmSelectedAccounts.button=Ödeme hesaplarını onayla +popup.accountSigning.signAccounts.headline=Ödeme hesaplarının imzalanmasını onaylayın +popup.accountSigning.signAccounts.description=Seçiminize göre, {0} ödeme hesabı imzalanacaktır. +popup.accountSigning.signAccounts.button=Ödeme hesaplarını imzala +popup.accountSigning.signAccounts.ECKey=Özel hakem anahtarını girin +popup.accountSigning.signAccounts.ECKey.error=Geçersiz hakem ECKey + +popup.accountSigning.success.headline=Tebrikler +popup.accountSigning.success.description=Tüm {0} ödeme hesabı başarıyla imzalandı! +popup.accountSigning.generalInformation=Tüm hesaplarınızın imzalama durumunu hesap bölümünde bulabilirsiniz.\n\n\ + Daha fazla bilgi için lütfen [HYPERLINK:https://docs.haveno.exchange/payment-methods#account-signing] adresini ziyaret edin. +popup.accountSigning.signedByArbitrator=Ödeme hesaplarınızdan biri bir hakem tarafından doğrulandı ve imzalandı. Bu hesapla ticaret yapmak, başarılı bir ticaretten sonra otomatik olarak ticaret ortağınızın hesabını imzalayacaktır.\n\n{0} +popup.accountSigning.signedByPeer=Ödeme hesaplarınızdan biri bir ticaret ortağı tarafından doğrulandı ve imzalandı. Başlangıçtaki ticaret limitiniz kaldırılacak ve {0} gün içinde diğer hesapları imzalayabileceksiniz.\n\n{1} +popup.accountSigning.peerLimitLifted=Hesaplarınızdan biri için başlangıç limiti kaldırıldı.\n\n{0} +popup.accountSigning.peerSigner=Hesaplarınızdan biri diğer ödeme hesaplarını imzalayacak kadar olgun \ + ve hesaplarınızdan biri için başlangıç limiti kaldırıldı.\n\n{0} + +popup.accountSigning.singleAccountSelect.headline=İmzalanmamış hesap yaş tanığını içe aktarın +popup.accountSigning.confirmSingleAccount.headline=Seçilen hesap yaş tanığını onaylayın +popup.accountSigning.confirmSingleAccount.selectedHash=Seçilen tanık hash +popup.accountSigning.confirmSingleAccount.button=Hesap yaş tanığını imzala +popup.accountSigning.successSingleAccount.description=Tanık {0} imzalandı +popup.accountSigning.successSingleAccount.success.headline=Başarı + +popup.accountSigning.unsignedPubKeys.headline=İmzalanmamış Pubkey'ler +popup.accountSigning.unsignedPubKeys.sign=Pubkey'leri imzala +popup.accountSigning.unsignedPubKeys.signed=Pubkey'ler imzalandı +popup.accountSigning.unsignedPubKeys.result.signed=İmzalanmış pubkey'ler +popup.accountSigning.unsignedPubKeys.result.failed=İmzalama başarısız oldu + +popup.info.buyerAsTakerWithoutDeposit.headline=Alıcıdan depozito gerekmez +popup.info.buyerAsTakerWithoutDeposit=Teklifiniz, XMR alıcısından güvenlik depozitosu veya ücret talep etmeyecektir.\n\nTeklifinizi kabul etmek için, ticaret ortağınızla Haveno dışında bir şifre paylaşmalısınız.\n\nŞifre otomatik olarak oluşturulur ve oluşturulduktan sonra teklif detaylarında görüntülenir. + +popup.info.torMigration.msg=Haveno düğümünüz muhtemelen eski bir Tor v2 adresi kullanıyor. \ + Lütfen Haveno düğümünüzü bir Tor v3 adresine geçirin. \ + Önceden veri dizininizi yedeklediğinizden emin olun. + +#################################################################### +# Notifications +#################################################################### + +notification.trade.headline=ID {0} olan ticaret için bildirim +notification.ticket.headline=ID {0} olan ticaret için destek bileti +notification.trade.completed=Ticaret şimdi tamamlandı ve fonlarınızı çekebilirsiniz. +notification.trade.accepted=Teklifiniz bir XMR {0} tarafından kabul edildi. +notification.trade.unlocked=Ticaretiniz onaylandı.\nÖdemeyi şimdi başlatabilirsiniz. +notification.trade.paymentSent=XMR alıcısı ödemeyi gönderdi. +notification.trade.selectTrade=Ticareti seçin +notification.trade.peerOpenedDispute=Ticaret ortağınız bir {0} açtı. +notification.trade.disputeClosed={0} kapatıldı. +notification.walletUpdate.headline=Ticaret cüzdanı güncellemesi +notification.walletUpdate.msg=Ticaret cüzdanınız yeterince fonlanmıştır.\nMiktar: {0} +notification.takeOffer.walletUpdate.msg=Ticaret cüzdanınız önceki bir teklif alma girişiminden yeterince fonlanmıştı.\nMiktar: {0} +notification.tradeCompleted.headline=Ticaret tamamlandı +notification.tradeCompleted.msg=Fonlarınızı harici bir Monero cüzdanına çekebilir veya Haveno cüzdanınızda tutabilirsiniz. + + +#################################################################### +# System Tray +#################################################################### + +systemTray.show=Uygulama penceresini göster +systemTray.hide=Uygulama penceresini gizle +systemTray.info=Haveno hakkında bilgi +systemTray.exit=Çıkış +systemTray.tooltip=Haveno: Merkezi olmayan bir Monero borsa ağı + + +#################################################################### +# GUI Util +#################################################################### + +guiUtil.accountExport.savedToPath=Ticaret hesapları şu yola kaydedildi:\n{0} +guiUtil.accountExport.noAccountSetup=Dışa aktarmak için ticaret hesaplarınız yok. +guiUtil.accountExport.selectPath={0} için yolu seçin +# suppress inspection "TrailingSpacesInProperty" +guiUtil.accountExport.tradingAccount=Kimlik numarası {0} olan ticaret hesabı\n +# suppress inspection "TrailingSpacesInProperty" +guiUtil.accountImport.noImport=Kimlik numarası {0} olan ticaret hesabını içe aktarmadık çünkü zaten mevcut.\n +guiUtil.accountExport.exportFailed=CSV'ye dışa aktarma bir hata nedeniyle başarısız oldu.\nHata = {0} +guiUtil.accountExport.selectExportPath=Dışa aktarma yolunu seçin +guiUtil.accountImport.imported=Ticaret hesabı şu yoldan içe aktarıldı:\n{0}\n\nİçe aktarılan hesaplar:\n{1} +guiUtil.accountImport.noAccountsFound=Şu yolda dışa aktarılmış ticaret hesabı bulunamadı: {0}.\nDosya adı {1}. +guiUtil.openWebBrowser.warning=\ +Sistem web tarayıcınızda bir web sayfası açmak üzeresiniz.\n\ +Web sayfasını şimdi açmak istiyor musunuz?\n\n\ +Eğer varsayılan sistem web tarayıcınız olarak \"Tor Browser\" kullanmıyorsanız,\ +web sayfasına açık ağda bağlanacaksınız.\n\n\ +URL: \"{0}\" +guiUtil.openWebBrowser.doOpen=Web sayfasını aç ve tekrar sorma +guiUtil.openWebBrowser.copyUrl=URL'yi kopyala ve iptal et +guiUtil.ofTradeAmount=işlem miktarının +guiUtil.requiredMinimum=(gerekli minimum) + +#################################################################### +# Component specific +#################################################################### + +list.currency.select=Para birimini seçin +list.currency.showAll=Hepsini göster +list.currency.editList=Para birimi listesini düzenle + +table.placeholder.noItems=Şu anda mevcut {0} yok +table.placeholder.noData=Şu anda mevcut veri yok +table.placeholder.processingData=Veriler işleniyor... + + +peerInfoIcon.tooltip.tradePeer=Ticaret ortağının +peerInfoIcon.tooltip.maker=Oluşturanın +peerInfoIcon.tooltip.trade.traded={0} onion adresi: {1}\nBu ortak ile {2} kez ticaret yaptınız\n{3} +peerInfoIcon.tooltip.trade.notTraded={0} onion adresi: {1}\nBu ortak ile henüz ticaret yapmadınız.\n{2} +peerInfoIcon.tooltip.age=Ödeme hesabı {0} önce oluşturuldu. +peerInfoIcon.tooltip.unknownAge=Ödeme hesabının yaşı bilinmiyor. +peerInfoIcon.tooltip.dispute={0}\nİhtilaf sayısı: {1}.\n{2} + +tooltip.openPopupForDetails=Ayrıntılar için açılır pencereyi aç +tooltip.invalidTradeState.warning=Bu ticaret geçersiz bir durumda. Daha fazla bilgi için ayrıntılar penceresini açın +tooltip.openBlockchainForAddress=Adresi dış blok zinciri gezgininde aç: {0} +tooltip.openBlockchainForTx=İşlemi dış blok zinciri gezgininde aç: {0} + +confidence.unknown=Bilinmeyen işlem durumu +confidence.seen={0} ortak tarafından görüldü / 0 onay +confidence.confirmed={0} onay +confidence.invalid=İşlem geçersiz + +peerInfo.title=Ortak bilgisi +peerInfo.nrOfTrades=Tamamlanan ticaret sayısı +peerInfo.notTradedYet=Bu kullanıcı ile henüz ticaret yapmadınız. +peerInfo.setTag=Bu ortak için etiket ayarla +peerInfo.age.noRisk=Ödeme hesabının yaşı +peerInfo.age.chargeBackRisk=İmzadan beri geçen süre +peerInfo.unknownAge=Yaş bilinmiyor + +addressTextField.openWallet=Varsayılan Monero cüzdanınızı açın +addressTextField.copyToClipboard=Adresi panoya kopyala +addressTextField.addressCopiedToClipboard=Adres panoya kopyalandı +addressTextField.openWallet.failed=Varsayılan Monero cüzdan uygulamasını açma başarısız oldu. Belki yüklü değildir? + +explorerAddressTextField.copyToClipboard=Adresi panoya kopyala +explorerAddressTextField.blockExplorerIcon.tooltip=Bu adres ile blok zinciri gezgini aç +explorerAddressTextField.missingTx.warning.tooltip=Gerekli adres eksik + +peerInfoIcon.tooltip={0}\nEtiket: {1} + +txIdTextField.copyIcon.tooltip=İşlem kimliğini panoya kopyala +txIdTextField.blockExplorerIcon.tooltip=Bu işlem kimliği ile blok zinciri gezgini aç +txIdTextField.missingTx.warning.tooltip=Gerekli işlem eksik + + +#################################################################### +# Navigation +#################################################################### + +navigation.account="Hesap" +navigation.account.walletSeed="Hesap/Cüzdan anahtarı" +navigation.funds.availableForWithdrawal="Fonlar/Fon gönder" +navigation.portfolio.myOpenOffers="Portföy/Açık tekliflerim" +navigation.portfolio.pending="Portföy/Açık ticaretler" +navigation.portfolio.closedTrades="Portföy/Tarihçe" +navigation.funds.depositFunds="Fonlar/Fon al" +navigation.settings.preferences="Ayarlar/Tercihler" +# suppress inspection "UnusedProperty" +navigation.funds.transactions="Fonlar/İşlemler" +navigation.support="Destek" + + +#################################################################### +# Formatter +#################################################################### + +formatter.formatVolumeLabel={0} miktar{1} +formatter.makerTaker=Yapan olarak {0} {1} / Alan olarak {2} {3} +formatter.makerTakerLocked=Yapıcı olarak {0} {1} / Alan olarak {2} {3} 🔒 +formatter.youAreAsMaker=Yapan sizsiniz: {1} {0} (maker) / Alan: {3} {2} +formatter.youAreAsTaker=Alan sizsiniz: {1} {0} (taker) / Yapan: {3} {2} +formatter.youAre=Şu anda sizsiniz {0} {1} ({2} {3}) +formatter.youAreCreatingAnOffer.traditional=Şu anda bir teklif oluşturuyorsunuz: {0} {1} +formatter.youAreCreatingAnOffer.crypto=Şu anda bir teklif oluşturuyorsunuz: {0} {1} ({2} {3}) +formatter.asMaker={0} {1} olarak +formatter.asTaker={0} {1} olarak + + +#################################################################### +# Domain specific +#################################################################### + +# we use enum values here +# dynamic values are not recognized by IntelliJ +# suppress inspection "UnusedProperty" +XMR_MAINNET=Monero Ana Ağı +# suppress inspection "UnusedProperty" +XMR_LOCAL=Monero Yerel Test Ağı +# suppress inspection "UnusedProperty" +XMR_STAGENET=Monero Stagenet + +time.year=Yıl +time.month=Ay +time.halfYear=Altı ay +time.quarter=Çeyrek +time.week=Hafta +time.day=Gün +time.hour=Saat +time.minute10=10 Dakika +time.hours=saat +time.days=gün +time.1hour=1 saat +time.1day=1 gün +time.minute=dakika +time.second=saniye +time.minutes=dakika +time.seconds=saniye + + +password.enterPassword=Şifre girin +password.confirmPassword=Şifreyi doğrula +password.tooLong=Şifre 500 karakterden az olmalıdır. +password.deriveKey=Şifreden anahtar türet +password.walletDecrypted=Cüzdan başarıyla şifresiz hale getirildi ve şifre koruması kaldırıldı. +password.wrongPw=Yanlış şifre girdiniz.\n\nLütfen şifrenizi dikkatlice kontrol ederek tekrar girin, yazım hatalarına dikkat edin. +password.walletEncrypted=Cüzdan başarıyla şifrelendi ve şifre koruması etkinleştirildi. +password.passwordsDoNotMatch=Girdiğiniz iki şifre eşleşmiyor. +password.forgotPassword=Şifrenizi mi unuttunuz? +password.backupReminder=Şifre ayarlarken tüm otomatik olarak oluşturulan şifresiz cüzdan yedekleri silinecektir.\n\n\ + Şifre ayarlamadan önce uygulama dizininin yedeğini almanız ve seed kelimelerinizi yazmanız şiddetle tavsiye edilir! +password.setPassword=Şifre Ayarla (Yedeğimi zaten aldım) +password.makeBackup=Yedek Al + +seed.seedWords=Cüzdan seed kelimeleri +seed.enterSeedWords=Cüzdan seed kelimelerini girin +seed.date=Cüzdan tarihi +seed.restore.title=Seed kelimelerinden cüzdanları geri yükle +seed.restore=Cüzdanları geri yükle +seed.creationDate=Oluşturma tarihi +seed.warn.walletNotEmpty.msg=Monero cüzdanınız boş değil.\n\n\ +Daha eski bir cüzdanı geri yüklemeye çalışmadan önce bu cüzdanı boşaltmalısınız, \ +çünkü cüzdanları karıştırmak yedeklerin geçersiz hale gelmesine yol açabilir.\n\n\ +Lütfen ticaretlerinizi tamamlayın, tüm açık tekliflerinizi kapatın ve Monero'nuzu çekmek için Fonlar bölümüne gidin.\n\ +Monero'nuza erişemiyorsanız cüzdanı boşaltmak için acil durum aracını kullanabilirsiniz.\n\ +Acil durum aracını açmak için \"Alt+e\" veya \"Cmd/Ctrl+e\" tuşlarına basın. +seed.warn.walletNotEmpty.restore=Yine de geri yüklemek istiyorum +seed.warn.walletNotEmpty.emptyWallet=Önce cüzdanlarımı boşaltacağım +seed.warn.notEncryptedAnymore=Cüzdanlarınız şifrelidir.\n\n\ +Geri yüklemeden sonra cüzdanlar artık şifreli olmayacak ve yeni bir şifre ayarlamanız gerekecek.\n\n\ +Devam etmek istiyor musunuz? +seed.warn.walletDateEmpty=Cüzdan tarihi belirtmediğiniz için Haveno 2013.10.09 tarihinden itibaren blok zincirini taramak zorunda kalacak (BIP39 epoch tarihi).\n\n\ +BIP39 cüzdanları Haveno'da ilk olarak 2017.06.28'de (v0.5 sürümü) tanıtıldı. Bu yüzden o tarihi kullanarak zaman kazanabilirsiniz.\n\n\ +İdeal olarak, cüzdan seed'inizin oluşturulduğu tarihi belirtmelisiniz.\n\n\n\ +Cüzdan tarihi belirtmeden devam etmek istediğinizden emin misiniz? +seed.restore.success=Cüzdanlar yeni seed kelimeleriyle başarıyla geri yüklendi.\n\nUygulamayı kapatıp yeniden başlatmanız gerekiyor. +seed.restore.error=Seed kelimeleriyle cüzdanları geri yüklerken bir hata oluştu.{0} +seed.restore.openOffers.warn=Seed kelimelerinden geri yüklerseniz açık teklifleriniz kaldırılacaktır.\n\ + Devam etmek istediğinizden emin misiniz? + + +#################################################################### +# Payment methods +#################################################################### + +payment.account=Hesap +payment.account.no=Hesap no. +payment.account.name=Hesap adı +payment.account.username=Kullanıcı adı +payment.account.phoneNr=Telefon numarası +payment.account.owner=Hesap sahibi tam adı +payment.account.fullName=Tam ad (ad, orta ad, soyad) +payment.account.state=Eyalet/İl/Bölge +payment.account.city=Şehir +payment.account.address=Adres +payment.bank.country=Bankanın ülkesi +payment.account.name.email=Hesap sahibi tam adı / email +payment.account.name.emailAndHolderId=Hesap sahibi tam adı / email / {0} +payment.bank.name=Banka adı +payment.select.account=Hesap türünü seçin +payment.select.region=Bölgeyi seçin +payment.select.country=Ülkeyi seçin +payment.select.bank.country=Bankanın ülkesini seçin +payment.foreign.currency=Ülkenin varsayılan para birimi dışındaki bir para birimini seçmek istediğinize emin misiniz? +payment.restore.default=Hayır, varsayılan para birimini geri yükle +payment.email=Email +payment.country=Ülke +payment.extras=Ek gereksinimler +payment.email.mobile=Email veya telefon numarası +payment.email.mobile.cashtag=Cashtag, email veya telefon numarası +payment.email.mobile.username=Kullanıcı adı, email veya telefon numarası +payment.crypto.address=Kripto para adresi +payment.crypto.tradeInstantCheckbox=Bu Kripto Para ile anında ticaret yap (1 saat içinde) +payment.crypto.tradeInstant.popup=Anında ticaret yapabilmek için her iki ticaret ortağının da çevrimiçi \ + olması ve ticareti 1 saatten kısa sürede tamamlaması gerekmektedir.\n\n\ + Eğer açık teklifleriniz varsa ve müsait değilseniz \ + lütfen bu teklifleri 'Portföy' ekranında devre dışı bırakın. +payment.crypto=Kripto para +payment.select.crypto=Kripto Para seçin veya arayın +payment.secret=Gizli soru +payment.answer=Cevap +payment.wallet=Cüzdan ID +payment.capitual.cap=CAP Kodu +payment.upi.virtualPaymentAddress=Sanal Ödeme Adresi + +# suppress inspection "UnusedProperty" +payment.swift.headline=Uluslararası SWIFT Havale +# suppress inspection "UnusedProperty" +payment.swift.title.bank=Alıcı Banka +# suppress inspection "UnusedProperty" +payment.swift.title.intermediary=Ara Banka (genişletmek için tıklayın) +# suppress inspection "UnusedProperty" +payment.swift.country.bank=Alıcı Banka Ülkesi +# suppress inspection "UnusedProperty" +payment.swift.country.intermediary=Ara Banka Ülkesi +# suppress inspection "UnusedProperty" +payment.swift.swiftCode.bank=Alıcı Banka SWIFT Kodu +# suppress inspection "UnusedProperty" +payment.swift.swiftCode.intermediary=Ara Banka SWIFT Kodu +# suppress inspection "UnusedProperty" +payment.swift.name.bank=Alıcı Banka adı +# suppress inspection "UnusedProperty" +payment.swift.name.intermediary=Ara Banka adı +# suppress inspection "UnusedProperty" +payment.swift.branch.bank=Alıcı Banka şubesi +# suppress inspection "UnusedProperty" +payment.swift.branch.intermediary=Ara Banka şubesi +# suppress inspection "UnusedProperty" +payment.swift.address.bank=Alıcı Banka adresi +# suppress inspection "UnusedProperty" +payment.swift.address.intermediary=Ara Banka adresi +# suppress inspection "UnusedProperty" +payment.swift.address.beneficiary=Alıcı adresi +# suppress inspection "UnusedProperty" +payment.swift.phone.beneficiary=Alıcı telefon numarası +payment.swift.account=Hesap No. (veya IBAN) +payment.swift.use.intermediary=Ara Banka Kullan +payment.swift.showPaymentInfo=Ödeme Bilgilerini Göster... +payment.account.owner.address=Hesap sahibi adresi +payment.transferwiseUsd.address=(ABD merkezli olmalı, banka adresini kullanmayı düşünün) + +payment.amazon.site=Hediye kartı satın al +payment.ask=Tüccar Sohbetinde Sor +payment.uphold.accountId=Kullanıcı adı veya email veya telefon numarası +payment.moneyBeam.accountId=Email veya telefon numarası +payment.popmoney.accountId=Email veya telefon numarası +payment.promptPay.promptPayId=Vatandaşlık Kimlik/ Vergi Kimlik veya telefon numarası +payment.supportedCurrencies=Desteklenen para birimleri +payment.supportedCurrenciesForReceiver=Fon alma para birimleri +payment.limitations=Kısıtlamalar +payment.salt=Hesap yaşı doğrulama için tuz +payment.error.noHexSalt=Tuz HEX formatında olmalıdır.\n\ + Sadece eski bir hesaptan tuz aktarıp hesap yaşını korumak istiyorsanız tuz alanını düzenlemeniz önerilir. \ + Hesap yaşı, hesap tuzu ve tanımlayıcı hesap verileri (örneğin IBAN) kullanılarak doğrulanır. +payment.accept.euro=Bu Euro ülkelerinden gelen işlemleri kabul et +payment.accept.nonEuro=Bu Euro dışı ülkelerden gelen işlemleri kabul et +payment.accepted.countries=Kabul edilen ülkeler +payment.accepted.banks=Kabul edilen bankalar (ID) +payment.mobile=Mobil numara +payment.postal.address=Posta adresi +payment.national.account.id.AR=CBU numarası +shared.accountSigningState=Hesap imzalama durumu + +#new +payment.crypto.address.dyn={0} adresi +payment.crypto.receiver.address=Alıcının kripto para adresi +payment.accountNr=Hesap numarası +payment.emailOrMobile=E-posta veya mobil no. +payment.useCustomAccountName=Özel hesap adı kullan +payment.maxPeriod=Maksimum izin verilen ticaret süresi +payment.maxPeriodAndLimit=Maksimum ticaret süresi: {0} / Maksimum satın alma: {1} / Maksimum satış: {2} / Hesap yaşı: {3} +payment.maxPeriodAndLimitCrypto=Maksimum ticaret süresi: {0} / Maksimum ticaret limiti: {1} +payment.currencyWithSymbol=Para birimi: {0} +payment.nameOfAcceptedBank=Kabul edilen bankanın adı +payment.addAcceptedBank=Kabul edilen banka ekle +payment.clearAcceptedBanks=Kabul edilen bankaları temizle +payment.bank.nameOptional=Banka adı (isteğe bağlı) +payment.bankCode=Banka kodu +payment.bankId=Banka kimliği (BIC/SWIFT) +payment.bankIdOptional=Banka kimliği (BIC/SWIFT) (isteğe bağlı) +payment.branchNr=Şube numarası +payment.branchNrOptional=Şube numarası (isteğe bağlı) +payment.accountNrLabel=Hesap numarası (IBAN) +payment.iban=IBAN +payment.tikkie.iban=Tikkie'de Haveno ticareti için kullanılan IBAN +payment.accountType=Hesap türü +payment.checking=Vadesiz +payment.savings=Vadeli +payment.personalId=Kişisel kimlik +payment.zelle.info=Zelle, başka bir banka *aracılığıyla* en iyi şekilde çalışan bir para transfer hizmetidir.\n\n\ + 1. Bankanızın Zelle ile çalışıp çalışmadığını ve nasıl çalıştığını görmek için bu sayfayı kontrol edin: [HYPERLINK:https://www.zellepay.com/get-started]\n\n\ + 2. Transfer limitlerinize özellikle dikkat edin—gönderme limitleri bankadan bankaya değişir ve bankalar genellikle ayrı günlük, haftalık ve aylık limitler belirler.\n\n\ + 3. Bankanız Zelle ile çalışmıyorsa, Zelle mobil uygulaması aracılığıyla hala kullanabilirsiniz, ancak transfer limitleriniz çok daha düşük olacaktır.\n\n\ + 4. Haveno hesabınızda belirtilen isim, Zelle/bank hesabınızdaki isimle EŞLEŞMELİDİR.\n\n\ + Ticaret sözleşmenizde belirtilen şekilde bir Zelle işlemini tamamlayamazsanız, güvenlik depozitonuzun bir kısmını (veya tamamını) kaybedebilirsiniz.\n\n\ + Zelle'in biraz daha yüksek geri ödeme riski nedeniyle, satıcılara, imzasız alıcılarla e-posta veya SMS yoluyla iletişime geçerek Haveno'da belirtilen \ + Zelle hesabına gerçekten sahip olduklarını doğrulamalarını öneririz. +payment.fasterPayments.newRequirements.info=Bazı bankalar, Faster Payments transferleri için alıcının tam adını \ +doğrulamaya başladı. Mevcut Faster Payments hesabınız tam bir isim belirtmiyor.\n\n\ + Lütfen gelecekteki {0} alıcılarına tam bir isim sağlamak için Haveno'da Faster Payments hesabınızı yeniden oluşturmayı düşünün.\n\n\ + Hesabı yeniden oluşturduğunuzda, eski hesabınızdaki tam sort kodunu, hesap numarasını ve hesap yaşı doğrulama \ + tuzu değerlerini yeni hesabınıza kopyaladığınızdan emin olun. Bu, mevcut hesabınızın yaşı ve imzalama \ + durumunun korunmasını sağlayacaktır. +payment.fasterPayments.ukSortCode="Birleşik Krallık sort kodu" +payment.moneyGram.info=MoneyGram kullanırken XMR alıcısının, Yetkilendirme numarasını ve makbuzun bir fotoğrafını e-posta ile XMR satıcısına göndermesi gerekir. \ + Makbuz, satıcının tam adını, ülkesini, eyaletini ve miktarını açıkça göstermelidir. Satıcının e-postası ticaret sürecinde alıcıya gösterilecektir. +payment.westernUnion.info=Western Union kullanırken XMR alıcısının, MTCN (izleme numarası) ve makbuzun bir fotoğrafını e-posta ile XMR satıcısına göndermesi gerekir. \ + Makbuz, satıcının tam adını, şehri, ülkeyi ve miktarı açıkça göstermelidir. Satıcının e-postası ticaret sürecinde alıcıya gösterilecektir. +payment.halCash.info=HalCash kullanırken XMR alıcısının, HalCash kodunu mobil telefonundan bir kısa mesaj ile XMR satıcısına göndermesi gerekir.\n\n\ + Lütfen HalCash ile göndermenize izin verilen maksimum miktarı aşmadığınızdan emin olun. \ + Minimum çekim miktarı 10 EUR ve maksimum miktar 600 EUR'dur. Tekrarlanan çekimlerde, \ + alıcı başına günlük 3000 EUR ve aylık 6000 EUR'dur. Lütfen bu limitlerin bankanızın \ + burada belirtilenlerle aynı limitleri kullandığından emin olmak için çapraz kontrol yapın.\n\n\ + Çekim miktarı, ATM'den başka miktarlar çekemeyeceğiniz için 10 EUR'nun katları olmalıdır. \ + Teklif oluşturma ve teklif alma ekranında kullanıcı arayüzü, EUR miktarının doğru olması için XMR miktarını ayarlayacaktır. Piyasa \ + bazlı fiyat kullanamazsınız çünkü EUR miktarı değişen fiyatlarla değişir.\n\n\ + Bir anlaşmazlık durumunda, XMR alıcısının EUR gönderdiğine dair kanıt sunması gerekir. +# suppress inspection "UnusedMessageFormatParameter" +payment.limits.info=Lütfen tüm banka transferlerinin belirli bir miktarda geri ödeme riski taşıdığını unutmayın. Bu riski azaltmak için, \ + Haveno, kullanılan ödeme yönteminin tahmini geri ödeme riski seviyesine dayalı olarak işlem başına limitler belirler.\n\ + \n\ + Bu ödeme yöntemi için, satın alma ve satma işlemlerinde işlem başına limitiniz {2}.\n\ + \n\ + Bu limit yalnızca tek bir işlemin boyutuna uygulanır—istediğiniz kadar işlem yapabilirsiniz.\n\ + \n\ + Daha fazla ayrıntı için wiki sayfasına bakın [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. +# suppress inspection "UnusedProperty" +payment.limits.info.withSigning=Geri ödeme riskini sınırlamak için, Haveno, bu ödeme hesabı türü için işlem başına limitler belirler \ + aşağıdaki 2 faktöre dayanır:\n\n\ + 1. Ödeme yöntemi için genel geri ödeme riski\n\ + 2. Hesap imzalama durumu\n\ + \n\ + Bu ödeme hesabı henüz imzalanmamış, bu nedenle işlem başına satın alma limiti {0} ile sınırlıdır. \ + İmzalamadan sonra, satın alma limitleri şu şekilde artacaktır:\n\ + \n\ + ● İmzalamadan önce ve imzalamadan sonraki 30 gün boyunca, işlem başına satın alma limitiniz {0} olacaktır\n\ + ● İmzalamadan 30 gün sonra, işlem başına satın alma limitiniz {1} olacaktır\n\ + ● İmzalamadan 60 gün sonra, işlem başına satın alma limitiniz {2} olacaktır\n\ + \n\ + Hesap imzalama, satış limitlerini etkilemez. Bir işlemde hemen {2} satabilirsiniz.\n\ + \n\ + Bu limitler yalnızca tek bir işlemin boyutuna uygulanır—istediğiniz kadar işlem yapabilirsiniz. \n\ + \n\ + Daha fazla ayrıntı için wiki sayfasına bakın [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. + +payment.cashDeposit.info=Lütfen bankanızın başka kişilerin hesaplarına nakit yatırma işlemlerine izin verdiğini onaylayın. \ + Örneğin, Bank of America ve Wells Fargo gibi bankalar bu tür yatırımlara artık izin vermemektedir. + +payment.revolut.info=Revolut, hesap kimliği olarak telefon numarası veya e-posta yerine 'Kullanıcı Adı'nı gerektirir. +payment.account.revolut.addUserNameInfo={0}\n\ + Mevcut Revolut hesabınız ({1}) 'Kullanıcı Adı'na sahip değil.\n\ + Hesap verilerinizi güncellemek için lütfen Revolut 'Kullanıcı Adınızı' girin.\n\ + Bu, hesap yaş imza durumunuzu etkilemeyecektir. +payment.revolut.addUserNameInfo.headLine=Revolut hesabını güncelle + +payment.cashapp.info=Cash App, çoğu banka transferine göre daha yüksek geri ödeme riskine sahiptir. Cash App ile ticaret yaparken bunun farkında olun. +payment.venmo.info=Venmo, çoğu banka transferine göre daha yüksek geri ödeme riskine sahiptir. Venmo ile ticaret yaparken bunun farkında olun. +payment.paypal.info=PayPal, çoğu banka transferine göre daha yüksek geri ödeme riskine sahiptir. PayPal ile ticaret yaparken bunun farkında olun. + +payment.amazonGiftCard.upgrade=Amazon hediye kartları ödeme yöntemi için ülkenin belirtilmesi gerekmektedir. +payment.account.amazonGiftCard.addCountryInfo={0}\n\ + Mevcut Amazon Hediye Kartı hesabınız ({1}) belirtilen bir ülkeye sahip değil.\n\ + Hesap verilerinizi güncellemek için lütfen Amazon Hediye Kartı Ülkenizi girin.\n\ + Bu, hesap yaş durumunuzu etkilemeyecektir. +payment.amazonGiftCard.upgrade.headLine=Amazon Hediye Kartı hesabını güncelle + +payment.swift.info.account=Haveno'da SWIFT kullanımı için temel yönergeleri dikkatlice inceleyin:\n\ +\n\ +- tüm alanları eksiksiz ve doğru şekilde doldurun \n\ +- alıcı, ödeme yapanın belirttiği para biriminde ödeme yapmalıdır \n\ +- alıcı, paylaşılan ücret modeli (SHA) kullanarak ödeme yapmalıdır \n\ +- alıcı ve satıcı ücretlerle karşılaşabilir, bu yüzden bankalarının ücret tarifelerini önceden kontrol etmelidirler \n\ +\n\ +SWIFT, diğer ödeme yöntemlerinden daha karmaşıktır, bu yüzden lütfen wiki'deki tam rehberi inceleyin [HYPERLINK:https://haveno.exchange/wiki/SWIFT]. + +payment.swift.info.buyer=SWIFT ile monero satın almak için şunları yapmalısınız:\n\ +\n\ +- ödeme yapanın belirttiği para biriminde ödeme yapın \n\ +- ödeme göndermek için paylaşılan ücret modeli (SHA) kullanın\n\ +\n\ +Ceza almamak ve sorunsuz ticaretler yapmak için lütfen wiki'deki daha fazla rehberi inceleyin [HYPERLINK:https://haveno.exchange/wiki/SWIFT]. + +payment.swift.info.seller=SWIFT gönderenler, ödemeleri göndermek için paylaşılan ücret modeli (SHA) kullanmak zorundadır.\n\ +\n\ +SHA kullanmayan bir SWIFT ödemesi alırsanız, bir arabuluculuk bileti açın.\n\ +\n\ +Ceza almamak ve sorunsuz ticaretler yapmak için lütfen wiki'deki daha fazla rehberi inceleyin [HYPERLINK:https://haveno.exchange/wiki/SWIFT]. + +payment.imps.info.account=Lütfen şunları dahil ettiğinizden emin olun:\n\n\ + ● Hesap sahibi tam adı\n\ + ● Hesap numarası\n\ + ● IFSC numarası\n\n\ +Bu detaylar, ödeme gönderip alacağınız banka hesabınızla eşleşmelidir.\n\n\ +Bir işlemde gönderilebilecek maksimum miktarın Rs. 200.000 olduğunu unutmayın. Bu miktarın üzerindeki işlemler için birden fazla işlem gerekecektir. Ancak, günde maksimum Rs. 1.000.000 gönderilebileceğini unutmayın.\n\n\ +Bazı bankaların müşterileri için farklı limitleri vardır. +payment.imps.info.buyer=Lütfen yalnızca Haveno'da sağlanan hesap bilgilerine ödeme gönderin.\n\n\ +Maksimum ticaret boyutu işlem başına Rs. 200.000'dir.\n\n\ +Ticaretiniz Rs. 200.000'den fazla ise birden fazla transfer yapmanız gerekecektir. Ancak, günde maksimum Rs. 1.000.000 gönderilebileceğini unutmayın.\n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. +payment.imps.info.seller=Bir ticarette Rs. 200.000'den fazla almayı planlıyorsanız, alıcının birden fazla transfer yapması gerektiğini beklemelisiniz. Ancak, günde maksimum Rs. 1.000.000 gönderilebileceğini unutmayın.\n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. + +payment.neft.info.account=Lütfen şunları dahil ettiğinizden emin olun:\n\n\ + ● Hesap sahibi tam adı\n\ + ● Hesap numarası\n\ + ● IFSC numarası\n\n\ +Bu detaylar, ödeme gönderip alacağınız banka hesabınızla eşleşmelidir.\n\n\ +Bir işlemde gönderilebilecek maksimum miktarın Rs. 50.000 olduğunu unutmayın. Bu miktarın üzerindeki işlemler için birden fazla işlem gerekecektir.\n\n\ +Bazı bankaların müşterileri için farklı limitleri vardır. +payment.neft.info.buyer=Lütfen yalnızca Haveno'da sağlanan hesap bilgilerine ödeme gönderin.\n\n\ +Maksimum ticaret boyutu işlem başına Rs. 50.000'dir.\n\n\ +Ticaretiniz Rs. 50.000'den fazla ise birden fazla transfer yapmanız gerekecektir.\n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. +payment.neft.info.seller=Bir ticarette Rs. 50.000'den fazla almayı planlıyorsanız, alıcının birden fazla transfer yapması gerektiğini beklemelisiniz.\n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. + +payment.paytm.info.account=PayTM hesabınızdaki e-posta veya telefon numaranızla eşleşen e-posta veya telefon numaranızı girdiğinizden emin olun. \n\n\ +KYC'siz bir PayTM hesabı kuran kullanıcılar şu sınırlamalara tabidir: \n\n\ + ● İşlem başına maksimum 5.000 Rs gönderilebilir.\n\ + ● Birinin PayTM cüzdanında maksimum 10.000 Rs tutulabilir.\n\n\ +Ticaret başına 5.000 Rs üzeri bir miktar ticareti yapmak istiyorsanız, PayTM ile KYC işlemini tamamlamanız gerekecektir. KYC ile kullanıcılar şu sınırlamalara tabidir:\n\n\ + ● İşlem başına maksimum 100.000 Rs gönderilebilir.\n\ + ● Birinin PayTM cüzdanında maksimum 100.000 Rs tutulabilir.\n\n\ +Kullanıcıların hesap limitlerinin de farkında olması gerekir. PayTM hesap limitlerinin üzerindeki ticaretler muhtemelen birden fazla günde gerçekleştirilmeli veya iptal edilmelidir. +payment.paytm.info.buyer=Lütfen yalnızca sağlanan e-posta adresine veya telefon numarasına ödeme gönderin.\n\n\ +Ticaret başına 5.000 Rs üzeri bir miktar ticareti yapmak istiyorsanız, PayTM ile KYC işlemini tamamlamanız gerekecektir.\n\n\ +KYC olmadan işlem başına 5.000 Rs gönderilebilir.\n\n\ +KYC ile kullanıcılar işlem başına 100.000 Rs gönderebilir. +payment.paytm.info.seller=Ticaret başına 5.000 Rs üzeri bir miktar ticareti yapmak istiyorsanız, PayTM ile KYC işlemini tamamlamanız gerekecektir. KYC ile kullanıcılar şu sınırlamalara tabidir:\n\n\ + ● İşlem başına maksimum 100.000 Rs gönderilebilir.\n\ + ● PayTM cüzdanınızda maksimum 100.000 Rs tutulabilir.\n\n\ +Kullanıcıların hesap limitlerinin de farkında olması gerekir. PayTM cüzdanınızda maksimum 100.000 Rs tutulabileceği için lütfen düzenli olarak rupee transferi yapın. + +payment.rtgs.info.account=RTGS, Rs. 200.000 veya üzeri büyük işlemler için kullanılır.\n\n\ +RTGS ödeme hesabınızı kurarken lütfen şunları dahil ettiğinizden emin olun:\n\n\ + ● Hesap sahibi tam adı\n\ + ● Hesap numarası\n\ + ● IFSC numarası\n\n\ +Bu detaylar, ödeme gönderip alacağınız banka hesabınızla eşleşmelidir.\n\n\ +İşlem başına gönderilebilecek minimum ticaret tutarının 200.000 Rs olduğunu unutmayın. Bu miktarın altındaki işlemler ya iptal edilir ya da her iki tüccarın başka bir ödeme yöntemi (örneğin IMPS veya UPI) üzerinde anlaşması gerekir. +payment.rtgs.info.buyer=Lütfen yalnızca Haveno'da sağlanan hesap bilgilerine ödeme gönderin.\n\n\ +İşlem başına gönderilebilecek minimum ticaret tutarının 200.000 Rs olduğunu unutmayın. Bu miktarın altındaki işlemler ya iptal edilir ya da her iki tüccarın başka bir ödeme yöntemi (örneğin IMPS veya UPI) üzerinde anlaşması gerekir. +payment.rtgs.info.seller=İşlem başına gönderilebilecek minimum ticaret tutarının 200.000 Rs olduğunu unutmayın. Bu miktarın altındaki işlemler ya iptal edilir ya da her iki tüccarın başka bir ödeme yöntemi (örneğin IMPS veya UPI) üzerinde anlaşması gerekir. + +payment.upi.info.account=Lütfen Sanal Ödeme Adresinizi (VPA) veya UPI ID'nizi eklediğinizden emin olun. Bu, ortasında “@” işareti bulunan bir e-posta kimliği gibi formatlanmıştır. Örneğin, UPI kimliğiniz “alıcı_adı@banka_adı” veya “telefon_numarası@banka_adı” olabilir. \n\n\ +UPI için işlem başına gönderilebilecek maksimum limitin 100.000 Rs olduğunu unutmayın. \n\n\ +Ticaret başına 100.000 Rs üzeri bir miktar ticareti yapmak istiyorsanız, işlemlerin muhtemelen birden fazla transferde gerçekleşeceğini unutmayın. \n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. +payment.upi.info.buyer=Lütfen yalnızca Haveno'da sağlanan VPA / UPI ID'ye ödeme gönderin. \n\n\ +İşlem başına maksimum ticaret boyutu 100.000 Rs'dir. \n\n\ +Ticaretiniz 100.000 Rs üzerinde ise birden fazla transfer yapmanız gerekecektir. \n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. +payment.upi.info.seller=Ticaret başına 100.000 Rs üzerinde almak istiyorsanız, alıcının birden fazla transfer yapmasını beklemelisiniz. \n\n\ +Bazı bankaların müşterileri için farklı limitleri olduğunu unutmayın. + +payment.celpay.info.account=Lütfen Celcius hesabınıza kayıtlı e-postayı eklediğinizden emin olun. \ + Bu, fon gönderdiğinizde doğru hesaptan görüneceğini ve fon aldığınızda hesabınıza kredilendirileceğini sağlar.\n\n\ +CelPay kullanıcıları 24 saat içinde $2,500 (veya diğer para birimi/kripto eşdeğeri) gönderme ile sınırlıdır.\n\n\ +CelPay hesap limitlerinin üzerindeki ticaretler muhtemelen birden fazla günde gerçekleştirilmeli veya iptal edilmelidir.\n\n\ +CelPay, birden fazla stablecoin'i destekler:\n\n\ + ● USD Stablecoin'ler; DAI, TrueUSD, USDC, ZUSD, BUSD, GUSD, PAX, USDT (ERC20)\n\ + ● CAD Stablecoin'ler; TrueCAD\n\ + ● GBP Stablecoin'ler; TrueGBP\n\ + ● HKD Stablecoin'ler; TrueHKD\n\ + ● AUD Stablecoin'ler; TrueAUD\n\n\ +XMR Alıcılar, XMR Satıcısına eşleşen herhangi bir para birimi stablecoin gönderebilir. +payment.celpay.info.buyer=Lütfen yalnızca XMR Satıcısı tarafından sağlanan e-posta adresine bir ödeme bağlantısı göndererek ödeme yapın.\n\n\ +CelPay, 24 saat içinde $2,500 (veya diğer para birimi/kripto eşdeğeri) gönderme ile sınırlıdır.\n\n\ +CelPay hesap limitlerinin üzerindeki ticaretler muhtemelen birden fazla günde gerçekleştirilmeli veya iptal edilmelidir.\n\n\ +CelPay, birden fazla stablecoin'i destekler:\n\n\ + ● USD Stablecoin'ler; DAI, TrueUSD, USDC, ZUSD, BUSD, GUSD, PAX, USDT (ERC20)\n\ + ● CAD Stablecoin'ler; TrueCAD\n\ + ● GBP Stablecoin'ler; TrueGBP\n\ + ● HKD Stablecoin'ler; TrueHKD\n\ + ● AUD Stablecoin'ler; TrueAUD\n\n\ +XMR Alıcılar, XMR Satıcısına eşleşen herhangi bir para birimi stablecoin gönderebilir. +payment.celpay.info.seller=XMR Satıcıları, güvenli bir ödeme bağlantısı aracılığıyla ödeme almayı beklemelidir. \ + Lütfen e-posta ödeme bağlantısının XMR Alıcısı tarafından sağlanan e-posta adresini içerdiğinden emin olun.\n\n\ +CelPay kullanıcıları 24 saat içinde $2,500 (veya diğer para birimi/kripto eşdeğeri) gönderme ile sınırlıdır.\n\n\ +CelPay hesap limitlerinin üzerindeki ticaretler muhtemelen birden fazla günde gerçekleştirilmeli veya iptal edilmelidir.\n\n\ +CelPay, birden fazla stablecoin'i destekler:\n\n\ + ● USD Stablecoin'ler; DAI, TrueUSD, USDC, ZUSD, BUSD, GUSD, PAX, USDT (ERC20)\n\ + ● CAD Stablecoin'ler; TrueCAD\n\ + ● GBP Stablecoin'ler; TrueGBP\n\ + ● HKD Stablecoin'ler; TrueHKD\n\ + ● AUD Stablecoin'ler; TrueAUD\n\n\ +XMR Satıcıları, XMR Alıcısından eşleşen herhangi bir para birimi stablecoin almayı beklemelidir. XMR Alıcısının eşleşen herhangi bir para birimi stablecoin göndermesi mümkündür. +payment.celpay.supportedCurrenciesForReceiver=Desteklenen para birimleri (lütfen dikkat edin: aşağıdaki tüm para birimleri Celcius uygulaması içinde desteklenen stablecoin'lerdir. Ticaretler stablecoin'ler içindir, fiat değil.) + +payment.nequi.info.account=Nequi hesabınızla ilişkilendirilen telefon numaranızı eklediğinizden emin olun.\n\n\ + Kullanıcılar bir Nequi hesabı kurduklarında, ödeme limitleri ayda maksimum ~ 7,000,000 COP olarak belirlenir.\n\n\ + Tek seferde 7,000,000 COP'dan fazla işlem yapmak istiyorsanız, Bancolombia ile KYC tamamlamanız ve yaklaşık 15,000 COP \ + tutarında bir ücret ödemeniz gerekecek. Bundan sonra, tüm işlemler %0,4 vergiye tabi olacaktır. Lütfen en son vergilerden haberdar olduğunuzdan emin olun.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.nequi.info.buyer=Lütfen ödemeyi yalnızca XMR Satıcısının Haveno hesabında belirtilen telefon numarasına gönderin.\n\n\ + Kullanıcılar bir Nequi hesabı kurduklarında, ödeme limitleri ayda maksimum ~ 7,000,000 COP olarak belirlenir.\n\n\ + Tek seferde 7,000,000 COP'dan fazla işlem yapmak istiyorsanız, Bancolombia ile KYC tamamlamanız ve yaklaşık 15,000 COP \ + tutarında bir ücret ödemeniz gerekecek. Bundan sonra, tüm işlemler %0,4 vergiye tabi olacaktır. Lütfen en son vergilerden haberdar olduğunuzdan emin olun.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.nequi.info.seller=Lütfen alınan ödemenin XMR Alıcısının Haveno hesabında belirtilen telefon numarasına uygun olup olmadığını kontrol edin.\n\n\ + Kullanıcılar bir Nequi hesabı kurduklarında, ödeme limitleri ayda maksimum ~ 7,000,000 COP olarak belirlenir.\n\n\ + Tek seferde 7,000,000 COP'dan fazla işlem yapmak istiyorsanız, Bancolombia ile KYC tamamlamanız ve yaklaşık 15,000 COP \ + tutarında bir ücret ödemeniz gerekecek. Bundan sonra, tüm işlemler %0,4 vergiye tabi olacaktır. Lütfen en son vergilerden haberdar olduğunuzdan emin olun.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. + +payment.bizum.info.account=Bizum kullanmak için İspanya'da bir banka hesabına (IBAN) sahip olmanız ve hizmete kayıtlı olmanız gerekir.\n\n\ + Bizum, €0.50 ile €1,000 arasındaki işlemler için kullanılabilir.\n\n\ + Bizum kullanarak gönderebileceğiniz/alabileceğiniz maksimum işlem tutarı günde €2,000'dır.\n\n\ + Bizum kullanıcıları ayda maksimum 150 işlem yapabilirler.\n\n\ + Ancak, her banka yukarıdaki limitler dahilinde kendi limitlerini belirleyebilir.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.bizum.info.buyer=Lütfen ödemeyi yalnızca Haveno'da belirtilen XMR Satıcısının cep telefonu numarasına gönderin.\n\n\ + Maksimum işlem tutarı ödeme başına €1,000'dır. Bizum kullanarak gönderebileceğiniz maksimum işlem tutarı günde €2,000'dır.\n\n\ + Yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.bizum.info.seller=Lütfen ödemenin, Haveno'da belirtilen XMR Alıcısının cep telefonu numarasından geldiğinden emin olun.\n\n\ + Maksimum işlem tutarı ödeme başına €1,000'dır. Bizum kullanarak alabileceğiniz maksimum işlem tutarı günde €2,000'dır.\n\n\ + Yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. + +payment.pix.info.account=Lütfen seçtiğiniz Pix Anahtarını eklediğinizden emin olun. Dört tür anahtar vardır: \ + CPF (Doğal Kişiler Kütüğü) veya CNPJ (Ulusal Hukuki Kişiler Sicili), e-posta adresi, telefon numarası veya sistem tarafından üretilen rastgele bir \ + anahtar olan evrensel benzersiz tanımlayıcı (UUID). Sahip olduğunuz her Pix hesabı için farklı bir anahtar kullanılmalıdır. \ + Bireyler sahip oldukları her hesap için beş anahtara kadar oluşturabilirler.\n\n\ + Haveno'da işlem yaparken, XMR Alıcılarının Pix Anahtarlarını ödeme açıklaması olarak kullanmaları gerekir, böylece XMR Satıcılarının ödemenin kendilerinden geldiğini kolayca tanımlamaları sağlanır. +payment.pix.info.buyer=Lütfen ödemeyi yalnızca XMR Satıcısının Haveno hesabında belirtilen Pix Anahtarına gönderin.\n\n\ + Ödemeyi kendinizden geldiğini kolayca tanımlaması için Pix Anahtarınızı ödeme referansı olarak kullanın. +payment.pix.info.seller=Lütfen alınan ödeme açıklamasının, XMR Alıcısının Haveno hesabında belirtilen Pix Anahtarı ile eşleştiğini kontrol edin. +payment.pix.key=Pix Anahtarı (CPF, CNPJ, E-posta, Telefon numarası veya UUID) + +payment.monese.info.account=Monese, GBP, EUR ve RON* kullanıcıları için bir banka uygulamasıdır. Monese, kullanıcıların \ + diğer Monese hesaplarına herhangi bir desteklenen para biriminde anında ve ücretsiz para göndermesine olanak tanır.\n\n\ +*Monese'de bir RON hesabı açmak için Romanya'da yaşamanız veya Romen vatandaşlığınızın olması gerekmektedir.\n\n\ + Haveno'da Monese hesabınızı kurarken, Monese hesabınızla eşleşen adınızı ve telefon numaranızı eklediğinizden emin olun. \ + Bu, para gönderdiğinizde doğru hesaptan geldiğini ve para aldığınızda hesabınıza kredi olarak işlendiğini \ + sağlayacaktır. +payment.monese.info.buyer=Lütfen ödemeyi yalnızca XMR Satıcısının Haveno hesabında belirtilen telefon numarasına gönderin. Lütfen ödeme açıklamasını boş bırakın. +payment.monese.info.seller=XMR Satıcıları, ödemenin XMR Alıcısının Haveno hesabında gösterilen telefon numarası / isimden gelmesini beklemelidir. + +payment.satispay.info.account=Satispay kullanmak için İtalya'da bir banka hesabına (IBAN) sahip olmanız ve hizmete kayıtlı olmanız gerekmektedir.\n\n\ +Satispay hesap limitleri bireysel olarak belirlenir. Daha yüksek tutarlarda işlem yapmak istiyorsanız, limitlerinizi artırmak için Satispay \ + desteğiyle iletişime geçmeniz gerekecektir. Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Eğer yukarıdaki limitleri aşarsanız \ + işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.satispay.info.buyer=Lütfen ödemeyi yalnızca Haveno'da belirtilen XMR Satıcısının cep telefonu numarasına gönderin.\n\n\ +Satispay hesap limitleri bireysel olarak belirlenir. Daha yüksek tutarlarda işlem yapmak istiyorsanız, limitlerinizi artırmak için Satispay \ + desteğiyle iletişime geçmeniz gerekecektir. Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Eğer yukarıdaki limitleri aşarsanız \ + işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.satispay.info.seller=Lütfen ödemenin, Haveno'da belirtilen XMR Alıcısının cep telefonu numarası / isminden geldiğinden emin olun.\n\n\ +Satispay hesap limitleri bireysel olarak belirlenir. Daha yüksek tutarlarda işlem yapmak istiyorsanız, limitlerinizi artırmak için Satispay \ + desteğiyle iletişime geçmeniz gerekecektir. Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Eğer yukarıdaki limitleri aşarsanız \ + işleminiz iptal edilebilir ve ceza uygulanabilir. + +payment.tikkie.info.account=Tikkie kullanmak için Hollanda'da bir banka hesabına (IBAN) sahip olmanız ve hizmete kayıtlı olmanız gerekmektedir.\n\n\ +Bir kişiye Tikkie ödeme talebi gönderdiğinizde, talep başına maksimum €750 talep edebilirsiniz.\n\n\ + Tikkie hesabı başına 24 saat içinde talep edebileceğiniz maksimum miktar €2,500'dır.\n\n\ + Ancak, her banka bu limitler dahilinde müşterileri için kendi limitlerini belirleyebilir.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Eğer yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.tikkie.info.buyer=Lütfen işlem sohbetinde XMR Satıcısından bir ödeme bağlantısı talep edin. XMR Satıcısı size \ + işlemin doğru tutarına uygun bir ödeme bağlantısı gönderdikten sonra ödeme işlemine devam edin.\n\n\ + XMR Satıcısı bir Tikkie ödemesi talep ettiğinde, talep başına maksimum €750 talep edebilir. Eğer \ + işlem bu tutarın üzerindeyse, XMR Satıcısının işlem tutarını tamamlamak için birden fazla talepte bulunması gerekecektir. Bir günde \ + talep edebileceğiniz maksimum miktar €2,500'dır.\n\n\ + Ancak, her banka bu limitler dahilinde müşterileri için kendi limitlerini belirleyebilir.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Eğer yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.tikkie.info.seller=Lütfen işlem sohbetinde XMR Alıcısına bir ödeme bağlantısı gönderin. XMR \ + Alıcısı size ödeme gönderdikten sonra, IBAN bilgilerinin Haveno'da belirtilen bilgilerle eşleştiğini kontrol edin.\n\n\ + XMR Satıcısı bir Tikkie ödemesi talep ettiğinde, talep başına maksimum €750 talep edebilir. Eğer \ + işlem bu tutarın üzerindeyse, XMR Satıcısının işlem tutarını tamamlamak için birden fazla talepte bulunması gerekecektir. Bir günde \ + talep edebileceğiniz maksimum miktar €2,500'dır.\n\n\ + Ancak, her banka bu limitler dahilinde müşterileri için kendi limitlerini belirleyebilir.\n\n\ + Kullanıcılar ayrıca hesap limitlerinin farkında olmalıdır. Eğer yukarıdaki limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. + +payment.verse.info.account=Verse, EUR, SEK, HUF, DKK ve PLN cinsinden ödeme gönderebilen ve alabilen çoklu para birimi ödeme yöntemidir.\n\n\ + Haveno'da Verse hesabınızı kurarken, Verse hesabınızdaki kullanıcı adınızla eşleşen kullanıcı adınızı eklediğinizden emin olun. \ + Bu, para gönderdiğinizde doğru hesaptan geldiğini ve para aldığınızda hesabınıza kredi olarak işlendiğini \ + sağlayacaktır.\n\n\ + Verse kullanıcıları, ödeme hesaplarından yapılan veya ödeme hesaplarına alınan toplam ödemeler için yılda €10,000 \ + (veya eşdeğer yabancı para tutarı) gönderme veya alma ile sınırlıdır. Bu limit, Verse talep üzerine artırılabilir. +payment.verse.info.buyer=Lütfen ödemeyi yalnızca XMR Satıcısının Haveno hesabında sağladığı kullanıcı adına gönderin. \ + Lütfen ödeme açıklamasını boş bırakın.\n\n\ + Verse kullanıcıları, ödeme hesaplarından yapılan veya ödeme hesaplarına alınan toplam ödemeler için yılda €10,000 \ + (veya eşdeğer yabancı para tutarı) gönderme veya alma ile sınırlıdır. Bu limit, Verse talep üzerine artırılabilir. +payment.verse.info.seller=XMR Satıcıları, ödemenin XMR Alıcısının Haveno hesabında gösterilen kullanıcı adından gelmesini beklemelidir.\n\n\ + Verse kullanıcıları, ödeme hesaplarından yapılan veya ödeme hesaplarına alınan toplam ödemeler için yılda €10,000 \ + (veya eşdeğer yabancı para tutarı) gönderme veya alma ile sınırlıdır. Bu limit, Verse talep üzerine artırılabilir. + +payment.achTransfer.info.account=Haveno'da ACH'yi bir ödeme yöntemi olarak eklerken kullanıcılar, ACH transferi \ +göndermenin ve almanın maliyetinin farkında olmalıdır. +payment.achTransfer.info.buyer=ACH transferi göndermenin size ne kadara mal olacağını bildiğinizden emin olun.\n\n\ + Ödeme yaparken, yalnızca XMR Satıcısının hesabında sağlanan ödeme bilgilerine ACH transferi kullanarak gönderin. +payment.achTransfer.info.seller=ACH transferi almanın size ne kadara mal olacağını bildiğinizden emin olun.\n\n\ + Ödeme alırken, ödemenin XMR Alıcısının hesabından bir ACH transferi olarak alındığını kontrol edin. + +payment.domesticWire.info.account=Haveno'da Yerel Havale Transferini bir ödeme yöntemi olarak eklerken kullanıcılar, \ +havale transferi göndermenin ve almanın maliyetinin farkında olmalıdır. +payment.domesticWire.info.buyer=Havale transferi göndermenin size ne kadara mal olacağını bildiğinizden emin olun.\n\n\ + Ödeme yaparken, yalnızca XMR Satıcısının hesabında sağlanan ödeme bilgilerine gönderin. +payment.domesticWire.info.seller=Havale transferi almanın size ne kadara mal olacağını bildiğinizden emin olun.\n\n\ + Ödeme alırken, ödemenin XMR Alıcısının hesabından alındığını kontrol edin. + +payment.strike.info.account=Lütfen Strike kullanıcı adınızı eklediğinizden emin olun.\n\n\ +Haveno'da Strike yalnızca fiat para birimi ödemeleri için kullanılır.\n\n\ +Strike limitlerinin farkında olduğunuzdan emin olun:\n\n\ +Yalnızca e-posta, isim ve telefon numarası ile kayıt olan kullanıcılar için limitler:\n\n\ + ● Mevduat başına maksimum $100\n\ + ● Haftalık toplam maksimum $1,000 mevduat\n\ + ● Ödeme başına maksimum $100\n\n\ +Strike'a daha fazla bilgi sağlayarak limitlerini artıran kullanıcılar için limitler:\n\n\ + ● Mevduat başına maksimum $1,000\n\ + ● Haftalık toplam maksimum $1,000 mevduat\n\ + ● Ödeme başına maksimum $1,000\n\n\ +Bu limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.strike.info.buyer=Ödemeyi yalnızca XMR Satıcısının Haveno'da sağlanan Strike kullanıcı adına gönderin.\n\n\ + Ödeme başına maksimum $1,000 işlem yapılabilir.\n\n\ +Bu limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. +payment.strike.info.seller=Ödemenin XMR Alıcısının Haveno'da sağlanan Strike kullanıcı adından alındığından emin olun.\n\n\ + Ödeme başına maksimum $1,000 işlem yapılabilir.\n\n\ +Bu limitleri aşarsanız, işleminiz iptal edilebilir ve ceza uygulanabilir. + +payment.transferwiseUsd.info.account=ABD bankacılık düzenlemeleri nedeniyle, USD ödemeleri göndermek ve almak, çoğu diğer \ +para biriminden daha fazla sınırlamaya tabidir. Bu nedenle USD, Haveno TransferWise ödeme yöntemine eklenmemiştir.\n\n\ + TransferWise-USD ödeme yöntemi, Haveno kullanıcılarının USD cinsinden ticaret yapmasına olanak tanır.\n\n\ +Wise, eski adıyla TransferWise hesabı olan herkes, Haveno'da TransferWise-USD'yi bir ödeme yöntemi olarak ekleyebilir. \ + Bu, USD ile XMR alıp satmalarını sağlar.\n\n\ +Haveno'da ticaret yaparken XMR Alıcıları, ödeme nedeni için herhangi bir referans kullanmamalıdır. Ödeme nedeni \ + gerekliyse, yalnızca TransferWise-USD hesap sahibinin tam adını kullanmalıdırlar. +payment.transferwiseUsd.info.buyer=Ödemeyi yalnızca XMR Satıcısının Haveno TransferWise-USD hesabındaki e-posta adresine gönderin. +payment.transferwiseUsd.info.seller=Alınan ödemenin, Haveno'daki TransferWise-USD hesabındaki XMR Alıcısının adıyla eşleştiğini kontrol edin. + +payment.usPostalMoneyOrder.info=Haveno'da ABD Posta Havale Emirleri (USPMO) kullanarak ticaret yapmak için aşağıdakileri anladığınızdan emin olmanız gerekmektedir:\n\ +\n\ + - XMR alıcıları, hem Ödeyen hem de Alacaklı alanlarına XMR Satıcısının adını yazmalı ve USPMO'nun ve zarfın yüksek çözünürlüklü bir fotoğrafını izleme kanıtı ile birlikte göndermeden önce çekmelidir.\n\ + - XMR alıcıları, USPMO'yu Teslimat Onayı ile XMR satıcısına göndermelidir.\n\ +\n\ + Arabuluculuk gerekirse veya bir ticaret anlaşmazlığı olursa, fotoğrafları Haveno arabulucusuna veya iade ajanına, USPMO Seri Numarası, Postane Numarası ve dolar miktarı ile birlikte göndermeniz gerekecektir, böylece detayları ABD Posta Servisi web sitesinde doğrulayabilirler.\n\n\ + Arabulucuya veya Hakeme gerekli bilgileri sağlayamamak, anlaşmazlık davasını kaybetmenize neden olacaktır.\n\n\ + Tüm anlaşmazlık davalarında, USPMO gönderen, arabulucuya veya hakeme kanıt sağlama sorumluluğunu %100 taşır.\n\n\ + Bu gereksinimleri anlamıyorsanız, Haveno'da USPMO kullanarak ticaret yapmayın. + +payment.payByMail.info=Haveno'da Posta ile Ödeme kullanarak ticaret yapmak için aşağıdakileri anladığınızdan emin olmanız gerekmektedir:\n\ + \n\ + ● XMR alıcısı, nakiti sahteciliğe karşı dayanıklı bir torbada paketlemelidir.\n\ + ● XMR alıcısı, nakit paketleme sürecini, adres ve takip numarası pakete zaten yapıştırılmış olarak filme almalı veya yüksek çözünürlüklü fotoğraflarını çekmelidir.\n\ + ● XMR alıcısı, nakit paketi Teslimat Onayı ve uygun sigorta ile XMR satıcısına göndermelidir.\n\ + ● XMR satıcısı, paketi açarken, gönderici tarafından sağlanan takip numarasının videoda görünür olduğundan emin olarak filme almalıdır.\n\ + ● Teklif veren, ödeme hesabının 'Ek Bilgiler' alanında herhangi bir özel şart veya koşulu belirtmelidir.\n\ + ● Teklifi kabul eden, teklifi alarak teklif verenin şart ve koşullarını kabul eder.\n\ + \n\ + Posta ile Ödeme ticaretleri, her iki tarafın da dürüst davranma sorumluluğunu üstlenir.\n\ + \n\ + ● Posta ile Ödeme ticaretleri, diğer geleneksel ticaretlerden daha az doğrulanabilir işlemlere sahiptir. Bu, anlaşmazlıkların çözümünü çok daha zor hale getirir.\n\ + ● Anlaşmazlıkları doğrudan trader sohbetini kullanarak çözmeye çalışın. Bu, herhangi bir Posta ile Ödeme anlaşmazlığını çözmenin en umut verici yoludur.\n\ + ● Hakemler, davanızı değerlendirip bir öneride bulunabilir, ancak yardım edecekleri GARANTİ EDİLEMEZ.\n\ + ● Hakemler, kendilerine sağlanan kanıtlara dayanarak bir karar verecektir. Bu nedenle, anlaşmazlık durumunda kanıt sağlamak için yukarıdaki süreçleri takip edip belgelendirin.\n\ + ● Haveno'ya, Posta ile Ödeme ticaretlerinden kaynaklanan kayıp fonlar için geri ödeme talepleri değerlendirilmeyecektir.\n\ + \n\ + Bu gereksinimleri anlamıyorsanız, Haveno'da Posta ile Ödeme kullanarak ticaret yapmayın. + +payment.payByMail.contact=İletişim bilgileri +payment.payByMail.contact.prompt=Zarfın üzerinde bulunması gereken isim veya takma ad +payment.payByMail.extraInfo.prompt=Tekliflerinize lütfen şunları belirtin: \n\n\ + Bulunduğunuz ülke (örneğin, Fransa); \n\ + Ticaret kabul edeceğiniz ülkeler/bölgeler (örneğin, Fransa, AB veya herhangi bir Avrupa ülkesi); \n\ + Herhangi bir özel şart/koşul; \n\ + Diğer detaylar. +payment.tradingRestrictions=Lütfen yapıcı tarafın şartlarını ve koşullarını gözden geçirin.\n\ + Gereksinimleri karşılamıyorsanız bu ticareti yapmayın. +payment.cashAtAtm.info=ATM'de Nakit: Kod kullanarak ATM'den kartsız para çekme\n\n\ + Bu ödeme yöntemini kullanmak için:\n\n\ + 1. Kabul ettiğiniz bankaları, bölgeleri veya teklifle birlikte gösterilecek diğer şartları listeleyerek bir ATM'de Nakit ödeme hesabı oluşturun.\n\n\ + 2. Ödeme hesabı ile bir teklif oluşturun veya bir teklifi kabul edin.\n\n\ + 3. Teklif kabul edildiğinde, ödeme detaylarını paylaşmak ve ödemeyi tamamlamak için eşinizle sohbet edin.\n\n\ + Ticaret sözleşmenizde belirtilen şekilde işlemi tamamlayamazsanız, güvenlik teminatınızın bir kısmını (veya tamamını) kaybedebilirsiniz. +payment.cashAtAtm.extraInfo.prompt=Tekliflerinize lütfen şunları belirtin: \n\n\ + Kabul ettiğiniz bankalar / konumlar; \n\ + Herhangi bir özel şart/koşul; \n\ + Diğer detaylar. +payment.f2f.contact=İletişim bilgileri +payment.f2f.contact.prompt=Alım satım eşiniz tarafından nasıl iletişime geçilmek istersiniz? (e-posta adresi, telefon numarası,...) +payment.f2f.city='Yüz yüze' buluşma için şehir +payment.f2f.city.prompt=Şehir teklifle birlikte gösterilecektir +payment.shared.optionalExtra=İsteğe bağlı ek bilgi +payment.shared.extraInfo=Ek bilgi +payment.shared.extraInfo.prompt=Bu ödeme hesabınız için tekliflerinize eklemek istediğiniz özel şart, koşul veya detayları tanımlayın (kullanıcılar bu bilgileri teklifleri kabul etmeden önce görecektir). +payment.f2f.info='Yüz Yüze' ticaretler farklı kurallara sahiptir ve çevrimiçi işlemlerden farklı riskler içerir.\n\n\ + Başlıca farklar şunlardır:\n\ + ● Ticaret eşleri, sağlanan iletişim bilgilerini kullanarak buluşma yeri ve zamanını paylaşmalıdır.\n\ + ● Ticaret eşleri, laptoplarını getirmeli ve ödeme gönderildi ve ödeme alındı onaylarını buluşma yerinde yapmalıdır.\n\ + ● Eğer yapıcı tarafın özel 'şart ve koşulları' varsa, bunları hesaplarındaki 'Ek bilgi' metin alanında belirtmelidir.\n\ + ● Bir teklifi kabul ederek, kabul eden taraf yapıcı tarafın belirtilen 'şart ve koşullarını' kabul eder.\n\ + ● Anlaşmazlık durumunda, arabulucu veya hakem genellikle buluşmada ne olduğunu kesin delillerle tespit etmek zor olduğu için pek \ + yardımcı olamaz. Bu tür durumlarda XMR fonları süresiz olarak veya ticaret eşleri anlaşmaya varana \ + kadar kilitlenebilir.\n\n\ + 'Yüz Yüze' ticaretlerin farklarını tam olarak anladığınızdan emin olmak için lütfen şu adresteki talimatları \ + ve tavsiyeleri okuyun: [HYPERLINK:https://docs.haveno.exchange/the-project/payment_methods/F2F] +payment.f2f.info.openURL=Web sayfasını aç +payment.f2f.offerbook.tooltip.countryAndCity=Ülke ve şehir: {0} / {1} +payment.f2f.offerbook.tooltip.extra=Ek bilgi: {0} +payment.ifsc=IFS Kodu +payment.ifsc.validation=IFSC formatı: XXXX0999999 + +payment.japan.bank=Banka +payment.japan.branch=Şube +payment.japan.account=Hesap +payment.japan.recipient=Alıcı Adı +payment.australia.payid=PayID +payment.payid=Finansal kuruma bağlı PayID. E-posta adresi veya cep telefonu gibi. +payment.payid.info=PayID, telefon numarası, e-posta adresi veya Avustralya İş Numarası (ABN) gibi, banka, kredi birliği veya yapı \ + toplum hesabınıza güvenli bir şekilde bağlayabileceğiniz bir kimliktir. Avustralya finans kurumunuzla zaten bir PayID oluşturmuş \ + olmanız gerekmektedir. Hem gönderici hem de alıcı finans kurumlarının PayID'yi desteklemesi gerekmektedir. +payment.amazonGiftCard.info=Amazon eGift Kart ile ödeme yapmak için, Amazon hesabınız aracılığıyla bir Amazon eGift Kartı'nı XMR satıcısına göndermeniz gerekecek. \n\n\ + Daha fazla ayrıntı ve en iyi uygulamalar için lütfen wiki'ye bakın: [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] \n\n\ + Üç önemli not:\n\ + - Amazon'un daha büyük hediye kartlarını sahtekarlık olarak işaretlediği bilindiğinden, 100 USD veya daha küçük tutarlarda hediye kartları göndermeye çalışın\n\ + - hediye kartının mesajı için yaratıcı, inanılabilir bir metin kullanmaya çalışın (örneğin, "Doğum günün kutlu olsun Metin Torun!") ve ticaret \ + kimliğini ekleyin (ve ticaret sohbetinde ticaret eşinize seçtiğiniz referans metnini söyleyin, böylece ödemenizi doğrulayabilirler)\n\ + - Amazon eGift Kartları, yalnızca satın alındıkları Amazon web sitesinde kullanılabilir (örneğin, amazon.it üzerinden satın alınan bir hediye kartı yalnızca amazon.it üzerinde kullanılabilir) + +# We use constants from the code so we do not use our normal naming convention +# dynamic values are not recognized by IntelliJ + +# Only translate general terms +NATIONAL_BANK=Ulusal banka transferi +SAME_BANK=Aynı banka transferi +SPECIFIC_BANKS=Belirli bankalarla transferler +US_POSTAL_MONEY_ORDER=ABD Posta Havalesi +CASH_DEPOSIT=Nakit Yatırma +PAY_BY_MAIL=Postayla Ödeme +CASH_AT_ATM=ATM'de Nakit +MONEY_GRAM=MoneyGram +WESTERN_UNION=Western Union +F2F=Yüz yüze (kişisel) +JAPAN_BANK=Japon Bankası Furikomi +AUSTRALIA_PAYID=Avustralya PayID + +# suppress inspection "UnusedProperty" +NATIONAL_BANK_SHORT=Ulusal bankalar +# suppress inspection "UnusedProperty" +SAME_BANK_SHORT=Aynı banka +# suppress inspection "UnusedProperty" +SPECIFIC_BANKS_SHORT=Belirli bankalar +# suppress inspection "UnusedProperty" +US_POSTAL_MONEY_ORDER_SHORT=ABD Havalesi +# suppress inspection "UnusedProperty" +CASH_DEPOSIT_SHORT=Nakit Yatırma +# suppress inspection "UnusedProperty" +PAY_BY_MAIL_SHORT=Postayla Ödeme +# suppress inspection "UnusedProperty" +CASH_AT_ATM_SHORT=ATM'de Nakit +# suppress inspection "UnusedProperty" +MONEY_GRAM_SHORT=MoneyGram +# suppress inspection "UnusedProperty" +WESTERN_UNION_SHORT=Western Union +# suppress inspection "UnusedProperty" +F2F_SHORT=Yüz yüze +# suppress inspection "UnusedProperty" +JAPAN_BANK_SHORT=Japon Furikomi +# suppress inspection "UnusedProperty" +AUSTRALIA_PAYID_SHORT=PayID + +# Do not translate brand names +# suppress inspection "UnusedProperty" +UPHOLD=Uphold +# suppress inspection "UnusedProperty" +MONEY_BEAM=MoneyBeam (N26) +# suppress inspection "UnusedProperty" +POPMONEY=Popmoney +# suppress inspection "UnusedProperty" +REVOLUT=Revolut +# suppress inspection "UnusedProperty" +PERFECT_MONEY=Perfect Money +# suppress inspection "UnusedProperty" +ALI_PAY=AliPay +# suppress inspection "UnusedProperty" +WECHAT_PAY=WeChat Pay +# suppress inspection "UnusedProperty" +SEPA=SEPA +# suppress inspection "UnusedProperty" +SEPA_INSTANT=SEPA Anında Ödemeler +# suppress inspection "UnusedProperty" +FASTER_PAYMENTS=Faster Payments +# suppress inspection "UnusedProperty" +SWISH=Swish +# suppress inspection "UnusedProperty" +ZELLE=Zelle +# suppress inspection "UnusedProperty" +CHASE_QUICK_PAY=Chase QuickPay +# suppress inspection "UnusedProperty" +INTERAC_E_TRANSFER=Interac e-Transfer +# suppress inspection "UnusedProperty" +HAL_CASH=HalCash +# suppress inspection "UnusedProperty" +BLOCK_CHAINS=Kripto Paralar +# suppress inspection "UnusedProperty" +PROMPT_PAY=PromptPay +# suppress inspection "UnusedProperty" +ADVANCED_CASH=Advanced Cash +# suppress inspection "UnusedProperty" +TRANSFERWISE=TransferWise +# suppress inspection "UnusedProperty" +TRANSFERWISE_USD=TransferWise-USD +# suppress inspection "UnusedProperty" +PAYSERA=Paysera +# suppress inspection "UnusedProperty" +PAXUM=Paxum +# suppress inspection "UnusedProperty" +NEFT=Hindistan/NEFT +# suppress inspection "UnusedProperty" +RTGS=Hindistan/RTGS +# suppress inspection "UnusedProperty" +IMPS=Hindistan/IMPS +# suppress inspection "UnusedProperty" +UPI=Hindistan/UPI +# suppress inspection "UnusedProperty" +PAYTM=Hindistan/PayTM +# suppress inspection "UnusedProperty" +NEQUI=Nequi +# suppress inspection "UnusedProperty" +BIZUM=Bizum +# suppress inspection "UnusedProperty" +PIX=Pix +# suppress inspection "UnusedProperty" +AMAZON_GIFT_CARD=Amazon Hediye Kartı +# suppress inspection "UnusedProperty" +BLOCK_CHAINS_INSTANT=Anında Kripto Para +# suppress inspection "UnusedProperty" +CAPITUAL=Capitual +# suppress inspection "UnusedProperty" +CELPAY=CelPay +# suppress inspection "UnusedProperty" +MONESE=Monese +# suppress inspection "UnusedProperty" +SATISPAY=Satispay +# suppress inspection "UnusedProperty" +TIKKIE=Tikkie +# suppress inspection "UnusedProperty" +VERSE=Verse +# suppress inspection "UnusedProperty" +STRIKE=Strike +# suppress inspection "UnusedProperty" +SWIFT=SWIFT International Wire Transfer +# suppress inspection "UnusedProperty" +ACH_TRANSFER=ACH Transfer +# suppress inspection "UnusedProperty" +DOMESTIC_WIRE_TRANSFER=Domestic Wire Transfer +# suppress inspection "UnusedProperty" +BSQ_SWAP=BSQ Swap + +# Deprecated: Cannot be deleted as it would break old trade history entries +# suppress inspection "UnusedProperty" +OK_PAY=OKPay +# suppress inspection "UnusedProperty" +CASH_APP=Cash App +# suppress inspection "UnusedProperty" +VENMO=Venmo +PAYPAL=PayPal + +# suppress inspection "UnusedProperty" +UPHOLD_SHORT=Uphold +# suppress inspection "UnusedProperty" +MONEY_BEAM_SHORT=MoneyBeam (N26) +# suppress inspection "UnusedProperty" +POPMONEY_SHORT=Popmoney +# suppress inspection "UnusedProperty" +REVOLUT_SHORT=Revolut +# suppress inspection "UnusedProperty" +PERFECT_MONEY_SHORT=Perfect Money +# suppress inspection "UnusedProperty" +ALI_PAY_SHORT=AliPay +# suppress inspection "UnusedProperty" +WECHAT_PAY_SHORT=WeChat Pay +# suppress inspection "UnusedProperty" +SEPA_SHORT=SEPA +# suppress inspection "UnusedProperty" +SEPA_INSTANT_SHORT=SEPA Anında +# suppress inspection "UnusedProperty" +FASTER_PAYMENTS_SHORT=Faster Payments +# suppress inspection "UnusedProperty" +SWISH_SHORT=Swish +# suppress inspection "UnusedProperty" +ZELLE_SHORT=Zelle +# suppress inspection "UnusedProperty" +CHASE_QUICK_PAY_SHORT=Chase QuickPay +# suppress inspection "UnusedProperty" +INTERAC_E_TRANSFER_SHORT=Interac e-Transfer +# suppress inspection "UnusedProperty" +HAL_CASH_SHORT=HalCash +# suppress inspection "UnusedProperty" +BLOCK_CHAINS_SHORT=Kripto Paralar +# suppress inspection "UnusedProperty" +PROMPT_PAY_SHORT=PromptPay +# suppress inspection "UnusedProperty" +ADVANCED_CASH_SHORT=Advanced Cash +# suppress inspection "UnusedProperty" +TRANSFERWISE_SHORT=TransferWise +# suppress inspection "UnusedProperty" +TRANSFERWISE_USD_SHORT=TransferWise-USD +# suppress inspection "UnusedProperty" +PAYSERA_SHORT=Paysera +# suppress inspection "UnusedProperty" +PAXUM_SHORT=Paxum +# suppress inspection "UnusedProperty" +NEFT_SHORT=NEFT +# suppress inspection "UnusedProperty" +RTGS_SHORT=RTGS +# suppress inspection "UnusedProperty" +IMPS_SHORT=IMPS +# suppress inspection "UnusedProperty" +UPI_SHORT=UPI +# suppress inspection "UnusedProperty" +PAYTM_SHORT=PayTM +# suppress inspection "UnusedProperty" +NEQUI_SHORT=Nequi +# suppress inspection "UnusedProperty" +BIZUM_SHORT=Bizum +# suppress inspection "UnusedProperty" +PIX_SHORT=Pix +# suppress inspection "UnusedProperty" +AMAZON_GIFT_CARD_SHORT=Amazon Hediye Kartı +# suppress inspection "UnusedProperty" +BLOCK_CHAINS_INSTANT_SHORT=Anında Kripto Para +# suppress inspection "UnusedProperty" +CAPITUAL_SHORT=Capitual +# suppress inspection "UnusedProperty" +CELPAY_SHORT=CelPay +# suppress inspection "UnusedProperty" +MONESE_SHORT=Monese +# suppress inspection "UnusedProperty" +SATISPAY_SHORT=Satispay +# suppress inspection "UnusedProperty" +TIKKIE_SHORT=Tikkie +# suppress inspection "UnusedProperty" +VERSE_SHORT=Verse +# suppress inspection "UnusedProperty" +STRIKE_SHORT=Strike +# suppress inspection "UnusedProperty" +SWIFT_SHORT=SWIFT +# suppress inspection "UnusedProperty" +ACH_TRANSFER_SHORT=ACH +# suppress inspection "UnusedProperty" +DOMESTIC_WIRE_TRANSFER_SHORT=Domestic Wire +# suppress inspection "UnusedProperty" +BSQ_SWAP_SHORT=BSQ Swap + +# Deprecated: Cannot be deleted as it would break old trade history entries +# suppress inspection "UnusedProperty" +OK_PAY_SHORT=OKPay +# suppress inspection "UnusedProperty" +CASH_APP_SHORT=Cash App +# suppress inspection "UnusedProperty" +VENMO_SHORT=Venmo +PAYPAL_SHORT=PayPal + + +#################################################################### +# Validation +#################################################################### + +validation.empty=Boş girişe izin verilmez. +validation.NaN=Giriş geçerli bir sayı değil. +validation.notAnInteger=Giriş bir tam sayı değeri değil. +validation.zero=0 değeri girişi izin verilmez. +validation.negative=Negatif bir değere izin verilmez. +validation.traditional.tooSmall=Minimum mümkün miktardan küçük girişe izin verilmez. +validation.traditional.tooLarge=Maksimum mümkün miktardan büyük girişe izin verilmez. +validation.xmr.fraction=Giriş, 1 satoshiden daha az bir monero değerine yol açacak +validation.xmr.tooLarge={0} değerinden büyük girişe izin verilmez. +validation.xmr.tooSmall={0} değerinden küçük girişe izin verilmez. +validation.passwordTooShort=Girdiğiniz şifre çok kısa. En az 8 karakter olmalıdır. +validation.passwordTooLong=Girdiğiniz şifre çok uzun. 50 karakterden uzun olamaz. +validation.sortCodeNumber={0} {1} rakamdan oluşmalıdır. +validation.sortCodeChars={0} {1} karakterden oluşmalıdır. +validation.bankIdNumber={0} {1} rakamdan oluşmalıdır. +validation.accountNr=Hesap numarası {0} rakamdan oluşmalıdır. +validation.accountNrChars=Hesap numarası {0} karakterden oluşmalıdır. +validation.xmr.invalidAddress=Adres doğru değil. Lütfen adres formatını kontrol edin. +validation.integerOnly=Lütfen sadece tam sayılar girin. +validation.inputError=Girdiğiniz bir hata oluşturdu:\n{0} +validation.xmr.exceedsMaxTradeLimit=İşlem limitiniz {0}. +validation.nationalAccountId={0} {1} rakamdan oluşmalıdır. + +#new +validation.invalidInput=Geçersiz giriş: {0} +validation.accountNrFormat=Hesap numarası şu formatta olmalıdır: {0} +# suppress inspection "UnusedProperty" +validation.crypto.wrongStructure=Adres doğrulaması, {0} adres yapısına uymadığı için başarısız oldu. +# suppress inspection "UnusedProperty" +validation.crypto.ltz.zAddressesNotSupported=LTZ adresi L ile başlamalıdır. z ile başlayan adresler desteklenmez. +# suppress inspection "UnusedProperty" +validation.crypto.zAddressesNotSupported=ZEC adresleri t ile başlamalıdır. z ile başlayan adresler desteklenmez. +# suppress inspection "UnusedProperty" +validation.crypto.invalidAddress=Adres geçerli bir {0} adresi değil! {1} +# suppress inspection "UnusedProperty" +validation.crypto.liquidBitcoin.invalidAddress=Yerel segwit adresleri ('lq' ile başlayanlar) desteklenmez. +validation.bic.invalidLength=Giriş uzunluğu 8 veya 11 olmalıdır. +validation.bic.letters=Banka ve Ülke kodu harflerden oluşmalıdır. +validation.bic.invalidLocationCode=BIC geçersiz konum kodu içeriyor. +validation.bic.invalidBranchCode=BIC geçersiz şube kodu içeriyor. +validation.bic.sepaRevolutBic=Revolut Sepa hesapları desteklenmez. +validation.btc.invalidFormat=Bitcoin adresi için geçersiz format. +validation.email.invalidAddress=Geçersiz adres. +validation.iban.invalidCountryCode=Ülke kodu geçersiz. +validation.iban.checkSumNotNumeric=Kontrol numarası sayısal olmalıdır. +validation.iban.nonNumericChars=Alfasayısal olmayan karakter tespit edildi. +validation.iban.checkSumInvalid=IBAN kontrol numarası geçersiz. +validation.iban.invalidLength=Numara 15 ile 34 karakter arasında olmalıdır. +validation.iban.sepaNotSupported=SEPA bu ülkede desteklenmiyor. +validation.interacETransfer.invalidAreaCode=Kanada dışı alan kodu. +validation.interacETransfer.invalidPhone=Lütfen geçerli bir 11 haneli telefon numarası (ör: 1-123-456-7890) veya bir e-posta adresi girin. +validation.interacETransfer.invalidQuestion=Sadece harfler, sayılar, boşluklar ve/veya ' _ , . ? - ' sembollerini içermelidir. +validation.interacETransfer.invalidAnswer=Tek kelime olmalı ve yalnızca harfler, sayılar ve/veya '-' sembolünü içermelidir. +validation.inputTooLarge=Giriş {0}'den büyük olmamalıdır. +validation.inputTooSmall=Giriş {0}'den büyük olmalıdır. +validation.inputToBeAtLeast=Giriş en az {0} olmalıdır. +validation.amountBelowDust=Toz limitinin altında bir miktar olan {0} satoshi'ye izin verilmez. +validation.length=Uzunluk {0} ile {1} arasında olmalıdır. +validation.fixedLength=Uzunluk {0} olmalıdır. +validation.pattern=Giriş şu formatta olmalıdır: {0} +validation.noHexString=Giriş HEX formatında değil. +validation.advancedCash.invalidFormat=Geçerli bir e-posta veya şu formatta cüzdan kimliği olmalıdır: X000000000000 +validation.invalidUrl=Geçersiz URL. +validation.mustBeDifferent=Girişiniz mevcut değerden farklı olmalıdır. +validation.cannotBeChanged=Parametre değiştirilemez. +validation.numberFormatException=Sayı formatı hatası {0} +validation.mustNotBeNegative=Giriş negatif olmamalıdır. +validation.phone.missingCountryCode=Telefon numarasını doğrulamak için iki harfli ülke kodu gerekli. +validation.phone.invalidCharacters=Telefon numarası {0} geçersiz karakterler içeriyor. +validation.phone.insufficientDigits={0}'da geçerli bir telefon numarası olacak kadar yeterli basamak yok. +validation.phone.tooManyDigits={0}'da geçerli bir telefon numarası için fazla basamak var. +validation.phone.invalidDialingCode=Numara {0} için ülke alan kodu ülke {1} için geçersiz. \ + Doğru alan kodu {2}. +validation.invalidAddressList=Geçerli adreslerin virgülle ayrılmış listesi olmalıdır. +validation.capitual.invalidFormat=Geçerli bir CAP kodu şu formatta olmalıdır: CAP-XXXXXX (6 alfasayısal karakter). + diff --git a/core/src/main/resources/i18n/displayStrings_vi.properties b/core/src/main/resources/i18n/displayStrings_vi.properties index 86328808d0..40b2b67940 100644 --- a/core/src/main/resources/i18n/displayStrings_vi.properties +++ b/core/src/main/resources/i18n/displayStrings_vi.properties @@ -36,14 +36,16 @@ shared.iUnderstand=Tôi hiểu shared.na=Không áp dụng shared.shutDown=Đóng shared.reportBug=Report bug on GitHub -shared.buyBitcoin=Mua bitcoin -shared.sellBitcoin=Bán bitcoin +shared.buyMonero=Mua monero +shared.sellMonero=Bán monero shared.buyCurrency=Mua {0} shared.sellCurrency=Bán {0} -shared.buyingBTCWith=đang mua BTC với {0} -shared.sellingBTCFor=đang bán BTC với {0} -shared.buyingCurrency=đang mua {0} (đang bán BTC) -shared.sellingCurrency=đang bán {0} (đang mua BTC) +shared.buyCurrencyLocked=Mua {0} 🔒 +shared.sellCurrencyLocked=Bán {0} 🔒 +shared.buyingXMRWith=đang mua XMR với {0} +shared.sellingXMRFor=đang bán XMR với {0} +shared.buyingCurrency=đang mua {0} (đang bán XMR) +shared.sellingCurrency=đang bán {0} (đang mua XMR) shared.buy=mua shared.sell=bán shared.buying=đang mua @@ -93,7 +95,7 @@ shared.amountMinMax=Số tiền (min - max) shared.amountHelp=Nếu mức chào giá được đặt mức tối thiểu và tối đa, bạn có thể giao dịch với bất kỳ số tiền nào trong phạm vi này shared.remove=Xoá shared.goTo=Đi đến {0} -shared.BTCMinMax=BTC (min - max) +shared.XMRMinMax=XMR (min - max) shared.removeOffer=Bỏ chào giá shared.dontRemoveOffer=Không được bỏ chào giá shared.editOffer=Chỉnh sửa chào giá @@ -103,16 +105,16 @@ shared.faq=Visit FAQ page shared.yesCancel=Có, hủy shared.nextStep=Bước tiếp theo shared.selectTradingAccount=Chọn tài khoản giao dịch -shared.fundFromSavingsWalletButton=Chuyển tiền từ Ví Haveno +shared.fundFromSavingsWalletButton=Áp dụng tiền từ ví Haveno shared.fundFromExternalWalletButton=Mở ví ngoài để nộp tiền -shared.openDefaultWalletFailed=Failed to open a Bitcoin wallet application. Are you sure you have one installed? +shared.openDefaultWalletFailed=Failed to open a Monero wallet application. Are you sure you have one installed? shared.belowInPercent=Thấp hơn % so với giá thị trường shared.aboveInPercent=Cao hơn % so với giá thị trường shared.enterPercentageValue=Nhập giá trị % shared.OR=HOẶC shared.notEnoughFunds=You don''t have enough funds in your Haveno wallet for this transaction—{0} is needed but only {1} is available.\n\nPlease add funds from an external wallet, or fund your Haveno wallet at Funds > Receive Funds. shared.waitingForFunds=Đợi nộp tiền... -shared.TheBTCBuyer=Người mua BTC +shared.TheXMRBuyer=Người mua XMR shared.You=Bạn shared.sendingConfirmation=Gửi xác nhận... shared.sendingConfirmationAgain=Hãy gửi lại xác nhận @@ -123,9 +125,8 @@ shared.noDateAvailable=Ngày tháng không hiển thị shared.noDetailsAvailable=Không có thông tin shared.notUsedYet=Chưa được sử dụng shared.date=Ngày -shared.sendFundsDetailsWithFee=Sending: {0}\nFrom address: {1}\nTo receiving address: {2}.\nRequired mining fee is: {3} ({4} satoshis/vbyte)\nTransaction vsize: {5} vKb\n\nThe recipient will receive: {6}\n\nAre you sure you want to withdraw this amount? # suppress inspection "TrailingSpacesInProperty" -shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Bitcoin consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n +shared.sendFundsDetailsDust=Haveno detected that this transaction would create a change output which is below the minimum dust threshold (and therefore not allowed by Monero consensus rules). Instead, this dust ({0} satoshi{1}) will be added to the mining fee.\n\n\n shared.copyToClipboard=Sao chép đến clipboard shared.language=Ngôn ngữ shared.country=Quốc gia @@ -140,6 +141,7 @@ shared.addNewAccount=Thêm tài khoản mới shared.ExportAccounts=Truy xuất tài khoản shared.importAccounts=Truy nhập tài khoản shared.createNewAccount=Tạo tài khoản mới +shared.createNewAccountDescription=Thông tin tài khoản của bạn được lưu trữ cục bộ trên thiết bị của bạn và chỉ được chia sẻ với đối tác giao dịch của bạn và trọng tài nếu xảy ra tranh chấp. shared.saveNewAccount=Lưu tài khoản mới shared.selectedAccount=Tài khoản được chọn shared.deleteAccount=Xóa tài khoản @@ -169,7 +171,7 @@ shared.payoutTxId=ID giao dịch chi trả shared.contractAsJson=Hợp đồng định dạng JSON shared.viewContractAsJson=Xem hợp đồng định dạng JSON shared.contract.title=Hợp đồng giao dịch có ID: {0} -shared.paymentDetails=Thông tin thanh toán BTC {0} +shared.paymentDetails=Thông tin thanh toán XMR {0} shared.securityDeposit=Tiền đặt cọc shared.yourSecurityDeposit=Tiền đặt cọc của bạn shared.contract=Hợp đồng @@ -179,19 +181,21 @@ shared.messageSendingFailed=Tin nhắn chưa gửi được. Lỗi: {0} shared.unlock=Mở khóa shared.toReceive=nhận shared.toSpend=chi -shared.btcAmount=Số lượng BTC +shared.xmrAmount=Số lượng XMR shared.yourLanguage=Ngôn ngữ của bạn shared.addLanguage=Thêm ngôn ngữ shared.total=Tổng shared.totalsNeeded=Số tiền cần shared.tradeWalletAddress=Địa chỉ ví giao dịch shared.tradeWalletBalance=Số dư ví giao dịch +shared.reserveExactAmount=Chỉ giữ lại số tiền cần thiết. Yêu cầu phí khai thác và khoảng 20 phút trước khi đề nghị của bạn được công khai. shared.makerTxFee=Người tạo: {0} shared.takerTxFee=Người nhận: {0} shared.iConfirm=Tôi xác nhận shared.openURL=Mở {0} shared.fiat=Tiền pháp định shared.crypto=Tiền mã hóa +shared.preciousMetals=Kim loại quý shared.all=Tất cả shared.edit=Chỉnh sửa shared.advancedOptions=Tùy chọn nâng cao @@ -226,8 +230,8 @@ shared.enabled=Enabled #################################################################### mainView.menu.market=Thị trường -mainView.menu.buyBtc=Mua BTC -mainView.menu.sellBtc=Bán BTC +mainView.menu.buyXmr=Mua XMR +mainView.menu.sellXmr=Bán XMR mainView.menu.portfolio=Danh Mục mainView.menu.funds=Số tiền mainView.menu.support=Hỗ trợ @@ -245,12 +249,15 @@ mainView.balance.reserved.short=Bảo lưu mainView.balance.pending.short=Bị khóa mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(Máy chủ nội bộ) +mainView.footer.localhostMoneroNode=(Máy chủ nội bộ) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=Đang kết nối với mạng Bitcoin -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=Đang kết nối với mạng Haveno +mainView.footer.xmrInfo.synchronizingWith=Đang đồng bộ với {0} tại khối: {1} / {2} +mainView.footer.xmrInfo.synchronizingWalletWith=Đang đồng bộ hóa ví với {0} tại khối: {1} / {2} +mainView.footer.xmrInfo.connectedTo=Kết nối với {0} tại khối {1} +mainView.footer.xmrInfo.syncedWith=Đã đồng bộ với {0} tại khối {1} mainView.footer.xmrInfo.connectingTo=Đang kết nối với mainView.footer.xmrInfo.connectionFailed=Connection failed to mainView.footer.xmrPeers=Monero network peers: {0} @@ -268,13 +275,13 @@ mainView.bootstrapWarning.bootstrappingToP2PFailed=Bootstrapping to Haveno netwo mainView.p2pNetworkWarnMsg.noNodesAvailable=Không có seed nodes hay đối tác ngang hàng để yêu cầu dữ liệu.\nVui lòng kiểm tra kết nối internet hoặc thử khởi động lại ứng dụng. mainView.p2pNetworkWarnMsg.connectionToP2PFailed=Connecting to the Haveno network failed (reported error: {0}).\nPlease check your internet connection or try to restart the application. -mainView.walletServiceErrorMsg.timeout=Kết nối tới mạng Bitcoin không thành công do hết thời gian chờ. -mainView.walletServiceErrorMsg.connectionError=Kết nối tới mạng Bitcoin không thành công do lỗi: {0} +mainView.walletServiceErrorMsg.timeout=Kết nối tới mạng Monero không thành công do hết thời gian chờ. +mainView.walletServiceErrorMsg.connectionError=Kết nối tới mạng Monero không thành công do lỗi: {0} mainView.walletServiceErrorMsg.rejectedTxException=A transaction was rejected from the network.\n\n{0} mainView.networkWarning.allConnectionsLost=Mất kết nối tới tất cả mạng ngang hàng {0}.\nCó thể bạn mất kết nối internet hoặc máy tính đang ở chế độ standby. -mainView.networkWarning.localhostBitcoinLost=Mất kết nối tới nút Bitcoin máy chủ nội bộ.\nVui lòng khởi động lại ứng dụng Haveno để nối với nút Bitcoin khác hoặc khởi động lại nút Bitcoin máy chủ nội bộ. +mainView.networkWarning.localhostMoneroLost=Mất kết nối tới nút Monero máy chủ nội bộ.\nVui lòng khởi động lại ứng dụng Haveno để nối với nút Monero khác hoặc khởi động lại nút Monero máy chủ nội bộ. mainView.version.update=(Có cập nhật) @@ -294,14 +301,14 @@ market.offerBook.buyWithTraditional=Mua {0} market.offerBook.sellWithTraditional=Bán {0} market.offerBook.sellOffersHeaderLabel=Bán {0} cho market.offerBook.buyOffersHeaderLabel=Mua {0} từ -market.offerBook.buy=Tôi muốn mua bitcoin -market.offerBook.sell=Tôi muốn bán bitcoin +market.offerBook.buy=Tôi muốn mua monero +market.offerBook.sell=Tôi muốn bán monero # SpreadView market.spread.numberOfOffersColumn=Tất cả chào giá ({0}) -market.spread.numberOfBuyOffersColumn=Mua BTC ({0}) -market.spread.numberOfSellOffersColumn=Bán BTC ({0}) -market.spread.totalAmountColumn=Tổng số BTC ({0}) +market.spread.numberOfBuyOffersColumn=Mua XMR ({0}) +market.spread.numberOfSellOffersColumn=Bán XMR ({0}) +market.spread.totalAmountColumn=Tổng số XMR ({0}) market.spread.spreadColumn=Chênh lệch giá market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=Tạo chào giá offerbook.takeOffer=Nhận chào giá offerbook.takeOfferToBuy=Nhận chào giá mua {0} offerbook.takeOfferToSell=Nhận chào giá bán {0} +offerbook.takeOffer.enterChallenge=Nhập mật khẩu đề nghị offerbook.trader=Trader offerbook.offerersBankId=ID ngân hàng của người tạo (BIC/SWIFT): {0} offerbook.offerersBankName=Tên ngân hàng của người tạo: {0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=Các quốc gia có ngân hàng được ch offerbook.availableOffers=Các chào giá hiện có offerbook.filterByCurrency=Lọc theo tiền tệ offerbook.filterByPaymentMethod=Lọc theo phương thức thanh toán -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=Các ưu đãi phù hợp với tài khoản của tôi +offerbook.filterNoDeposit=Không đặt cọc +offerbook.noDepositOffers=Các ưu đãi không yêu cầu đặt cọc (cần mật khẩu) offerbook.timeSinceSigning=Account info offerbook.timeSinceSigning.info=This account was verified and {0} offerbook.timeSinceSigning.info.arbitrator=signed by an arbitrator and can sign peer accounts @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=account was banned offerbook.timeSinceSigning.daysSinceSigning={0} ngày offerbook.timeSinceSigning.daysSinceSigning.long={0} since signing offerbook.xmrAutoConf=Is auto-confirm enabled +offerbook.buyXmrWith=Mua XMR với: +offerbook.sellXmrFor=Bán XMR để: offerbook.timeSinceSigning.help=When you successfully complete a trade with a peer who has a signed payment account, your payment account is signed.\n{0} days later, the initial limit of {1} is lifted and your account can sign other peers'' payment accounts. offerbook.timeSinceSigning.notSigned=Not signed yet @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=Crypto accounts do not feature signing or aging offerbook.nrOffers=Số chào giá: {0} offerbook.volume={0} (min - max) -offerbook.deposit=Deposit BTC (%) +offerbook.deposit=Deposit XMR (%) offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed. +offerbook.createNewOffer=Tạo ưu đãi cho {0} {1} offerbook.createOfferToBuy=Tạo chào giá mua mới {0} offerbook.createOfferToSell=Tạo chào giá bán mới {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=With this version of the software, trad popup.warning.tradeLimitDueAccountAgeRestriction.seller=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- The buyer''s account has not been signed by an arbitrator or a peer\n- The time since signing of the buyer''s account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=The allowed trade amount is limited to {0} because of security restrictions based on the following criteria:\n- Your account has not been signed by an arbitrator or a peer\n- The time since signing of your account is not at least 30 days\n- The payment method for this offer is considered risky for bank chargebacks\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=Phương thức thanh toán này tạm thời chỉ được giới hạn đến {0} cho đến {1} vì tất cả các người mua đều có tài khoản mới.\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=Đề nghị của bạn sẽ bị giới hạn chỉ đối với các người mua có tài khoản đã ký và có tuổi vì nó vượt quá {0}.\n\n{1} offerbook.warning.wrongTradeProtocol=Lệnh này cần phiên bản giao thức khác với được sử dụng trong phiên bản phần mềm của bạn.\n\nHãy kiểm tra xem bạn đã cài đặt phiên bản mới nhất chưa, nếu không người dùng đã tạo lệnh đã sử dụng phiên bản cũ.\n\nNgười dùng không thể giao dịch với phiên bản giao thức giao dịch không tương thích. offerbook.warning.userIgnored=Bạn đã thêm địa chỉ onion của người dùng vào danh sách bỏ qua. @@ -394,7 +409,6 @@ offerbook.warning.offerBlocked=Báo giá này bị chặn bởi các lập trìn offerbook.warning.currencyBanned=Loại tiền sử dụng trong báo giá này bị chặn bởi các lập trình viên Haveno.\nTruy cập diễn đàn Haveno để biết thêm thông tin. offerbook.warning.paymentMethodBanned=Phương thức thanh toán sử dụng trong báo giá này bị chặn bởi các lập trình viên Haveno.\nTruy cập diễn đàn Haveno để biết thêm thông tin. offerbook.warning.nodeBlocked=Địa chỉ onion của Thương gia bị chặn bởi các lập trình viên Haveno.\nCó thể có sự cố chưa được xử lý dẫn tới vấn đề khi nhận báo giá từ Thương gia này. -offerbook.warning.requireUpdateToNewVersion=Your version of Haveno is not compatible for trading anymore.\nPlease update to the latest Haveno version at [HYPERLINK:https://haveno.exchange/downloads]. offerbook.warning.offerWasAlreadyUsedInTrade=You cannot take this offer because you already took it earlier. It could be that your previous take-offer attempt resulted in a failed trade. offerbook.info.sellAtMarketPrice=Bạn sẽ bán với giá thị trường (cập nhật mỗi phút). @@ -412,13 +426,13 @@ offerbook.info.roundedFiatVolume=Số lượng đã được làm tròn để t # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=Nhập số tiền bằng BTC +createOffer.amount.prompt=Nhập số tiền bằng XMR createOffer.price.prompt=Nhập giá createOffer.volume.prompt=Nhập số tiền bằng {0} -createOffer.amountPriceBox.amountDescription=Số tiền BTC đến {0} +createOffer.amountPriceBox.amountDescription=Số tiền XMR đến {0} createOffer.amountPriceBox.buy.volumeDescription=Số tiền {0} để chi trả createOffer.amountPriceBox.sell.volumeDescription=Số tiền {0} để nhận -createOffer.amountPriceBox.minAmountDescription=Số tiền BTC nhỏ nhất +createOffer.amountPriceBox.minAmountDescription=Số tiền XMR nhỏ nhất createOffer.securityDeposit.prompt=Tiền đặt cọc createOffer.fundsBox.title=Nộp tiền cho chào giá của bạn createOffer.fundsBox.offerFee=Phí giao dịch @@ -434,7 +448,7 @@ createOffer.info.sellAboveMarketPrice=Bạn sẽ luôn nhận {0}% cao hơn so v createOffer.info.buyBelowMarketPrice=Bạn sẽ luôn trả {0}% thấp hơn so với giá thị trường hiện tại vì báo giá của bạn sẽ luôn được cập nhật. createOffer.warning.sellBelowMarketPrice=Bạn sẽ luôn nhận {0}% thấp hơn so với giá thị trường hiện tại vì báo giá của bạn sẽ luôn được cập nhật. createOffer.warning.buyAboveMarketPrice=Bạn sẽ luôn trả {0}% cao hơn so với giá thị trường hiện tại vì báo giá của bạn sẽ luôn được cập nhật. -createOffer.tradeFee.descriptionBTCOnly=Phí giao dịch +createOffer.tradeFee.descriptionXMROnly=Phí giao dịch createOffer.tradeFee.descriptionBSQEnabled=Chọn loại tiền trả phí giao dịch createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +462,12 @@ createOffer.placeOfferButton=Kiểm tra:: Đặt báo giá cho {0} monero createOffer.createOfferFundWalletInfo.headline=Nộp tiền cho báo giá của bạn # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- Khoản tiền giao dịch: {0} \n -createOffer.createOfferFundWalletInfo.msg=Bạn cần đặt cọc {0} cho báo giá này.\n\nCác khoản tiền này sẽ được giữ trong ví nội bộ của bạn và sẽ bị khóa vào địa chỉ đặt cọc multisig khi có người nhận báo giá của bạn.\n\nKhoản tiền này là tổng của:\n{1}- tiền gửi đại lý của bạn: {2}\n- Phí giao dịch: {3}\n- Phí đào: {4}\n\nBạn có thể chọn giữa hai phương án khi nộp tiền cho giao dịch:\n- Sử dụng ví Haveno của bạn (tiện lợi, nhưng giao dịch có thể bị kết nối) OR\n- Chuyển từ ví bên ngoài (riêng tư hơn)\n\nBạn sẽ xem các phương án nộp tiền và thông tin chi tiết sau khi đóng cửa sổ này. +createOffer.createOfferFundWalletInfo.msg=Bạn cần nạp {0} cho lời đề nghị này.\n\n\ + Số tiền này sẽ được giữ trong ví cục bộ của bạn và sẽ được khóa vào ví multisig ngay khi có người chấp nhận lời đề nghị của bạn.\n\n\ + Số tiền bao gồm:\n\ + {1}\ + - Tiền đặt cọc bảo đảm của bạn: {2}\n\ + - Phí giao dịch: {3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=Có lỗi xảy ra khi đặt chào giá:\n\n{0}\n\nKhông còn tiền trong ví của bạn.\nHãy khởi động lại ứng dụng và kiểm tra kết nối mạng. @@ -470,30 +489,35 @@ createOffer.setDepositAsBuyer=Cài đặt tiền đặt cọc của tôi với v createOffer.setDepositForBothTraders=Set both traders' security deposit (%) createOffer.securityDepositInfo=Số tiền đặt cọc cho người mua của bạn sẽ là {0} createOffer.securityDepositInfoAsBuyer=Số tiền đặt cọc của bạn với vai trò người mua sẽ là {0} -createOffer.minSecurityDepositUsed=Min. buyer security deposit is used +createOffer.minSecurityDepositUsed=Khoản tiền đặt cọc bảo mật tối thiểu được sử dụng +createOffer.buyerAsTakerWithoutDeposit=Không cần đặt cọc từ người mua (được bảo vệ bằng mật khẩu) +createOffer.myDeposit=Tiền đặt cọc bảo mật của tôi (%) +createOffer.myDepositInfo=Khoản tiền đặt cọc của bạn sẽ là {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=Nhập giá trị bằng BTC -takeOffer.amountPriceBox.buy.amountDescription=Số lượng BTC bán -takeOffer.amountPriceBox.sell.amountDescription=Số lượng BTC mua -takeOffer.amountPriceBox.priceDescription=Giá mỗi bitcoin bằng {0} +takeOffer.amount.prompt=Nhập giá trị bằng XMR +takeOffer.amountPriceBox.buy.amountDescription=Số lượng XMR bán +takeOffer.amountPriceBox.sell.amountDescription=Số lượng XMR mua +takeOffer.amountPriceBox.priceDescription=Giá mỗi monero bằng {0} takeOffer.amountPriceBox.amountRangeDescription=Số lượng khả dụng -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=Giá trị bạn vừa nhập vượt quá số ký tự thập phân cho phép.\nGiá trị phải được điều chỉnh về 4 số thập phân. +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=Giá trị bạn vừa nhập vượt quá số ký tự thập phân cho phép.\nGiá trị phải được điều chỉnh về 4 số thập phân. takeOffer.validation.amountSmallerThanMinAmount=Số tiền không được nhỏ hơn giá trị nhỏ nhất của lệnh. takeOffer.validation.amountLargerThanOfferAmount=Số tiền nhập không được cao hơn số tiền cao nhất của lệnh -takeOffer.validation.amountLargerThanOfferAmountMinusFee=Giá trị nhập này sẽ làm thay đổi đối với người bán BTC. +takeOffer.validation.amountLargerThanOfferAmountMinusFee=Giá trị nhập này sẽ làm thay đổi đối với người bán XMR. takeOffer.fundsBox.title=Nộp tiền cho giao dịch của bạn takeOffer.fundsBox.isOfferAvailable=Kiểm tra xem có chào giá không ... takeOffer.fundsBox.tradeAmount=Số tiền để bán takeOffer.fundsBox.offerFee=Phí giao dịch takeOffer.fundsBox.networkFee=Tổng phí đào -takeOffer.fundsBox.takeOfferSpinnerInfo=Đang nhận chào giá ... +takeOffer.fundsBox.takeOfferSpinnerInfo=Chấp nhận đề xuất: {0} takeOffer.fundsBox.paymentLabel=giao dịch Haveno có ID {0} takeOffer.fundsBox.fundsStructure=({0} tiền gửi đại lý, {1} phí giao dịch, {2} phí đào) +takeOffer.fundsBox.noFundingRequiredTitle=Không cần tài trợ +takeOffer.fundsBox.noFundingRequiredDescription=Lấy mật khẩu giao dịch từ người bán ngoài Haveno để nhận đề nghị này. takeOffer.success.headline=Bạn đã nhận báo giá thành công. takeOffer.success.info=Bạn có thể xem trạng thái giao dịch của bạn tại \"Portfolio/Các giao dịch mở\". takeOffer.error.message=Có lỗi xảy ra khi nhận báo giá.\n\n{0} @@ -504,7 +528,7 @@ takeOffer.noPriceFeedAvailable=Bạn không thể nhận báo giá này do sử takeOffer.takeOfferFundWalletInfo.headline=Nộp tiền cho giao dịch của bạn # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- Giá trị giao dịch: {0} \n -takeOffer.takeOfferFundWalletInfo.msg=Bạn cần nộp {0} để nhận báo giá này.\n\nGiá trị này là tổng của:\n{1}- Tiền ứng trước của bạn: {2}\n- phí giao dịch: {3}\n- Tổng phí đào: {4}\n\nBạn có thể chọn một trong hai phương án khi nộp tiền cho giao dịch của bạn:\n- Sử dụng ví Haveno (tiện lợi, nhưng giao dịch có thể bị kết nối) OR\n- Chuyển từ ví ngoài (riêng tư hơn)\n\nBạn sẽ thấy các phương án nộp tiền và thông tin chi tiết sau khi đóng cửa sổ này. +takeOffer.takeOfferFundWalletInfo.msg=Bạn cần phải deposit {0} để chấp nhận đề nghị này.\n\nSố tiền là tổng của:\n{1}- Khoản tiền đặt cọc của bạn: {2}\n- Phí giao dịch: {3} takeOffer.alreadyPaidInFunds=Bạn đã thanh toán, bạn có thể rút số tiền này tại màn hình \"Vốn/Gửi vốn\". takeOffer.paymentInfo=Thông tin thanh toán takeOffer.setAmountPrice=Cài đặt số tiền @@ -597,29 +621,29 @@ portfolio.pending.step1.openForDispute=The deposit transaction is still not conf # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=Hãy chuyển từ ví ngoài {0} của bạn\n{1} cho người bán BTC.\n\n +portfolio.pending.step2_buyer.crypto=Hãy chuyển từ ví ngoài {0} của bạn\n{1} cho người bán XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=Hãy đến ngân hàng và thanh toán {0} cho người bán BTC.\n\n -portfolio.pending.step2_buyer.cash.extra=YÊU CẦU QUAN TRỌNG:\nSau khi bạn đã thanh toán xong hãy viết lên giấy biên nhận: KHÔNG HOÀN TRẢ.\nSau đó xé thành 2 phần, chụp ảnh và gửi tới email của người bán BTC. +portfolio.pending.step2_buyer.cash=Hãy đến ngân hàng và thanh toán {0} cho người bán XMR.\n\n +portfolio.pending.step2_buyer.cash.extra=YÊU CẦU QUAN TRỌNG:\nSau khi bạn đã thanh toán xong hãy viết lên giấy biên nhận: KHÔNG HOÀN TRẢ.\nSau đó xé thành 2 phần, chụp ảnh và gửi tới email của người bán XMR. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=Vui lòng trả {0} cho người bán BTC qua MoneyGram.\n\n -portfolio.pending.step2_buyer.moneyGram.extra=Yêu cầu quan trọng:\nSau khi bạn hoàn thành chi trả hãy gửi Số xác thực và hình chụp hoá đơn qua email cho người bán BTC.\nHoá đơn phải chỉ rõ họ tên đầy đủ, quốc gia, tiểu bang và số tiền. Email người bán là: {0}. +portfolio.pending.step2_buyer.moneyGram=Vui lòng trả {0} cho người bán XMR qua MoneyGram.\n\n +portfolio.pending.step2_buyer.moneyGram.extra=Yêu cầu quan trọng:\nSau khi bạn hoàn thành chi trả hãy gửi Số xác thực và hình chụp hoá đơn qua email cho người bán XMR.\nHoá đơn phải chỉ rõ họ tên đầy đủ, quốc gia, tiểu bang và số tiền. Email người bán là: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=Hãy thanh toán {0} cho người bán BTC bằng cách sử dụng Western Union.\n\n -portfolio.pending.step2_buyer.westernUnion.extra=YÊU CẦU QUAN TRỌNG:\nSau khi bạn đã thanh toán xong hãy gửi MTCN (số theo dõi) và ảnh giấy biên nhận bằng email cho người bán BTC.\nGiấy biên nhận phải ghi rõ họ tên của người bán, thành phố, quốc gia và số tiền. Địa chỉ email của người bán là: {0}. +portfolio.pending.step2_buyer.westernUnion=Hãy thanh toán {0} cho người bán XMR bằng cách sử dụng Western Union.\n\n +portfolio.pending.step2_buyer.westernUnion.extra=YÊU CẦU QUAN TRỌNG:\nSau khi bạn đã thanh toán xong hãy gửi MTCN (số theo dõi) và ảnh giấy biên nhận bằng email cho người bán XMR.\nGiấy biên nhận phải ghi rõ họ tên của người bán, thành phố, quốc gia và số tiền. Địa chỉ email của người bán là: {0}. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=Hãy gửi {0} bằng \"Phiếu chuyển tiền US\" cho người bán BTC.\n\n +portfolio.pending.step2_buyer.postal=Hãy gửi {0} bằng \"Phiếu chuyển tiền US\" cho người bán XMR.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=Vui lòng liên hệ người bán BTC và cung cấp số liên hệ và sắp xếp cuộc hẹn để thanh toán {0}.\n\n +portfolio.pending.step2_buyer.f2f=Vui lòng liên hệ người bán XMR và cung cấp số liên hệ và sắp xếp cuộc hẹn để thanh toán {0}.\n\n portfolio.pending.step2_buyer.startPaymentUsing=Thanh toán bắt đầu sử dụng {0} portfolio.pending.step2_buyer.recipientsAccountData=Recipients {0} portfolio.pending.step2_buyer.amountToTransfer=Số tiền chuyển @@ -628,27 +652,27 @@ portfolio.pending.step2_buyer.buyerAccount=Tài khoản thanh toán sẽ sử d portfolio.pending.step2_buyer.paymentSent=Bắt đầu thanh toán portfolio.pending.step2_buyer.warn=You still have not done your {0} payment!\nPlease note that the trade has to be completed by {1}. portfolio.pending.step2_buyer.openForDispute=You have not completed your payment!\nThe max. period for the trade has elapsed.Please contact the mediator for assistance. -portfolio.pending.step2_buyer.paperReceipt.headline=Bạn đã gửi giấy biên nhận cho người bán BTC chưa? -portfolio.pending.step2_buyer.paperReceipt.msg=Remember:\nBạn cần phải viết trên giấy biên nhận: KHÔNG HOÀN TRẢ.\nSau đó xé thành 2 phần, chụp ảnh và gửi đến email của người bán BTC. +portfolio.pending.step2_buyer.paperReceipt.headline=Bạn đã gửi giấy biên nhận cho người bán XMR chưa? +portfolio.pending.step2_buyer.paperReceipt.msg=Remember:\nBạn cần phải viết trên giấy biên nhận: KHÔNG HOÀN TRẢ.\nSau đó xé thành 2 phần, chụp ảnh và gửi đến email của người bán XMR. portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=Gửi số xác nhận và hoá đơn -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Bạn cần gửi số xác thực và ảnh chụp của hoá đơn qua email đến người bán BTC.\nHoá đơn phải ghi rõ họ tên đầy đủ người bán, quốc gia, tiểu bang và số lượng. Email người bán là: {0}.\n\nBạn đã gửi số xác thực và hợp đồng cho người bán? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=Bạn cần gửi số xác thực và ảnh chụp của hoá đơn qua email đến người bán XMR.\nHoá đơn phải ghi rõ họ tên đầy đủ người bán, quốc gia, tiểu bang và số lượng. Email người bán là: {0}.\n\nBạn đã gửi số xác thực và hợp đồng cho người bán? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=Gửi MTCN và biên nhận -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Bạn cần phải gửi MTCN (số theo dõi) và ảnh chụp giấy biên nhận bằng email cho người bán BTC.\nGiấy biên nhận phải nêu rõ họ tên, thành phố, quốc gia của người bán và số tiền. Địa chỉ email của người bán là: {0}.\n\nBạn đã gửi MTCN và hợp đồng cho người bán chưa? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=Bạn cần phải gửi MTCN (số theo dõi) và ảnh chụp giấy biên nhận bằng email cho người bán XMR.\nGiấy biên nhận phải nêu rõ họ tên, thành phố, quốc gia của người bán và số tiền. Địa chỉ email của người bán là: {0}.\n\nBạn đã gửi MTCN và hợp đồng cho người bán chưa? portfolio.pending.step2_buyer.halCashInfo.headline=Gửi mã HalCash -portfolio.pending.step2_buyer.halCashInfo.msg=Bạn cần nhắn tin mã HalCash và mã giao dịch ({0}) tới người bán BTC. \nSố điện thoại của người bán là {1}.\n\nBạn đã gửi mã tới người bán chưa? +portfolio.pending.step2_buyer.halCashInfo.msg=Bạn cần nhắn tin mã HalCash và mã giao dịch ({0}) tới người bán XMR. \nSố điện thoại của người bán là {1}.\n\nBạn đã gửi mã tới người bán chưa? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=Some banks might verify the receiver's name. Faster Payments accounts created in old Haveno clients do not provide the receiver's name, so please use trade chat to obtain it (if needed). portfolio.pending.step2_buyer.confirmStart.headline=Xác nhận rằng bạn đã bắt đầu thanh toán portfolio.pending.step2_buyer.confirmStart.msg=Bạn đã kích hoạt thanh toán {0} cho Đối tác giao dịch của bạn chưa? portfolio.pending.step2_buyer.confirmStart.yes=Có, tôi đã bắt đầu thanh toán portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=You have not provided proof of payment -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the BTC as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=You have not entered the transaction ID and the transaction key.\n\nBy not providing this data the peer cannot use the auto-confirm feature to release the XMR as soon the XMR has been received.\nBeside that, Haveno requires that the sender of the XMR transaction is able to provide this information to the mediator or arbitrator in case of a dispute.\nSee more details on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=Input is not a 32 byte hexadecimal value portfolio.pending.step2_buyer.confirmStart.warningButton=Ignore and continue anyway portfolio.pending.step2_seller.waitPayment.headline=Đợi thanh toán portfolio.pending.step2_seller.f2fInfo.headline=Thông tin liên lạc của người mua -portfolio.pending.step2_seller.waitPayment.msg=Giao dịch đặt cọc có ít nhất một xác nhận blockchain.\nBạn cần phải đợi cho đến khi người mua BTC bắt đầu thanh toán {0}. -portfolio.pending.step2_seller.warn=Người mua BTC vẫn chưa thanh toán {0}.\nBạn cần phải đợi cho đến khi người mua bắt đầu thanh toán.\nNếu giao dịch không được hoàn thành vào {1} trọng tài sẽ điều tra. -portfolio.pending.step2_seller.openForDispute=The BTC buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. +portfolio.pending.step2_seller.waitPayment.msg=Giao dịch đặt cọc có ít nhất một xác nhận blockchain.\nBạn cần phải đợi cho đến khi người mua XMR bắt đầu thanh toán {0}. +portfolio.pending.step2_seller.warn=Người mua XMR vẫn chưa thanh toán {0}.\nBạn cần phải đợi cho đến khi người mua bắt đầu thanh toán.\nNếu giao dịch không được hoàn thành vào {1} trọng tài sẽ điều tra. +portfolio.pending.step2_seller.openForDispute=The XMR buyer has not started their payment!\nThe max. allowed period for the trade has elapsed.\nYou can wait longer and give the trading peer more time or contact the mediator for assistance. tradeChat.chatWindowTitle=Chat window for trade with ID ''{0}'' tradeChat.openChat=Open chat window tradeChat.rules=You can communicate with your trade peer to resolve potential problems with this trade.\nIt is not mandatory to reply in the chat.\nIf a trader violates any of the rules below, open a dispute and report it to the mediator or arbitrator.\n\nChat rules:\n\t● Do not send any links (risk of malware). You can send the transaction ID and the name of a block explorer.\n\t● Do not send your seed words, private keys, passwords or other sensitive information!\n\t● Do not encourage trading outside of Haveno (no security).\n\t● Do not engage in any form of social engineering scam attempts.\n\t● If a peer is not responding and prefers to not communicate via chat, respect their decision.\n\t● Keep conversation scope limited to the trade. This chat is not a messenger replacement or troll-box.\n\t● Keep conversation friendly and respectful. @@ -666,26 +690,26 @@ message.state.ACKNOWLEDGED=Người nhận xác nhận tin nhắn # suppress inspection "UnusedProperty" message.state.FAILED=Gửi tin nhắn không thành công -portfolio.pending.step3_buyer.wait.headline=Đợi người bán BTC xác nhận thanh toán -portfolio.pending.step3_buyer.wait.info=Đợi người bán BTC xác nhận đã nhận thanh toán {0}. +portfolio.pending.step3_buyer.wait.headline=Đợi người bán XMR xác nhận thanh toán +portfolio.pending.step3_buyer.wait.info=Đợi người bán XMR xác nhận đã nhận thanh toán {0}. portfolio.pending.step3_buyer.wait.msgStateInfo.label=Thông báo trạng thái thanh toán đã bắt đầu portfolio.pending.step3_buyer.warn.part1a=trên blockchain {0} portfolio.pending.step3_buyer.warn.part1b=tại nhà cung cấp thanh toán của bạn (VD: ngân hàng) -portfolio.pending.step3_buyer.warn.part2=The BTC seller still has not confirmed your payment. Please check {0} if the payment sending was successful. -portfolio.pending.step3_buyer.openForDispute=The BTC seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. +portfolio.pending.step3_buyer.warn.part2=The XMR seller still has not confirmed your payment. Please check {0} if the payment sending was successful. +portfolio.pending.step3_buyer.openForDispute=The XMR seller has not confirmed your payment! The max. period for the trade has elapsed. You can wait longer and give the trading peer more time or request assistance from the mediator. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=Đối tác giao dịch của bạn đã xác nhận rằng họ đã kích hoạt thanh toán {0}.\n\n portfolio.pending.step3_seller.crypto.explorer=Trên trình duyệt blockchain explorer {0} ưa thích của bạn portfolio.pending.step3_seller.crypto.wallet=Trên ví {0} của bạn portfolio.pending.step3_seller.crypto={0}Vui lòng kiểm tra {1} xem giao dịch tới địa chỉ nhận của bạn \n{2}\nđã nhận được đủ xác nhận blockchain hay chưa.\nSố tiền thanh toán phải là {3}\n\nBạn có thể copy & paste địa chỉ {4} của bạn từ màn hình chính sau khi đóng cửa sổ này. -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=Vì thanh toán được thực hiện qua Tiền gửi tiền mặt nên người mua BTC phải viết rõ \"KHÔNG HOÀN LẠI\" trên giấy biên nhận, xé làm 2 phần và gửi ảnh cho bạn qua email.\n\nĐể tránh bị đòi tiền lại, chỉ xác nhận bạn đã nhận được email và bạn chắc chắn giấy biên nhận là có hiệu lực.\nNếu bạn không chắc chắn, {0} -portfolio.pending.step3_seller.moneyGram=Người mua phải gửi mã số xác nhận và ảnh chụp của hoá đơn qua email.\nHoá đơn cần ghi rõ họ tên đầy đủ, quốc gia, tiêu bang và số lượng. Vui lòng kiểm tra email nếu bạn nhận được số xác thực.\n\nSau khi popup đóng, bạn sẽ thấy tên người mua BTC và địa chỉ để nhận tiền từ MoneyGram.\n\nChỉ xác nhận hoá đơn sau khi bạn hoàn thành việc nhận tiền. -portfolio.pending.step3_seller.westernUnion=Người mua phải gửi cho bạn MTCN (số theo dõi) và ảnh giấy biên nhận qua email.\nGiấy biên nhận phải ghi rõ họ tên của bạn, thành phố, quốc gia và số tiền. Hãy kiểm tra email xem bạn đã nhận được MTCN chưa.\n\nSau khi đóng cửa sổ này, bạn sẽ thấy tên và địa chỉ của người mua BTC để nhận tiền từ Western Union.\n\nChỉ xác nhận giấy biên nhận sau khi bạn đã nhận tiền thành công! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=Vì thanh toán được thực hiện qua Tiền gửi tiền mặt nên người mua XMR phải viết rõ \"KHÔNG HOÀN LẠI\" trên giấy biên nhận, xé làm 2 phần và gửi ảnh cho bạn qua email.\n\nĐể tránh bị đòi tiền lại, chỉ xác nhận bạn đã nhận được email và bạn chắc chắn giấy biên nhận là có hiệu lực.\nNếu bạn không chắc chắn, {0} +portfolio.pending.step3_seller.moneyGram=Người mua phải gửi mã số xác nhận và ảnh chụp của hoá đơn qua email.\nHoá đơn cần ghi rõ họ tên đầy đủ, quốc gia, tiêu bang và số lượng. Vui lòng kiểm tra email nếu bạn nhận được số xác thực.\n\nSau khi popup đóng, bạn sẽ thấy tên người mua XMR và địa chỉ để nhận tiền từ MoneyGram.\n\nChỉ xác nhận hoá đơn sau khi bạn hoàn thành việc nhận tiền. +portfolio.pending.step3_seller.westernUnion=Người mua phải gửi cho bạn MTCN (số theo dõi) và ảnh giấy biên nhận qua email.\nGiấy biên nhận phải ghi rõ họ tên của bạn, thành phố, quốc gia và số tiền. Hãy kiểm tra email xem bạn đã nhận được MTCN chưa.\n\nSau khi đóng cửa sổ này, bạn sẽ thấy tên và địa chỉ của người mua XMR để nhận tiền từ Western Union.\n\nChỉ xác nhận giấy biên nhận sau khi bạn đã nhận tiền thành công! portfolio.pending.step3_seller.halCash=Người mua phải gửi mã HalCash cho bạn bằng tin nhắn. Ngoài ra, bạn sẽ nhận được một tin nhắn từ HalCash với thông tin cần thiết để rút EUR từ một máy ATM có hỗ trợ HalCash. \n\nSau khi nhận được tiền từ ATM vui lòng xác nhận lại biên lai thanh toán tại đây! portfolio.pending.step3_seller.amazonGiftCard=The buyer has sent you an Amazon eGift Card by email or by text message to your mobile phone. Please redeem now the Amazon eGift Card at your Amazon account and once accepted confirm the payment receipt. @@ -701,7 +725,7 @@ portfolio.pending.step3_seller.xmrTxHash=ID giao dịch portfolio.pending.step3_seller.xmrTxKey=Transaction key portfolio.pending.step3_seller.buyersAccount=Buyers account data portfolio.pending.step3_seller.confirmReceipt=Xác nhận đã nhận được thanh toán -portfolio.pending.step3_seller.buyerStartedPayment=Người mua BTC đã bắt đầu thanh toán {0}.\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=Người mua XMR đã bắt đầu thanh toán {0}.\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=Kiểm tra xác nhận blockchain ở ví crypto của bạn hoặc block explorer và xác nhận thanh toán nếu bạn nhận được đủ xác nhận blockchain. portfolio.pending.step3_seller.buyerStartedPayment.traditional=Kiểm tra tại tài khoản giao dịch của bạn (VD: Tài khoản ngân hàng) và xác nhận khi bạn đã nhận được thanh toán. portfolio.pending.step3_seller.warn.part1a=trên {0} blockchain @@ -713,7 +737,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=Bạn đã nhận đượ # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=Please also verify that the name of the sender specified on the trade contract matches the name that appears on your bank statement:\nSender''s name, per trade contract: {0}\n\nIf the names are not exactly the same, don''t confirm payment receipt. Instead, open a dispute by pressing \"alt + o\" or \"option + o\".\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the BTC buyer and the security deposit will be refunded.\n\n +portfolio.pending.step3_seller.onPaymentReceived.note=Please note, that as soon you have confirmed the receipt, the locked trade amount will be released to the XMR buyer and the security deposit will be refunded.\n\n portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=Xác nhận rằng bạn đã nhận được thanh toán portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=Vâng, tôi đã nhận được thanh toán portfolio.pending.step3_seller.onPaymentReceived.signer=IMPORTANT: By confirming receipt of payment, you are also verifying the account of the counterparty and signing it accordingly. Since the account of the counterparty hasn't been signed yet, you should delay confirmation of the payment as long as possible to reduce the risk of a chargeback. @@ -723,7 +747,7 @@ portfolio.pending.step5_buyer.tradeFee=Phí giao dịch portfolio.pending.step5_buyer.makersMiningFee=Phí đào portfolio.pending.step5_buyer.takersMiningFee=Tổng phí đào portfolio.pending.step5_buyer.refunded=tiền gửi đặt cọc được hoàn lại -portfolio.pending.step5_buyer.withdrawBTC=Rút bitcoin của bạn +portfolio.pending.step5_buyer.withdrawXMR=Rút monero của bạn portfolio.pending.step5_buyer.amount=Số tiền được rút portfolio.pending.step5_buyer.withdrawToAddress=rút tới địa chỉ portfolio.pending.step5_buyer.moveToHavenoWallet=Keep funds in Haveno wallet @@ -732,7 +756,7 @@ portfolio.pending.step5_buyer.alreadyWithdrawn=Số tiền của bạn đã đư portfolio.pending.step5_buyer.confirmWithdrawal=Xác nhận yêu cầu rút portfolio.pending.step5_buyer.amountTooLow=Số tiền chuyển nhỏ hơn phí giao dịch và giá trị tx tối thiểu (dust). portfolio.pending.step5_buyer.withdrawalCompleted.headline=Rút hoàn tất -portfolio.pending.step5_buyer.withdrawalCompleted.msg=Các giao dịch đã hoàn thành của bạn được lưu trong \"Portfolio/Lịch sử\".\nBạn có thể xem lại tất cả giao dịch bitcoin của bạn tại \"Vốn/Giao dịch\" +portfolio.pending.step5_buyer.withdrawalCompleted.msg=Các giao dịch đã hoàn thành của bạn được lưu trong \"Portfolio/Lịch sử\".\nBạn có thể xem lại tất cả giao dịch monero của bạn tại \"Vốn/Giao dịch\" portfolio.pending.step5_buyer.bought=Bạn đã mua portfolio.pending.step5_buyer.paid=Bạn đã thanh toán @@ -794,7 +818,7 @@ portfolio.pending.mediationResult.popup.alreadyAccepted=You've already accepted portfolio.pending.failedTrade.taker.missingTakerFeeTx=The taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked and no trade fee has been paid. You can move this trade to failed trades. portfolio.pending.failedTrade.maker.missingTakerFeeTx=The peer's taker fee transaction is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked. Your offer is still available to other traders, so you have not lost the maker fee. You can move this trade to failed trades. portfolio.pending.failedTrade.missingDepositTx=The deposit transaction (the 2-of-2 multisig transaction) is missing.\n\nWithout this tx, the trade cannot be completed. No funds have been locked but your trade fee has been paid. You can make a request to be reimbursed the trade fee here: [HYPERLINK:https://github.com/bisq-network/support/issues]\n\nFeel free to move this trade to failed trades. -portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the BTC seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] +portfolio.pending.failedTrade.buyer.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing, but funds have been locked in the deposit transaction.\n\nPlease do NOT send the traditional or crypto payment to the XMR seller, because without the delayed payout tx, arbitration cannot be opened. Instead, open a mediation ticket with Cmd/Ctrl+o. The mediator should suggest that both peers each get back the the full amount of their security deposits (with seller receiving full trade amount back as well). This way, there is no security risk, and only trade fees are lost. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.seller.existingDepositTxButMissingDelayedPayoutTx=The delayed payout transaction is missing but funds have been locked in the deposit transaction.\n\nIf the buyer is also missing the delayed payout transaction, they will be instructed to NOT send the payment and open a mediation ticket instead. You should also open a mediation ticket with Cmd/Ctrl+o. \n\nIf the buyer has not sent payment yet, the mediator should suggest that both peers each get back the full amount of their security deposits (with seller receiving full trade amount back as well). Otherwise the trade amount should go to the buyer. \n\nYou can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.errorMsgSet=There was an error during trade protocol execution.\n\nError: {0}\n\nIt might be that this error is not critical, and the trade can be completed normally. If you are unsure, open a mediation ticket to get advice from Haveno mediators. \n\nIf the error was critical and the trade cannot be completed, you might have lost your trade fee. Request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] portfolio.pending.failedTrade.missingContract=The trade contract is not set.\n\nThe trade cannot be completed and you might have lost your trade fee. If so, you can request a reimbursement for lost trade fees here: [HYPERLINK:https://github.com/bisq-network/support/issues] @@ -833,7 +857,7 @@ funds.deposit.fundHavenoWallet=Nộp tiền ví Haveno funds.deposit.noAddresses=Chưa có địa chỉ nộp tiền được tạo funds.deposit.fundWallet=Nộp tiền cho ví của bạn funds.deposit.withdrawFromWallet=Chuyển tiền từ ví -funds.deposit.amount=Số tiền bằng BTC (tùy chọn) +funds.deposit.amount=Số tiền bằng XMR (tùy chọn) funds.deposit.generateAddress=Tạo địa chỉ mới funds.deposit.generateAddressSegwit=Native segwit format (Bech32) funds.deposit.selectUnused=Vui lòng chọn địa chỉ chưa sử dụng từ bảng trên hơn là tạo một địa chỉ mới. @@ -892,7 +916,7 @@ funds.tx.direction.self=Gửi cho chính bạn funds.tx.reimbursementRequestTxFee=Yêu cầu bồi hoàn funds.tx.compensationRequestTxFee=Yêu cầu bồi thường funds.tx.dustAttackTx=Số dư nhỏ đã nhận -funds.tx.dustAttackTx.popup=Giao dịch này đang gửi một lượng BTC rất nhỏ vào ví của bạn và có thể đây là cách các công ty phân tích chuỗi đang tìm cách theo dõi ví của bạn.\nNếu bạn sử dụng đầu ra giao dịch đó cho một giao dịch chi tiêu, họ sẽ phát hiện ra rằng rất có thể bạn cũng là người sở hửu cái ví kia (nhập coin). \n\nĐể bảo vệ quyền riêng tư của bạn, ví Haveno sẽ bỏ qua các đầu ra có số dư nhỏ dành cho mục đích chi tiêu cũng như hiển thị số dư. Bạn có thể thiết lập ngưỡng khi một đầu ra được cho là có số dư nhỏ trong phần cài đặt. +funds.tx.dustAttackTx.popup=Giao dịch này đang gửi một lượng XMR rất nhỏ vào ví của bạn và có thể đây là cách các công ty phân tích chuỗi đang tìm cách theo dõi ví của bạn.\nNếu bạn sử dụng đầu ra giao dịch đó cho một giao dịch chi tiêu, họ sẽ phát hiện ra rằng rất có thể bạn cũng là người sở hửu cái ví kia (nhập coin). \n\nĐể bảo vệ quyền riêng tư của bạn, ví Haveno sẽ bỏ qua các đầu ra có số dư nhỏ dành cho mục đích chi tiêu cũng như hiển thị số dư. Bạn có thể thiết lập ngưỡng khi một đầu ra được cho là có số dư nhỏ trong phần cài đặt. #################################################################### # Support @@ -906,7 +930,6 @@ support.filter=Search disputes support.filter.prompt=Nhập ID giao dịch, ngày tháng, địa chỉ onion hoặc dữ liệu tài khoản support.sigCheck.button=Check signature -support.sigCheck.popup.info=In case of a reimbursement request to the DAO you need to paste the summary message of the mediation and arbitration process in your reimbursement request on Github. To make this statement verifiable any user can check with this tool if the signature of the mediator or arbitrator matches the summary message. support.sigCheck.popup.header=Verify dispute result signature support.sigCheck.popup.msg.label=Summary message support.sigCheck.popup.msg.prompt=Copy & paste summary message from dispute @@ -942,8 +965,8 @@ support.savedInMailbox=Tin nhắn lưu trong hộp thư của người nhận support.arrived=Tin nhắn đã đến người nhận support.acknowledged=xác nhận tin nhắn đã được gửi bởi người nhận support.error=Người nhận không thể tiến hành gửi tin nhắn: Lỗi: {0} -support.buyerAddress=Địa chỉ người mua BTC -support.sellerAddress=Địa chỉ người bán BTC +support.buyerAddress=Địa chỉ người mua XMR +support.sellerAddress=Địa chỉ người bán XMR support.role=Vai trò support.agent=Support agent support.state=Trạng thái @@ -951,13 +974,12 @@ support.chat=Chat support.closed=Đóng support.open=Mở support.process=Process -support.buyerMaker=Người mua BTC/Người tạo -support.sellerMaker=Người bán BTC/Người tạo -support.buyerTaker=Người mua BTC/Người nhận -support.sellerTaker=Người bán BTC/Người nhận +support.buyerMaker=Người mua XMR/Người tạo +support.sellerMaker=Người bán XMR/Người tạo +support.buyerTaker=Người mua XMR/Người nhận +support.sellerTaker=Người bán XMR/Người nhận -support.backgroundInfo=Haveno is not a company, so it handles disputes differently.\n\nTraders can communicate within the application via secure chat on the open trades screen to try solving disputes on their own. If that is not sufficient, a mediator can step in to help. The mediator will evaluate the situation and suggest a payout of trade funds. If both traders accept this suggestion, the payout transaction is completed and the trade is closed. If one or both traders do not agree to the mediator's suggested payout, they can request arbitration.The arbitrator will re-evaluate the situation and, if warranted, personally pay the trader back and request reimbursement for this payment from Haveno. -support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the BTC buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the BTC seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} +support.initialInfo=Please enter a description of your problem in the text field below. Add as much information as possible to speed up dispute resolution time.\n\nHere is a check list for information you should provide:\n\t● If you are the XMR buyer: Did you make the Fiat or Crypto transfer? If so, did you click the 'payment started' button in the application?\n\t● If you are the XMR seller: Did you receive the Fiat or Crypto payment? If so, did you click the 'payment received' button in the application?\n\t● Which version of Haveno are you using?\n\t● Which operating system are you using?\n\t● If you encountered an issue with failed transactions please consider switching to a new data directory.\n\t Sometimes the data directory gets corrupted and leads to strange bugs. \n\t See: https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\nPlease make yourself familiar with the basic rules for the dispute process:\n\t● You need to respond to the {0}''s requests within 2 days.\n\t● Mediators respond in between 2 days. Arbitrators respond in between 5 business days.\n\t● The maximum period for a dispute is 14 days.\n\t● You need to cooperate with the {1} and provide the information they request to make your case.\n\t● You accepted the rules outlined in the dispute document in the user agreement when you first started the application.\n\nYou can read more about the dispute process at: {2} support.systemMsg=Tin nhắn hệ thống: {0} support.youOpenedTicket=Bạn đã mở yêu cầu hỗ trợ.\n\n{0}\n\nPhiên bản Haveno: {1} support.youOpenedDispute=Bạn đã mở yêu cầu giải quyết tranh chấp.\n\n{0}\n\nPhiên bản Haveno: {1} @@ -981,13 +1003,14 @@ settings.tab.network=Thông tin mạng settings.tab.about=Về setting.preferences.general=Tham khảo chung -setting.preferences.explorer=Bitcoin Explorer +setting.preferences.explorer=Monero Explorer setting.preferences.deviation=Sai lệch tối đa so với giá thị trường setting.preferences.avoidStandbyMode=Tránh để chế độ chờ +setting.preferences.useSoundForNotifications=Phát âm thanh cho thông báo setting.preferences.autoConfirmXMR=XMR auto-confirm setting.preferences.autoConfirmEnabled=Enabled setting.preferences.autoConfirmRequiredConfirmations=Required confirmations -setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (BTC) +setting.preferences.autoConfirmMaxTradeSize=Max. trade amount (XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer URLs (uses Tor, except for localhost, LAN IP addresses, and *.local hostnames) setting.preferences.deviationToLarge=Giá trị không được phép lớn hơn {0}%. setting.preferences.txFee=Withdrawal transaction fee (satoshis/vbyte) @@ -1024,29 +1047,31 @@ settings.preferences.editCustomExplorer.name=Tên settings.preferences.editCustomExplorer.txUrl=Transaction URL settings.preferences.editCustomExplorer.addressUrl=Address URL -settings.net.btcHeader=Mạng Bitcoin +settings.net.xmrHeader=Mạng Monero settings.net.p2pHeader=Haveno network settings.net.onionAddressLabel=Địa chỉ onion của tôi settings.net.xmrNodesLabel=Sử dụng nút Monero thông dụng settings.net.moneroPeersLabel=Các đối tác được kết nối +settings.net.connection=Kết nối +settings.net.connected=Kết nối settings.net.useTorForXmrJLabel=Sử dụng Tor cho mạng Monero settings.net.moneroNodesLabel=nút Monero để kết nối -settings.net.useProvidedNodesRadio=Sử dụng các nút Bitcoin Core đã cung cấp -settings.net.usePublicNodesRadio=Sử dụng mạng Bitcoin công cộng -settings.net.useCustomNodesRadio=Sử dụng nút Bitcoin Core thông dụng +settings.net.useProvidedNodesRadio=Sử dụng các nút Monero Core đã cung cấp +settings.net.usePublicNodesRadio=Sử dụng mạng Monero công cộng +settings.net.useCustomNodesRadio=Sử dụng nút Monero Core thông dụng settings.net.warn.usePublicNodes=If you use public Monero nodes, you are subject to any risk of using untrusted remote nodes.\n\nPlease read more details at [HYPERLINK:https://www.getmonero.org/resources/moneropedia/remote-node.html].\n\nAre you sure you want to use public nodes? settings.net.warn.usePublicNodes.useProvided=Không, sử dụng nút được cung cấp settings.net.warn.usePublicNodes.usePublic=Vâng, sử dụng nút công cộng -settings.net.warn.useCustomNodes.B2XWarning=Vui lòng chắc chắn rằng nút Bitcoin của bạn là nút Bitcoin Core đáng tin cậy!\n\nKết nối với nút không tuân thủ nguyên tắc đồng thuận Bitcoin Core có thể làm hỏng ví của bạn và gây ra các vấn đề trong quá trình giao dịch.\n\nNgười dùng kết nối với nút vi phạm nguyên tắc đồng thuận chịu trách nhiệm đối với các thiệt hại mà việc này gây ra. Các khiếu nại do điều này gây ra sẽ được quyết định theo hướng có lợi cho đối tác bên kia. Sẽ không có hỗ trợ về mặt kỹ thuật nào cho người dùng không tuân thủ cơ chế cảnh báo và bảo vệ của chúng tôi! -settings.net.warn.invalidBtcConfig=Connection to the Bitcoin network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Bitcoin nodes instead. You will need to restart the application. -settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Bitcoin node when starting. If it is found, Haveno will communicate with the Bitcoin network exclusively through it. +settings.net.warn.useCustomNodes.B2XWarning=Vui lòng chắc chắn rằng nút Monero của bạn là nút Monero Core đáng tin cậy!\n\nKết nối với nút không tuân thủ nguyên tắc đồng thuận Monero Core có thể làm hỏng ví của bạn và gây ra các vấn đề trong quá trình giao dịch.\n\nNgười dùng kết nối với nút vi phạm nguyên tắc đồng thuận chịu trách nhiệm đối với các thiệt hại mà việc này gây ra. Các khiếu nại do điều này gây ra sẽ được quyết định theo hướng có lợi cho đối tác bên kia. Sẽ không có hỗ trợ về mặt kỹ thuật nào cho người dùng không tuân thủ cơ chế cảnh báo và bảo vệ của chúng tôi! +settings.net.warn.invalidXmrConfig=Connection to the Monero network failed because your configuration is invalid.\n\nYour configuration has been reset to use the provided Monero nodes instead. You will need to restart the application. +settings.net.localhostXmrNodeInfo=Background information: Haveno looks for a local Monero node when starting. If it is found, Haveno will communicate with the Monero network exclusively through it. settings.net.p2PPeersLabel=Các đối tác được kết nối settings.net.onionAddressColumn=Địa chỉ onion settings.net.creationDateColumn=Đã thiết lập settings.net.connectionTypeColumn=Vào/Ra settings.net.sentDataLabel=Sent data statistics settings.net.receivedDataLabel=Received data statistics -settings.net.chainHeightLabel=Latest BTC block height +settings.net.chainHeightLabel=Latest XMR block height settings.net.roundTripTimeColumn=Khứ hồi settings.net.sentBytesColumn=Đã gửi settings.net.receivedBytesColumn=Đã nhận @@ -1061,7 +1086,7 @@ settings.net.needRestart=Bạn cần khởi động lại ứng dụng để tha settings.net.notKnownYet=Chưa biết... settings.net.sentData=Sent data: {0}, {1} messages, {2} messages/sec settings.net.receivedData=Received data: {0}, {1} messages, {2} messages/sec -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=[Địa chỉ IP:tên cổng | máy chủ:cổng | Địa chỉ onion:cổng] (tách bằng dấu phẩy). Cổng có thể bỏ qua nếu sử dụng mặc định (8333). settings.net.seedNode=nút cung cấp thông tin settings.net.directPeer=Đối tác (trực tiếp) @@ -1070,7 +1095,7 @@ settings.net.peer=Đối tác settings.net.inbound=chuyến về settings.net.outbound=chuyến đi setting.about.aboutHaveno=Về Haveno -setting.about.about=Haveno là một phần mềm mã nguồn mở nhằm hỗ trợ quá trình trao đổi giữa bitcoin và tiền tệ quốc gia (và các loại tiền crypto khác) thông qua một mạng lưới ngang hàng phi tập trung hoạt động trên cơ sở bảo vệ tối đa quyền riêng tư của người dùng. Vui lòng tìm hiểu thêm về Haveno trên trang web dự án của chúng tôi. +setting.about.about=Haveno là một phần mềm mã nguồn mở nhằm hỗ trợ quá trình trao đổi giữa monero và tiền tệ quốc gia (và các loại tiền crypto khác) thông qua một mạng lưới ngang hàng phi tập trung hoạt động trên cơ sở bảo vệ tối đa quyền riêng tư của người dùng. Vui lòng tìm hiểu thêm về Haveno trên trang web dự án của chúng tôi. setting.about.web=Trang web Haveno setting.about.code=Mã nguồn setting.about.agpl=Giấy phép AGPL @@ -1107,7 +1132,7 @@ setting.about.shortcuts.openDispute.value=Select pending trade and click: {0} setting.about.shortcuts.walletDetails=Open wallet details window -setting.about.shortcuts.openEmergencyBtcWalletTool=Open emergency wallet tool for BTC wallet +setting.about.shortcuts.openEmergencyXmrWalletTool=Open emergency wallet tool for XMR wallet setting.about.shortcuts.showTorLogs=Toggle log level for Tor messages between DEBUG and WARN @@ -1133,7 +1158,7 @@ setting.about.shortcuts.sendPrivateNotification=Send private notification to pee setting.about.shortcuts.sendPrivateNotification.value=Open peer info at avatar and press: {0} setting.info.headline=New XMR auto-confirm Feature -setting.info.msg=When selling BTC for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of BTC per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades] +setting.info.msg=When selling XMR for XMR you can use the auto-confirm feature to verify that the correct amount of XMR was sent to your wallet so that Haveno can automatically mark the trade as complete, making trades quicker for everyone.\n\nAuto-confirm checks the XMR transaction on at least 2 XMR explorer nodes using the private transaction key provided by the XMR sender. By default, Haveno uses explorer nodes run by Haveno contributors, but we recommend running your own XMR explorer node for maximum privacy and security.\n\nYou can also set the maximum amount of XMR per trade to auto-confirm as well as the number of required confirmations here in Settings.\n\nSee more details (including how to set up your own explorer node) on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades] #################################################################### # Account #################################################################### @@ -1142,7 +1167,7 @@ account.tab.mediatorRegistration=Mediator registration account.tab.refundAgentRegistration=Refund agent registration account.tab.signing=Signing account.info.headline=Chào mừng đến với tài khoản Haveno của bạn -account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Bitcoin wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Bitcoin wallet seed words (see tab on the top) and consider adding a password before funding. Bitcoin deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Bitcoin addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). +account.info.msg=Here you can add trading accounts for national currencies & cryptos and create a backup of your wallet & account data.\n\nA new Monero wallet was created the first time you started Haveno.\n\nWe strongly recommend that you write down your Monero wallet seed words (see tab on the top) and consider adding a password before funding. Monero deposits and withdrawals are managed in the \"Funds\" section.\n\nPrivacy & security note: because Haveno is a decentralized exchange, all your data is kept on your computer. There are no servers, so we have no access to your personal info, your funds, or even your IP address. Data such as bank account numbers, crypto & Monero addresses, etc are only shared with your trading partner to fulfill trades you initiate (in case of a dispute the mediator or arbitrator will see the same data as your trading peer). account.menu.paymentAccount=Tài khoản tiền tệ quốc gia account.menu.altCoinsAccountView=Tài khoản Crypto @@ -1153,7 +1178,7 @@ account.menu.backup=Dự phòng account.menu.notifications=Thông báo account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1182,7 +1207,7 @@ account.crypto.popup.upx.msg=Trading UPX on Haveno requires that you understand # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=Trading ARQ on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending ARQ, you need to use either the official ArQmA GUI wallet or ArQmA CLI wallet with the store-tx-info flag enabled (default in new versions). Please be sure you can access the tx key as that would be required in case of a dispute.\narqma-wallet-cli (use the command get_tx_key)\narqma-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nAt normal block explorers the transfer is not verifiable.\n\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The ARQ sender is responsible for providing verification of the ARQ transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process visit ArQmA discord channel (https://discord.gg/s9BQpJT) or the ArQmA forum (https://labs.arqma.com) to find more information. # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://bisq.wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://bisq.wiki/Trading_Monero#Auto-confirming_trades]. +account.crypto.popup.xmr.msg=Trading XMR on Haveno requires that you understand the following requirement.\n\nIf selling XMR, you must be able to provide the following information to a mediator or arbitrator in case of a dispute:\n- the transaction key (Tx Key, Tx Secret Key or Tx Private Key)\n- the transaction ID (Tx ID or Tx Hash)\n- the destination address (recipient's address)\n\nSee the wiki for details on where to find this information on popular Monero wallets [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Proving_payments].\nFailure to provide the required transaction data will result in losing disputes.\n\nAlso note that Haveno now offers automatic confirming for XMR transactions to make trades quicker, but you need to enable it in Settings.\n\nSee the wiki for more information about the auto-confirm feature: [HYPERLINK:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades]. # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=Trading MSR on Haveno requires that you understand and fulfill the following requirements:\n\nFor sending MSR, you need to use either the official Masari GUI wallet, Masari CLI wallet with the store-tx-info flag enabled (enabled by default) or the Masari web wallet (https://wallet.getmasari.org). Please be sure you can access the tx key as that would be required in case of a dispute.\nmasari-wallet-cli (use the command get_tx_key)\nmasari-wallet-gui (go to history tab and click on the (P) button for payment proof)\n\nMasari Web Wallet (goto Account -> transaction history and view details on your sent transaction)\n\nVerification can be accomplished in-wallet.\nmasari-wallet-cli : using command (check_tx_key).\nmasari-wallet-gui : on the Advanced > Prove/Check page.\nVerification can be accomplished in the block explorer \nOpen block explorer (https://explorer.getmasari.org), use the search bar to find your transaction hash.\nOnce transaction is found, scroll to bottom to the 'Prove Sending' area and fill in details as needed.\nYou need to provide the mediator or arbitrator the following data in case of a dispute:\n- The tx private key\n- The transaction hash\n- The recipient's public address\n\nFailure to provide the above data, or if you used an incompatible wallet, will result in losing the dispute case. The MSR sender is responsible for providing verification of the MSR transfer to the mediator or arbitrator in case of a dispute.\n\nThere is no payment ID required, just the normal public address.\nIf you are not sure about that process, ask for help on the Official Masari Discord (https://discord.gg/sMCwMqs). # suppress inspection "UnusedProperty" @@ -1210,7 +1235,7 @@ account.crypto.popup.pars.msg=Trading ParsiCoin on Haveno requires that you unde account.crypto.popup.blk-burnt.msg=To trade burnt blackcoins, you need to know the following:\n\nBurnt blackcoins are unspendable. To trade them on Haveno, output scripts need to be in the form: OP_RETURN OP_PUSHDATA, followed by associated data bytes which, after being hex-encoded, constitute addresses. For example, burnt blackcoins with an address 666f6f (“foo” in UTF-8) will have the following script:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\nTo create burnt blackcoins, one may use the “burn” RPC command available in some wallets.\n\nFor possible use cases, one may look at https://ibo.laboratorium.ee .\n\nAs burnt blackcoins are unspendable, they can not be reselled. “Selling” burnt blackcoins means burning ordinary blackcoins (with associated data equal to the destination address).\n\nIn case of a dispute, the BLK seller needs to provide the transaction hash. # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=Trading L-BTC on Haveno requires that you understand the following:\n\nWhen receiving L-BTC for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-BTC into the Liquid Elements Core wallet, or another L-BTC wallet which allows you to obtain the blinding key for your blinded L-BTC address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-BTC address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-BTC receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-BTC on Haveno. +account.crypto.popup.liquidmonero.msg=Trading L-XMR on Haveno requires that you understand the following:\n\nWhen receiving L-XMR for a trade on Haveno, you cannot use the mobile Blockstream Green Wallet app or a custodial/exchange wallet. You must only receive L-XMR into the Liquid Elements Core wallet, or another L-XMR wallet which allows you to obtain the blinding key for your blinded L-XMR address.\n\nIn the event mediation is necessary, or if a trade dispute arises, you must disclose the blinding key for your receiving L-XMR address to the Haveno mediator or refund agent so they can verify the details of your Confidential Transaction on their own Elements Core full node.\n\nFailure to provide the required information to the mediator or refund agent will result in losing the dispute case. In all cases of dispute, the L-XMR receiver bears 100% of the burden of responsibility in providing cryptographic proof to the mediator or refund agent.\n\nIf you do not understand these requirements, do not trade L-XMR on Haveno. account.traditional.yourTraditionalAccounts=Các tài khoản tiền tệ quốc gia của bạn @@ -1230,13 +1255,13 @@ account.password.setPw.button=Cài đặt mật khẩu account.password.setPw.headline=Cài đặt bảo vệ mật khẩu cho ví account.password.info=Khi bật tính năng bảo vệ bằng mật khẩu, bạn sẽ cần nhập mật khẩu khi khởi chạy ứng dụng, khi rút monero ra khỏi ví và khi hiển thị các từ khóa khôi phục. -account.seed.backup.title=Sao lưu dự phòng từ khởi tạo ví của bạn -account.seed.info=Hãy viết ra từ khởi tạo ví của bạn và ngày! Bạn có thể khôi phục ví của bạn bất cứ lúc nào với các từ khởi tạo và ngày này.\nTừ khởi tạo được sử dụng chung cho cả ví BTC và BSQ.\n\nBạn nên viết các từ khởi tạo ra tờ giấy. Không được lưu trên máy tính.\n\nLưu ý rằng từ khởi tạo KHÔNG PHẢI là phương án thay thế cho sao lưu dự phòng.\nBạn cần sao lưu dự phòng toàn bộ thư mục của ứng dụng tại màn hình \"Tài khoản/Sao lưu dự phòng\" để khôi phục trạng thái và dữ liệu ứng dụng.\nNhập từ khởi tạo chỉ được thực hiện trong tình huống khẩn cấp. Ứng dụng sẽ không hoạt động mà không có dự phòng các file dữ liệu và khóa phù hợp! -account.seed.backup.warning=Please note that the seed words are NOT a replacement for a backup.\nYou need to create a backup of the whole application directory from the \"Account/Backup\" screen to recover application state and data.\nImporting seed words is only recommended for emergency cases. The application will not be functional without a proper backup of the database files and keys!\n\nSee the wiki page [HYPERLINK:https://bisq.wiki/Backing_up_application_data] for extended info. +account.seed.backup.title=Sao lưu từ khóa hạt giống của ví của bạn +account.seed.info=Vui lòng ghi chép cả từ khóa hạt giống ví và ngày tháng. Bạn có thể khôi phục ví bất cứ lúc nào với từ khóa hạt giống và ngày tháng đó.\n\nBạn nên ghi chép từ khóa hạt giống trên một tờ giấy. Không nên lưu chúng trên máy tính.\n\nLưu ý rằng từ khóa hạt giống KHÔNG thay thế cho việc sao lưu. Bạn cần tạo một bản sao lưu của toàn bộ thư mục ứng dụng từ màn hình "Tài khoản/Sao lưu" để khôi phục trạng thái và dữ liệu của ứng dụng. +account.seed.backup.warning=Vui lòng lưu ý rằng từ khóa hạt giống KHÔNG thay thế cho việc sao lưu.\nBạn cần tạo một bản sao lưu của toàn bộ thư mục ứng dụng từ màn hình "Tài khoản/Sao lưu" để khôi phục trạng thái và dữ liệu của ứng dụng. account.seed.warn.noPw.msg=Bạn đã tạo mật khẩu ví để bảo vệ tránh hiển thị Seed words.\n\nBạn có muốn hiển thị Seed words? account.seed.warn.noPw.yes=Có và không hỏi lại account.seed.enterPw=Nhập mật khẩu để xem seed words -account.seed.restore.info=Vui lòng tạo sao lưu dự phòng trước khi tiến hành khôi phục ví từ các từ khởi tạo. Phải hiểu rằng việc khôi phục ví chỉ nên thực hiện trong các trường hợp khẩn cấp và có thể gây sự cố với cơ sở dữ liệu ví bên trong.\nĐây không phải là một cách sao lưu dự phòng! Vui lòng sử dụng sao lưu dự phòng từ thư mục dữ liệu của ứng dụng để khôi phục trạng thái ban đầu của ứng dụng.\n\nSau khi khôi phục ứng dụng sẽ tự động tắt. Sau khi bạn khởi động lại, ứng dụng sẽ tái đồng bộ với mạng Bitcoin. Quá trình này có thể mất một lúc và tiêu tốn khá nhiều CPU, đặc biệt là khi ví đã cũ và có nhiều giao dịch. Vui lòng không làm gián đoạn quá trình này, nếu không bạn có thể sẽ phảỉ xóa file chuỗi SPV một lần nữa hoặc lặp lại quy trình khôi phục. +account.seed.restore.info=Vui lòng tạo sao lưu dự phòng trước khi tiến hành khôi phục ví từ các từ khởi tạo. Phải hiểu rằng việc khôi phục ví chỉ nên thực hiện trong các trường hợp khẩn cấp và có thể gây sự cố với cơ sở dữ liệu ví bên trong.\nĐây không phải là một cách sao lưu dự phòng! Vui lòng sử dụng sao lưu dự phòng từ thư mục dữ liệu của ứng dụng để khôi phục trạng thái ban đầu của ứng dụng.\n\nSau khi khôi phục ứng dụng sẽ tự động tắt. Sau khi bạn khởi động lại, ứng dụng sẽ tái đồng bộ với mạng Monero. Quá trình này có thể mất một lúc và tiêu tốn khá nhiều CPU, đặc biệt là khi ví đã cũ và có nhiều giao dịch. Vui lòng không làm gián đoạn quá trình này, nếu không bạn có thể sẽ phảỉ xóa file chuỗi SPV một lần nữa hoặc lặp lại quy trình khôi phục. account.seed.restore.ok=Được, hãy thực hiện khôi phục và tắt ứng dụng Haveno @@ -1261,13 +1286,13 @@ account.notifications.trade.label=Nhận tin nhắn giao dịch account.notifications.market.label=Nhận thông báo chào hàng account.notifications.price.label=Nhận thông báo về giá account.notifications.priceAlert.title=Thông báo về giá -account.notifications.priceAlert.high.label=Thông báo nếu giá BTC cao hơn -account.notifications.priceAlert.low.label=Thông báo nếu giá BTC thấp hơn +account.notifications.priceAlert.high.label=Thông báo nếu giá XMR cao hơn +account.notifications.priceAlert.low.label=Thông báo nếu giá XMR thấp hơn account.notifications.priceAlert.setButton=Đặt thông báo giá account.notifications.priceAlert.removeButton=Gỡ thông báo giá account.notifications.trade.message.title=Trạng thái giao dịch thay đổi account.notifications.trade.message.msg.conf=Lệnh nạp tiền cho giao dịch có mã là {0} đã được xác nhận. Vui lòng mở ứng dụng Haveno và bắt đầu thanh toán. -account.notifications.trade.message.msg.started=Người mua BTC đã tiến hành thanh toán cho giao dịch có mã là {0}. +account.notifications.trade.message.msg.started=Người mua XMR đã tiến hành thanh toán cho giao dịch có mã là {0}. account.notifications.trade.message.msg.completed=Giao dịch có mã là {0} đã hoàn thành. account.notifications.offer.message.title=Chào giá của bạn đã được chấp nhận account.notifications.offer.message.msg=Chào giá mã {0} của bạn đã được chấp nhận @@ -1277,10 +1302,10 @@ account.notifications.dispute.message.msg=Bạn nhận được một tin nhắn account.notifications.marketAlert.title=Thông báo chào giá account.notifications.marketAlert.selectPaymentAccount=Tài khoản thanh toán khớp với chào giá account.notifications.marketAlert.offerType.label=Loại chào giátôi muốn -account.notifications.marketAlert.offerType.buy=Chào mua (Tôi muốn bán BTC) -account.notifications.marketAlert.offerType.sell=Chào bán (Tôi muốn mua BTC) +account.notifications.marketAlert.offerType.buy=Chào mua (Tôi muốn bán XMR) +account.notifications.marketAlert.offerType.sell=Chào bán (Tôi muốn mua XMR) account.notifications.marketAlert.trigger=Khoảng cách giá chào (%) -account.notifications.marketAlert.trigger.info=Khi đặt khoảng cách giá, bạn chỉ nhận được thông báo khi có một chào giá bằng (hoặc cao hơn) giá bạn yêu cầu được đăng lên. Ví dụ: Bạn muốn bán BTC, nhưng chỉ bán với giá cao hơn thị trường hiện tại 2%. Đặt trường này ở mức 2% sẽ đảm bảo là bạn chỉ nhận được thông báo từ những chào giá cao hơn 2%(hoặc hơn) so với giá thị trường hiện tại. +account.notifications.marketAlert.trigger.info=Khi đặt khoảng cách giá, bạn chỉ nhận được thông báo khi có một chào giá bằng (hoặc cao hơn) giá bạn yêu cầu được đăng lên. Ví dụ: Bạn muốn bán XMR, nhưng chỉ bán với giá cao hơn thị trường hiện tại 2%. Đặt trường này ở mức 2% sẽ đảm bảo là bạn chỉ nhận được thông báo từ những chào giá cao hơn 2%(hoặc hơn) so với giá thị trường hiện tại. account.notifications.marketAlert.trigger.prompt=Khoảng cách phần trăm so với giá thị trường (vd: 2.50%, -0.50%, ...) account.notifications.marketAlert.addButton=Thêm thông báo chào giá account.notifications.marketAlert.manageAlertsButton=Quản lý thông báo chào giá @@ -1307,10 +1332,10 @@ inputControlWindow.balanceLabel=Số dư hiện có contractWindow.title=Thông tin khiếu nại contractWindow.dates=Ngày chào giá / Ngày giao dịch -contractWindow.btcAddresses=Địa chỉ Bitcoin người mua BTC / người bán BTC -contractWindow.onions=Địa chỉ mạng người mua BTC / người bán BTC -contractWindow.accountAge=Tuổi tài khoản người mua BTC/người bán BTC -contractWindow.numDisputes=Số khiếu nại người mua BTC / người bán BTC +contractWindow.xmrAddresses=Địa chỉ Monero người mua XMR / người bán XMR +contractWindow.onions=Địa chỉ mạng người mua XMR / người bán XMR +contractWindow.accountAge=Tuổi tài khoản người mua XMR/người bán XMR +contractWindow.numDisputes=Số khiếu nại người mua XMR / người bán XMR contractWindow.contractHash=Hash của hợp đồng displayAlertMessageWindow.headline=Thông tin quan trọng! @@ -1336,8 +1361,8 @@ disputeSummaryWindow.title=Tóm tắt disputeSummaryWindow.openDate=Ngày mở đơn disputeSummaryWindow.role=Vai trò của người giao dịch disputeSummaryWindow.payout=Khoản tiền giao dịch hoàn lại -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} nhận được khoản tiền giao dịch hoàn lại -disputeSummaryWindow.payout.getsAll=Max. payout to BTC {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} nhận được khoản tiền giao dịch hoàn lại +disputeSummaryWindow.payout.getsAll=Max. payout to XMR {0} disputeSummaryWindow.payout.custom=Thuế hoàn lại disputeSummaryWindow.payoutAmount.buyer=Khoản tiền hoàn lại của người mua disputeSummaryWindow.payoutAmount.seller=Khoản tiền hoàn lại của người bán @@ -1379,7 +1404,7 @@ disputeSummaryWindow.close.button=Đóng đơn # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for BTC buyer: {6}\nPayout amount for BTC seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n +disputeSummaryWindow.close.msg=Ticket closed on {0}\n{1} node address: {2}\n\nSummary:\nTrade ID: {3}\nCurrency: {4}\nTrade amount: {5}\nPayout amount for XMR buyer: {6}\nPayout amount for XMR seller: {7}\n\nReason for dispute: {8}\n\nSummary notes:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1422,18 +1447,18 @@ filterWindow.mediators=Filtered mediators (comma sep. onion addresses) filterWindow.refundAgents=Filtered refund agents (comma sep. onion addresses) filterWindow.seedNode=Node cung cấp thông tin đã lọc (địa chỉ onion cách nhau bằng dấu phẩy) filterWindow.priceRelayNode=nút rơle giá đã lọc (địa chỉ onion cách nhau bằng dấu phẩy) -filterWindow.xmrNode=nút Bitcoin đã lọc (địa chỉ cách nhau bằng dấu phẩy + cửa) -filterWindow.preventPublicXmrNetwork=Ngăn sử dụng mạng Bitcoin công cộng +filterWindow.xmrNode=nút Monero đã lọc (địa chỉ cách nhau bằng dấu phẩy + cửa) +filterWindow.preventPublicXmrNetwork=Ngăn sử dụng mạng Monero công cộng filterWindow.disableAutoConf=Disable auto-confirm filterWindow.autoConfExplorers=Filtered auto-confirm explorers (comma sep. addresses) filterWindow.disableTradeBelowVersion=Phiên bản tối thiể yêu cầu cho giao dịch filterWindow.add=Thêm bộ lọc filterWindow.remove=Gỡ bỏ bộ lọc -filterWindow.xmrFeeReceiverAddresses=BTC fee receiver addresses +filterWindow.xmrFeeReceiverAddresses=XMR fee receiver addresses filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=Giá trị BTC tối thiểu +offerDetailsWindow.minXmrAmount=Giá trị XMR tối thiểu offerDetailsWindow.min=(min. {0}) offerDetailsWindow.distance=(chênh lệch so với giá thị trường: {0}) offerDetailsWindow.myTradingAccount=itài khoản giao dịch của tôi @@ -1448,6 +1473,7 @@ offerDetailsWindow.confirm.maker=Xác nhận: Đặt chào giá cho {0} monero offerDetailsWindow.confirm.taker=Xác nhận: Nhận chào giáo cho {0} monero offerDetailsWindow.creationDate=Ngày tạo offerDetailsWindow.makersOnion=Địa chỉ onion của người tạo +offerDetailsWindow.challenge=Mã bảo vệ giao dịch qRCodeWindow.headline=QR Code qRCodeWindow.msg=Please use this QR code for funding your Haveno wallet from your external wallet. @@ -1476,7 +1502,7 @@ showWalletDataWindow.walletData=Dữ liệu ví showWalletDataWindow.includePrivKeys=Bao gồm khóa cá nhân setXMRTxKeyWindow.headline=Prove sending of XMR -setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=Adding tx info below enables auto-confirm for quicker trades. See more: https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=Transaction ID (optional) setXMRTxKeyWindow.txKey=Transaction key (optional) @@ -1488,7 +1514,7 @@ tacWindow.disagree=Tôi không đồng ý và thoát tacWindow.arbitrationSystem=Dispute resolution tradeDetailsWindow.headline=giao dịch -tradeDetailsWindow.disputedPayoutTxId=ID giao dịch hoàn tiền khiếu nại: +tradeDetailsWindow.disputedPayoutTxId=ID giao dịch hoàn tiền khiếu nại tradeDetailsWindow.tradeDate=Ngày giao dịch tradeDetailsWindow.txFee=Phí đào tradeDetailsWindow.tradePeersOnion=Địa chỉ onion Đối tác giao dịch @@ -1498,8 +1524,10 @@ tradeDetailsWindow.agentAddresses=Arbitrator/Mediator tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=Bạn đã gửi XMR. +txDetailsWindow.xmr.noteReceived=Bạn đã nhận được XMR. +txDetailsWindow.sentTo=Gửi đến +txDetailsWindow.receivedWith=Đã nhận với txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1508,7 +1536,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=Nhập mật khẩu để mở khóa @@ -1534,12 +1562,12 @@ torNetworkSettingWindow.bridges.header=Tor bị khoá? torNetworkSettingWindow.bridges.info=Nếu Tor bị kẹt do nhà cung cấp internet hoặc quốc gia của bạn, bạn có thể thử dùng cầu nối Tor.\nTruy cập trang web Tor tại: https://bridges.torproject.org/bridges để biết thêm về cầu nối và phương tiện vận chuyển kết nối được. feeOptionWindow.headline=Chọn đồng tiền để thanh toán phí giao dịch -feeOptionWindow.info=Bạn có thể chọn thanh toán phí giao dịch bằng BSQ hoặc BTC. Nếu bạn chọn BSQ, bạn sẽ được khấu trừ phí giao dịch. +feeOptionWindow.info=Bạn có thể chọn thanh toán phí giao dịch bằng BSQ hoặc XMR. Nếu bạn chọn BSQ, bạn sẽ được khấu trừ phí giao dịch. feeOptionWindow.optionsLabel=Chọn đồng tiền để thanh toán phí giao dịch -feeOptionWindow.useBTC=Sử dụng BTC +feeOptionWindow.useXMR=Sử dụng XMR feeOptionWindow.fee={0} (≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1581,9 +1609,9 @@ popup.warning.noTradingAccountSetup.msg=Bạn cần thiết lập tiền tệ qu popup.warning.noArbitratorsAvailable=Hiện không có trọng tài nào popup.warning.noMediatorsAvailable=There are no mediators available. popup.warning.notFullyConnected=Bạn cần phải đợi cho đến khi kết nối hoàn toàn với mạng.\nĐiều này mất khoảng 2 phút khi khởi động. -popup.warning.notSufficientConnectionsToBtcNetwork=Bạn cần phải đợi cho đến khi bạn có ít nhất {0} kết nối với mạng Bitcoin. -popup.warning.downloadNotComplete=Bạn cần phải đợi cho đến khi download xong các block Bitcoin còn thiếu. -popup.warning.chainNotSynced=The Haveno wallet blockchain height is not synced correctly. If you recently started the application, please wait until one Bitcoin block has been published.\n\nYou can check the blockchain height in Settings/Network Info. If more than one block passes and this problem persists it may be stalled, in which case you should do an SPV resync. [HYPERLINK:https://bisq.wiki/Resyncing_SPV_file] +popup.warning.notSufficientConnectionsToXmrNetwork=Bạn cần phải đợi cho đến khi bạn có ít nhất {0} kết nối với mạng Monero. +popup.warning.downloadNotComplete=Bạn cần phải đợi cho đến khi download xong các block Monero còn thiếu. +popup.warning.walletNotSynced=Ví Haveno chưa được đồng bộ với chiều cao khối chuỗi khối mới nhất. Vui lòng đợi cho đến khi ví được đồng bộ hoặc kiểm tra kết nối của bạn. popup.warning.removeOffer=Bạn có chắc bạn muốn gỡ bỏ Báo giá này? popup.warning.tooLargePercentageValue=Bạn không thể cài đặt phần trăm là 100% hoặc cao hơn. popup.warning.examplePercentageValue=Vui lòng nhập số phần trăm như \"5.4\" cho 5,4% @@ -1602,14 +1630,13 @@ popup.warning.nodeBanned=One of the {0} nodes got banned. popup.warning.priceRelay=rơle giá popup.warning.seed=seed popup.warning.mandatoryUpdate.trading=Please update to the latest Haveno version. A mandatory update was released which disables trading for old versions. Please check out the Haveno Forum for more information. -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=Không thể thực hiện giao dịch, vì phí đào {0} vượt quá số lượng {1} cần chuyển. Vui lòng chờ tới khi phí đào thấp xuống hoặc khi bạn tích lũy đủ BTC để chuyển. +popup.warning.burnXMR=Không thể thực hiện giao dịch, vì phí đào {0} vượt quá số lượng {1} cần chuyển. Vui lòng chờ tới khi phí đào thấp xuống hoặc khi bạn tích lũy đủ XMR để chuyển. -popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Bitcoin network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.openOffer.makerFeeTxRejected=The maker fee transaction for offer with ID {0} was rejected by the Monero network.\nTransaction ID={1}.\nThe offer has been removed to avoid further problems.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.trade.txRejected.tradeFee=trade fee popup.warning.trade.txRejected.deposit=deposit -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=The maker fee transaction for offer with ID {0} is invalid.\nTransaction ID={1}.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. @@ -1618,13 +1645,13 @@ popup.info.securityDepositInfo=Để đảm bảo cả hai người giao dịch popup.info.cashDepositInfo=Chắc chắn rằng khu vực của bạn có chi nhánh ngân hàng có thể gửi tiền mặt.\nID (BIC/SWIFT) ngân hàng của bên bán là: {0}. popup.info.cashDepositInfo.confirm=Tôi xác nhận tôi đã gửi tiền popup.info.shutDownWithOpenOffers=Haveno đang đóng, nhưng vẫn có các chào giá đang mở. \n\nNhững chào giá này sẽ không có tại mạng P2P khi Haveno đang đóng, nhưng chúng sẽ được công bố lại trên mạng P2P vào lần tiếp theo bạn khởi động Haveno.\nĐể giữ các chào giá luôn trực tuyến, vui lòng để Haveno chạy và đảm bảo là máy tính của bạn cũng đang trực tuyến(có nghĩa là đảm bảo là máy tính của bạn không chuyển về chế độ chờ...nếu màn hình về chế độ chờ thì không sao). -popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://bisq.wiki/Running_Haveno_on_Qubes]. +popup.info.qubesOSSetupInfo=It appears you are running Haveno on Qubes OS. \n\nPlease make sure your Haveno qube is setup according to our Setup Guide at [HYPERLINK:https://haveno.exchange/wiki/Running_Haveno_on_Qubes]. popup.warn.downGradePrevention=Downgrade from version {0} to version {1} is not supported. Please use the latest Haveno version. popup.privateNotification.headline=Thông báo riêng tư quan trọng! popup.securityRecommendation.headline=Khuyến cáo an ninh quan trọng -popup.securityRecommendation.msg=Chúng tôi muốn nhắc nhở bạn sử dụng bảo vệ bằng mật khẩu cho ví của bạn nếu bạn vẫn chưa sử dụng.\n\nChúng tôi cũng khuyên bạn nên viết Seed words ví của bạn ra giấy. Các Seed words này như là mật khẩu chủ để khôi phục ví Bitcoin của bạn.\nBạn có thể xem thông tin ở mục \"Wallet Seed\".\n\nNgoài ra bạn nên sao lưu dự phòng folder dữ liệu ứng dụng đầy đủ ở mục \"Backup\". +popup.securityRecommendation.msg=Chúng tôi muốn nhắc nhở bạn sử dụng bảo vệ bằng mật khẩu cho ví của bạn nếu bạn vẫn chưa sử dụng.\n\nChúng tôi cũng khuyên bạn nên viết Seed words ví của bạn ra giấy. Các Seed words này như là mật khẩu chủ để khôi phục ví Monero của bạn.\nBạn có thể xem thông tin ở mục \"Wallet Seed\".\n\nNgoài ra bạn nên sao lưu dự phòng folder dữ liệu ứng dụng đầy đủ ở mục \"Backup\". popup.shutDownInProgress.headline=Đang tắt ứng dụng popup.shutDownInProgress.msg=Tắt ứng dụng sẽ mất vài giây.\nVui lòng không gián đoạn quá trình này. @@ -1670,6 +1697,9 @@ popup.accountSigning.unsignedPubKeys.signed=Pubkeys were signed popup.accountSigning.unsignedPubKeys.result.signed=Signed pubkeys popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign +popup.info.buyerAsTakerWithoutDeposit.headline=Không cần đặt cọc từ người mua +popup.info.buyerAsTakerWithoutDeposit=Lời đề nghị của bạn sẽ không yêu cầu khoản đặt cọc bảo mật hoặc phí từ người mua XMR.\n\nĐể chấp nhận lời đề nghị của bạn, bạn phải chia sẻ một mật khẩu với đối tác giao dịch ngoài Haveno.\n\nMật khẩu được tạo tự động và hiển thị trong chi tiết lời đề nghị sau khi tạo. + #################################################################### # Notifications #################################################################### @@ -1677,9 +1707,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=Failed to sign notification.trade.headline=Thông báo với giao dịch có ID {0} notification.ticket.headline=Vé hỗ trợ cho giao dịch có ID {0} notification.trade.completed=giao dịch đã hoàn thành và bạn có thể rút tiền. -notification.trade.accepted=Chào giá của bạn đã được chấp thuận bởi BTC {0}. +notification.trade.accepted=Chào giá của bạn đã được chấp thuận bởi XMR {0}. notification.trade.unlocked=giao dịch của bạn có ít nhất một xác nhận blockchain.\nBạn có thể bắt đầu thanh toán bây giờ. -notification.trade.paymentSent=Người mua BTC đã bắt đầu thanh toán. +notification.trade.paymentSent=Người mua XMR đã bắt đầu thanh toán. notification.trade.selectTrade=Lựa chọn giao dịch notification.trade.peerOpenedDispute=Đối tác giao dịch của bạn đã mở một {0}. notification.trade.disputeClosed={0} đã đóng. @@ -1698,7 +1728,7 @@ systemTray.show=Hiển thị cửa sổ ứng dung systemTray.hide=Ẩn cửa sổ ứng dụng systemTray.info=Thông tin về Haveno systemTray.exit=Thoát -systemTray.tooltip=Haveno: A decentralized bitcoin exchange network +systemTray.tooltip=Haveno: A decentralized monero exchange network #################################################################### @@ -1749,7 +1779,7 @@ tooltip.openBlockchainForTx=Mở blockchain explorer ngoài để xem giao dịc confidence.unknown=Trạng thái giao dịch chưa biết confidence.seen=Đã xem bởi {0} đối tác / 0 xác nhận -confidence.confirmed=Xác nhận tại {0} block +confidence.confirmed={0} xác nhận confidence.invalid=Giao dịch không có hiệu lực peerInfo.title=Thông tin đối tác @@ -1760,10 +1790,10 @@ peerInfo.age.noRisk=Tuổi tài khoản thanh toán peerInfo.age.chargeBackRisk=Time since signing peerInfo.unknownAge=Tuổi chưa biết -addressTextField.openWallet=Mở ví Bitcoin mặc định của bạn +addressTextField.openWallet=Mở ví Monero mặc định của bạn addressTextField.copyToClipboard=Copy địa chỉ vào clipboard addressTextField.addressCopiedToClipboard=Địa chỉ đã được copy vào clipboard -addressTextField.openWallet.failed=Mở ứng dụng ví Bitcoin mặc định không thành công. Có lẽ bạn chưa cài đặt? +addressTextField.openWallet.failed=Mở ứng dụng ví Monero mặc định không thành công. Có lẽ bạn chưa cài đặt? peerInfoIcon.tooltip={0}\nTag: {1} @@ -1795,6 +1825,7 @@ navigation.support=\"Hỗ trợ\" formatter.formatVolumeLabel={0} giá trị {1} formatter.makerTaker=Người tạo là {0} {1} / Người nhận là {2} {3} +formatter.makerTakerLocked=Người tạo là {0} {1} / Người nhận là {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=Bạn là {0} {1} ({2} {3}) @@ -1811,11 +1842,11 @@ formatter.asTaker={0} {1} như người nhận # we use enum values here # dynamic values are not recognized by IntelliJ # suppress inspection "UnusedProperty" -XMR_MAINNET=Bitcoin Mainnet +XMR_MAINNET=Monero Mainnet # suppress inspection "UnusedProperty" -XMR_LOCAL=Bitcoin Testnet +XMR_LOCAL=Monero Testnet # suppress inspection "UnusedProperty" -XMR_STAGENET=Bitcoin Regtest +XMR_STAGENET=Monero Regtest time.year=Năm time.month=Tháng @@ -1840,7 +1871,6 @@ password.deriveKey=Lấy khóa từ mật khẩu password.walletDecrypted=Ví đã giải mã thành công và bảo vệ bằng mật khẩu bị gỡ bỏ. password.wrongPw=Bạn nhập sai mật khẩu.\n\nVui lòng nhập lại mật khẩu, kiểm tra lỗi do gõ phí hoặc lỗi chính tả cẩn thận. password.walletEncrypted=Ví đã được mã hóa thành công và bảo vệ bằng mật khẩu được kích hoạt. -password.walletEncryptionFailed=Wallet password could not be set. You may have imported seed words which do not match the wallet database. Please contact the developers on Keybase ([HYPERLINK:https://keybase.io/team/haveno]). password.passwordsDoNotMatch=2 mật khẩu bạn nhập không khớp. password.forgotPassword=Quên mật khẩu? password.backupReminder=Please note that when setting a wallet password all automatically created backups from the unencrypted wallet will be deleted.\n\nIt is highly recommended that you make a backup of the application directory and write down your seed words before setting a password! @@ -1854,7 +1884,7 @@ seed.date=Ngày ví seed.restore.title=Khôi phục vú từ Seed words seed.restore=Khôi phục ví seed.creationDate=Ngày tạo -seed.warn.walletNotEmpty.msg=Your Bitcoin wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your bitcoin.\nIn case you cannot access your bitcoin you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". +seed.warn.walletNotEmpty.msg=Your Monero wallet is not empty.\n\nYou must empty this wallet before attempting to restore an older one, as mixing wallets together can lead to invalidated backups.\n\nPlease finalize your trades, close all your open offers and go to the Funds section to withdraw your monero.\nIn case you cannot access your monero you can use the emergency tool to empty the wallet.\nTo open the emergency tool press \"Alt+e\" or \"Cmd/Ctrl+e\". seed.warn.walletNotEmpty.restore=Tôi muốn khôi phục seed.warn.walletNotEmpty.emptyWallet=Tôi sẽ làm trống ví trước seed.warn.notEncryptedAnymore=Ví của bạn đã được mã hóa.\n\nSau khi khôi phục, ví sẽ không còn được mã hóa và bạn phải cài đặt mật khẩu mới.\n\nBạn có muốn tiếp tục? @@ -1871,7 +1901,7 @@ seed.restore.openOffers.warn=You have open offers which will be removed if you r payment.account=Tài khoản payment.account.no=Tài khoản số payment.account.name=Tên tài khoản -payment.account.userName=User name +payment.account.username=Username payment.account.phoneNr=Phone number payment.account.owner=Họ tên chủ tài khoản payment.account.fullName=Họ tên (họ, tên lót, tên) @@ -1903,7 +1933,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=Tên người dùng hoặc email hoặc số điện thoại payment.moneyBeam.accountId=Email hoặc số điện thoại -payment.venmo.venmoUserName=Tên người dùng Venmo payment.popmoney.accountId=Email hoặc số điện thoại payment.promptPay.promptPayId=ID công dân/ ID thuế hoặc số điện thoại payment.supportedCurrencies=Tiền tệ hỗ trợ @@ -1945,28 +1974,28 @@ payment.checking=Đang kiểm tra payment.savings=Tiết kiệm payment.personalId=ID cá nhân payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle is a money transfer service that works best *through* another bank.\n\n1. Check this page to see if (and how) your bank works with Zelle: [HYPERLINK:https://www.zellepay.com/get-started]\n\n2. Take special note of your transfer limits—sending limits vary by bank, and banks often specify separate daily, weekly, and monthly limits.\n\n3. If your bank does not work with Zelle, you can still use it through the Zelle mobile app, but your transfer limits will be much lower.\n\n4. The name specified on your Haveno account MUST match the name on your Zelle/bank account. \n\nIf you cannot complete a Zelle transaction as specified in your trade contract, you may lose some (or all) of your security deposit.\n\nBecause of Zelle''s somewhat higher chargeback risk, sellers are advised to contact unsigned buyers through email or SMS to verify that the buyer really owns the Zelle account specified in Haveno. payment.fasterPayments.newRequirements.info=Some banks have started verifying the receiver''s full name for Faster Payments transfers. Your current Faster Payments account does not specify a full name.\n\nPlease consider recreating your Faster Payments account in Haveno to provide future {0} buyers with a full name.\n\nWhen you recreate the account, make sure to copy the precise sort code, account number and account age verification salt values from your old account to your new account. This will ensure your existing account''s age and signing status are preserved. -payment.moneyGram.info=When using MoneyGram the BTC buyer has to send the Authorisation number and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.westernUnion.info=When using Western Union the BTC buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the BTC seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. -payment.halCash.info=Khi sử dụng HalCash người mua BTC cần phải gửi cho người bán BTC mã HalCash bằng tin nhắn điện thoại.\n\nVui lòng đảm bảo là lượng tiền này không vượt quá số lượng tối đa mà ngân hàng của bạn cho phép gửi khi dùng HalCash. Số lượng rút tối thiểu là 10 EUR và tối đa là 600 EUR. Nếu rút nhiều lần thì giới hạn sẽ là 3000 EUR/ người nhận/ ngày và 6000 EUR/người nhận/tháng. Vui lòng kiểm tra chéo những giới hạn này với ngân hàng của bạn để chắc chắn là họ cũng dùng những giới hạn như ghi ở đây.\n\nSố tiền rút phải là bội số của 10 EUR vì bạn không thể rút các mệnh giá khác từ ATM. Giao diện người dùng ở phần 'tạo chào giá' và 'chấp nhận chào giá' sẽ điều chỉnh lượng btc sao cho lượng EUR tương ứng sẽ chính xác. Bạn không thể dùng giá thị trường vì lượng EUR có thể sẽ thay đổi khi giá thay đổi.\n\nTrường hợp tranh chấp, người mua BTC cần phải cung cấp bằng chứng chứng minh mình đã gửi EUR. +payment.moneyGram.info=When using MoneyGram the XMR buyer has to send the Authorisation number and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, country, state and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.westernUnion.info=When using Western Union the XMR buyer has to send the MTCN (tracking number) and a photo of the receipt by email to the XMR seller. The receipt must clearly show the seller's full name, city, country and the amount. The seller's email will be displayed to the buyer during the trade process. +payment.halCash.info=Khi sử dụng HalCash người mua XMR cần phải gửi cho người bán XMR mã HalCash bằng tin nhắn điện thoại.\n\nVui lòng đảm bảo là lượng tiền này không vượt quá số lượng tối đa mà ngân hàng của bạn cho phép gửi khi dùng HalCash. Số lượng rút tối thiểu là 10 EUR và tối đa là 600 EUR. Nếu rút nhiều lần thì giới hạn sẽ là 3000 EUR/ người nhận/ ngày và 6000 EUR/người nhận/tháng. Vui lòng kiểm tra chéo những giới hạn này với ngân hàng của bạn để chắc chắn là họ cũng dùng những giới hạn như ghi ở đây.\n\nSố tiền rút phải là bội số của 10 EUR vì bạn không thể rút các mệnh giá khác từ ATM. Giao diện người dùng ở phần 'tạo chào giá' và 'chấp nhận chào giá' sẽ điều chỉnh lượng btc sao cho lượng EUR tương ứng sẽ chính xác. Bạn không thể dùng giá thị trường vì lượng EUR có thể sẽ thay đổi khi giá thay đổi.\n\nTrường hợp tranh chấp, người mua XMR cần phải cung cấp bằng chứng chứng minh mình đã gửi EUR. # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info=Please be aware that all bank transfers carry a certain amount of chargeback risk. To mitigate this risk, Haveno sets per-trade limits based on the estimated level of chargeback risk for the payment method used.\n\nFor this payment method, your per-trade limit for buying and selling is {2}.\n\nThis limit only applies to the size of a single trade—you can place as many trades as you like.\n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://bisq.wiki/Account_limits]. +payment.limits.info.withSigning=To limit chargeback risk, Haveno sets per-trade limits for this payment account type based on the following 2 factors:\n\n1. General chargeback risk for the payment method\n2. Account signing status\n\nThis payment account is not yet signed, so it is limited to buying {0} per trade. After signing, buy limits will increase as follows:\n\n● Before signing, and for 30 days after signing, your per-trade buy limit will be {0}\n● 30 days after signing, your per-trade buy limit will be {1}\n● 60 days after signing, your per-trade buy limit will be {2}\n\nSell limits are not affected by account signing. You can sell {2} in a single trade immediately.\n\nThese limits only apply to the size of a single trade—you can place as many trades as you like. \n\nSee more details on the wiki [HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]. payment.cashDeposit.info=Vui lòng xác nhận rằng ngân hàng của bạn cho phép nạp tiền mặt vào tài khoản của người khác. Chẳng hạn, Ngân Hàng Mỹ và Wells Fargo không còn cho phép nạp tiền như vậy nữa. -payment.revolut.info=Revolut requires the 'User name' as account ID not the phone number or email as it was the case in the past. -payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''User name''.\nPlease enter your Revolut ''User name'' to update your account data.\nThis will not affect your account age signing status. +payment.revolut.info=Revolut requires the 'Username' as account ID not the phone number or email as it was the case in the past. +payment.account.revolut.addUserNameInfo={0}\nYour existing Revolut account ({1}) does not have a ''Username''.\nPlease enter your Revolut ''Username'' to update your account data.\nThis will not affect your account age signing status. payment.revolut.addUserNameInfo.headLine=Update Revolut account payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the country to be specified. payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- BTC buyers must write the BTC Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- BTC buyers must send the USPMO to the BTC seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. +payment.usPostalMoneyOrder.info=Trading using US Postal Money Orders (USPMO) on Haveno requires that you understand the following:\n\n- XMR buyers must write the XMR Seller’s name in both the Payer and the Payee’s fields & take a high-resolution photo of the USPMO and envelope with proof of tracking before sending.\n- XMR buyers must send the USPMO to the XMR seller with Delivery Confirmation.\n\nIn the event mediation is necessary, or if there is a trade dispute, you will be required to send the photos to the Haveno mediator or refund agent, together with the USPMO Serial Number, Post Office Number, and dollar amount, so they can verify the details on the US Post Office website.\n\nFailure to provide the required information to the Mediator or Arbitrator will result in losing the dispute case.\n\nIn all dispute cases, the USPMO sender bears 100% of the burden of responsibility in providing evidence/proof to the Mediator or Arbitrator.\n\nIf you do not understand these requirements, do not trade using USPMO on Haveno. payment.payByMail.contact=thông tin liên hệ payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1977,7 +2006,7 @@ payment.f2f.city.prompt=Thành phố sẽ được hiển thị cùng báo giá payment.shared.optionalExtra=Thông tin thêm tuỳ chọn. payment.shared.extraInfo=thông tin thêm payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the BTC funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] +payment.f2f.info='Face to Face' trades have different rules and come with different risks than online transactions.\n\nThe main differences are:\n● The trading peers need to exchange information about the meeting location and time by using their provided contact details.\n● The trading peers need to bring their laptops and do the confirmation of 'payment sent' and 'payment received' at the meeting place.\n● If a maker has special 'terms and conditions' they must state those in the 'Additional information' text field in the account.\n● By taking an offer the taker agrees to the maker's stated 'terms and conditions'.\n● In case of a dispute the mediator or arbitrator cannot be of much assistance as it is usually difficult to get tamper-proof evidence of what happened at the meeting. In such cases the XMR funds might get locked indefinitely or until the trading peers come to an agreement.\n\nTo be sure you fully understand the differences with 'Face to Face' trades please read the instructions and recommendations at: [HYPERLINK:https://docs.haveno.exchange/trading-rules.html#f2f-trading] payment.f2f.info.openURL=Mở trang web payment.f2f.offerbook.tooltip.countryAndCity=Country and city: {0} / {1} payment.f2f.offerbook.tooltip.extra=Thông tin thêm: {0} @@ -1989,7 +2018,7 @@ payment.japan.recipient=Tên payment.australia.payid=PayID payment.payid=PayID linked to financial institution. Like email address or mobile phone. payment.payid.info=A PayID like a phone number, email address or an Australian Business Number (ABN), that you can securely link to your bank, credit union or building society account. You need to have already created a PayID with your Australian financial institution. Both sending and receiving financial institutions must support PayID. For more information please check [HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2147,7 +2176,7 @@ validation.zero=Không cho phép nhập giá trị 0. validation.negative=Không cho phép nhập giá trị âm. validation.traditional.tooSmall=Không cho phép giá trị nhập nhỏ hơn giá trị có thể nhỏ nhất. validation.traditional.tooLarge=Không cho phép giá trị nhập lớn hơn giá trị có thể lớn nhất. -validation.xmr.fraction=Input will result in a bitcoin value of less than 1 satoshi +validation.xmr.fraction=Input will result in a monero value of less than 1 satoshi validation.xmr.tooLarge=Không cho phép giá trị nhập lớn hơn {0}. validation.xmr.tooSmall=Không cho phép giá trị nhập nhỏ hơn {0}. validation.passwordTooShort=The password you entered is too short. It needs to have a min. of 8 characters. @@ -2157,10 +2186,10 @@ validation.sortCodeChars={0} phải có {1} ký tự. validation.bankIdNumber={0} phải có {1} số. validation.accountNr=Số tài khoản phải có {0} số. validation.accountNrChars=Số tài khoản phải có {0} ký tự. -validation.btc.invalidAddress=Địa chỉ không đúng. Vui lỏng kiểm tra lại định dạng địa chỉ. +validation.xmr.invalidAddress=Địa chỉ không đúng. Vui lỏng kiểm tra lại định dạng địa chỉ. validation.integerOnly=Vui lòng chỉ nhập số nguyên. validation.inputError=Giá trị nhập của bạn gây lỗi:\n{0} -validation.btc.exceedsMaxTradeLimit=Giới hạn giao dịch của bạn là {0}. +validation.xmr.exceedsMaxTradeLimit=Giới hạn giao dịch của bạn là {0}. validation.nationalAccountId={0} phải có {1} số. #new diff --git a/core/src/main/resources/i18n/displayStrings_zh-hans.properties b/core/src/main/resources/i18n/displayStrings_zh-hans.properties index 5b790d6398..b495893a29 100644 --- a/core/src/main/resources/i18n/displayStrings_zh-hans.properties +++ b/core/src/main/resources/i18n/displayStrings_zh-hans.properties @@ -36,14 +36,16 @@ shared.iUnderstand=我了解 shared.na=N/A shared.shutDown=完全关闭 shared.reportBug=在 Github 报告错误 -shared.buyBitcoin=买入比特币 -shared.sellBitcoin=卖出比特币 +shared.buyMonero=买入比特币 +shared.sellMonero=卖出比特币 shared.buyCurrency=买入 {0} shared.sellCurrency=卖出 {0} -shared.buyingBTCWith=用 {0} 买入 BTC -shared.sellingBTCFor=卖出 BTC 为 {0} -shared.buyingCurrency=买入 {0}(卖出 BTC) -shared.sellingCurrency=卖出 {0}(买入 BTC) +shared.buyCurrencyLocked=买入 {0} 🔒 +shared.sellCurrencyLocked=卖出 {0} 🔒 +shared.buyingXMRWith=用 {0} 买入 XMR +shared.sellingXMRFor=卖出 XMR 为 {0} +shared.buyingCurrency=买入 {0}(卖出 XMR) +shared.sellingCurrency=卖出 {0}(买入 XMR) shared.buy=买 shared.sell=卖 shared.buying=买入 @@ -93,7 +95,7 @@ shared.amountMinMax=总额(最小 - 最大) shared.amountHelp=如果报价包含最小和最大限制,那么您可以在这个范围内的任意数量进行交易。 shared.remove=移除 shared.goTo=前往 {0} -shared.BTCMinMax=BTC(最小 - 最大) +shared.XMRMinMax=XMR(最小 - 最大) shared.removeOffer=移除报价 shared.dontRemoveOffer=不要移除报价 shared.editOffer=编辑报价 @@ -103,7 +105,7 @@ shared.faq=访问 FAQ 页面 shared.yesCancel=是的,取消 shared.nextStep=下一步 shared.selectTradingAccount=选择交易账户 -shared.fundFromSavingsWalletButton=从 Haveno 钱包资金划转 +shared.fundFromSavingsWalletButton=从 Haveno 钱包申请资金 shared.fundFromExternalWalletButton=从您的外部钱包充值 shared.openDefaultWalletFailed=打开默认的比特币钱包应用程序失败了。您确定您安装了吗? shared.belowInPercent=低于市场价格 % @@ -112,7 +114,7 @@ shared.enterPercentageValue=输入 % 值 shared.OR=或者 shared.notEnoughFunds=您的 Haveno 钱包中没有足够的资金去支付这一交易 需要{0} 您可用余额为 {1}。\n\n请从外部比特币钱包注入资金或在“资金/存款”充值到您的 Haveno 钱包。 shared.waitingForFunds=等待资金充值... -shared.TheBTCBuyer=BTC 买家 +shared.TheXMRBuyer=XMR 买家 shared.You=您 shared.sendingConfirmation=发送确认... shared.sendingConfirmationAgain=请再次发送确认 @@ -123,7 +125,6 @@ shared.noDateAvailable=没有可用数据 shared.noDetailsAvailable=没有可用详细 shared.notUsedYet=尚未使用 shared.date=日期 -shared.sendFundsDetailsWithFee=发送:{0}\n来自:{1}\n接收地址:{2}\n要求的最低交易费:{3}({4} 聪/byte)\n交易大小:{5} Kb\n\n收款方将收到:{6}\n\n您确定您想要提现吗? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Haveno 检测到,该交易将产生一个低于最低零头阈值的输出(不被比特币共识规则所允许)。相反,这些零头({0}satoshi{1})将被添加到挖矿手续费中。 shared.copyToClipboard=复制到剪贴板 @@ -140,6 +141,7 @@ shared.addNewAccount=添加新的账户 shared.ExportAccounts=导出账户 shared.importAccounts=导入账户 shared.createNewAccount=创建新的账户 +shared.createNewAccountDescription=您的账户详情存储在您的设备上,仅与您的交易对手和仲裁员在出现争议时共享。 shared.saveNewAccount=保存新的账户 shared.selectedAccount=选中的账户 shared.deleteAccount=删除账户 @@ -169,7 +171,7 @@ shared.payoutTxId=支出交易 ID shared.contractAsJson=JSON 格式的合同 shared.viewContractAsJson=查看 JSON 格式的合同 shared.contract.title=交易 ID:{0} 的合同 -shared.paymentDetails=BTC {0} 支付详情 +shared.paymentDetails=XMR {0} 支付详情 shared.securityDeposit=保证金 shared.yourSecurityDeposit=你的保证金 shared.contract=合同 @@ -179,19 +181,21 @@ shared.messageSendingFailed=消息发送失败。错误:{0} shared.unlock=解锁 shared.toReceive=接收 shared.toSpend=花费 -shared.btcAmount=BTC 总额 +shared.xmrAmount=XMR 总额 shared.yourLanguage=你的语言 shared.addLanguage=添加语言 shared.total=合计 shared.totalsNeeded=需要资金 shared.tradeWalletAddress=交易钱包地址 shared.tradeWalletBalance=交易钱包余额 +shared.reserveExactAmount=仅保留必要的资金。需要支付矿工费用,并且大约需要 20 分钟后您的报价才会生效。 shared.makerTxFee=卖家:{0} shared.takerTxFee=买家:{0} shared.iConfirm=我确认 shared.openURL=打开 {0} shared.fiat=法定货币 shared.crypto=加密 +shared.preciousMetals=贵金属 shared.all=全部 shared.edit=编辑 shared.advancedOptions=高级选项 @@ -226,8 +230,8 @@ shared.enabled=启用 #################################################################### mainView.menu.market=交易项目 -mainView.menu.buyBtc=买入 BTC -mainView.menu.sellBtc=卖出 BTC +mainView.menu.buyXmr=买入 XMR +mainView.menu.sellXmr=卖出 XMR mainView.menu.portfolio=业务 mainView.menu.funds=资金 mainView.menu.support=帮助 @@ -245,12 +249,15 @@ mainView.balance.reserved.short=保证 mainView.balance.pending.short=冻结 mainView.footer.usingTor=(通过 Tor) -mainView.footer.localhostBitcoinNode=(本地主机) +mainView.footer.localhostMoneroNode=(本地主机) +mainView.footer.clearnet=(通过 clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ 矿工手费率:{0} 聪/字节 -mainView.footer.xmrInfo.initializing=连接至比特币网络 -mainView.footer.xmrInfo.synchronizingWith=正在通过{0}同步区块:{1}/{2} -mainView.footer.xmrInfo.synchronizedWith=已通过{0}同步至区块{1} +mainView.footer.xmrFeeRate=/ 矿工手费率:{0} 聪/字节 +mainView.footer.xmrInfo.initializing=连接到 Haveno 网络 +mainView.footer.xmrInfo.synchronizingWith=同步中,区块:{1} / {2},与 {0} 同步中 +mainView.footer.xmrInfo.connectedTo=连接到 {0} 在区块 {1} 处 +mainView.footer.xmrInfo.synchronizingWalletWith=同步中,区块:{1} / {2},与 {0} 的钱包同步中 +mainView.footer.xmrInfo.syncedWith=已同步至 {0} 在区块 {1} mainView.footer.xmrInfo.connectingTo=连接至 mainView.footer.xmrInfo.connectionFailed=连接失败: mainView.footer.xmrPeers=Monero网络节点:{0} @@ -274,7 +281,7 @@ mainView.walletServiceErrorMsg.connectionError=错误:{0} 比特币网络连 mainView.walletServiceErrorMsg.rejectedTxException=交易被网络拒绝。\n\n{0} mainView.networkWarning.allConnectionsLost=您失去了所有与 {0} 网络节点的连接。\n您失去了互联网连接或您的计算机处于待机状态。 -mainView.networkWarning.localhostBitcoinLost=您丢失了与本地主机比特币节点的连接。\n请重启 Haveno 应用程序连接到其他比特币节点或重新启动主机比特币节点。 +mainView.networkWarning.localhostMoneroLost=您丢失了与本地主机比特币节点的连接。\n请重启 Haveno 应用程序连接到其他比特币节点或重新启动主机比特币节点。 mainView.version.update=(有更新可用) @@ -299,9 +306,9 @@ market.offerBook.sell=我想要卖出比特币 # SpreadView market.spread.numberOfOffersColumn=所有报价({0}) -market.spread.numberOfBuyOffersColumn=买入 BTC({0}) -market.spread.numberOfSellOffersColumn=卖出 BTC({0}) -market.spread.totalAmountColumn=总共 BTC({0}) +market.spread.numberOfBuyOffersColumn=买入 XMR({0}) +market.spread.numberOfSellOffersColumn=卖出 XMR({0}) +market.spread.totalAmountColumn=总共 XMR({0}) market.spread.spreadColumn=差价 market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=创建报价 offerbook.takeOffer=接受报价 offerbook.takeOfferToBuy=接受报价来收购 {0} offerbook.takeOfferToSell=接受报价来出售 {0} +offerbook.takeOffer.enterChallenge=输入报价密码 offerbook.trader=商人 offerbook.offerersBankId=卖家的银行 ID(BIC/SWIFT):{0} offerbook.offerersBankName=卖家的银行名称:{0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=接受的银行所在国家(买家):\n offerbook.availableOffers=可用报价 offerbook.filterByCurrency=以货币筛选 offerbook.filterByPaymentMethod=以支付方式筛选 -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=匹配我的账户的报价 +offerbook.filterNoDeposit=无押金 +offerbook.noDepositOffers=无押金的报价(需要密码短语) offerbook.timeSinceSigning=账户信息 offerbook.timeSinceSigning.info=此账户已验证,{0} offerbook.timeSinceSigning.info.arbitrator=由仲裁员验证,并可以验证伙伴账户 @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=账户已被封禁 offerbook.timeSinceSigning.daysSinceSigning={0} 天 offerbook.timeSinceSigning.daysSinceSigning.long=自验证{0} offerbook.xmrAutoConf=是否开启自动确认 +offerbook.buyXmrWith=使用以下方式购买 XMR: +offerbook.sellXmrFor=出售 XMR 以换取: offerbook.timeSinceSigning.help=当您成功地完成与拥有已验证付款帐户的伙伴交易时,您的付款帐户已验证。\n{0} 天后,最初的 {1} 的限制解除以及你的账户可以验证其他人的付款账户。 offerbook.timeSinceSigning.notSigned=尚未验证 @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=数字货币不适用账龄与签名 offerbook.nrOffers=报价数量:{0} offerbook.volume={0}(最小 - 最大) -offerbook.deposit=BTC 保证金(%) +offerbook.deposit=XMR 保证金(%) offerbook.deposit.help=交易双方均已支付保证金确保这个交易正常进行。这会在交易完成时退还。 +offerbook.createNewOffer=創建報價給 {0} {1} offerbook.createOfferToBuy=创建新的报价来买入 {0} offerbook.createOfferToSell=创建新的报价来卖出 {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=使用这个版本的软件,交易伙 popup.warning.tradeLimitDueAccountAgeRestriction.seller=基于以下标准的安全限制,允许的交易金额限制为 {0}:\n- 买方的帐目没有由仲裁员或伙伴验证\n- 买方帐户自验证之日起不足30天\n- 本报价的付款方式被认为存在银行退款的风险\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=基于以下标准的安全限制,允许的交易金额限制为{0}:\n- 你的买家帐户没有由仲裁员或伙伴验证\n- 自验证你的帐户以来的时间少于30天\n- 本报价的付款方式被认为存在银行退款的风险\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=这种付款方法暂时限于 {0} 到 {1},因为所有的买家都是新帐户。\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=您的报价将仅限于具有签署和经过时代化的帐户的买家,因为它超出了{0}。\n\n{1} offerbook.warning.wrongTradeProtocol=该报价要求的软件版本与您现在运行的版本不一致。\n\n请检查您是否运行最新版本,或者是该报价用户在使用一个旧的版本。\n用户不能与不兼容的交易协议版本进行交易。 offerbook.warning.userIgnored=您已添加该用户的匿名地址在您的忽略列表里。 @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=金额四舍五入是为了增加您的交易 # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=输入 BTC 数量 +createOffer.amount.prompt=输入 XMR 数量 createOffer.price.prompt=输入价格 createOffer.volume.prompt=输入 {0} 金额 createOffer.amountPriceBox.amountDescription=比特币数量 {0} createOffer.amountPriceBox.buy.volumeDescription=花费 {0} 数量 createOffer.amountPriceBox.sell.volumeDescription=接收 {0} 数量 -createOffer.amountPriceBox.minAmountDescription=最小 BTC 数量 +createOffer.amountPriceBox.minAmountDescription=最小 XMR 数量 createOffer.securityDeposit.prompt=保证金 createOffer.fundsBox.title=为您的报价充值 createOffer.fundsBox.offerFee=挂单费 @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=由于您的价格是持续更新的,因 createOffer.info.buyBelowMarketPrice=由于您的价格是持续更新的,因此您将始终支付低于市场价 {0}% 的价格。 createOffer.warning.sellBelowMarketPrice=由于您的价格是持续更新的,因此您将始终按照低于市场价 {0}% 的价格出售。 createOffer.warning.buyAboveMarketPrice=由于您的价格是持续更新的,因此您将始终支付高于市场价 {0}% 的价格。 -createOffer.tradeFee.descriptionBTCOnly=挂单费 +createOffer.tradeFee.descriptionXMROnly=挂单费 createOffer.tradeFee.descriptionBSQEnabled=选择手续费币种 createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +463,12 @@ createOffer.placeOfferButton=复审:报价挂单 {0} 比特币 createOffer.createOfferFundWalletInfo.headline=为您的报价充值 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 交易数量:{0}\n -createOffer.createOfferFundWalletInfo.msg=这个报价您需要 {0} 作为保证金。\n\n这些资金保留在您的本地钱包并会被冻结到多重验证保证金地址直到报价交易成功。\n\n总数量:{1}\n- 保证金:{2}\n- 挂单费:{3}\n- 矿工手续费:{4}\n\n您有两种选项可以充值您的交易:\n- 使用您的 Haveno 钱包(方便,但交易可能会被链接到)或者\n- 从外部钱包转入(或许这样更隐秘一些)\n\n关闭此弹出窗口后,您将看到所有资金选项和详细信息。 +createOffer.createOfferFundWalletInfo.msg=您需要为此报价存入 {0}。\n\n\ + 这些资金将保留在您的本地钱包中,并在有人接受您的报价后锁定到多签钱包中。\n\n\ + 金额是以下各项的总和:\n\ + {1}\ + - 您的保证金:{2}\n\ + - 交易费用:{3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=提交报价发生错误:\n\n{0}\n\n没有资金从您钱包中扣除。\n请检查您的互联网连接或尝试重启应用程序。 @@ -470,19 +490,22 @@ createOffer.setDepositAsBuyer=设置自己作为买家的保证金(%) createOffer.setDepositForBothTraders=设置双方的保证金比例(%) createOffer.securityDepositInfo=您的买家的保证金将会是 {0} createOffer.securityDepositInfoAsBuyer=您作为买家的保证金将会是 {0} -createOffer.minSecurityDepositUsed=已使用最低买家保证金 +createOffer.minSecurityDepositUsed=最低安全押金已使用 +createOffer.buyerAsTakerWithoutDeposit=无需买家支付押金(使用口令保护) +createOffer.myDeposit=我的安全押金 (%) +createOffer.myDepositInfo=您的保证金为 {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=输入 BTC 数量 +takeOffer.amount.prompt=输入 XMR 数量 takeOffer.amountPriceBox.buy.amountDescription=卖出比特币数量 takeOffer.amountPriceBox.sell.amountDescription=买入比特币数量 takeOffer.amountPriceBox.priceDescription=每个比特币的 {0} 价格 takeOffer.amountPriceBox.amountRangeDescription=可用数量范围 -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=你输入的数量超过允许的小数位数。\n数量已被调整为4位小数。 +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=你输入的数量超过允许的小数位数。\n数量已被调整为4位小数。 takeOffer.validation.amountSmallerThanMinAmount=数量不能比报价内设置的最小数量小。 takeOffer.validation.amountLargerThanOfferAmount=数量不能比报价提供的总量大。 takeOffer.validation.amountLargerThanOfferAmountMinusFee=该输入数量可能会给卖家造成比特币碎片。 @@ -491,9 +514,11 @@ takeOffer.fundsBox.isOfferAvailable=检查报价是否有效... takeOffer.fundsBox.tradeAmount=卖出数量 takeOffer.fundsBox.offerFee=挂单费 takeOffer.fundsBox.networkFee=总共挖矿手续费 -takeOffer.fundsBox.takeOfferSpinnerInfo=正在下单... +takeOffer.fundsBox.takeOfferSpinnerInfo=接受报价:{0} takeOffer.fundsBox.paymentLabel=Haveno 交易 ID {0} takeOffer.fundsBox.fundsStructure=({0} 保证金,{1} 交易费,{2} 采矿费) +takeOffer.fundsBox.noFundingRequiredTitle=无需资金 +takeOffer.fundsBox.noFundingRequiredDescription=从卖方处获取交易密码(在Haveno之外)以接受此报价。 takeOffer.success.headline=你已成功下单一个报价。 takeOffer.success.info=你可以在“业务/未完成交易”页面内查看您的未完成交易。 takeOffer.error.message=下单时发生了一个错误。\n\n{0} @@ -504,7 +529,7 @@ takeOffer.noPriceFeedAvailable=您不能对这笔报价下单,因为它使用 takeOffer.takeOfferFundWalletInfo.headline=为交易充值 # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- 交易数量:{0}\n -takeOffer.takeOfferFundWalletInfo.msg=这个报价您需要付出 {0} 保证金。\n\n这些资金保留在您的本地钱包并会被冻结到多重验证保证金地址直到报价交易成功。\n\n总数量:{1}\n- 保证金:{2}\n- 挂单费:{3}\n- 矿工手续费:{4}\n\n您有两种选项可以充值您的交易:\n- 使用您的 Haveno 钱包(方便,但交易可能会被链接到)或者\n- 从外部钱包转入(或许这样更隐秘一些)\n\n关闭此弹出窗口后,您将看到所有资金选项和详细信息。 +takeOffer.takeOfferFundWalletInfo.msg=您需要存入 {0} 以接受此报价。\n\n该金额为以下总和:\n{1}- 您的保证金:{2}\n- 交易费用:{3} takeOffer.alreadyPaidInFunds=如果你已经支付,你可以在“资金/提现”提现它。 takeOffer.paymentInfo=付款信息 takeOffer.setAmountPrice=设置数量 @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=保证金交易仍未得到确认。请 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=请从您的外部 {0} 钱包划转\n{1} 到 BTC 卖家。\n\n +portfolio.pending.step2_buyer.crypto=请从您的外部 {0} 钱包划转\n{1} 到 XMR 卖家。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=请到银行并支付 {0} 给 BTC 卖家。\n\n -portfolio.pending.step2_buyer.cash.extra=重要要求:\n完成付款后在纸质收据上写下:不退款。\n然后将其撕成2份,拍照片并发送给 BTC 卖家的电子邮件地址。 +portfolio.pending.step2_buyer.cash=请到银行并支付 {0} 给 XMR 卖家。\n\n +portfolio.pending.step2_buyer.cash.extra=重要要求:\n完成付款后在纸质收据上写下:不退款。\n然后将其撕成2份,拍照片并发送给 XMR 卖家的电子邮件地址。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=请使用 MoneyGram 向 BTC 卖家支付 {0}。\n\n -portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付后,请通过电邮发送授权编号和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。 +portfolio.pending.step2_buyer.moneyGram=请使用 MoneyGram 向 XMR 卖家支付 {0}。\n\n +portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付后,请通过电邮发送授权编号和照片给 XMR 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=请使用 Western Union 向 BTC 卖家支付 {0}。\n\n -portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付后,请通过电邮发送 MTCN(追踪号码)和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。 +portfolio.pending.step2_buyer.westernUnion=请使用 Western Union 向 XMR 卖家支付 {0}。\n\n +portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付后,请通过电邮发送 MTCN(追踪号码)和照片给 XMR 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=请用“美国邮政汇票”发送 {0} 给 BTC 卖家。\n\n +portfolio.pending.step2_buyer.postal=请用“美国邮政汇票”发送 {0} 给 XMR 卖家。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=请通过提供的联系人与 BTC 卖家联系,并安排会议支付 {0}。\n\n +portfolio.pending.step2_buyer.f2f=请通过提供的联系人与 XMR 卖家联系,并安排会议支付 {0}。\n\n portfolio.pending.step2_buyer.startPaymentUsing=使用 {0} 开始付款 portfolio.pending.step2_buyer.recipientsAccountData=接受 {0} portfolio.pending.step2_buyer.amountToTransfer=划转数量 @@ -628,27 +653,27 @@ portfolio.pending.step2_buyer.buyerAccount=您的付款帐户将被使用 portfolio.pending.step2_buyer.paymentSent=付款开始 portfolio.pending.step2_buyer.warn=你还没有完成你的 {0} 付款!\n请注意,交易必须在 {1} 之前完成。 portfolio.pending.step2_buyer.openForDispute=您还没有完成您的付款!\n最大交易期限已过。请联系调解员寻求帮助。 -portfolio.pending.step2_buyer.paperReceipt.headline=您是否将纸质收据发送给 BTC 卖家? -portfolio.pending.step2_buyer.paperReceipt.msg=请牢记:\n完成付款后在纸质收据上写下:不退款。\n然后将其撕成2份,拍照片并发送给 BTC 卖家的电子邮件地址。 +portfolio.pending.step2_buyer.paperReceipt.headline=您是否将纸质收据发送给 XMR 卖家? +portfolio.pending.step2_buyer.paperReceipt.msg=请牢记:\n完成付款后在纸质收据上写下:不退款。\n然后将其撕成2份,拍照片并发送给 XMR 卖家的电子邮件地址。 portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=发送授权编号和收据 -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=请通过电邮发送授权编号和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。\n\n您把授权编号和合同发给卖方了吗? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=请通过电邮发送授权编号和照片给 XMR 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。\n\n您把授权编号和合同发给卖方了吗? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=发送 MTCN 和收据 -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=请通过电邮发送 MTCN(追踪号码)和照片给 BTC 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。\n\n您把 MTCN 和合同发给卖方了吗? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=请通过电邮发送 MTCN(追踪号码)和照片给 XMR 卖家。\n收据必须清楚地向卖家写明您的全名、城市、国家或地区、数量。卖方的电子邮件是:{0}。\n\n您把 MTCN 和合同发给卖方了吗? portfolio.pending.step2_buyer.halCashInfo.headline=请发送 HalCash 代码 -portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 BTC 卖家发送带有 HalCash 代码和交易 ID({0})的文本消息。\n\n卖方的手机号码是 {1} 。\n\n您是否已经将代码发送至卖家? +portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 XMR 卖家发送带有 HalCash 代码和交易 ID({0})的文本消息。\n\n卖方的手机号码是 {1} 。\n\n您是否已经将代码发送至卖家? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=有些银行可能会要求接收方的姓名。在较旧的 Haveno 客户端创建的快速支付帐户没有提供收款人的姓名,所以请使用交易聊天来获得收款人姓名(如果需要)。 portfolio.pending.step2_buyer.confirmStart.headline=确定您已经付款 portfolio.pending.step2_buyer.confirmStart.msg=您是否向您的交易伙伴发起 {0} 付款? portfolio.pending.step2_buyer.confirmStart.yes=是的,我已经开始付款 portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=你没有提供任何付款证明 -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=您还没有输入交易 ID 以及交易密钥\n\n如果不提供此数据您的交易伙伴无法在收到 XMR 后使用自动确认功能以快速释放 BTC。\n另外,Haveno 要求 XMR 发送者在发生纠纷的时候能够向调解员和仲裁员提供这些信息。\n更多细节在 Haveno Wiki:https://bisq.wiki/Trading_Monero#Auto-confirming_trades +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=您还没有输入交易 ID 以及交易密钥\n\n如果不提供此数据您的交易伙伴无法在收到 XMR 后使用自动确认功能以快速释放 XMR。\n另外,Haveno 要求 XMR 发送者在发生纠纷的时候能够向调解员和仲裁员提供这些信息。\n更多细节在 Haveno Wiki:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=输入并不是一个 32 字节的哈希值 portfolio.pending.step2_buyer.confirmStart.warningButton=忽略并继续 portfolio.pending.step2_seller.waitPayment.headline=等待付款 portfolio.pending.step2_seller.f2fInfo.headline=买家的合同信息 -portfolio.pending.step2_seller.waitPayment.msg=存款交易至少有一个区块链确认。\n您需要等到 BTC 买家开始 {0} 付款。 -portfolio.pending.step2_seller.warn=BTC 买家仍然没有完成 {0} 付款。\n你需要等到他开始付款。\n如果 {1} 交易尚未完成,仲裁员将进行调查。 -portfolio.pending.step2_seller.openForDispute=BTC 买家尚未开始付款!\n允许的最长交易期限已经过去了。你可以继续等待给予交易双方更多时间,或联系仲裁员以争取解决纠纷。 +portfolio.pending.step2_seller.waitPayment.msg=存款交易至少有一个区块链确认。\n您需要等到 XMR 买家开始 {0} 付款。 +portfolio.pending.step2_seller.warn=XMR 买家仍然没有完成 {0} 付款。\n你需要等到他开始付款。\n如果 {1} 交易尚未完成,仲裁员将进行调查。 +portfolio.pending.step2_seller.openForDispute=XMR 买家尚未开始付款!\n允许的最长交易期限已经过去了。你可以继续等待给予交易双方更多时间,或联系仲裁员以争取解决纠纷。 tradeChat.chatWindowTitle=使用 ID “{0}” 进行交易的聊天窗口 tradeChat.openChat=打开聊天窗口 tradeChat.rules=您可以与您的伙伴沟通,以解决该交易的潜在问题。\n在聊天中不强制回复。\n如果交易员违反了下面的任何规则,打开纠纷并向调解员或仲裁员报告。\n聊天规则:\n\n\t●不要发送任何链接(有恶意软件的风险)。您可以发送交易 ID 和区块资源管理器的名称。\n\t●不要发送还原密钥、私钥、密码或其他敏感信息!\n\t●不鼓励 Haveno 以外的交易(无安全保障)。\n\t●不要参与任何形式的危害社会安全的计划。\n\t●如果对方没有回应,也不愿意通过聊天进行沟通,那就尊重对方的决定。\n\t●将谈话范围限制在行业内。这个聊天不是一个社交软件替代品或troll-box。\n\t●保持友好和尊重的交谈。 @@ -666,28 +691,28 @@ message.state.ACKNOWLEDGED=对方确认消息回执 # suppress inspection "UnusedProperty" message.state.FAILED=发送消息失败 -portfolio.pending.step3_buyer.wait.headline=等待 BTC 卖家付款确定 -portfolio.pending.step3_buyer.wait.info=等待 BTC 卖家确认收到 {0} 付款。 +portfolio.pending.step3_buyer.wait.headline=等待 XMR 卖家付款确定 +portfolio.pending.step3_buyer.wait.info=等待 XMR 卖家确认收到 {0} 付款。 portfolio.pending.step3_buyer.wait.msgStateInfo.label=支付开始消息状态 portfolio.pending.step3_buyer.warn.part1a=在 {0} 区块链 portfolio.pending.step3_buyer.warn.part1b=在您的支付供应商(例如:银行) -portfolio.pending.step3_buyer.warn.part2=BTC 卖家仍然没有确认您的付款。如果付款发送成功,请检查 {0}。 -portfolio.pending.step3_buyer.openForDispute=BTC 卖家还没有确认你的付款!最大交易期限已过。您可以等待更长时间,并给交易伙伴更多时间或请求调解员的帮助。 +portfolio.pending.step3_buyer.warn.part2=XMR 卖家仍然没有确认您的付款。如果付款发送成功,请检查 {0}。 +portfolio.pending.step3_buyer.openForDispute=XMR 卖家还没有确认你的付款!最大交易期限已过。您可以等待更长时间,并给交易伙伴更多时间或请求调解员的帮助。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=您的交易伙伴已经确认他们已经发起了 {0} 付款。\n\n portfolio.pending.step3_seller.crypto.explorer=在您最喜欢的 {0} 区块链浏览器 portfolio.pending.step3_seller.crypto.wallet=在您的 {0} 钱包 portfolio.pending.step3_seller.crypto={0} 请检查 {1} 是否交易已经到您的接收地址\n{2}\n已经有足够的区块链确认了\n支付金额必须为 {3}\n\n关闭该弹出窗口后,您可以从主界面复制并粘贴 {4} 地址。 -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=因为付款是通过现金存款完成的,BTC 买家必须在纸质收据上写“不退款”,将其撕成2份,并通过电子邮件向您发送照片。\n\n为避免退款风险,请仅确认您是否收到电子邮件,如果您确定收据有效。\n如果您不确定,{0} -portfolio.pending.step3_seller.moneyGram=买方必须发送授权编码和一张收据的照片。\n收据必须清楚地显示您的全名、城市、国家或地区、数量。如果您收到授权编码,请查收邮件。\n\n关闭弹窗后,您将看到 BTC 买家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到钱之后,再确认收据! -portfolio.pending.step3_seller.westernUnion=买方必须发送 MTCN(跟踪号码)和一张收据的照片。\n收据必须清楚地显示您的全名、城市、国家或地区、数量。如果您收到 MTCN,请查收邮件。\n\n关闭弹窗后,您将看到 BTC 买家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到钱之后,再确认收据! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=因为付款是通过现金存款完成的,XMR 买家必须在纸质收据上写“不退款”,将其撕成2份,并通过电子邮件向您发送照片。\n\n为避免退款风险,请仅确认您是否收到电子邮件,如果您确定收据有效。\n如果您不确定,{0} +portfolio.pending.step3_seller.moneyGram=买方必须发送授权编码和一张收据的照片。\n收据必须清楚地显示您的全名、城市、国家或地区、数量。如果您收到授权编码,请查收邮件。\n\n关闭弹窗后,您将看到 XMR 买家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到钱之后,再确认收据! +portfolio.pending.step3_seller.westernUnion=买方必须发送 MTCN(跟踪号码)和一张收据的照片。\n收据必须清楚地显示您的全名、城市、国家或地区、数量。如果您收到 MTCN,请查收邮件。\n\n关闭弹窗后,您将看到 XMR 买家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到钱之后,再确认收据! portfolio.pending.step3_seller.halCash=买方必须将 HalCash代码 用短信发送给您。除此之外,您将收到来自 HalCash 的消息,其中包含从支持 HalCash 的 ATM 中提取欧元所需的信息\n从 ATM 取款后,请在此确认付款收据! -portfolio.pending.step3_seller.amazonGiftCard=BTC 买家已经发送了一张亚马逊电子礼品卡到您的邮箱或手机短信。请现在立即兑换亚马逊电子礼品卡到您的亚马逊账户中以及确认交易信息。 +portfolio.pending.step3_seller.amazonGiftCard=XMR 买家已经发送了一张亚马逊电子礼品卡到您的邮箱或手机短信。请现在立即兑换亚马逊电子礼品卡到您的亚马逊账户中以及确认交易信息。 portfolio.pending.step3_seller.bankCheck=\n\n还请确认您的银行对帐单中的发件人姓名与委托合同中的发件人姓名相符:\n发件人姓名:{0}\n\n如果名称与此处显示的名称不同,则 {1} # suppress inspection "TrailingSpacesInProperty" @@ -701,7 +726,7 @@ portfolio.pending.step3_seller.xmrTxHash=交易记录 ID portfolio.pending.step3_seller.xmrTxKey=交易密钥 portfolio.pending.step3_seller.buyersAccount=买方账号数据 portfolio.pending.step3_seller.confirmReceipt=确定付款收据 -portfolio.pending.step3_seller.buyerStartedPayment=BTC 买家已经开始 {0} 的付款。\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=XMR 买家已经开始 {0} 的付款。\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=检查您的数字货币钱包或块浏览器的区块链确认,并确认付款时,您有足够的块链确认。 portfolio.pending.step3_seller.buyerStartedPayment.traditional=检查您的交易账户(例如银行帐户),并确认您何时收到付款。 portfolio.pending.step3_seller.warn.part1a=在 {0} 区块链 @@ -713,7 +738,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=您是否收到了您交 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=还请确认您的银行对帐单中的发件人姓名与委托合同中的发件人姓名相符:\n每个交易合约的发送者姓名:{0}\n\n如果名称与此处显示的名称不一致,请不要通过确认付款,而是通过“alt + o”或“option + o”打开纠纷。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=请注意,一旦您确认收到,冻结交易金额将被发放给 BTC 买家,保证金将被退还。 +portfolio.pending.step3_seller.onPaymentReceived.note=请注意,一旦您确认收到,冻结交易金额将被发放给 XMR 买家,保证金将被退还。 portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=确定您已经收到付款 portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=是的,我已经收到付款。 portfolio.pending.step3_seller.onPaymentReceived.signer=重要提示:通过确认收到付款,你也验证了对方的账户,并获得验证。因为对方的账户还没有验证,所以你应该尽可能的延迟付款的确认,以减少退款的风险。 @@ -723,7 +748,7 @@ portfolio.pending.step5_buyer.tradeFee=挂单费 portfolio.pending.step5_buyer.makersMiningFee=矿工手续费 portfolio.pending.step5_buyer.takersMiningFee=总共挖矿手续费 portfolio.pending.step5_buyer.refunded=退还保证金 -portfolio.pending.step5_buyer.withdrawBTC=提现您的比特币 +portfolio.pending.step5_buyer.withdrawXMR=提现您的比特币 portfolio.pending.step5_buyer.amount=提现数量 portfolio.pending.step5_buyer.withdrawToAddress=提现地址 portfolio.pending.step5_buyer.moveToHavenoWallet=在 Haveno 钱包中保留资金 @@ -833,7 +858,7 @@ funds.deposit.fundHavenoWallet=充值 Haveno 钱包 funds.deposit.noAddresses=尚未生成存款地址 funds.deposit.fundWallet=充值您的钱包 funds.deposit.withdrawFromWallet=从钱包转出资金 -funds.deposit.amount=BTC 数量(可选) +funds.deposit.amount=XMR 数量(可选) funds.deposit.generateAddress=生成新的地址 funds.deposit.generateAddressSegwit=原生 segwit 格式(Bech32) funds.deposit.selectUnused=请从上表中选择一个未使用的地址,而不是生成一个新地址。 @@ -904,7 +929,7 @@ support.filter=查找纠纷 support.filter.prompt=输入 交易 ID、日期、洋葱地址或账户信息 support.sigCheck.button=Check signature -support.sigCheck.popup.info=如果向在 DAO 发送赔偿请求,您需要在 Github 上粘贴您的赔偿请求中的调解和仲裁过程的摘要消息。要使此声明可验证,任何用户都可以使用此工具检查调解或仲裁人员的签名是否与摘要消息匹配。 +support.sigCheck.popup.info=请粘贴仲裁过程的摘要信息。使用这个工具,任何用户都可以检查仲裁者的签名是否与摘要信息相符。 support.sigCheck.popup.header=确认纠纷结果签名 support.sigCheck.popup.msg.label=总结消息 support.sigCheck.popup.msg.prompt=复制粘贴纠纷总结消息 @@ -940,8 +965,8 @@ support.savedInMailbox=消息保存在收件人的信箱中 support.arrived=消息抵达收件人 support.acknowledged=收件人已确认接收消息 support.error=收件人无法处理消息。错误:{0} -support.buyerAddress=BTC 买家地址 -support.sellerAddress=BTC 卖家地址 +support.buyerAddress=XMR 买家地址 +support.sellerAddress=XMR 卖家地址 support.role=角色 support.agent=Support agent support.state=状态 @@ -949,13 +974,13 @@ support.chat=Chat support.closed=关闭 support.open=打开 support.process=Process -support.buyerMaker=BTC 买家/挂单者 -support.sellerMaker=BTC 卖家/挂单者 -support.buyerTaker=BTC 买家/买单者 -support.sellerTaker=BTC 卖家/买单者 +support.buyerMaker=XMR 买家/挂单者 +support.sellerMaker=XMR 卖家/挂单者 +support.buyerTaker=XMR 买家/买单者 +support.sellerTaker=XMR 卖家/买单者 -support.backgroundInfo=Haveno 不是一家公司,所以它处理纠纷的方式不同。\n\n交易双方可以在应用程序中通过未完成交易页面上的安全聊天进行通信,以尝试自行解决争端。如果这还不够,调解员可以介入帮助。调解员将对情况进行评估,并对交易资金的支出提出建议。如果两个交易者都接受这个建议,那么支付交易就完成了,交易也结束了。如果一方或双方不同意调解员的建议,他们可以要求仲裁。仲裁员将重新评估情况,如果有必要,将亲自向交易员付款,并要求 Haveno DAO 对这笔付款进行补偿。 -support.initialInfo=请在下面的文本框中输入您的问题描述。添加尽可能多的信息,以加快解决纠纷的时间。\n\n以下是你应提供的资料核对表:\n\t●如果您是 BTC 买家:您是否使用法定货币或其他加密货币转账?如果是,您是否点击了应用程序中的“支付开始”按钮?\n\t●如果您是 BTC 卖家:您是否收到法定货币或其他加密货币的付款了?如果是,你是否点击了应用程序中的“已收到付款”按钮?\n\t●您使用的是哪个版本的 Haveno?\n\t●您使用的是哪种操作系统?\n\t●如果遇到操作执行失败的问题,请考虑切换到新的数据目录。\n\t有时数据目录会损坏,并导致奇怪的错误。\n详见:https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n请熟悉纠纷处理的基本规则:\n\t●您需要在2天内答复 {0} 的请求。\n\t●调解员会在2天之内答复,仲裁员会在5天之内答复。\n\t●纠纷的最长期限为14天。\n\t●你需要与仲裁员合作,提供他们为你的案件所要求的信息。\n\t●当您第一次启动应用程序时,您接受了用户协议中争议文档中列出的规则。\n\n您可以通过 {2} 了解有关纠纷处理的更多信息 +support.backgroundInfo=Haveno 不是一家公司,因此它以不同的方式处理纠纷。\n\n交易者可以在应用程序内通过打开交易屏幕上的安全聊天来尝试自行解决纠纷。如果这不够,仲裁员将评估情况并决定交易资金的支付。 +support.initialInfo=请在下面的文本框中输入您的问题描述。添加尽可能多的信息,以加快解决纠纷的时间。\n\n以下是你应提供的资料核对表:\n\t●如果您是 XMR 买家:您是否使用法定货币或其他加密货币转账?如果是,您是否点击了应用程序中的“支付开始”按钮?\n\t●如果您是 XMR 卖家:您是否收到法定货币或其他加密货币的付款了?如果是,你是否点击了应用程序中的“已收到付款”按钮?\n\t●您使用的是哪个版本的 Haveno?\n\t●您使用的是哪种操作系统?\n\t●如果遇到操作执行失败的问题,请考虑切换到新的数据目录。\n\t有时数据目录会损坏,并导致奇怪的错误。\n详见:https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n请熟悉纠纷处理的基本规则:\n\t●您需要在2天内答复 {0} 的请求。\n\t●调解员会在2天之内答复,仲裁员会在5天之内答复。\n\t●纠纷的最长期限为14天。\n\t●你需要与仲裁员合作,提供他们为你的案件所要求的信息。\n\t●当您第一次启动应用程序时,您接受了用户协议中争议文档中列出的规则。\n\n您可以通过 {2} 了解有关纠纷处理的更多信息 support.systemMsg=系统消息:{0} support.youOpenedTicket=您创建了帮助请求。\n\n{0}\n\nHaveno 版本:{1} support.youOpenedDispute=您创建了一个纠纷请求。\n\n{0}\n\nHaveno 版本:{1} @@ -982,10 +1007,11 @@ setting.preferences.general=通用偏好 setting.preferences.explorer=比特币区块浏览器 setting.preferences.deviation=与市场价格最大差价 setting.preferences.avoidStandbyMode=避免待机模式 +setting.preferences.useSoundForNotifications=播放通知声音 setting.preferences.autoConfirmXMR=XMR 自动确认 setting.preferences.autoConfirmEnabled=启用 setting.preferences.autoConfirmRequiredConfirmations=已要求确认 -setting.preferences.autoConfirmMaxTradeSize=最大交易量(BTC) +setting.preferences.autoConfirmMaxTradeSize=最大交易量(XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer 链接(使用Tor,但本地主机,LAN IP地址和 *.local 主机名除外) setting.preferences.deviationToLarge=值不允许大于30% setting.preferences.txFee=提现交易手续费(聪/字节) @@ -1022,11 +1048,13 @@ settings.preferences.editCustomExplorer.name=名称 settings.preferences.editCustomExplorer.txUrl=交易 URL settings.preferences.editCustomExplorer.addressUrl=地址 URL -settings.net.btcHeader=比特币网络 +settings.net.xmrHeader=比特币网络 settings.net.p2pHeader=Haveno 网络 settings.net.onionAddressLabel=我的匿名地址 settings.net.xmrNodesLabel=使用自定义比特币主节点 settings.net.moneroPeersLabel=已连接节点 +settings.net.connection=连接 +settings.net.connected=连接 settings.net.useTorForXmrJLabel=使用 Tor 连接 Monero 网络 settings.net.moneroNodesLabel=需要连接 Monero settings.net.useProvidedNodesRadio=使用公共比特币核心节点 @@ -1036,7 +1064,7 @@ settings.net.warn.usePublicNodes=如果您使用公共的Monero节点,您将 settings.net.warn.usePublicNodes.useProvided=不,使用给定的节点 settings.net.warn.usePublicNodes.usePublic=使用公共网络 settings.net.warn.useCustomNodes.B2XWarning=请确保您的比特币节点是一个可信的比特币核心节点!\n\n连接到不遵循比特币核心共识规则的节点可能会损坏您的钱包,并在交易过程中造成问题。\n\n连接到违反共识规则的节点的用户应对任何由此造成的损害负责。任何由此产生的纠纷都将有利于另一方。对于忽略此警告和保护机制的用户,不提供任何技术支持! -settings.net.warn.invalidBtcConfig=由于您的配置无效,无法连接至比特币网络。\n\n您的配置已经被重置为默认比特币节点。你需要重启 Haveno。 +settings.net.warn.invalidXmrConfig=由于您的配置无效,无法连接至比特币网络。\n\n您的配置已经被重置为默认比特币节点。你需要重启 Haveno。 settings.net.localhostXmrNodeInfo=背景信息:Haveno 在启动时会在本地查找比特币节点。如果有,Haveno 将只通过它与比特币网络进行通信。 settings.net.p2PPeersLabel=已连接节点 settings.net.onionAddressColumn=匿名地址 @@ -1044,7 +1072,7 @@ settings.net.creationDateColumn=已建立连接 settings.net.connectionTypeColumn=入/出 settings.net.sentDataLabel=统计数据已发送 settings.net.receivedDataLabel=统计数据已接收 -settings.net.chainHeightLabel=最新 BTC 区块高度 +settings.net.chainHeightLabel=最新 XMR 区块高度 settings.net.roundTripTimeColumn=延迟 settings.net.sentBytesColumn=发送 settings.net.receivedBytesColumn=接收 @@ -1059,7 +1087,7 @@ settings.net.needRestart=您需要重启应用程序以同意这次变更。\n settings.net.notKnownYet=至今未知... settings.net.sentData=已发送数据 {0},{1} 条消息,{2} 条消息/秒 settings.net.receivedData=已接收数据 {0},{1} 条消息,{2} 条消息/秒 -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=添加逗号分隔的 IP 地址及端口,如使用8333端口可不填写。 settings.net.seedNode=种子节点 settings.net.directPeer=节点(直连) @@ -1105,7 +1133,7 @@ setting.about.shortcuts.openDispute.value=选择未完成交易并点击:{0} setting.about.shortcuts.walletDetails=打开钱包详情窗口 -setting.about.shortcuts.openEmergencyBtcWalletTool=打开应急 BTC 钱包工具 +setting.about.shortcuts.openEmergencyXmrWalletTool=打开应急 XMR 钱包工具 setting.about.shortcuts.showTorLogs=在 DEBUG 与 WARN 之间切换 Tor 日志等级 @@ -1131,7 +1159,7 @@ setting.about.shortcuts.sendPrivateNotification=发送私人通知到对等点 setting.about.shortcuts.sendPrivateNotification.value=点击交易伙伴头像并按下:{0} 以显示更多信息 setting.info.headline=新 XMR 自动确认功能 -setting.info.msg=当你完成 BTC/XMR 交易时,您可以使用自动确认功能来验证是否向您的钱包中发送了正确数量的 XMR,以便 Haveno 可以自动将交易标记为完成,从而使每个人都可以更快地进行交易。\n\n自动确认使用 XMR 发送方提供的交易密钥在至少 2 个 XMR 区块浏览器节点上检查 XMR 交易。在默认情况下,Haveno 使用由 Haveno 贡献者运行的区块浏览器节点,但是我们建议运行您自己的 XMR 区块浏览器节点以最大程度地保护隐私和安全。\n\n您还可以在``设置''中将每笔交易的最大 BTC 数量设置为自动确认以及所需确认的数量。\n\n在 Haveno Wiki 上查看更多详细信息(包括如何设置自己的区块浏览器节点):https://bisq.wiki/Trading_Monero#Auto-confirming_trades +setting.info.msg=当你完成 XMR/XMR 交易时,您可以使用自动确认功能来验证是否向您的钱包中发送了正确数量的 XMR,以便 Haveno 可以自动将交易标记为完成,从而使每个人都可以更快地进行交易。\n\n自动确认使用 XMR 发送方提供的交易密钥在至少 2 个 XMR 区块浏览器节点上检查 XMR 交易。在默认情况下,Haveno 使用由 Haveno 贡献者运行的区块浏览器节点,但是我们建议运行您自己的 XMR 区块浏览器节点以最大程度地保护隐私和安全。\n\n您还可以在``设置''中将每笔交易的最大 XMR 数量设置为自动确认以及所需确认的数量。\n\n在 Haveno Wiki 上查看更多详细信息(包括如何设置自己的区块浏览器节点):https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades #################################################################### # Account #################################################################### @@ -1151,7 +1179,7 @@ account.menu.backup=备份 account.menu.notifications=通知 account.menu.walletInfo.balance.headLine=钱包余额 -account.menu.walletInfo.balance.info=这里包括内部钱包余额包括未确认交易。\n对于 BTC,下方显示的内部钱包的余额将会是窗口右上方的“可用”与“保留”余额的总和。 +account.menu.walletInfo.balance.info=这里包括内部钱包余额包括未确认交易。\n对于 XMR,下方显示的内部钱包的余额将会是窗口右上方的“可用”与“保留”余额的总和。 account.menu.walletInfo.xpub.headLine=监控密钥(xpub keys) account.menu.walletInfo.walletSelector={0} {1} 钱包 account.menu.walletInfo.path.headLine=HD 密钥链路径 @@ -1180,7 +1208,7 @@ account.crypto.popup.upx.msg=在 Haveno 上交易 UPX 需要您了解并满足 # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=在 Haveno 上交易 ARQ 需要您了解并满足以下要求:\n\n要发送 ARQ ,您需要使用官方的 ArQmA GUI 钱包或启用 store-tx-info 标志的 ArQmA CLI 钱包(在新版本中是默认的)。请确保您可以访问Tx密钥,因为在纠纷状态时需要。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高级>证明/检查页面。\n\n在普通的区块链浏览器中,这种交易是不可验证的。\n\n如有纠纷,你须向调解员或仲裁员提供下列资料:\n\n- Tx私钥\n- 交易哈希\n- 接收者的公开地址\n\n如未能提供上述资料,或使用不兼容的钱包,将会导致纠纷败诉。如果发生纠纷,ARQ 发送方负责向调解员或仲裁员提供 ARQ 转账的验证。\n\n不需要交易 ID,只需要普通的公共地址。\n\n如果您对该流程不确定,请访问 ArQmA Discord 频道(https://discord.gg/s9BQpJT)或 ArQmA 论坛(https://labs.arqma.com)了解更多信息。 # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=在 Haveno 上交易 XMR 需要你理解并满足以下要求。\n\n如果您出售 XMR,当您在纠纷中您必须要提供下列信息给调解员或仲裁员:\n- 交易密钥(Tx 公钥,Tx密钥,Tx私钥)\n- 交易 ID(Tx ID 或 Tx 哈希)\n- 交易目标地址(接收者地址)\n\n在 wiki 中查看更多关于 Monero 钱包的信息:\nhttps://bisq.wiki/Trading_Monero#Proving_payments\n\n如未能提供要求的交易数据将在纠纷中直接判负\n\n还要注意,Haveno 现在提供了自动确认 XMR 交易的功能,以使交易更快,但是您需要在设置中启用它。\n\n有关自动确认功能的更多信息,请参见 Wiki:\nhttps://bisq.wiki/Trading_Monero#Auto-confirming_trades +account.crypto.popup.xmr.msg=在 Haveno 上交易 XMR 需要你理解并满足以下要求。\n\n如果您出售 XMR,当您在纠纷中您必须要提供下列信息给调解员或仲裁员:\n- 交易密钥(Tx 公钥,Tx密钥,Tx私钥)\n- 交易 ID(Tx ID 或 Tx 哈希)\n- 交易目标地址(接收者地址)\n\n在 wiki 中查看更多关于 Monero 钱包的信息:\nhttps://haveno.exchange/wiki/Trading_Monero#Proving_payments\n\n如未能提供要求的交易数据将在纠纷中直接判负\n\n还要注意,Haveno 现在提供了自动确认 XMR 交易的功能,以使交易更快,但是您需要在设置中启用它。\n\n有关自动确认功能的更多信息,请参见 Wiki:\nhttps://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=区块链浏览器在 Haveno 上交易 XMR 需要您了解并满足以下要求:\n\n发送MSR时,您需要使用官方的 Masari GUI 钱包、启用store-tx-info标记的Masari CLI钱包(默认启用)或Masari 网页钱包(https://wallet.getmasari.org)。请确保您可以访问的 tx 密钥,因为如果发生纠纷这是需要的。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高级>证明/检查页面。\n\nMasari 网页钱包(前往 帐户->交易历史和查看您发送的交易细节)\n\n验证可以在钱包中完成。\nmonero-wallet-cli:使用命令(check_tx_key)。\nmonero-wallet-gui:在高级>证明/检查页面\n验证可以在区块浏览器中完成\n打开区块浏览器(https://explorer.getmasari.org),使用搜索栏查找您的事务哈希。\n一旦找到交易,滚动到底部的“证明发送”区域,并填写所需的详细信息。\n如有纠纷,你须向调解员或仲裁员提供下列资料:\n- Tx私钥\n- 交易哈希\n- 接收者的公开地址\n\n不需要交易 ID,只需要正常的公共地址。\n如未能提供上述资料,或使用不兼容的钱包,将会导致纠纷败诉。如果发生纠纷,XMR 发送方负责向调解员或仲裁员提供 XMR 转账的验证。\n\n如果您对该流程不确定,请访问官方的 Masari Discord(https://discord.gg/sMCwMqs)上寻求帮助。 # suppress inspection "UnusedProperty" @@ -1208,7 +1236,7 @@ account.crypto.popup.pars.msg=在 Haveno 上交易 ParsiCoin 需要您了解并 account.crypto.popup.blk-burnt.msg=要交易烧毁的货币,你需要知道以下几点:\n\n烧毁的货币是不能花的。要在 Haveno 上交易它们,输出脚本需要采用以下形式:OP_RETURN OP_PUSHDATA,后跟相关的数据字节,这些字节经过十六进制编码后构成地址。例如,地址为666f6f(在UTF-8中的"foo")的烧毁的货币将有以下脚本:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\n要创建烧毁的货币,您可以使用“烧毁”RPC命令,它在一些钱包可用。\n\n对于可能的情况,可以查看 https://ibo.laboratorium.ee\n\n因为烧毁的货币是不能用的,所以不能重新出售。“出售”烧毁的货币意味着焚烧初始的货币(与目的地地址相关联的数据)。\n\n如果发生争议,BLK 卖方需要提供交易哈希。 # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=在 Haveno 上交易 L-BTC 你必须理解下述条款:\n\n当你在 Haveno 上接受 L-BTC 交易时,你不能使用手机 Blockstream Green Wallet 或者是一个托管/交易钱包。你必须只接收 L-BTC 到 Liquid Elements Core 钱包,或另一个 L-BTC 钱包且允许你获得匿名的 L-BTC 地址以及密钥。\n\n在需要进行调解的情况下,或者如果发生了交易纠纷,您必须将接收 L-BTC地址的安全密钥披露给 Haveno 调解员或退款代理,以便他们能够在他们自己的 Elements Core 全节点上验证您的匿名交易的细节。\n\n如果你不了解或了解这些要求,不要在 Haveno 上交易 L-BTC。 +account.crypto.popup.liquidmonero.msg=在 Haveno 上交易 L-XMR 你必须理解下述条款:\n\n当你在 Haveno 上接受 L-XMR 交易时,你不能使用手机 Blockstream Green Wallet 或者是一个托管/交易钱包。你必须只接收 L-XMR 到 Liquid Elements Core 钱包,或另一个 L-XMR 钱包且允许你获得匿名的 L-XMR 地址以及密钥。\n\n在需要进行调解的情况下,或者如果发生了交易纠纷,您必须将接收 L-XMR地址的安全密钥披露给 Haveno 调解员或退款代理,以便他们能够在他们自己的 Elements Core 全节点上验证您的匿名交易的细节。\n\n如果你不了解或了解这些要求,不要在 Haveno 上交易 L-XMR。 account.traditional.yourTraditionalAccounts=您的法定货币账户 @@ -1228,9 +1256,9 @@ account.password.setPw.button=设置密码 account.password.setPw.headline=设置钱包的密码保护 account.password.info=启用密码保护后,在应用程序启动时、从您的钱包提取门罗币时以及显示种子词时,您将需要输入密码。 -account.seed.backup.title=备份您的钱包还原密钥 -account.seed.info=请写下钱包还原密钥和时间!\n您可以通过还原密钥和时间在任何时候恢复您的钱包。\n还原密钥用于 BTC 和 BSQ 钱包。\n\n您应该在一张纸上写下还原密钥并且不要保存它们在您的电脑上。\n请注意还原密钥并不能代替备份。\n您需要备份完整的应用程序目录在”账户/备份“界面去恢复有效的应用程序状态和数据。 -account.seed.backup.warning=请注意种子词不能替代备份。您需要为整个应用目录(在“账户/备份”选项卡中)以恢复应用状态以及数据。\n导入种子词仅在紧急情况时才推荐使用。 如果没有正确备份数据库文件和密钥,该应用程序将无法运行!\n\n在 Haveno wiki 中查看更多信息: https://bisq.wiki/Backing_up_application_data +account.seed.backup.title=备份您的钱包种子词 +account.seed.info=请记下钱包种子词和日期。您随时可以使用种子词和日期来恢复您的钱包。\n\n您应该将种子词写在一张纸上。不要将它们保存在电脑上。\n\n请注意,种子词并不能替代备份。\n您需要在“账户/备份”屏幕上创建整个应用程序目录的备份,以便恢复应用程序的状态和数据。 +account.seed.backup.warning=请注意,种子词并不是备份的替代品。\n您需要在“账户/备份”屏幕上创建整个应用程序目录的备份,以便还原应用程序的状态和数据。 account.seed.warn.noPw.msg=您还没有设置一个可以保护还原密钥显示的钱包密码。\n\n要显示还原密钥吗? account.seed.warn.noPw.yes=是的,不要再问我 account.seed.enterPw=输入密码查看还原密钥 @@ -1259,13 +1287,13 @@ account.notifications.trade.label=接收交易信息 account.notifications.market.label=接收报价提醒 account.notifications.price.label=接收价格提醒 account.notifications.priceAlert.title=价格提醒 -account.notifications.priceAlert.high.label=提醒条件:当 BTC 价格高于 -account.notifications.priceAlert.low.label=提醒条件:当 BTC 价格低于 +account.notifications.priceAlert.high.label=提醒条件:当 XMR 价格高于 +account.notifications.priceAlert.low.label=提醒条件:当 XMR 价格低于 account.notifications.priceAlert.setButton=设置价格提醒 account.notifications.priceAlert.removeButton=取消价格提醒 account.notifications.trade.message.title=交易状态已变更 account.notifications.trade.message.msg.conf=ID 为 {0} 的交易的存款交易已被确认。请打开您的 Haveno 应用程序并开始付款。 -account.notifications.trade.message.msg.started=BTC 买家已经开始支付 ID 为 {0} 的交易。 +account.notifications.trade.message.msg.started=XMR 买家已经开始支付 ID 为 {0} 的交易。 account.notifications.trade.message.msg.completed=ID 为 {0} 的交易已完成。 account.notifications.offer.message.title=您的报价已被接受 account.notifications.offer.message.msg=您的 ID 为 {0} 的报价已被接受 @@ -1275,10 +1303,10 @@ account.notifications.dispute.message.msg=您收到了一个 ID 为 {0} 的交 account.notifications.marketAlert.title=报价提醒 account.notifications.marketAlert.selectPaymentAccount=提供匹配的付款帐户 account.notifications.marketAlert.offerType.label=我感兴趣的报价类型 -account.notifications.marketAlert.offerType.buy=买入报价(我想要出售 BTC ) -account.notifications.marketAlert.offerType.sell=卖出报价(我想要购买 BTC ) +account.notifications.marketAlert.offerType.buy=买入报价(我想要出售 XMR ) +account.notifications.marketAlert.offerType.sell=卖出报价(我想要购买 XMR ) account.notifications.marketAlert.trigger=报价距离(%) -account.notifications.marketAlert.trigger.info=设置价格区间后,只有当满足(或超过)您的需求的报价发布时,您才会收到提醒。您想卖 BTC ,但你只能以当前市价的 2% 溢价出售。将此字段设置为 2% 将确保您只收到高于当前市场价格 2%(或更多)的报价的提醒。 +account.notifications.marketAlert.trigger.info=设置价格区间后,只有当满足(或超过)您的需求的报价发布时,您才会收到提醒。您想卖 XMR ,但你只能以当前市价的 2% 溢价出售。将此字段设置为 2% 将确保您只收到高于当前市场价格 2%(或更多)的报价的提醒。 account.notifications.marketAlert.trigger.prompt=与市场价格的百分比距离(例如 2.50%, -0.50% 等) account.notifications.marketAlert.addButton=添加报价提醒 account.notifications.marketAlert.manageAlertsButton=管理报价提醒 @@ -1305,10 +1333,10 @@ inputControlWindow.balanceLabel=可用余额 contractWindow.title=纠纷详情 contractWindow.dates=报价时间/交易时间 -contractWindow.btcAddresses=BTC 买家/BTC 卖家的比特币地址 -contractWindow.onions=BTC 买家/BTC 卖家的网络地址 -contractWindow.accountAge=BTC 买家/BTC 卖家的账龄 -contractWindow.numDisputes=BTC 买家/BTC 卖家的纠纷编号 +contractWindow.xmrAddresses=XMR 买家/XMR 卖家的比特币地址 +contractWindow.onions=XMR 买家/XMR 卖家的网络地址 +contractWindow.accountAge=XMR 买家/XMR 卖家的账龄 +contractWindow.numDisputes=XMR 买家/XMR 卖家的纠纷编号 contractWindow.contractHash=合同哈希 displayAlertMessageWindow.headline=重要资料! @@ -1334,8 +1362,8 @@ disputeSummaryWindow.title=概要 disputeSummaryWindow.openDate=工单创建时间 disputeSummaryWindow.role=交易者的角色 disputeSummaryWindow.payout=交易金额支付 -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} 获得交易金额支付 -disputeSummaryWindow.payout.getsAll=最大 BTC 支付数 {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} 获得交易金额支付 +disputeSummaryWindow.payout.getsAll=最大 XMR 支付数 {0} disputeSummaryWindow.payout.custom=自定义支付 disputeSummaryWindow.payoutAmount.buyer=买家支付金额 disputeSummaryWindow.payoutAmount.seller=卖家支付金额 @@ -1377,7 +1405,7 @@ disputeSummaryWindow.close.button=关闭话题 # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=工单已关闭{0}\n{1} 节点地址:{12}\n\n总结:\n交易 ID:{3}\n货币:{4}\n交易金额:{5}\nBTC 买家支付金额:{6}\nBTC 卖家支付金额:{7}\n\n纠纷原因:{8}\n\n总结:\n{9}\n +disputeSummaryWindow.close.msg=工单已关闭{0}\n{1} 节点地址:{12}\n\n总结:\n交易 ID:{3}\n货币:{4}\n交易金额:{5}\nXMR 买家支付金额:{6}\nXMR 卖家支付金额:{7}\n\n纠纷原因:{8}\n\n总结:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1432,7 +1460,7 @@ filterWindow.xmrFeeReceiverAddresses=比特币手续费接收地址 filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=最小 BTC 数量 +offerDetailsWindow.minXmrAmount=最小 XMR 数量 offerDetailsWindow.min=(最小 {0}) offerDetailsWindow.distance=(与市场价格的差距:{0}) offerDetailsWindow.myTradingAccount=我的交易账户 @@ -1447,6 +1475,7 @@ offerDetailsWindow.confirm.maker=确定:发布报价 {0} 比特币 offerDetailsWindow.confirm.taker=确定:下单买入 {0} 比特币 offerDetailsWindow.creationDate=创建时间 offerDetailsWindow.makersOnion=卖家的匿名地址 +offerDetailsWindow.challenge=提供密码 qRCodeWindow.headline=二维码 qRCodeWindow.msg=请使用二维码从外部钱包充值至 Haveno 钱包 @@ -1475,7 +1504,7 @@ showWalletDataWindow.walletData=钱包数据 showWalletDataWindow.includePrivKeys=包含私钥 setXMRTxKeyWindow.headline=证明已发送 XMR -setXMRTxKeyWindow.note=在下面添加 tx 信息可以更快的自动确认交易。更多信息::https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=在下面添加 tx 信息可以更快的自动确认交易。更多信息::https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=交易 ID (可选) setXMRTxKeyWindow.txKey=交易密钥 (可选) @@ -1487,7 +1516,7 @@ tacWindow.disagree=我不同意并退出 tacWindow.arbitrationSystem=纠纷解决方案 tradeDetailsWindow.headline=交易 -tradeDetailsWindow.disputedPayoutTxId=纠纷支付交易 ID: +tradeDetailsWindow.disputedPayoutTxId=纠纷支付交易 ID tradeDetailsWindow.tradeDate=交易时间 tradeDetailsWindow.txFee=矿工手续费 tradeDetailsWindow.tradePeersOnion=交易伙伴匿名地址 @@ -1497,8 +1526,10 @@ tradeDetailsWindow.agentAddresses=仲裁员/调解员 tradeDetailsWindow.detailData=详情数据 txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=您已发送 XMR。 +txDetailsWindow.xmr.noteReceived=你已收到XMR。 +txDetailsWindow.sentTo=发送至 +txDetailsWindow.receivedWith=已收到,带有 txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1507,7 +1538,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=输入密码解锁 @@ -1534,12 +1565,12 @@ torNetworkSettingWindow.bridges.header=Tor 网络被屏蔽? torNetworkSettingWindow.bridges.info=如果 Tor 被您的 Internet 提供商或您的国家或地区屏蔽,您可以尝试使用 Tor 网桥。\n \n访问 Tor 网页:https://bridges.torproject.org/bridges,了解关于网桥和可插拔传输的更多信息。 feeOptionWindow.headline=选择货币支付交易手续费 -feeOptionWindow.info=您可以选择用 BSQ 或 BTC 支付交易费用。如果您选择 BSQ ,您会感谢这些交易手续费折扣。 +feeOptionWindow.info=您可以选择用 BSQ 或 XMR 支付交易费用。如果您选择 BSQ ,您会感谢这些交易手续费折扣。 feeOptionWindow.optionsLabel=选择货币支付交易手续费 -feeOptionWindow.useBTC=使用 BTC +feeOptionWindow.useXMR=使用 XMR feeOptionWindow.fee={0}(≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1581,9 +1612,9 @@ popup.warning.noTradingAccountSetup.msg=您需要设置法定货币或数字货 popup.warning.noArbitratorsAvailable=没有仲裁员可用。 popup.warning.noMediatorsAvailable=没有调解员可用。 popup.warning.notFullyConnected=您需要等到您完全连接到网络\n在启动时可能需要2分钟。 -popup.warning.notSufficientConnectionsToBtcNetwork=你需要等待至少有{0}个与比特币网络的连接点。 +popup.warning.notSufficientConnectionsToXmrNetwork=你需要等待至少有{0}个与比特币网络的连接点。 popup.warning.downloadNotComplete=您需要等待,直到丢失的比特币区块被下载完毕。 -popup.warning.chainNotSynced=Haveno 钱包区块链高度没有正确地同步。如果最近才打开应用,请等待一个新发布的比特币区块。\n\n你可以检查区块链高度在设置/网络信息。如果经过了一个区块但问题还是没有解决,你应该及时的完成 SPV 链重新同步。https://bisq.wiki/Resyncing_SPV_file +popup.warning.walletNotSynced=Haveno 钱包尚未与最新的区块链高度同步。请等待钱包同步完成或检查您的连接。 popup.warning.removeOffer=您确定要移除该报价吗? popup.warning.tooLargePercentageValue=您不能设置100%或更大的百分比。 popup.warning.examplePercentageValue=请输入百分比数字,如 5.4% 是“5.4” @@ -1604,8 +1635,7 @@ popup.warning.nodeBanned=其中一个 {0} 节点已被禁用 popup.warning.priceRelay=价格传递 popup.warning.seed=种子 popup.warning.mandatoryUpdate.trading=请更新到最新的 Haveno 版本。强制更新禁止了旧版本进行交易。更多信息请访问 Haveno 论坛。 -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=这笔交易是无法实现,因为 {0} 的挖矿手续费用会超过 {1} 的转账金额。请等到挖矿手续费再次降低或您积累了更多的 BTC 来转账。 +popup.warning.burnXMR=这笔交易是无法实现,因为 {0} 的挖矿手续费用会超过 {1} 的转账金额。请等到挖矿手续费再次降低或您积累了更多的 XMR 来转账。 popup.warning.openOffer.makerFeeTxRejected=交易 ID 为 {0} 的挂单费交易被比特币网络拒绝。\n交易 ID = {1}\n交易已被移至失败交易。\n请到“设置/网络信息”进行 SPV 重新同步。\n如需更多帮助,请联系 Haveno Keybase 团队的 Support 频道 @@ -1620,7 +1650,7 @@ popup.info.securityDepositInfo=为了确保双方都遵守交易协议,双方 popup.info.cashDepositInfo=请确保您在您的地区有一个银行分行,以便能够进行现金存款。\n卖方银行的银行 ID(BIC/SWIFT)为:{0}。 popup.info.cashDepositInfo.confirm=我确认我可以支付保证金 popup.info.shutDownWithOpenOffers=Haveno 正在被关闭,但仍有公开的报价。\n\n当 Haveno 关闭时,这些提供将不能在 P2P 网络上使用,但是它们将在您下次启动 Haveno 时重新发布到 P2P 网络上。\n\n为了让您的报价在线,保持 Haveno 运行,并确保这台计算机也在线(即,确保它不会进入待机模式…显示器待机不是问题)。 -popup.info.qubesOSSetupInfo=你似乎好像在 Qubes OS 上运行 Haveno。\n\n请确保您的 Haveno qube 是参考设置指南的说明设置的 https://bisq.wiki/Running_Haveno_on_Qubes +popup.info.qubesOSSetupInfo=你似乎好像在 Qubes OS 上运行 Haveno。\n\n请确保您的 Haveno qube 是参考设置指南的说明设置的 https://haveno.exchange/wiki/Running_Haveno_on_Qubes popup.warn.downGradePrevention=不支持从 {0} 版本降级到 {1} 版本。请使用最新的 Haveno 版本。 popup.privateNotification.headline=重要私人通知! @@ -1628,7 +1658,7 @@ popup.privateNotification.headline=重要私人通知! popup.securityRecommendation.headline=重要安全建议 popup.securityRecommendation.msg=如果您还没有启用,我们想提醒您考虑为您的钱包使用密码保护。\n\n强烈建议你写下钱包还原密钥。 那些还原密钥就是恢复你的比特币钱包的主密码。\n在“钱包密钥”部分,您可以找到更多信息\n\n此外,您应该在“备份”界面备份完整的应用程序数据文件夹。 -popup.moneroLocalhostNode.msg=Haveno 侦测到本机(本地)运行着一个门罗币节点(位于 localhost)。\n\n请确保在启动 Haveno 之前,节点已完全同步。 +popup.xmrLocalNode.msg=Haveno 侦测到本机(本地)运行着一个门罗币节点(位于 localhost)。\n\n请确保在启动 Haveno 之前,节点已完全同步。 popup.shutDownInProgress.headline=正在关闭 popup.shutDownInProgress.msg=关闭应用可能会花一点时间。\n请不要打断关闭过程。 @@ -1674,6 +1704,9 @@ popup.accountSigning.unsignedPubKeys.signed=公钥已被验证 popup.accountSigning.unsignedPubKeys.result.signed=已验证公钥 popup.accountSigning.unsignedPubKeys.result.failed=未能验证公钥 +popup.info.buyerAsTakerWithoutDeposit.headline=买家无需支付保证金 +popup.info.buyerAsTakerWithoutDeposit=您的报价将不需要来自XMR买家的保证金或费用。\n\n要接受您的报价,您必须与交易伙伴在Haveno外共享一个密码短语。\n\n密码短语会自动生成,并在创建后显示在报价详情中。 + #################################################################### # Notifications #################################################################### @@ -1681,9 +1714,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=未能验证公钥 notification.trade.headline=交易 ID {0} 的通知 notification.ticket.headline=交易 ID {0} 的帮助话题 notification.trade.completed=交易现在完成,您可以提取资金。 -notification.trade.accepted=您 BTC {0} 的报价被接受。 +notification.trade.accepted=您 XMR {0} 的报价被接受。 notification.trade.unlocked=您的交易至少有一个区块链确认。\n您现在可以开始付款。 -notification.trade.paymentSent=BTC 买家已经开始付款。 +notification.trade.paymentSent=XMR 买家已经开始付款。 notification.trade.selectTrade=选择交易 notification.trade.peerOpenedDispute=您的交易对象创建了一个 {0}。 notification.trade.disputeClosed=这个 {0} 被关闭。 @@ -1753,7 +1786,7 @@ tooltip.openBlockchainForTx=使用外部区块链浏览器打开交易:{0} confidence.unknown=未知交易状态 confidence.seen=被 {0} 人查看 / 0 确定 -confidence.confirmed=在 {0} 区块中确认 +confidence.confirmed={0} 确认(s) confidence.invalid=交易无效 peerInfo.title=对象资料 @@ -1799,6 +1832,7 @@ navigation.support=“帮助” formatter.formatVolumeLabel={0} 数量 {1} formatter.makerTaker=卖家 {0} {1} / 买家 {2} {3} +formatter.makerTakerLocked=卖家 {0} {1} / 买家 {2} {3} 🔒 formatter.youAreAsMaker=您是 {1} {0} 卖家 / 买家是 {3} {2} formatter.youAreAsTaker=您是 {1} {0} 买家 / 卖家是 {3} {2} formatter.youAre=您是 {0} {1} ({2} {3}) @@ -1844,7 +1878,6 @@ password.deriveKey=从密码中提取密钥 password.walletDecrypted=钱包成功解密并移除密码保护 password.wrongPw=你输入了错误的密码。\n\n请再次尝试输入密码,仔细检查拼写错误。 password.walletEncrypted=钱包成功加密并开启密码保护。 -password.walletEncryptionFailed=无法设置钱包密码。您可能导入了与钱包数据库不匹配的还原密钥。请在 Keybase 上联系开发者(https://keybase.io/team/haveno]) password.passwordsDoNotMatch=这2个密码您输入的不相同 password.forgotPassword=忘记密码? password.backupReminder=请注意,设置钱包密码时,所有未加密的钱包的自动创建的备份将被删除。\n\n强烈建议您备份应用程序的目录,并在设置密码之前记下您的还原密钥! @@ -1875,7 +1908,7 @@ seed.restore.openOffers.warn=您有公开报价,如果您从种子词恢复, payment.account=账户 payment.account.no=账户编号 payment.account.name=账户名称 -payment.account.userName=用户昵称 +payment.account.username=用户昵称 payment.account.phoneNr=电话号码 payment.account.owner=账户拥有者姓名: payment.account.fullName=全称(名,中间名,姓) @@ -1907,7 +1940,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=用户名或电子邮箱或电话号码 payment.moneyBeam.accountId=电子邮箱或者电话号码 -payment.venmo.venmoUserName=Venmo 用户名: payment.popmoney.accountId=电子邮箱或者电话号码 payment.promptPay.promptPayId=公民身份证/税号或电话号码 payment.supportedCurrencies=支持的货币 @@ -1949,16 +1981,16 @@ payment.checking=检查 payment.savings=保存 payment.personalId=个人 ID payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle是一项转账服务,转账到其他银行做的很好。\n\n1.检查此页面以查看您的银行是否(以及如何)与 Zelle 合作:\nhttps://www.zellepay.com/get-started\n\n2.特别注意您的转账限额-汇款限额因银行而异,银行通常分别指定每日,每周和每月的限额。\n\n3.如果您的银行不能使用 Zelle,您仍然可以通过 Zelle 移动应用程序使用它,但是您的转账限额会低得多。\n\n4.您的 Haveno 帐户上指定的名称必须与 Zelle/银行帐户上的名称匹配。 \n\n如果您无法按照贸易合同中的规定完成 Zelle 交易,则可能会损失部分(或全部)保证金。\n\n由于 Zelle 的拒付风险较高,因此建议卖家通过电子邮件或 SMS 与未签名的买家联系,以确认买家确实拥有 Haveno 中指定的 Zelle 帐户。 payment.fasterPayments.newRequirements.info=有些银行已经开始核实快捷支付收款人的全名。您当前的快捷支付帐户没有填写全名。\n\n请考虑在 Haveno 中重新创建您的快捷支付帐户,为将来的 {0} 买家提供一个完整的姓名。\n\n重新创建帐户时,请确保将银行区号、帐户编号和帐龄验证盐值从旧帐户复制到新帐户。这将确保您现有的帐龄和签名状态得到保留。 -payment.moneyGram.info=使用 MoneyGram 时,BTC 买方必须将授权号码和收据的照片通过电子邮件发送给 BTC 卖方。收据必须清楚地显示卖方的全名、国家或地区、州和金额。买方将在交易过程中显示卖方的电子邮件。 -payment.westernUnion.info=使用 Western Union 时,BTC 买方必须通过电子邮件将 MTCN(运单号)和收据照片发送给 BTC 卖方。收据上必须清楚地显示卖方的全名、城市、国家或地区和金额。买方将在交易过程中显示卖方的电子邮件。 -payment.halCash.info=使用 HalCash 时,BTC 买方需要通过手机短信向 BTC 卖方发送 HalCash 代码。\n\n请确保不要超过银行允许您用半现金汇款的最高金额。每次取款的最低金额是 10 欧元,最高金额是 10 欧元。金额是 600 欧元。对于重复取款,每天每个接收者 3000 欧元,每月每个接收者 6000 欧元。请与您的银行核对这些限额,以确保它们使用与此处所述相同的限额。\n\n提现金额必须是 10 欧元的倍数,因为您不能从 ATM 机提取其他金额。 创建报价和下单屏幕中的 UI 将调整 BTC 金额,使 EUR 金额正确。你不能使用基于市场的价格,因为欧元的数量会随着价格的变化而变化。\n +payment.moneyGram.info=使用 MoneyGram 时,XMR 买方必须将授权号码和收据的照片通过电子邮件发送给 XMR 卖方。收据必须清楚地显示卖方的全名、国家或地区、州和金额。买方将在交易过程中显示卖方的电子邮件。 +payment.westernUnion.info=使用 Western Union 时,XMR 买方必须通过电子邮件将 MTCN(运单号)和收据照片发送给 XMR 卖方。收据上必须清楚地显示卖方的全名、城市、国家或地区和金额。买方将在交易过程中显示卖方的电子邮件。 +payment.halCash.info=使用 HalCash 时,XMR 买方需要通过手机短信向 XMR 卖方发送 HalCash 代码。\n\n请确保不要超过银行允许您用半现金汇款的最高金额。每次取款的最低金额是 10 欧元,最高金额是 10 欧元。金额是 600 欧元。对于重复取款,每天每个接收者 3000 欧元,每月每个接收者 6000 欧元。请与您的银行核对这些限额,以确保它们使用与此处所述相同的限额。\n\n提现金额必须是 10 欧元的倍数,因为您不能从 ATM 机提取其他金额。 创建报价和下单屏幕中的 UI 将调整 XMR 金额,使 EUR 金额正确。你不能使用基于市场的价格,因为欧元的数量会随着价格的变化而变化。\n # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=请注意,所有银行转账都有一定的退款风险。为了降低这一风险,Haveno 基于使用的付款方式的退款风险。\n\n对于付款方式,您的每笔交易的出售和购买的限额为{2}\n\n限制只应用在单笔交易,你可以尽可能多的进行交易。\n\n在 Haveno Wiki 查看更多信息[HYPERLINK:https://bisq.wiki/Account_limits]。 +payment.limits.info=请注意,所有银行转账都有一定的退款风险。为了降低这一风险,Haveno 基于使用的付款方式的退款风险。\n\n对于付款方式,您的每笔交易的出售和购买的限额为{2}\n\n限制只应用在单笔交易,你可以尽可能多的进行交易。\n\n在 Haveno Wiki 查看更多信息[HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]。 # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=为了降低这一风险,Haveno 基于两个因素对该付款方式每笔交易设置了限制:\n\n1. 使用的付款方法的预估退款风险水平\n2. 您的付款方式的账龄\n\n这个付款账户还没有被验证,所以他每个交易最多购买{0}。在验证之后,购买限制会以以下规则逐渐增加:\n\n●签署前,以及签署后30天内,您的每笔最大交易将限制为{0}\n●签署后30天,每笔最大交易将限制为{1}\n●签署后60天,每笔最大交易将限制为{2}\n\n出售限制不会被账户验证状态限制,你可以理科进行单笔为{2}的交易\n\n限制只应用在单笔交易,你可以尽可能多的进行交易。\n\n在 Haveno Wiki 上查看更多:\nhttps://bisq.wiki/Account_limits +payment.limits.info.withSigning=为了降低这一风险,Haveno 基于两个因素对该付款方式每笔交易设置了限制:\n\n1. 使用的付款方法的预估退款风险水平\n2. 您的付款方式的账龄\n\n这个付款账户还没有被验证,所以他每个交易最多购买{0}。在验证之后,购买限制会以以下规则逐渐增加:\n\n●签署前,以及签署后30天内,您的每笔最大交易将限制为{0}\n●签署后30天,每笔最大交易将限制为{1}\n●签署后60天,每笔最大交易将限制为{2}\n\n出售限制不会被账户验证状态限制,你可以理科进行单笔为{2}的交易\n\n限制只应用在单笔交易,你可以尽可能多的进行交易。\n\n在 Haveno Wiki 上查看更多:\nhttps://docs.haveno.exchange/the-project/account_limits payment.cashDeposit.info=请确认您的银行允许您将现金存款汇入他人账户。例如,美国银行和富国银行不再允许此类存款。 @@ -1970,7 +2002,7 @@ payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the cou payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=在 Haveno 上交易 US Postal Money Orders (USPMO)您必须理解下述条款:\n\n- BTC 买方必须在发送方和收款人字段中都写上 BTC 卖方的名称,并在发送之前对 USPMO 和信封进行高分辨率照片拍照,并带有跟踪证明。\n- BTC 买方必须将 USPMO 连同交货确认书一起发送给 BTC 卖方。\n\n如果需要调解,或有交易纠纷,您将需要将照片连同 USPMO 编号,邮局编号和交易金额一起发送给 Haveno 调解员或退款代理,以便他们进行验证美国邮局网站上的详细信息。\n\n如未能提供要求的交易数据将在纠纷中直接判负\n\n在所有争议案件中,USPMO 发送方在向调解人或仲裁员提供证据/证明时承担 100% 的责任。\n\n如果您不理解这些要求,请不要在 Haveno 上使用 USPMO 进行交易。 +payment.usPostalMoneyOrder.info=在 Haveno 上交易 US Postal Money Orders (USPMO)您必须理解下述条款:\n\n- XMR 买方必须在发送方和收款人字段中都写上 XMR 卖方的名称,并在发送之前对 USPMO 和信封进行高分辨率照片拍照,并带有跟踪证明。\n- XMR 买方必须将 USPMO 连同交货确认书一起发送给 XMR 卖方。\n\n如果需要调解,或有交易纠纷,您将需要将照片连同 USPMO 编号,邮局编号和交易金额一起发送给 Haveno 调解员或退款代理,以便他们进行验证美国邮局网站上的详细信息。\n\n如未能提供要求的交易数据将在纠纷中直接判负\n\n在所有争议案件中,USPMO 发送方在向调解人或仲裁员提供证据/证明时承担 100% 的责任。\n\n如果您不理解这些要求,请不要在 Haveno 上使用 USPMO 进行交易。 payment.payByMail.contact=联系方式 payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1981,7 +2013,7 @@ payment.f2f.city.prompt=城市将与报价一同显示 payment.shared.optionalExtra=可选的附加信息 payment.shared.extraInfo=附加信息 payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info=与网上交易相比,“面对面”交易有不同的规则,也有不同的风险。\n\n主要区别是:\n●交易伙伴需要使用他们提供的联系方式交换关于会面地点和时间的信息。\n●交易双方需要携带笔记本电脑,在会面地点确认“已发送付款”和“已收到付款”。\n●如果交易方有特殊的“条款和条件”,他们必须在账户的“附加信息”文本框中声明这些条款和条件。\n●在发生争议时,调解员或仲裁员不能提供太多帮助,因为通常很难获得有关会面上所发生情况的篡改证据。在这种情况下,BTC 资金可能会被无限期锁定,或者直到交易双方达成协议。\n\n为确保您完全理解“面对面”交易的不同之处,请阅读以下说明和建议:“https://docs.haveno.exchange/trading-rules.html#f2f-trading” +payment.f2f.info=与网上交易相比,“面对面”交易有不同的规则,也有不同的风险。\n\n主要区别是:\n●交易伙伴需要使用他们提供的联系方式交换关于会面地点和时间的信息。\n●交易双方需要携带笔记本电脑,在会面地点确认“已发送付款”和“已收到付款”。\n●如果交易方有特殊的“条款和条件”,他们必须在账户的“附加信息”文本框中声明这些条款和条件。\n●在发生争议时,调解员或仲裁员不能提供太多帮助,因为通常很难获得有关会面上所发生情况的篡改证据。在这种情况下,XMR 资金可能会被无限期锁定,或者直到交易双方达成协议。\n\n为确保您完全理解“面对面”交易的不同之处,请阅读以下说明和建议:“https://docs.haveno.exchange/trading-rules.html#f2f-trading” payment.f2f.info.openURL=打开网页 payment.f2f.offerbook.tooltip.countryAndCity=国家或地区及城市:{0} / {1} payment.f2f.offerbook.tooltip.extra=附加信息:{0} @@ -1993,7 +2025,7 @@ payment.japan.recipient=名称 payment.australia.payid=PayID payment.payid=PayID 需链接至金融机构。例如电子邮件地址或手机。 payment.payid.info=PayID,如电话号码、电子邮件地址或澳大利亚商业号码(ABN),您可以安全地连接到您的银行、信用合作社或建立社会帐户。你需要在你的澳大利亚金融机构创建一个 PayID。发送和接收金融机构都必须支持 PayID。更多信息请查看[HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2161,10 +2193,10 @@ validation.sortCodeChars={0} 必须由 {1} 个字符构成。 validation.bankIdNumber={0} 必须由 {1} 个数字构成。 validation.accountNr=账号必须由 {0} 个数字构成。 validation.accountNrChars=账户必须由 {0} 个字符构成。 -validation.btc.invalidAddress=地址不正确,请检查地址格式。 +validation.xmr.invalidAddress=地址不正确,请检查地址格式。 validation.integerOnly=请输入整数。 validation.inputError=您的输入引起了错误:\n{0} -validation.btc.exceedsMaxTradeLimit=您的交易限额为 {0}。 +validation.xmr.exceedsMaxTradeLimit=您的交易限额为 {0}。 validation.nationalAccountId={0} 必须由{1}个数字组成。 #new diff --git a/core/src/main/resources/i18n/displayStrings_zh-hant.properties b/core/src/main/resources/i18n/displayStrings_zh-hant.properties index f517733dc3..9132242ee7 100644 --- a/core/src/main/resources/i18n/displayStrings_zh-hant.properties +++ b/core/src/main/resources/i18n/displayStrings_zh-hant.properties @@ -36,14 +36,16 @@ shared.iUnderstand=我瞭解 shared.na=N/A shared.shutDown=完全關閉 shared.reportBug=在 Github 報吿錯誤 -shared.buyBitcoin=買入比特幣 -shared.sellBitcoin=賣出比特幣 +shared.buyMonero=買入比特幣 +shared.sellMonero=賣出比特幣 shared.buyCurrency=買入 {0} shared.sellCurrency=賣出 {0} -shared.buyingBTCWith=用 {0} 買入 BTC -shared.sellingBTCFor=賣出 BTC 為 {0} -shared.buyingCurrency=買入 {0}(賣出 BTC) -shared.sellingCurrency=賣出 {0}(買入 BTC) +shared.buyCurrencyLocked=買入 {0} 🔒 +shared.sellCurrencyLocked=賣出 {0} 🔒 +shared.buyingXMRWith=用 {0} 買入 XMR +shared.sellingXMRFor=賣出 XMR 為 {0} +shared.buyingCurrency=買入 {0}(賣出 XMR) +shared.sellingCurrency=賣出 {0}(買入 XMR) shared.buy=買 shared.sell=賣 shared.buying=買入 @@ -93,7 +95,7 @@ shared.amountMinMax=總額(最小 - 最大) shared.amountHelp=如果報價包含最小和最大限制,那麼您可以在這個範圍內的任意數量進行交易。 shared.remove=移除 shared.goTo=前往 {0} -shared.BTCMinMax=BTC(最小 - 最大) +shared.XMRMinMax=XMR(最小 - 最大) shared.removeOffer=移除報價 shared.dontRemoveOffer=不要移除報價 shared.editOffer=編輯報價 @@ -103,7 +105,7 @@ shared.faq=訪問 FAQ 頁面 shared.yesCancel=是的,取消 shared.nextStep=下一步 shared.selectTradingAccount=選擇交易賬户 -shared.fundFromSavingsWalletButton=從 Haveno 錢包資金劃轉 +shared.fundFromSavingsWalletButton=從 Haveno 錢包申請資金 shared.fundFromExternalWalletButton=從您的外部錢包充值 shared.openDefaultWalletFailed=打開默認的比特幣錢包應用程序失敗了。您確定您安裝了嗎? shared.belowInPercent=低於市場價格 % @@ -112,7 +114,7 @@ shared.enterPercentageValue=輸入 % 值 shared.OR=或者 shared.notEnoughFunds=您的 Haveno 錢包中沒有足夠的資金去支付這一交易 需要{0} 您可用餘額為 {1}。\n\n請從外部比特幣錢包注入資金或在“資金/存款”充值到您的 Haveno 錢包。 shared.waitingForFunds=等待資金充值... -shared.TheBTCBuyer=BTC 買家 +shared.TheXMRBuyer=XMR 買家 shared.You=您 shared.sendingConfirmation=發送確認... shared.sendingConfirmationAgain=請再次發送確認 @@ -123,7 +125,6 @@ shared.noDateAvailable=沒有可用數據 shared.noDetailsAvailable=沒有可用詳細 shared.notUsedYet=尚未使用 shared.date=日期 -shared.sendFundsDetailsWithFee=發送:{0}\n來自:{1}\n接收地址:{2}\n要求的最低交易費:{3}({4} 聰/byte)\n交易大小:{5} Kb\n\n收款方將收到:{6}\n\n您確定您想要提現嗎? # suppress inspection "TrailingSpacesInProperty" shared.sendFundsDetailsDust=Haveno 檢測到,該交易將產生一個低於最低零頭閾值的輸出(不被比特幣共識規則所允許)。相反,這些零頭({0}satoshi{1})將被添加到挖礦手續費中。 shared.copyToClipboard=複製到剪貼板 @@ -140,6 +141,7 @@ shared.addNewAccount=添加新的賬户 shared.ExportAccounts=導出賬户 shared.importAccounts=導入賬户 shared.createNewAccount=創建新的賬户 +shared.createNewAccountDescription=您的帳戶詳細資料儲存在您的裝置上,僅在開啟爭議時與您的交易夥伴和仲裁者分享。 shared.saveNewAccount=保存新的賬户 shared.selectedAccount=選中的賬户 shared.deleteAccount=刪除賬户 @@ -169,7 +171,7 @@ shared.payoutTxId=支出交易 ID shared.contractAsJson=JSON 格式的合同 shared.viewContractAsJson=查看 JSON 格式的合同 shared.contract.title=交易 ID:{0} 的合同 -shared.paymentDetails=BTC {0} 支付詳情 +shared.paymentDetails=XMR {0} 支付詳情 shared.securityDeposit=保證金 shared.yourSecurityDeposit=你的保證金 shared.contract=合同 @@ -179,19 +181,21 @@ shared.messageSendingFailed=消息發送失敗。錯誤:{0} shared.unlock=解鎖 shared.toReceive=接收 shared.toSpend=花費 -shared.btcAmount=BTC 總額 +shared.xmrAmount=XMR 總額 shared.yourLanguage=你的語言 shared.addLanguage=添加語言 shared.total=合計 shared.totalsNeeded=需要資金 shared.tradeWalletAddress=交易錢包地址 shared.tradeWalletBalance=交易錢包餘額 +shared.reserveExactAmount=僅保留必要的資金。需支付礦工費,約 20 分鐘後您的報價才會上線。 shared.makerTxFee=賣家:{0} shared.takerTxFee=買家:{0} shared.iConfirm=我確認 shared.openURL=打開 {0} shared.fiat=法定貨幣 shared.crypto=加密 +shared.preciousMetals=貴金屬 shared.all=全部 shared.edit=編輯 shared.advancedOptions=高級選項 @@ -226,8 +230,8 @@ shared.enabled=啟用 #################################################################### mainView.menu.market=交易項目 -mainView.menu.buyBtc=買入 BTC -mainView.menu.sellBtc=賣出 BTC +mainView.menu.buyXmr=買入 XMR +mainView.menu.sellXmr=賣出 XMR mainView.menu.portfolio=業務 mainView.menu.funds=資金 mainView.menu.support=幫助 @@ -245,12 +249,15 @@ mainView.balance.reserved.short=保證 mainView.balance.pending.short=凍結 mainView.footer.usingTor=(via Tor) -mainView.footer.localhostBitcoinNode=(本地主機) +mainView.footer.localhostMoneroNode=(本地主機) +mainView.footer.clearnet=(via clearnet) mainView.footer.xmrInfo={0} {1} -mainView.footer.btcFeeRate=/ Fee rate: {0} sat/vB -mainView.footer.xmrInfo.initializing=連接至比特幣網絡 -mainView.footer.xmrInfo.synchronizingWith=Synchronizing with {0} at block: {1} / {2} -mainView.footer.xmrInfo.synchronizedWith=Synced with {0} at block {1} +mainView.footer.xmrFeeRate=/ Fee rate: {0} sat/vB +mainView.footer.xmrInfo.initializing=連接到 Haveno 網路 +mainView.footer.xmrInfo.synchronizingWith=同步中,區塊:{1} / {2},與 {0} 同步中 +mainView.footer.xmrInfo.connectedTo=已连接至 {0},在区块 {1} 处 +mainView.footer.xmrInfo.synchronizingWalletWith=同步中,區塊:{1} / {2},與 {0} 的錢包同步中 +mainView.footer.xmrInfo.syncedWith=已同步至 {0} 在區塊 {1} mainView.footer.xmrInfo.connectingTo=連接至 mainView.footer.xmrInfo.connectionFailed=連接失敗: mainView.footer.xmrPeers=Monero網絡節點:{0} @@ -274,7 +281,7 @@ mainView.walletServiceErrorMsg.connectionError=錯誤:{0} 比特幣網絡連 mainView.walletServiceErrorMsg.rejectedTxException=交易被網絡拒絕。\n\n{0} mainView.networkWarning.allConnectionsLost=您失去了所有與 {0} 網絡節點的連接。\n您失去了互聯網連接或您的計算機處於待機狀態。 -mainView.networkWarning.localhostBitcoinLost=您丟失了與本地主機比特幣節點的連接。\n請重啟 Haveno 應用程序連接到其他比特幣節點或重新啟動主機比特幣節點。 +mainView.networkWarning.localhostMoneroLost=您丟失了與本地主機比特幣節點的連接。\n請重啟 Haveno 應用程序連接到其他比特幣節點或重新啟動主機比特幣節點。 mainView.version.update=(有更新可用) @@ -299,9 +306,9 @@ market.offerBook.sell=我想要賣出比特幣 # SpreadView market.spread.numberOfOffersColumn=所有報價({0}) -market.spread.numberOfBuyOffersColumn=買入 BTC({0}) -market.spread.numberOfSellOffersColumn=賣出 BTC({0}) -market.spread.totalAmountColumn=總共 BTC({0}) +market.spread.numberOfBuyOffersColumn=買入 XMR({0}) +market.spread.numberOfSellOffersColumn=賣出 XMR({0}) +market.spread.totalAmountColumn=總共 XMR({0}) market.spread.spreadColumn=差價 market.spread.expanded=Expanded view @@ -325,6 +332,7 @@ offerbook.createOffer=創建報價 offerbook.takeOffer=接受報價 offerbook.takeOfferToBuy=接受報價來收購 {0} offerbook.takeOfferToSell=接受報價來出售 {0} +offerbook.takeOffer.enterChallenge=輸入報價密碼 offerbook.trader=商人 offerbook.offerersBankId=賣家的銀行 ID(BIC/SWIFT):{0} offerbook.offerersBankName=賣家的銀行名稱:{0} @@ -334,7 +342,9 @@ offerbook.offerersAcceptedBankSeats=接受的銀行所在國家(買家):\n offerbook.availableOffers=可用報價 offerbook.filterByCurrency=以貨幣篩選 offerbook.filterByPaymentMethod=以支付方式篩選 -offerbook.matchingOffers=Offers matching my accounts +offerbook.matchingOffers=符合我的帳戶的報價 +offerbook.filterNoDeposit=無押金 +offerbook.noDepositOffers=無押金的報價(需要密碼短語) offerbook.timeSinceSigning=賬户信息 offerbook.timeSinceSigning.info=此賬户已驗證,{0} offerbook.timeSinceSigning.info.arbitrator=由仲裁員驗證,並可以驗證夥伴賬户 @@ -345,6 +355,8 @@ offerbook.timeSinceSigning.info.banned=賬户已被封禁 offerbook.timeSinceSigning.daysSinceSigning={0} 天 offerbook.timeSinceSigning.daysSinceSigning.long=自驗證{0} offerbook.xmrAutoConf=是否開啟自動確認 +offerbook.buyXmrWith=購買 XMR 使用: +offerbook.sellXmrFor=出售 XMR 以換取: offerbook.timeSinceSigning.help=當您成功地完成與擁有已驗證付款帳户的夥伴交易時,您的付款帳户已驗證。\n{0} 天后,最初的 {1} 的限制解除以及你的賬户可以驗證其他人的付款賬户。 offerbook.timeSinceSigning.notSigned=尚未驗證 @@ -357,8 +369,9 @@ shared.notSigned.noNeedAlts=數字貨幣不適用賬齡與簽名 offerbook.nrOffers=報價數量:{0} offerbook.volume={0}(最小 - 最大) -offerbook.deposit=BTC 保證金(%) +offerbook.deposit=XMR 保證金(%) offerbook.deposit.help=交易雙方均已支付保證金確保這個交易正常進行。這會在交易完成時退還。 +offerbook.createNewOffer=創建報價給 {0} {1} offerbook.createOfferToBuy=創建新的報價來買入 {0} offerbook.createOfferToSell=創建新的報價來賣出 {0} @@ -387,6 +400,8 @@ offerbook.warning.newVersionAnnouncement=使用這個版本的軟件,交易夥 popup.warning.tradeLimitDueAccountAgeRestriction.seller=基於以下標準的安全限制,允許的交易金額限制為 {0}:\n- 買方的帳目沒有由仲裁員或夥伴驗證\n- 買方帳户自驗證之日起不足30天\n- 本報價的付款方式被認為存在銀行退款的風險\n\n{1} popup.warning.tradeLimitDueAccountAgeRestriction.buyer=基於以下標準的安全限制,允許的交易金額限制為{0}:\n- 你的買家帳户沒有由仲裁員或夥伴驗證\n- 自驗證你的帳户以來的時間少於30天\n- 本報價的付款方式被認為存在銀行退款的風險\n\n{1} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit=這個付款方式暫時只限於 {0} 到 {1},因為所有買家都是新帳戶。\n\n{2} +popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit=您的報價將僅限於已簽署且歷史悠久的帳戶購買,因為它超過了{0}。\n\n{1} offerbook.warning.wrongTradeProtocol=該報價要求的軟件版本與您現在運行的版本不一致。\n\n請檢查您是否運行最新版本,或者是該報價用户在使用一箇舊的版本。\n用户不能與不兼容的交易協議版本進行交易。 offerbook.warning.userIgnored=您已添加該用户的匿名地址在您的忽略列表裏。 @@ -412,13 +427,13 @@ offerbook.info.roundedFiatVolume=金額四捨五入是為了增加您的交易 # Offerbook / Create offer #################################################################### -createOffer.amount.prompt=輸入 BTC 數量 +createOffer.amount.prompt=輸入 XMR 數量 createOffer.price.prompt=輸入價格 createOffer.volume.prompt=輸入 {0} 金額 createOffer.amountPriceBox.amountDescription=比特幣數量 {0} createOffer.amountPriceBox.buy.volumeDescription=花費 {0} 數量 createOffer.amountPriceBox.sell.volumeDescription=接收 {0} 數量 -createOffer.amountPriceBox.minAmountDescription=最小 BTC 數量 +createOffer.amountPriceBox.minAmountDescription=最小 XMR 數量 createOffer.securityDeposit.prompt=保證金 createOffer.fundsBox.title=為您的報價充值 createOffer.fundsBox.offerFee=掛單費 @@ -434,7 +449,7 @@ createOffer.info.sellAboveMarketPrice=由於您的價格是持續更新的,因 createOffer.info.buyBelowMarketPrice=由於您的價格是持續更新的,因此您將始終支付低於市場價 {0}% 的價格。 createOffer.warning.sellBelowMarketPrice=由於您的價格是持續更新的,因此您將始終按照低於市場價 {0}% 的價格出售。 createOffer.warning.buyAboveMarketPrice=由於您的價格是持續更新的,因此您將始終支付高於市場價 {0}% 的價格。 -createOffer.tradeFee.descriptionBTCOnly=掛單費 +createOffer.tradeFee.descriptionXMROnly=掛單費 createOffer.tradeFee.descriptionBSQEnabled=選擇手續費幣種 createOffer.triggerPrice.prompt=Set optional trigger price @@ -448,7 +463,12 @@ createOffer.placeOfferButton=複審:報價掛單 {0} 比特幣 createOffer.createOfferFundWalletInfo.headline=為您的報價充值 # suppress inspection "TrailingSpacesInProperty" createOffer.createOfferFundWalletInfo.tradeAmount=- 交易數量:{0}\n -createOffer.createOfferFundWalletInfo.msg=這個報價您需要 {0} 作為保證金。\n\n這些資金保留在您的本地錢包並會被凍結到多重驗證保證金地址直到報價交易成功。\n\n總數量:{1}\n- 保證金:{2}\n- 掛單費:{3}\n- 礦工手續費:{4}\n\n您有兩種選項可以充值您的交易:\n- 使用您的 Haveno 錢包(方便,但交易可能會被鏈接到)或者\n- 從外部錢包轉入(或許這樣更隱祕一些)\n\n關閉此彈出窗口後,您將看到所有資金選項和詳細信息。 +createOffer.createOfferFundWalletInfo.msg=您需要為此報價存入 {0}。\n\n\ + 這些資金會保留在您的本地錢包中,並在有人接受您的報價後鎖定到多重簽名錢包中。\n\n\ + 金額總和為:\n\ + {1}\ + - 您的保證金:{2}\n\ + - 交易費:{3} # only first part "An error occurred when placing the offer:" has been used before. We added now the rest (need update in existing translations!) createOffer.amountPriceBox.error.message=提交報價發生錯誤:\n\n{0}\n\n沒有資金從您錢包中扣除。\n請檢查您的互聯網連接或嘗試重啟應用程序。 @@ -470,19 +490,22 @@ createOffer.setDepositAsBuyer=設置自己作為買家的保證金(%) createOffer.setDepositForBothTraders=設置雙方的保證金比例(%) createOffer.securityDepositInfo=您的買家的保證金將會是 {0} createOffer.securityDepositInfoAsBuyer=您作為買家的保證金將會是 {0} -createOffer.minSecurityDepositUsed=已使用最低買家保證金 +createOffer.minSecurityDepositUsed=最低保證金已使用 +createOffer.buyerAsTakerWithoutDeposit=買家無需支付保證金(通行密碼保護) +createOffer.myDeposit=我的保證金(%) +createOffer.myDepositInfo=您的保證金將為 {0} #################################################################### # Offerbook / Take offer #################################################################### -takeOffer.amount.prompt=輸入 BTC 數量 +takeOffer.amount.prompt=輸入 XMR 數量 takeOffer.amountPriceBox.buy.amountDescription=賣出比特幣數量 takeOffer.amountPriceBox.sell.amountDescription=買入比特幣數量 takeOffer.amountPriceBox.priceDescription=每個比特幣的 {0} 價格 takeOffer.amountPriceBox.amountRangeDescription=可用數量範圍 -takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces=你輸入的數量超過允許的小數位數。\n數量已被調整為4位小數。 +takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces=你輸入的數量超過允許的小數位數。\n數量已被調整為4位小數。 takeOffer.validation.amountSmallerThanMinAmount=數量不能比報價內設置的最小數量小。 takeOffer.validation.amountLargerThanOfferAmount=數量不能比報價提供的總量大。 takeOffer.validation.amountLargerThanOfferAmountMinusFee=該輸入數量可能會給賣家造成比特幣碎片。 @@ -491,9 +514,11 @@ takeOffer.fundsBox.isOfferAvailable=檢查報價是否有效... takeOffer.fundsBox.tradeAmount=賣出數量 takeOffer.fundsBox.offerFee=掛單費 takeOffer.fundsBox.networkFee=總共挖礦手續費 -takeOffer.fundsBox.takeOfferSpinnerInfo=正在下單... +takeOffer.fundsBox.takeOfferSpinnerInfo=接受報價:{0} takeOffer.fundsBox.paymentLabel=Haveno 交易 ID {0} takeOffer.fundsBox.fundsStructure=({0} 保證金,{1} 交易費,{2} 採礦費) +takeOffer.fundsBox.noFundingRequiredTitle=無需資金 +takeOffer.fundsBox.noFundingRequiredDescription=從賣家那裡在 Haveno 之外獲取優惠密碼以接受此優惠。 takeOffer.success.headline=你已成功下單一個報價。 takeOffer.success.info=你可以在“業務/未完成交易”頁面內查看您的未完成交易。 takeOffer.error.message=下單時發生了一個錯誤。\n\n{0} @@ -504,7 +529,7 @@ takeOffer.noPriceFeedAvailable=您不能對這筆報價下單,因為它使用 takeOffer.takeOfferFundWalletInfo.headline=為交易充值 # suppress inspection "TrailingSpacesInProperty" takeOffer.takeOfferFundWalletInfo.tradeAmount=- 交易數量:{0}\n -takeOffer.takeOfferFundWalletInfo.msg=這個報價您需要付出 {0} 保證金。\n\n這些資金保留在您的本地錢包並會被凍結到多重驗證保證金地址直到報價交易成功。\n\n總數量:{1}\n- 保證金:{2}\n- 掛單費:{3}\n- 礦工手續費:{4}\n\n您有兩種選項可以充值您的交易:\n- 使用您的 Haveno 錢包(方便,但交易可能會被鏈接到)或者\n- 從外部錢包轉入(或許這樣更隱祕一些)\n\n關閉此彈出窗口後,您將看到所有資金選項和詳細信息。 +takeOffer.takeOfferFundWalletInfo.msg=您需要存入 {0} 才能接受此報價。\n\n該金額是以下總和:\n{1}- 您的保證金:{2}\n- 交易費用:{3} takeOffer.alreadyPaidInFunds=如果你已經支付,你可以在“資金/提現”提現它。 takeOffer.paymentInfo=付款信息 takeOffer.setAmountPrice=設置數量 @@ -597,29 +622,29 @@ portfolio.pending.step1.openForDispute=保證金交易仍未得到確認。請 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2.confReached=Your trade has reached at least one blockchain confirmation.\n\n -portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'bitcoin', 'BTC', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. +portfolio.pending.step2_buyer.refTextWarn=Important: when making the payment, leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'. You are free to discuss via trader chat if an alternate \"reason for payment\" would be suitable to you both. # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step2_buyer.fees=If your bank charges you any fees to make the transfer, you are responsible for paying those fees. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.crypto=請從您的外部 {0} 錢包劃轉\n{1} 到 BTC 賣家。\n\n +portfolio.pending.step2_buyer.crypto=請從您的外部 {0} 錢包劃轉\n{1} 到 XMR 賣家。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.cash=請到銀行並支付 {0} 給 BTC 賣家。\n\n -portfolio.pending.step2_buyer.cash.extra=重要要求:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併發送給 BTC 賣家的電子郵件地址。 +portfolio.pending.step2_buyer.cash=請到銀行並支付 {0} 給 XMR 賣家。\n\n +portfolio.pending.step2_buyer.cash.extra=重要要求:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併發送給 XMR 賣家的電子郵件地址。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.moneyGram=請使用 MoneyGram 向 BTC 賣家支付 {0}。\n\n -portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付後,請通過電郵發送授權編號和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 +portfolio.pending.step2_buyer.moneyGram=請使用 MoneyGram 向 XMR 賣家支付 {0}。\n\n +portfolio.pending.step2_buyer.moneyGram.extra=重要要求:\n完成支付後,請通過電郵發送授權編號和照片給 XMR 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.westernUnion=請使用 Western Union 向 BTC 賣家支付 {0}。\n\n -portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付後,請通過電郵發送 MTCN(追蹤號碼)和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 +portfolio.pending.step2_buyer.westernUnion=請使用 Western Union 向 XMR 賣家支付 {0}。\n\n +portfolio.pending.step2_buyer.westernUnion.extra=重要要求:\n完成支付後,請通過電郵發送 MTCN(追蹤號碼)和照片給 XMR 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。 # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.postal=請用“美國郵政匯票”發送 {0} 給 BTC 賣家。\n\n +portfolio.pending.step2_buyer.postal=請用“美國郵政匯票”發送 {0} 給 XMR 賣家。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the BTC seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://bisq.wiki/Cash_by_Mail].\n\n +portfolio.pending.step2_buyer.payByMail=Please send {0} using \"Pay by Mail\" to the XMR seller. Specific instructions are in the trade contract, or if unclear you may ask questions via trader chat. See more details about Pay by Mail on the Haveno wiki [HYPERLINK:https://haveno.exchange/wiki/Cash_by_Mail].\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the BTC seller. You''ll find the seller's account details on the next screen.\n\n +portfolio.pending.step2_buyer.pay=Please pay {0} via the specified payment method to the XMR seller. You''ll find the seller's account details on the next screen.\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step2_buyer.f2f=請通過提供的聯繫人與 BTC 賣家聯繫,並安排會議支付 {0}。\n\n +portfolio.pending.step2_buyer.f2f=請通過提供的聯繫人與 XMR 賣家聯繫,並安排會議支付 {0}。\n\n portfolio.pending.step2_buyer.startPaymentUsing=使用 {0} 開始付款 portfolio.pending.step2_buyer.recipientsAccountData=接受 {0} portfolio.pending.step2_buyer.amountToTransfer=劃轉數量 @@ -628,27 +653,27 @@ portfolio.pending.step2_buyer.buyerAccount=您的付款帳户將被使用 portfolio.pending.step2_buyer.paymentSent=付款開始 portfolio.pending.step2_buyer.warn=你還沒有完成你的 {0} 付款!\n請注意,交易必須在 {1} 之前完成。 portfolio.pending.step2_buyer.openForDispute=您還沒有完成您的付款!\n最大交易期限已過。請聯繫調解員尋求幫助。 -portfolio.pending.step2_buyer.paperReceipt.headline=您是否將紙質收據發送給 BTC 賣家? -portfolio.pending.step2_buyer.paperReceipt.msg=請牢記:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併發送給 BTC 賣家的電子郵件地址。 +portfolio.pending.step2_buyer.paperReceipt.headline=您是否將紙質收據發送給 XMR 賣家? +portfolio.pending.step2_buyer.paperReceipt.msg=請牢記:\n完成付款後在紙質收據上寫下:不退款。\n然後將其撕成2份,拍照片併發送給 XMR 賣家的電子郵件地址。 portfolio.pending.step2_buyer.moneyGramMTCNInfo.headline=發送授權編號和收據 -portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=請通過電郵發送授權編號和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把授權編號和合同發給賣方了嗎? +portfolio.pending.step2_buyer.moneyGramMTCNInfo.msg=請通過電郵發送授權編號和照片給 XMR 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把授權編號和合同發給賣方了嗎? portfolio.pending.step2_buyer.westernUnionMTCNInfo.headline=發送 MTCN 和收據 -portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=請通過電郵發送 MTCN(追蹤號碼)和照片給 BTC 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把 MTCN 和合同發給賣方了嗎? +portfolio.pending.step2_buyer.westernUnionMTCNInfo.msg=請通過電郵發送 MTCN(追蹤號碼)和照片給 XMR 賣家。\n收據必須清楚地向賣家寫明您的全名、城市、國家或地區、數量。賣方的電子郵件是:{0}。\n\n您把 MTCN 和合同發給賣方了嗎? portfolio.pending.step2_buyer.halCashInfo.headline=請發送 HalCash 代碼 -portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 BTC 賣家發送帶有 HalCash 代碼和交易 ID({0})的文本消息。\n\n賣方的手機號碼是 {1} 。\n\n您是否已經將代碼發送至賣家? +portfolio.pending.step2_buyer.halCashInfo.msg=您需要向 XMR 賣家發送帶有 HalCash 代碼和交易 ID({0})的文本消息。\n\n賣方的手機號碼是 {1} 。\n\n您是否已經將代碼發送至賣家? portfolio.pending.step2_buyer.fasterPaymentsHolderNameInfo=有些銀行可能會要求接收方的姓名。在較舊的 Haveno 客户端創建的快速支付帳户沒有提供收款人的姓名,所以請使用交易聊天來獲得收款人姓名(如果需要)。 portfolio.pending.step2_buyer.confirmStart.headline=確定您已經付款 portfolio.pending.step2_buyer.confirmStart.msg=您是否向您的交易夥伴發起 {0} 付款? portfolio.pending.step2_buyer.confirmStart.yes=是的,我已經開始付款 portfolio.pending.step2_buyer.confirmStart.proof.warningTitle=你沒有提供任何付款證明 -portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=您還沒有輸入交易 ID 以及交易密鑰\n\n如果不提供此數據您的交易夥伴無法在收到 XMR 後使用自動確認功能以快速釋放 BTC。\n另外,Haveno 要求 XMR 發送者在發生糾紛的時候能夠向調解員和仲裁員提供這些信息。\n更多細節在 Haveno Wiki:https://bisq.wiki/Trading_Monero#Auto-confirming_trades +portfolio.pending.step2_buyer.confirmStart.proof.noneProvided=您還沒有輸入交易 ID 以及交易密鑰\n\n如果不提供此數據您的交易夥伴無法在收到 XMR 後使用自動確認功能以快速釋放 XMR。\n另外,Haveno 要求 XMR 發送者在發生糾紛的時候能夠向調解員和仲裁員提供這些信息。\n更多細節在 Haveno Wiki:https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades portfolio.pending.step2_buyer.confirmStart.proof.invalidInput=輸入並不是一個 32 字節的哈希值 portfolio.pending.step2_buyer.confirmStart.warningButton=忽略並繼續 portfolio.pending.step2_seller.waitPayment.headline=等待付款 portfolio.pending.step2_seller.f2fInfo.headline=買家的合同信息 -portfolio.pending.step2_seller.waitPayment.msg=存款交易至少有一個區塊鏈確認。\n您需要等到 BTC 買家開始 {0} 付款。 -portfolio.pending.step2_seller.warn=BTC 買家仍然沒有完成 {0} 付款。\n你需要等到他開始付款。\n如果 {1} 交易尚未完成,仲裁員將進行調查。 -portfolio.pending.step2_seller.openForDispute=BTC 買家尚未開始付款!\n允許的最長交易期限已經過去了。你可以繼續等待給予交易雙方更多時間,或聯繫仲裁員以爭取解決糾紛。 +portfolio.pending.step2_seller.waitPayment.msg=存款交易至少有一個區塊鏈確認。\n您需要等到 XMR 買家開始 {0} 付款。 +portfolio.pending.step2_seller.warn=XMR 買家仍然沒有完成 {0} 付款。\n你需要等到他開始付款。\n如果 {1} 交易尚未完成,仲裁員將進行調查。 +portfolio.pending.step2_seller.openForDispute=XMR 買家尚未開始付款!\n允許的最長交易期限已經過去了。你可以繼續等待給予交易雙方更多時間,或聯繫仲裁員以爭取解決糾紛。 tradeChat.chatWindowTitle=使用 ID “{0}” 進行交易的聊天窗口 tradeChat.openChat=打開聊天窗口 tradeChat.rules=您可以與您的夥伴溝通,以解決該交易的潛在問題。\n在聊天中不強制回覆。\n如果交易員違反了下面的任何規則,打開糾紛並向調解員或仲裁員報吿。\n聊天規則:\n\n\t●不要發送任何鏈接(有惡意軟件的風險)。您可以發送交易 ID 和區塊資源管理器的名稱。\n\t●不要發送還原密鑰、私鑰、密碼或其他敏感信息!\n\t●不鼓勵 Haveno 以外的交易(無安全保障)。\n\t●不要參與任何形式的危害社會安全的計劃。\n\t●如果對方沒有迴應,也不願意通過聊天進行溝通,那就尊重對方的決定。\n\t●將談話範圍限制在行業內。這個聊天不是一個社交軟件替代品或troll-box。\n\t●保持友好和尊重的交談。 @@ -666,28 +691,28 @@ message.state.ACKNOWLEDGED=對方確認消息回執 # suppress inspection "UnusedProperty" message.state.FAILED=發送消息失敗 -portfolio.pending.step3_buyer.wait.headline=等待 BTC 賣家付款確定 -portfolio.pending.step3_buyer.wait.info=等待 BTC 賣家確認收到 {0} 付款。 +portfolio.pending.step3_buyer.wait.headline=等待 XMR 賣家付款確定 +portfolio.pending.step3_buyer.wait.info=等待 XMR 賣家確認收到 {0} 付款。 portfolio.pending.step3_buyer.wait.msgStateInfo.label=支付開始消息狀態 portfolio.pending.step3_buyer.warn.part1a=在 {0} 區塊鏈 portfolio.pending.step3_buyer.warn.part1b=在您的支付供應商(例如:銀行) -portfolio.pending.step3_buyer.warn.part2=BTC 賣家仍然沒有確認您的付款。如果付款發送成功,請檢查 {0}。 -portfolio.pending.step3_buyer.openForDispute=BTC 賣家還沒有確認你的付款!最大交易期限已過。您可以等待更長時間,並給交易夥伴更多時間或請求調解員的幫助。 +portfolio.pending.step3_buyer.warn.part2=XMR 賣家仍然沒有確認您的付款。如果付款發送成功,請檢查 {0}。 +portfolio.pending.step3_buyer.openForDispute=XMR 賣家還沒有確認你的付款!最大交易期限已過。您可以等待更長時間,並給交易夥伴更多時間或請求調解員的幫助。 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.part=您的交易夥伴已經確認他們已經發起了 {0} 付款。\n\n portfolio.pending.step3_seller.crypto.explorer=在您最喜歡的 {0} 區塊鏈瀏覽器 portfolio.pending.step3_seller.crypto.wallet=在您的 {0} 錢包 portfolio.pending.step3_seller.crypto={0} 請檢查 {1} 是否交易已經到您的接收地址\n{2}\n已經有足夠的區塊鏈確認了\n支付金額必須為 {3}\n\n關閉該彈出窗口後,您可以從主界面複製並粘貼 {4} 地址。 -portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the BTC buyer. +portfolio.pending.step3_seller.postal={0}Please check if you have received {1} with \"US Postal Money Order\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the BTC buyer. +portfolio.pending.step3_seller.payByMail={0}Please check if you have received {1} with \"Pay by Mail\" from the XMR buyer. # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the BTC buyer. -portfolio.pending.step3_seller.cash=因為付款是通過現金存款完成的,BTC 買家必須在紙質收據上寫“不退款”,將其撕成2份,並通過電子郵件向您發送照片。\n\n為避免退款風險,請僅確認您是否收到電子郵件,如果您確定收據有效。\n如果您不確定,{0} -portfolio.pending.step3_seller.moneyGram=買方必須發送授權編碼和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到授權編碼,請查收郵件。\n\n關閉彈窗後,您將看到 BTC 買家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! -portfolio.pending.step3_seller.westernUnion=買方必須發送 MTCN(跟蹤號碼)和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到 MTCN,請查收郵件。\n\n關閉彈窗後,您將看到 BTC 買家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! +portfolio.pending.step3_seller.bank=Your trading partner has confirmed that they have initiated the {0} payment.\n\nPlease go to your online banking web page and check if you have received {1} from the XMR buyer. +portfolio.pending.step3_seller.cash=因為付款是通過現金存款完成的,XMR 買家必須在紙質收據上寫“不退款”,將其撕成2份,並通過電子郵件向您發送照片。\n\n為避免退款風險,請僅確認您是否收到電子郵件,如果您確定收據有效。\n如果您不確定,{0} +portfolio.pending.step3_seller.moneyGram=買方必須發送授權編碼和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到授權編碼,請查收郵件。\n\n關閉彈窗後,您將看到 XMR 買家的姓名和在 MoneyGram 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! +portfolio.pending.step3_seller.westernUnion=買方必須發送 MTCN(跟蹤號碼)和一張收據的照片。\n收據必須清楚地顯示您的全名、城市、國家或地區、數量。如果您收到 MTCN,請查收郵件。\n\n關閉彈窗後,您將看到 XMR 買家的姓名和在 Western Union 的收款地址。\n\n只有在您成功收到錢之後,再確認收據! portfolio.pending.step3_seller.halCash=買方必須將 HalCash代碼 用短信發送給您。除此之外,您將收到來自 HalCash 的消息,其中包含從支持 HalCash 的 ATM 中提取歐元所需的信息\n從 ATM 取款後,請在此確認付款收據! -portfolio.pending.step3_seller.amazonGiftCard=BTC 買家已經發送了一張亞馬遜電子禮品卡到您的郵箱或手機短信。請現在立即兑換亞馬遜電子禮品卡到您的亞馬遜賬户中以及確認交易信息。 +portfolio.pending.step3_seller.amazonGiftCard=XMR 買家已經發送了一張亞馬遜電子禮品卡到您的郵箱或手機短信。請現在立即兑換亞馬遜電子禮品卡到您的亞馬遜賬户中以及確認交易信息。 portfolio.pending.step3_seller.bankCheck=\n\n還請確認您的銀行對帳單中的發件人姓名與委託合同中的發件人姓名相符:\n發件人姓名:{0}\n\n如果名稱與此處顯示的名稱不同,則 {1} # suppress inspection "TrailingSpacesInProperty" @@ -701,7 +726,7 @@ portfolio.pending.step3_seller.xmrTxHash=交易記錄 ID portfolio.pending.step3_seller.xmrTxKey=交易密鑰 portfolio.pending.step3_seller.buyersAccount=買方賬號數據 portfolio.pending.step3_seller.confirmReceipt=確定付款收據 -portfolio.pending.step3_seller.buyerStartedPayment=BTC 買家已經開始 {0} 的付款。\n{1} +portfolio.pending.step3_seller.buyerStartedPayment=XMR 買家已經開始 {0} 的付款。\n{1} portfolio.pending.step3_seller.buyerStartedPayment.crypto=檢查您的數字貨幣錢包或塊瀏覽器的區塊鏈確認,並確認付款時,您有足夠的塊鏈確認。 portfolio.pending.step3_seller.buyerStartedPayment.traditional=檢查您的交易賬户(例如銀行帳户),並確認您何時收到付款。 portfolio.pending.step3_seller.warn.part1a=在 {0} 區塊鏈 @@ -713,7 +738,7 @@ portfolio.pending.step3_seller.onPaymentReceived.part1=您是否收到了您交 # suppress inspection "TrailingSpacesInProperty" portfolio.pending.step3_seller.onPaymentReceived.name=還請確認您的銀行對帳單中的發件人姓名與委託合同中的發件人姓名相符:\n每個交易合約的發送者姓名:{0}\n\n如果名稱與此處顯示的名稱不一致,請不要通過確認付款,而是通過“alt + o”或“option + o”打開糾紛。\n\n # suppress inspection "TrailingSpacesInProperty" -portfolio.pending.step3_seller.onPaymentReceived.note=請注意,一旦您確認收到,凍結交易金額將被髮放給 BTC 買家,保證金將被退還。 +portfolio.pending.step3_seller.onPaymentReceived.note=請注意,一旦您確認收到,凍結交易金額將被髮放給 XMR 買家,保證金將被退還。 portfolio.pending.step3_seller.onPaymentReceived.confirm.headline=確定您已經收到付款 portfolio.pending.step3_seller.onPaymentReceived.confirm.yes=是的,我已經收到付款。 portfolio.pending.step3_seller.onPaymentReceived.signer=重要提示:通過確認收到付款,你也驗證了對方的賬户,並獲得驗證。因為對方的賬户還沒有驗證,所以你應該儘可能的延遲付款的確認,以減少退款的風險。 @@ -723,7 +748,7 @@ portfolio.pending.step5_buyer.tradeFee=掛單費 portfolio.pending.step5_buyer.makersMiningFee=礦工手續費 portfolio.pending.step5_buyer.takersMiningFee=總共挖礦手續費 portfolio.pending.step5_buyer.refunded=退還保證金 -portfolio.pending.step5_buyer.withdrawBTC=提現您的比特幣 +portfolio.pending.step5_buyer.withdrawXMR=提現您的比特幣 portfolio.pending.step5_buyer.amount=提現數量 portfolio.pending.step5_buyer.withdrawToAddress=提現地址 portfolio.pending.step5_buyer.moveToHavenoWallet=在 Haveno 錢包中保留資金 @@ -833,7 +858,7 @@ funds.deposit.fundHavenoWallet=充值 Haveno 錢包 funds.deposit.noAddresses=尚未生成存款地址 funds.deposit.fundWallet=充值您的錢包 funds.deposit.withdrawFromWallet=從錢包轉出資金 -funds.deposit.amount=BTC 數量(可選) +funds.deposit.amount=XMR 數量(可選) funds.deposit.generateAddress=生成新的地址 funds.deposit.generateAddressSegwit=原生 segwit 格式(Bech32) funds.deposit.selectUnused=請從上表中選擇一個未使用的地址,而不是生成一個新地址。 @@ -904,7 +929,7 @@ support.filter=查找糾紛 support.filter.prompt=輸入 交易 ID、日期、洋葱地址或賬户信息 support.sigCheck.button=Check signature -support.sigCheck.popup.info=如果向在 DAO 發送賠償請求,您需要在 Github 上粘貼您的賠償請求中的調解和仲裁過程的摘要消息。要使此聲明可驗證,任何用户都可以使用此工具檢查調解或仲裁人員的簽名是否與摘要消息匹配。 +support.sigCheck.popup.info=請貼上仲裁程序的摘要訊息。利用這個工具,任何使用者都可以檢查仲裁者的簽名是否與摘要訊息相符。 support.sigCheck.popup.header=確認糾紛結果簽名 support.sigCheck.popup.msg.label=總結消息 support.sigCheck.popup.msg.prompt=複製粘貼糾紛總結消息 @@ -940,8 +965,8 @@ support.savedInMailbox=消息保存在收件人的信箱中 support.arrived=消息抵達收件人 support.acknowledged=收件人已確認接收消息 support.error=收件人無法處理消息。錯誤:{0} -support.buyerAddress=BTC 買家地址 -support.sellerAddress=BTC 賣家地址 +support.buyerAddress=XMR 買家地址 +support.sellerAddress=XMR 賣家地址 support.role=角色 support.agent=Support agent support.state=狀態 @@ -949,13 +974,13 @@ support.chat=Chat support.closed=關閉 support.open=打開 support.process=Process -support.buyerMaker=BTC 買家/掛單者 -support.sellerMaker=BTC 賣家/掛單者 -support.buyerTaker=BTC 買家/買單者 -support.sellerTaker=BTC 賣家/買單者 +support.buyerMaker=XMR 買家/掛單者 +support.sellerMaker=XMR 賣家/掛單者 +support.buyerTaker=XMR 買家/買單者 +support.sellerTaker=XMR 賣家/買單者 -support.backgroundInfo=Haveno 不是一家公司,所以它處理糾紛的方式不同。\n\n交易雙方可以在應用程序中通過未完成交易頁面上的安全聊天進行通信,以嘗試自行解決爭端。如果這還不夠,調解員可以介入幫助。調解員將對情況進行評估,並對交易資金的支出提出建議。如果兩個交易者都接受這個建議,那麼支付交易就完成了,交易也結束了。如果一方或雙方不同意調解員的建議,他們可以要求仲裁。仲裁員將重新評估情況,如果有必要,將親自向交易員付款,並要求 Haveno DAO 對這筆付款進行補償。 -support.initialInfo=請在下面的文本框中輸入您的問題描述。添加儘可能多的信息,以加快解決糾紛的時間。\n\n以下是你應提供的資料核對表:\n\t●如果您是 BTC 買家:您是否使用法定貨幣或其他加密貨幣轉賬?如果是,您是否點擊了應用程序中的“支付開始”按鈕?\n\t●如果您是 BTC 賣家:您是否收到法定貨幣或其他加密貨幣的付款了?如果是,你是否點擊了應用程序中的“已收到付款”按鈕?\n\t●您使用的是哪個版本的 Haveno?\n\t●您使用的是哪種操作系統?\n\t●如果遇到操作執行失敗的問題,請考慮切換到新的數據目錄。\n\t有時數據目錄會損壞,並導致奇怪的錯誤。\n詳見:https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n請熟悉糾紛處理的基本規則:\n\t●您需要在2天內答覆 {0} 的請求。\n\t●調解員會在2天之內答覆,仲裁員會在5天之內答覆。\n\t●糾紛的最長期限為14天。\n\t●你需要與仲裁員合作,提供他們為你的案件所要求的信息。\n\t●當您第一次啟動應用程序時,您接受了用户協議中爭議文檔中列出的規則。\n\n您可以通過 {2} 瞭解有關糾紛處理的更多信息 +support.backgroundInfo=Haveno 不是一家公司,因此它以不同的方式處理爭議。\n\n交易者可以在應用程式中透過在打開交易畫面上的安全聊天來嘗試自行解決爭議。\n如果這不夠,一名仲裁者將評估情況並決定交易資金的支付。 +support.initialInfo=請在下面的文本框中輸入您的問題描述。添加儘可能多的信息,以加快解決糾紛的時間。\n\n以下是你應提供的資料核對表:\n\t●如果您是 XMR 買家:您是否使用法定貨幣或其他加密貨幣轉賬?如果是,您是否點擊了應用程序中的“支付開始”按鈕?\n\t●如果您是 XMR 賣家:您是否收到法定貨幣或其他加密貨幣的付款了?如果是,你是否點擊了應用程序中的“已收到付款”按鈕?\n\t●您使用的是哪個版本的 Haveno?\n\t●您使用的是哪種操作系統?\n\t●如果遇到操作執行失敗的問題,請考慮切換到新的數據目錄。\n\t有時數據目錄會損壞,並導致奇怪的錯誤。\n詳見:https://docs.haveno.exchange/backup-recovery.html#switch-to-a-new-data-directory\n\n請熟悉糾紛處理的基本規則:\n\t●您需要在2天內答覆 {0} 的請求。\n\t●調解員會在2天之內答覆,仲裁員會在5天之內答覆。\n\t●糾紛的最長期限為14天。\n\t●你需要與仲裁員合作,提供他們為你的案件所要求的信息。\n\t●當您第一次啟動應用程序時,您接受了用户協議中爭議文檔中列出的規則。\n\n您可以通過 {2} 瞭解有關糾紛處理的更多信息 support.systemMsg=系統消息:{0} support.youOpenedTicket=您創建了幫助請求。\n\n{0}\n\nHaveno 版本:{1} support.youOpenedDispute=您創建了一個糾紛請求。\n\n{0}\n\nHaveno 版本:{1} @@ -982,10 +1007,11 @@ setting.preferences.general=通用偏好 setting.preferences.explorer=比特幣區塊瀏覽器 setting.preferences.deviation=與市場價格最大差價 setting.preferences.avoidStandbyMode=避免待機模式 +setting.preferences.useSoundForNotifications=播放通知音效 setting.preferences.autoConfirmXMR=XMR 自動確認 setting.preferences.autoConfirmEnabled=啟用 setting.preferences.autoConfirmRequiredConfirmations=已要求確認 -setting.preferences.autoConfirmMaxTradeSize=最大交易量(BTC) +setting.preferences.autoConfirmMaxTradeSize=最大交易量(XMR) setting.preferences.autoConfirmServiceAddresses=Monero Explorer 鏈接(使用Tor,但本地主機,LAN IP地址和 *.local 主機名除外) setting.preferences.deviationToLarge=值不允許大於30% setting.preferences.txFee=提現交易手續費(聰/字節) @@ -1022,11 +1048,13 @@ settings.preferences.editCustomExplorer.name=名稱 settings.preferences.editCustomExplorer.txUrl=交易 URL settings.preferences.editCustomExplorer.addressUrl=地址 URL -settings.net.btcHeader=比特幣網絡 +settings.net.xmrHeader=比特幣網絡 settings.net.p2pHeader=Haveno 網絡 settings.net.onionAddressLabel=我的匿名地址 settings.net.xmrNodesLabel=使用自定义Monero节点 settings.net.moneroPeersLabel=已連接節點 +settings.net.connection=連接 +settings.net.connected=連接完成 settings.net.useTorForXmrJLabel=使用 Tor 連接 Monero 網絡 settings.net.moneroNodesLabel=需要連接 Monero settings.net.useProvidedNodesRadio=使用公共比特幣核心節點 @@ -1036,7 +1064,7 @@ settings.net.warn.usePublicNodes=如果您使用公共的Monero节点,您将 settings.net.warn.usePublicNodes.useProvided=不,使用給定的節點 settings.net.warn.usePublicNodes.usePublic=使用公共網絡 settings.net.warn.useCustomNodes.B2XWarning=請確保您的比特幣節點是一個可信的比特幣核心節點!\n\n連接到不遵循比特幣核心共識規則的節點可能會損壞您的錢包,並在交易過程中造成問題。\n\n連接到違反共識規則的節點的用户應對任何由此造成的損害負責。任何由此產生的糾紛都將有利於另一方。對於忽略此警吿和保護機制的用户,不提供任何技術支持! -settings.net.warn.invalidBtcConfig=由於您的配置無效,無法連接至比特幣網絡。\n\n您的配置已經被重置為默認比特幣節點。你需要重啟 Haveno。 +settings.net.warn.invalidXmrConfig=由於您的配置無效,無法連接至比特幣網絡。\n\n您的配置已經被重置為默認比特幣節點。你需要重啟 Haveno。 settings.net.localhostXmrNodeInfo=背景信息:Haveno 在啟動時會在本地查找比特幣節點。如果有,Haveno 將只通過它與比特幣網絡進行通信。 settings.net.p2PPeersLabel=已連接節點 settings.net.onionAddressColumn=匿名地址 @@ -1044,7 +1072,7 @@ settings.net.creationDateColumn=已建立連接 settings.net.connectionTypeColumn=入/出 settings.net.sentDataLabel=統計數據已發送 settings.net.receivedDataLabel=統計數據已接收 -settings.net.chainHeightLabel=最新 BTC 區塊高度 +settings.net.chainHeightLabel=最新 XMR 區塊高度 settings.net.roundTripTimeColumn=延遲 settings.net.sentBytesColumn=發送 settings.net.receivedBytesColumn=接收 @@ -1059,7 +1087,7 @@ settings.net.needRestart=您需要重啟應用程序以同意這次變更。\n settings.net.notKnownYet=至今未知... settings.net.sentData=已發送數據 {0},{1} 條消息,{2} 條消息/秒 settings.net.receivedData=已接收數據 {0},{1} 條消息,{2} 條消息/秒 -settings.net.chainHeight=Bitcoin Peers chain height: {0} +settings.net.chainHeight=Monero Peers chain height: {0} settings.net.ips=添加逗號分隔的 IP 地址及端口,如使用8333端口可不填寫。 settings.net.seedNode=種子節點 settings.net.directPeer=節點(直連) @@ -1105,7 +1133,7 @@ setting.about.shortcuts.openDispute.value=選擇未完成交易並點擊:{0} setting.about.shortcuts.walletDetails=打開錢包詳情窗口 -setting.about.shortcuts.openEmergencyBtcWalletTool=打開應急 BTC 錢包工具 +setting.about.shortcuts.openEmergencyXmrWalletTool=打開應急 XMR 錢包工具 setting.about.shortcuts.showTorLogs=在 DEBUG 與 WARN 之間切換 Tor 日誌等級 @@ -1131,7 +1159,7 @@ setting.about.shortcuts.sendPrivateNotification=發送私人通知到對等點 setting.about.shortcuts.sendPrivateNotification.value=點擊交易夥伴頭像並按下:{0} 以顯示更多信息 setting.info.headline=新 XMR 自動確認功能 -setting.info.msg=當你完成 BTC/XMR 交易時,您可以使用自動確認功能來驗證是否向您的錢包中發送了正確數量的 XMR,以便 Haveno 可以自動將交易標記為完成,從而使每個人都可以更快地進行交易。\n\n自動確認使用 XMR 發送方提供的交易密鑰在至少 2 個 XMR 區塊瀏覽器節點上檢查 XMR 交易。在默認情況下,Haveno 使用由 Haveno 貢獻者運行的區塊瀏覽器節點,但是我們建議運行您自己的 XMR 區塊瀏覽器節點以最大程度地保護隱私和安全。\n\n您還可以在``設置''中將每筆交易的最大 BTC 數量設置為自動確認以及所需確認的數量。\n\n在 Haveno Wiki 上查看更多詳細信息(包括如何設置自己的區塊瀏覽器節點):https://bisq.wiki/Trading_Monero#Auto-confirming_trades +setting.info.msg=當你完成 XMR/XMR 交易時,您可以使用自動確認功能來驗證是否向您的錢包中發送了正確數量的 XMR,以便 Haveno 可以自動將交易標記為完成,從而使每個人都可以更快地進行交易。\n\n自動確認使用 XMR 發送方提供的交易密鑰在至少 2 個 XMR 區塊瀏覽器節點上檢查 XMR 交易。在默認情況下,Haveno 使用由 Haveno 貢獻者運行的區塊瀏覽器節點,但是我們建議運行您自己的 XMR 區塊瀏覽器節點以最大程度地保護隱私和安全。\n\n您還可以在``設置''中將每筆交易的最大 XMR 數量設置為自動確認以及所需確認的數量。\n\n在 Haveno Wiki 上查看更多詳細信息(包括如何設置自己的區塊瀏覽器節點):https://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades #################################################################### # Account #################################################################### @@ -1151,7 +1179,7 @@ account.menu.backup=備份 account.menu.notifications=通知 account.menu.walletInfo.balance.headLine=Wallet balances -account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor BTC, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. +account.menu.walletInfo.balance.info=This shows the internal wallet balance including unconfirmed transactions.\nFor XMR, the internal wallet balance shown below should match the sum of the 'Available' and 'Reserved' balances shown in the top right of this window. account.menu.walletInfo.xpub.headLine=Watch keys (xpub keys) account.menu.walletInfo.walletSelector={0} {1} wallet account.menu.walletInfo.path.headLine=HD keychain paths @@ -1180,7 +1208,7 @@ account.crypto.popup.upx.msg=在 Haveno 上交易 UPX 需要您瞭解並滿足 # suppress inspection "UnusedProperty" account.crypto.popup.arq.msg=在 Haveno 上交易 ARQ 需要您瞭解並滿足以下要求:\n\n要發送 ARQ ,您需要使用官方的 ArQmA GUI 錢包或啟用 store-tx-info 標誌的 ArQmA CLI 錢包(在新版本中是默認的)。請確保您可以訪問Tx密鑰,因為在糾紛狀態時需要。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高級>證明/檢查頁面。\n\n在普通的區塊鏈瀏覽器中,這種交易是不可驗證的。\n\n如有糾紛,你須向調解員或仲裁員提供下列資料:\n\n- Tx私鑰\n- 交易哈希\n- 接收者的公開地址\n\n如未能提供上述資料,或使用不兼容的錢包,將會導致糾紛敗訴。如果發生糾紛,ARQ 發送方負責向調解員或仲裁員提供 ARQ 轉賬的驗證。\n\n不需要交易 ID,只需要普通的公共地址。\n\n如果您對該流程不確定,請訪問 ArQmA Discord 頻道(https://discord.gg/s9BQpJT)或 ArQmA 論壇(https://labs.arqma.com)瞭解更多信息。 # suppress inspection "UnusedProperty" -account.crypto.popup.xmr.msg=在 Haveno 上交易 XMR 需要你理解並滿足以下要求。\n\n如果您出售 XMR,當您在糾紛中您必須要提供下列信息給調解員或仲裁員:\n- 交易密鑰(Tx 公鑰,Tx密鑰,Tx私鑰)\n- 交易 ID(Tx ID 或 Tx 哈希)\n- 交易目標地址(接收者地址)\n\n在 wiki 中查看更多關於 Monero 錢包的信息:\nhttps://bisq.wiki/Trading_Monero#Proving_payments\n\n如未能提供要求的交易數據將在糾紛中直接判負\n\n還要注意,Haveno 現在提供了自動確認 XMR 交易的功能,以使交易更快,但是您需要在設置中啟用它。\n\n有關自動確認功能的更多信息,請參見 Wiki:\nhttps://bisq.wiki/Trading_Monero#Auto-confirming_trades +account.crypto.popup.xmr.msg=在 Haveno 上交易 XMR 需要你理解並滿足以下要求。\n\n如果您出售 XMR,當您在糾紛中您必須要提供下列信息給調解員或仲裁員:\n- 交易密鑰(Tx 公鑰,Tx密鑰,Tx私鑰)\n- 交易 ID(Tx ID 或 Tx 哈希)\n- 交易目標地址(接收者地址)\n\n在 wiki 中查看更多關於 Monero 錢包的信息:\nhttps://haveno.exchange/wiki/Trading_Monero#Proving_payments\n\n如未能提供要求的交易數據將在糾紛中直接判負\n\n還要注意,Haveno 現在提供了自動確認 XMR 交易的功能,以使交易更快,但是您需要在設置中啟用它。\n\n有關自動確認功能的更多信息,請參見 Wiki:\nhttps://haveno.exchange/wiki/Trading_Monero#Auto-confirming_trades # suppress inspection "UnusedProperty" account.crypto.popup.msr.msg=區塊鏈瀏覽器在 Haveno 上交易 XMR 需要您瞭解並滿足以下要求:\n\n發送MSR時,您需要使用官方的 Masari GUI 錢包、啟用store-tx-info標記的Masari CLI錢包(默認啟用)或Masari 網頁錢包(https://wallet.getmasari.org)。請確保您可以訪問的 tx 密鑰,因為如果發生糾紛這是需要的。\nmonero-wallet-cli(使用get_Tx_key命令)\nmonero-wallet-gui:在高級>證明/檢查頁面。\n\nMasari 網頁錢包(前往 帳户->交易歷史和查看您發送的交易細節)\n\n驗證可以在錢包中完成。\nmonero-wallet-cli:使用命令(check_tx_key)。\nmonero-wallet-gui:在高級>證明/檢查頁面\n驗證可以在區塊瀏覽器中完成\n打開區塊瀏覽器(https://explorer.getmasari.org),使用搜索欄查找您的事務哈希。\n一旦找到交易,滾動到底部的“證明發送”區域,並填寫所需的詳細信息。\n如有糾紛,你須向調解員或仲裁員提供下列資料:\n- Tx私鑰\n- 交易哈希\n- 接收者的公開地址\n\n不需要交易 ID,只需要正常的公共地址。\n如未能提供上述資料,或使用不兼容的錢包,將會導致糾紛敗訴。如果發生糾紛,XMR 發送方負責向調解員或仲裁員提供 XMR 轉賬的驗證。\n\n如果您對該流程不確定,請訪問官方的 Masari Discord(https://discord.gg/sMCwMqs)上尋求幫助。 # suppress inspection "UnusedProperty" @@ -1208,7 +1236,7 @@ account.crypto.popup.pars.msg=在 Haveno 上交易 ParsiCoin 需要您瞭解並 account.crypto.popup.blk-burnt.msg=要交易燒燬的貨幣,你需要知道以下幾點:\n\n燒燬的貨幣是不能花的。要在 Haveno 上交易它們,輸出腳本需要採用以下形式:OP_RETURN OP_PUSHDATA,後跟相關的數據字節,這些字節經過十六進制編碼後構成地址。例如,地址為666f6f(在UTF-8中的"foo")的燒燬的貨幣將有以下腳本:\n\nOP_RETURN OP_PUSHDATA 666f6f\n\n要創建燒燬的貨幣,您可以使用“燒燬”RPC命令,它在一些錢包可用。\n\n對於可能的情況,可以查看 https://ibo.laboratorium.ee\n\n因為燒燬的貨幣是不能用的,所以不能重新出售。“出售”燒燬的貨幣意味着焚燒初始的貨幣(與目的地地址相關聯的數據)。\n\n如果發生爭議,BLK 賣方需要提供交易哈希。 # suppress inspection "UnusedProperty" -account.crypto.popup.liquidbitcoin.msg=在 Haveno 上交易 L-BTC 你必須理解下述條款:\n\n當你在 Haveno 上接受 L-BTC 交易時,你不能使用手機 Blockstream Green Wallet 或者是一個託管/交易錢包。你必須只接收 L-BTC 到 Liquid Elements Core 錢包,或另一個 L-BTC 錢包且允許你獲得匿名的 L-BTC 地址以及密鑰。\n\n在需要進行調解的情況下,或者如果發生了交易糾紛,您必須將接收 L-BTC地址的安全密鑰披露給 Haveno 調解員或退款代理,以便他們能夠在他們自己的 Elements Core 全節點上驗證您的匿名交易的細節。\n\n如果你不瞭解或瞭解這些要求,不要在 Haveno 上交易 L-BTC。 +account.crypto.popup.liquidmonero.msg=在 Haveno 上交易 L-XMR 你必須理解下述條款:\n\n當你在 Haveno 上接受 L-XMR 交易時,你不能使用手機 Blockstream Green Wallet 或者是一個託管/交易錢包。你必須只接收 L-XMR 到 Liquid Elements Core 錢包,或另一個 L-XMR 錢包且允許你獲得匿名的 L-XMR 地址以及密鑰。\n\n在需要進行調解的情況下,或者如果發生了交易糾紛,您必須將接收 L-XMR地址的安全密鑰披露給 Haveno 調解員或退款代理,以便他們能夠在他們自己的 Elements Core 全節點上驗證您的匿名交易的細節。\n\n如果你不瞭解或瞭解這些要求,不要在 Haveno 上交易 L-XMR。 account.traditional.yourTraditionalAccounts=您的法定貨幣賬户 @@ -1228,9 +1256,9 @@ account.password.setPw.button=設置密碼 account.password.setPw.headline=設置錢包的密碼保護 account.password.info=啟用密碼保護後,在應用程式啟動時、從您的錢包提取門羅幣時以及顯示種子詞語時,您將需要輸入密碼。 -account.seed.backup.title=備份您的錢包還原密鑰 -account.seed.info=請寫下錢包還原密鑰和時間!\n您可以通過還原密鑰和時間在任何時候恢復您的錢包。\n還原密鑰用於 BTC 和 BSQ 錢包。\n\n您應該在一張紙上寫下還原密鑰並且不要保存它們在您的電腦上。\n請注意還原密鑰並不能代替備份。\n您需要備份完整的應用程序目錄在”賬户/備份“界面去恢復有效的應用程序狀態和數據。 -account.seed.backup.warning=請注意種子詞不能替代備份。您需要為整個應用目錄(在“賬户/備份”選項卡中)以恢復應用狀態以及數據。\n導入種子詞僅在緊急情況時才推薦使用。 如果沒有正確備份數據庫文件和密鑰,該應用程序將無法運行!\n\n在 Haveno wiki 中查看更多信息: https://bisq.wiki/Backing_up_application_data +account.seed.backup.title=備份您的錢包種子詞 +account.seed.info=請記下錢包種子詞和日期。您隨時可以使用種子詞和日期還原您的錢包。\n\n應該將種子詞寫在一張紙上,不要保存在電腦上。\n\n請注意,種子詞並不是備份的替代品。\n您需要在\"帳戶/備份\"畫面中創建整個應用程式目錄的備份,以還原應用程式的狀態和數據。 +account.seed.backup.warning=請注意,種子詞並非備份的替代品。\n您需要從\"帳戶/備份\"畫面中創建整個應用程式目錄的備份,以還原應用程式的狀態和數據。 account.seed.warn.noPw.msg=您還沒有設置一個可以保護還原密鑰顯示的錢包密碼。\n\n要顯示還原密鑰嗎? account.seed.warn.noPw.yes=是的,不要再問我 account.seed.enterPw=輸入密碼查看還原密鑰 @@ -1259,13 +1287,13 @@ account.notifications.trade.label=接收交易信息 account.notifications.market.label=接收報價提醒 account.notifications.price.label=接收價格提醒 account.notifications.priceAlert.title=價格提醒 -account.notifications.priceAlert.high.label=提醒條件:當 BTC 價格高於 -account.notifications.priceAlert.low.label=提醒條件:當 BTC 價格低於 +account.notifications.priceAlert.high.label=提醒條件:當 XMR 價格高於 +account.notifications.priceAlert.low.label=提醒條件:當 XMR 價格低於 account.notifications.priceAlert.setButton=設置價格提醒 account.notifications.priceAlert.removeButton=取消價格提醒 account.notifications.trade.message.title=交易狀態已變更 account.notifications.trade.message.msg.conf=ID 為 {0} 的交易的存款交易已被確認。請打開您的 Haveno 應用程序並開始付款。 -account.notifications.trade.message.msg.started=BTC 買家已經開始支付 ID 為 {0} 的交易。 +account.notifications.trade.message.msg.started=XMR 買家已經開始支付 ID 為 {0} 的交易。 account.notifications.trade.message.msg.completed=ID 為 {0} 的交易已完成。 account.notifications.offer.message.title=您的報價已被接受 account.notifications.offer.message.msg=您的 ID 為 {0} 的報價已被接受 @@ -1275,10 +1303,10 @@ account.notifications.dispute.message.msg=您收到了一個 ID 為 {0} 的交 account.notifications.marketAlert.title=報價提醒 account.notifications.marketAlert.selectPaymentAccount=提供匹配的付款帳户 account.notifications.marketAlert.offerType.label=我感興趣的報價類型 -account.notifications.marketAlert.offerType.buy=買入報價(我想要出售 BTC ) -account.notifications.marketAlert.offerType.sell=賣出報價(我想要購買 BTC ) +account.notifications.marketAlert.offerType.buy=買入報價(我想要出售 XMR ) +account.notifications.marketAlert.offerType.sell=賣出報價(我想要購買 XMR ) account.notifications.marketAlert.trigger=報價距離(%) -account.notifications.marketAlert.trigger.info=設置價格區間後,只有當滿足(或超過)您的需求的報價發佈時,您才會收到提醒。您想賣 BTC ,但你只能以當前市價的 2% 溢價出售。將此字段設置為 2% 將確保您只收到高於當前市場價格 2%(或更多)的報價的提醒。 +account.notifications.marketAlert.trigger.info=設置價格區間後,只有當滿足(或超過)您的需求的報價發佈時,您才會收到提醒。您想賣 XMR ,但你只能以當前市價的 2% 溢價出售。將此字段設置為 2% 將確保您只收到高於當前市場價格 2%(或更多)的報價的提醒。 account.notifications.marketAlert.trigger.prompt=與市場價格的百分比距離(例如 2.50%, -0.50% 等) account.notifications.marketAlert.addButton=添加報價提醒 account.notifications.marketAlert.manageAlertsButton=管理報價提醒 @@ -1305,10 +1333,10 @@ inputControlWindow.balanceLabel=可用餘額 contractWindow.title=糾紛詳情 contractWindow.dates=報價時間/交易時間 -contractWindow.btcAddresses=BTC 買家/BTC 賣家的比特幣地址 -contractWindow.onions=BTC 買家/BTC 賣家的網絡地址 -contractWindow.accountAge=BTC 買家/BTC 賣家的賬齡 -contractWindow.numDisputes=BTC 買家/BTC 賣家的糾紛編號 +contractWindow.xmrAddresses=XMR 買家/XMR 賣家的比特幣地址 +contractWindow.onions=XMR 買家/XMR 賣家的網絡地址 +contractWindow.accountAge=XMR 買家/XMR 賣家的賬齡 +contractWindow.numDisputes=XMR 買家/XMR 賣家的糾紛編號 contractWindow.contractHash=合同哈希 displayAlertMessageWindow.headline=重要資料! @@ -1334,8 +1362,8 @@ disputeSummaryWindow.title=概要 disputeSummaryWindow.openDate=工單創建時間 disputeSummaryWindow.role=交易者的角色 disputeSummaryWindow.payout=交易金額支付 -disputeSummaryWindow.payout.getsTradeAmount=BTC {0} 獲得交易金額支付 -disputeSummaryWindow.payout.getsAll=最大 BTC 支付數 {0} +disputeSummaryWindow.payout.getsTradeAmount=XMR {0} 獲得交易金額支付 +disputeSummaryWindow.payout.getsAll=最大 XMR 支付數 {0} disputeSummaryWindow.payout.custom=自定義支付 disputeSummaryWindow.payoutAmount.buyer=買家支付金額 disputeSummaryWindow.payoutAmount.seller=賣家支付金額 @@ -1377,7 +1405,7 @@ disputeSummaryWindow.close.button=關閉話題 # Do no change any line break or order of tokens as the structure is used for signature verification # suppress inspection "TrailingSpacesInProperty" -disputeSummaryWindow.close.msg=工單已關閉{0}\n{1} 節點地址:{12}\n\n總結:\n交易 ID:{3}\n貨幣:{4}\n交易金額:{5}\nBTC 買家支付金額:{6}\nBTC 賣家支付金額:{7}\n\n糾紛原因:{8}\n\n總結:\n{9}\n +disputeSummaryWindow.close.msg=工單已關閉{0}\n{1} 節點地址:{12}\n\n總結:\n交易 ID:{3}\n貨幣:{4}\n交易金額:{5}\nXMR 買家支付金額:{6}\nXMR 賣家支付金額:{7}\n\n糾紛原因:{8}\n\n總結:\n{9}\n # Do no change any line break or order of tokens as the structure is used for signature verification disputeSummaryWindow.close.msgWithSig={0}{1}{2}{3} @@ -1432,7 +1460,7 @@ filterWindow.xmrFeeReceiverAddresses=比特幣手續費接收地址 filterWindow.disableApi=Disable API filterWindow.disableMempoolValidation=Disable Mempool Validation -offerDetailsWindow.minBtcAmount=最小 BTC 數量 +offerDetailsWindow.minXmrAmount=最小 XMR 數量 offerDetailsWindow.min=(最小 {0}) offerDetailsWindow.distance=(與市場價格的差距:{0}) offerDetailsWindow.myTradingAccount=我的交易賬户 @@ -1447,6 +1475,7 @@ offerDetailsWindow.confirm.maker=確定:發佈報價 {0} 比特幣 offerDetailsWindow.confirm.taker=確定:下單買入 {0} 比特幣 offerDetailsWindow.creationDate=創建時間 offerDetailsWindow.makersOnion=賣家的匿名地址 +offerDetailsWindow.challenge=提供密碼 qRCodeWindow.headline=二維碼 qRCodeWindow.msg=請使用二維碼從外部錢包充值至 Haveno 錢包 @@ -1475,7 +1504,7 @@ showWalletDataWindow.walletData=錢包數據 showWalletDataWindow.includePrivKeys=包含私鑰 setXMRTxKeyWindow.headline=證明已發送 XMR -setXMRTxKeyWindow.note=在下面添加 tx 信息可以更快的自動確認交易。更多信息::https://bisq.wiki/Trading_Monero +setXMRTxKeyWindow.note=在下面添加 tx 信息可以更快的自動確認交易。更多信息::https://haveno.exchange/wiki/Trading_Monero setXMRTxKeyWindow.txHash=交易 ID (可選) setXMRTxKeyWindow.txKey=交易密鑰 (可選) @@ -1487,7 +1516,7 @@ tacWindow.disagree=我不同意並退出 tacWindow.arbitrationSystem=糾紛解決方案 tradeDetailsWindow.headline=交易 -tradeDetailsWindow.disputedPayoutTxId=糾紛支付交易 ID: +tradeDetailsWindow.disputedPayoutTxId=糾紛支付交易 ID tradeDetailsWindow.tradeDate=交易時間 tradeDetailsWindow.txFee=礦工手續費 tradeDetailsWindow.tradePeersOnion=交易夥伴匿名地址 @@ -1497,8 +1526,10 @@ tradeDetailsWindow.agentAddresses=仲裁員/調解員 tradeDetailsWindow.detailData=Detail data txDetailsWindow.headline=Transaction Details -txDetailsWindow.xmr.note=You have sent BTC. -txDetailsWindow.sentTo=Sent to +txDetailsWindow.xmr.noteSent=您已發送XMR。 +txDetailsWindow.xmr.noteReceived=您已收到 XMR。 +txDetailsWindow.sentTo=發送至 +txDetailsWindow.receivedWith=已收到與 txDetailsWindow.txId=TxId closedTradesSummaryWindow.headline=Trade history summary @@ -1507,7 +1538,7 @@ closedTradesSummaryWindow.totalAmount.value={0} ({1} with current market price) closedTradesSummaryWindow.totalVolume.title=Total amount traded in {0} closedTradesSummaryWindow.totalMinerFee.title=Sum of all miner fees closedTradesSummaryWindow.totalMinerFee.value={0} ({1} of total trade amount) -closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in BTC +closedTradesSummaryWindow.totalTradeFeeInXmr.title=Sum of all trade fees paid in XMR closedTradesSummaryWindow.totalTradeFeeInXmr.value={0} ({1} of total trade amount) walletPasswordWindow.headline=輸入密碼解鎖 @@ -1534,10 +1565,10 @@ torNetworkSettingWindow.bridges.info=如果 Tor 被您的 Internet 提供商或 feeOptionWindow.headline=選擇貨幣支付交易手續費 feeOptionWindow.optionsLabel=選擇貨幣支付交易手續費 -feeOptionWindow.useBTC=使用 BTC +feeOptionWindow.useXMR=使用 XMR feeOptionWindow.fee={0}(≈ {1}) -feeOptionWindow.btcFeeWithFiatAndPercentage={0} (≈ {1} / {2}) -feeOptionWindow.btcFeeWithPercentage={0} ({1}) +feeOptionWindow.xmrFeeWithFiatAndPercentage={0} (≈ {1} / {2}) +feeOptionWindow.xmrFeeWithPercentage={0} ({1}) #################################################################### @@ -1579,9 +1610,9 @@ popup.warning.noTradingAccountSetup.msg=您需要設置法定貨幣或數字貨 popup.warning.noArbitratorsAvailable=沒有仲裁員可用。 popup.warning.noMediatorsAvailable=沒有調解員可用。 popup.warning.notFullyConnected=您需要等到您完全連接到網絡\n在啟動時可能需要2分鐘。 -popup.warning.notSufficientConnectionsToBtcNetwork=你需要等待至少有{0}個與比特幣網絡的連接點。 +popup.warning.notSufficientConnectionsToXmrNetwork=你需要等待至少有{0}個與比特幣網絡的連接點。 popup.warning.downloadNotComplete=您需要等待,直到丟失的比特幣區塊被下載完畢。 -popup.warning.chainNotSynced=Haveno 錢包區塊鏈高度沒有正確地同步。如果最近才打開應用,請等待一個新發布的比特幣區塊。\n\n你可以檢查區塊鏈高度在設置/網絡信息。如果經過了一個區塊但問題還是沒有解決,你應該及時的完成 SPV 鏈重新同步。https://bisq.wiki/Resyncing_SPV_file +popup.warning.walletNotSynced=Haveno 錢包尚未與最新的區塊鏈高度同步。請等待錢包同步完成或檢查您的連接。 popup.warning.removeOffer=您確定要移除該報價嗎? popup.warning.tooLargePercentageValue=您不能設置100%或更大的百分比。 popup.warning.examplePercentageValue=請輸入百分比數字,如 5.4% 是“5.4” @@ -1600,14 +1631,13 @@ popup.warning.nodeBanned=其中一個 {0} 節點已被禁用 popup.warning.priceRelay=價格傳遞 popup.warning.seed=種子 popup.warning.mandatoryUpdate.trading=請更新到最新的 Haveno 版本。強制更新禁止了舊版本進行交易。更多信息請訪問 Haveno 論壇。 -popup.warning.noFilter=We did not receive a filter object from the seed nodes. This is a not expected situation. Please inform the Haveno developers. -popup.warning.burnBTC=這筆交易是無法實現,因為 {0} 的挖礦手續費用會超過 {1} 的轉賬金額。請等到挖礦手續費再次降低或您積累了更多的 BTC 來轉賬。 +popup.warning.burnXMR=這筆交易是無法實現,因為 {0} 的挖礦手續費用會超過 {1} 的轉賬金額。請等到挖礦手續費再次降低或您積累了更多的 XMR 來轉賬。 popup.warning.openOffer.makerFeeTxRejected=交易 ID 為 {0} 的掛單費交易被比特幣網絡拒絕。\n交易 ID = {1}\n交易已被移至失敗交易。\n請到“設置/網絡信息”進行 SPV 重新同步。\n如需更多幫助,請聯繫 Haveno Keybase 團隊的 Support 頻道 popup.warning.trade.txRejected.tradeFee=交易手續費 popup.warning.trade.txRejected.deposit=押金 -popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Bitcoin network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. +popup.warning.trade.txRejected=The {0} transaction for trade with ID {1} was rejected by the Monero network.\nTransaction ID={2}\nThe trade has been moved to failed trades.\nPlease go to \"Settings/Network info\" and do a SPV resync.\nFor further help please contact the Haveno support channel at the Haveno Keybase team. popup.warning.openOfferWithInvalidMakerFeeTx=交易 ID 為 {0} 的掛單費交易無效。\n交易 ID = {1}。\n請到“設置/網絡信息”進行 SPV 重新同步。\n如需更多幫助,請聯繫 Haveno Keybase 團隊的 Support 頻道 @@ -1616,7 +1646,7 @@ popup.info.securityDepositInfo=為了確保雙方都遵守交易協議,雙方 popup.info.cashDepositInfo=請確保您在您的地區有一個銀行分行,以便能夠進行現金存款。\n賣方銀行的銀行 ID(BIC/SWIFT)為:{0}。 popup.info.cashDepositInfo.confirm=我確認我可以支付保證金 popup.info.shutDownWithOpenOffers=Haveno 正在被關閉,但仍有公開的報價。\n\n當 Haveno 關閉時,這些提供將不能在 P2P 網絡上使用,但是它們將在您下次啟動 Haveno 時重新發布到 P2P 網絡上。\n\n為了讓您的報價在線,保持 Haveno 運行,並確保這台計算機也在線(即,確保它不會進入待機模式…顯示器待機不是問題)。 -popup.info.qubesOSSetupInfo=你似乎好像在 Qubes OS 上運行 Haveno。\n\n請確保您的 Haveno qube 是參考設置指南的説明設置的 https://bisq.wiki/Running_Haveno_on_Qubes +popup.info.qubesOSSetupInfo=你似乎好像在 Qubes OS 上運行 Haveno。\n\n請確保您的 Haveno qube 是參考設置指南的説明設置的 https://haveno.exchange/wiki/Running_Haveno_on_Qubes popup.warn.downGradePrevention=不支持從 {0} 版本降級到 {1} 版本。請使用最新的 Haveno 版本。 popup.privateNotification.headline=重要私人通知! @@ -1668,6 +1698,9 @@ popup.accountSigning.unsignedPubKeys.signed=公鑰已被驗證 popup.accountSigning.unsignedPubKeys.result.signed=已驗證公鑰 popup.accountSigning.unsignedPubKeys.result.failed=未能驗證公鑰 +popup.info.buyerAsTakerWithoutDeposit.headline=買家無需支付保證金 +popup.info.buyerAsTakerWithoutDeposit=您的報價不需要來自XMR買家的保證金或費用。\n\n要接受您的報價,您必須與您的交易夥伴在Haveno之外分享密碼短語。\n\n密碼短語會自動生成並在報價創建後顯示在報價詳情中。 + #################################################################### # Notifications #################################################################### @@ -1675,9 +1708,9 @@ popup.accountSigning.unsignedPubKeys.result.failed=未能驗證公鑰 notification.trade.headline=交易 ID {0} 的通知 notification.ticket.headline=交易 ID {0} 的幫助話題 notification.trade.completed=交易現在完成,您可以提取資金。 -notification.trade.accepted=您 BTC {0} 的報價被接受。 +notification.trade.accepted=您 XMR {0} 的報價被接受。 notification.trade.unlocked=您的交易至少有一個區塊鏈確認。\n您現在可以開始付款。 -notification.trade.paymentSent=BTC 買家已經開始付款。 +notification.trade.paymentSent=XMR 買家已經開始付款。 notification.trade.selectTrade=選擇交易 notification.trade.peerOpenedDispute=您的交易對象創建了一個 {0}。 notification.trade.disputeClosed=這個 {0} 被關閉。 @@ -1747,7 +1780,7 @@ tooltip.openBlockchainForTx=使用外部區塊鏈瀏覽器打開交易:{0} confidence.unknown=未知交易狀態 confidence.seen=被 {0} 人查看 / 0 確定 -confidence.confirmed=在 {0} 區塊中確認 +confidence.confirmed={0} 確認(s) confidence.invalid=交易無效 peerInfo.title=對象資料 @@ -1793,6 +1826,7 @@ navigation.support=“幫助” formatter.formatVolumeLabel={0} 數量 {1} formatter.makerTaker=賣家 {0} {1} / 買家 {2} {3} +formatter.makerTakerLocked=賣家 {0} {1} / 買家 {2} {3} 🔒 formatter.youAreAsMaker=You are: {1} {0} (maker) / Taker is: {3} {2} formatter.youAreAsTaker=You are: {1} {0} (taker) / Maker is: {3} {2} formatter.youAre=您是 {0} {1} ({2} {3}) @@ -1838,7 +1872,6 @@ password.deriveKey=從密碼中提取密鑰 password.walletDecrypted=錢包成功解密並移除密碼保護 password.wrongPw=你輸入了錯誤的密碼。\n\n請再次嘗試輸入密碼,仔細檢查拼寫錯誤。 password.walletEncrypted=錢包成功加密並開啟密碼保護。 -password.walletEncryptionFailed=無法設置錢包密碼。您可能導入了與錢包數據庫不匹配的還原密鑰。請在 Keybase 上聯繫開發者(https://keybase.io/team/haveno]) password.passwordsDoNotMatch=這2個密碼您輸入的不相同 password.forgotPassword=忘記密碼? password.backupReminder=請注意,設置錢包密碼時,所有未加密的錢包的自動創建的備份將被刪除。\n\n強烈建議您備份應用程序的目錄,並在設置密碼之前記下您的還原密鑰! @@ -1869,7 +1902,7 @@ seed.restore.openOffers.warn=您有公開報價,如果您從種子詞恢復, payment.account=賬户 payment.account.no=賬户編號 payment.account.name=賬户名稱 -payment.account.userName=用户暱稱 +payment.account.username=用户暱稱 payment.account.phoneNr=電話號碼 payment.account.owner=賬户擁有者姓名: payment.account.fullName=全稱(名,中間名,姓) @@ -1901,7 +1934,6 @@ payment.amazon.site=Buy giftcard at payment.ask=Ask in Trader Chat payment.uphold.accountId=用户名或電子郵箱或電話號碼 payment.moneyBeam.accountId=電子郵箱或者電話號碼 -payment.venmo.venmoUserName=Venmo 用户名: payment.popmoney.accountId=電子郵箱或者電話號碼 payment.promptPay.promptPayId=公民身份證/税號或電話號碼 payment.supportedCurrencies=支持的貨幣 @@ -1943,16 +1975,16 @@ payment.checking=檢查 payment.savings=保存 payment.personalId=個人 ID payment.makeOfferToUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- make offers >{0}, so you only deal with signed/trusted buyers\n- keep any offers to sell <{0} to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. -payment.takeOfferFromUnsignedAccount.warning=With the recent rise in BTC price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. +payment.takeOfferFromUnsignedAccount.warning=With the recent rise in XMR price, beware that selling {0} or less incurs higher risk than before.\n\nIt is highly recommended to either:\n- take offers from signed buyers only\n- keep trades with unsigned/untrusted buyers to around ~100 USD in value, as this value has (historically) discouraged scammers\n\nHaveno developers are working on better ways to secure the payment account model for such smaller trades. Join the discussion here: [HYPERLINK:https://github.com/bisq-network/bisq/discussions/5339]. payment.zelle.info=Zelle是一項轉賬服務,轉賬到其他銀行做的很好。\n\n1.檢查此頁面以查看您的銀行是否(以及如何)與 Zelle 合作:\nhttps://www.zellepay.com/get-started\n\n2.特別注意您的轉賬限額-匯款限額因銀行而異,銀行通常分別指定每日,每週和每月的限額。\n\n3.如果您的銀行不能使用 Zelle,您仍然可以通過 Zelle 移動應用程序使用它,但是您的轉賬限額會低得多。\n\n4.您的 Haveno 帳户上指定的名稱必須與 Zelle/銀行帳户上的名稱匹配。 \n\n如果您無法按照貿易合同中的規定完成 Zelle 交易,則可能會損失部分(或全部)保證金。\n\n由於 Zelle 的拒付風險較高,因此建議賣家通過電子郵件或 SMS 與未簽名的買家聯繫,以確認買家確實擁有 Haveno 中指定的 Zelle 帳户。 payment.fasterPayments.newRequirements.info=有些銀行已經開始核實快捷支付收款人的全名。您當前的快捷支付帳户沒有填寫全名。\n\n請考慮在 Haveno 中重新創建您的快捷支付帳户,為將來的 {0} 買家提供一個完整的姓名。\n\n重新創建帳户時,請確保將銀行區號、帳户編號和帳齡驗證鹽值從舊帳户複製到新帳户。這將確保您現有的帳齡和簽名狀態得到保留。 -payment.moneyGram.info=使用 MoneyGram 時,BTC 買方必須將授權號碼和收據的照片通過電子郵件發送給 BTC 賣方。收據必須清楚地顯示賣方的全名、國家或地區、州和金額。買方將在交易過程中顯示賣方的電子郵件。 -payment.westernUnion.info=使用 Western Union 時,BTC 買方必須通過電子郵件將 MTCN(運單號)和收據照片發送給 BTC 賣方。收據上必須清楚地顯示賣方的全名、城市、國家或地區和金額。買方將在交易過程中顯示賣方的電子郵件。 -payment.halCash.info=使用 HalCash 時,BTC 買方需要通過手機短信向 BTC 賣方發送 HalCash 代碼。\n\n請確保不要超過銀行允許您用半現金匯款的最高金額。每次取款的最低金額是 10 歐元,最高金額是 10 歐元。金額是 600 歐元。對於重複取款,每天每個接收者 3000 歐元,每月每個接收者 6000 歐元。請與您的銀行核對這些限額,以確保它們使用與此處所述相同的限額。\n\n提現金額必須是 10 歐元的倍數,因為您不能從 ATM 機提取其他金額。 創建報價和下單屏幕中的 UI 將調整 BTC 金額,使 EUR 金額正確。你不能使用基於市場的價格,因為歐元的數量會隨着價格的變化而變化。\n +payment.moneyGram.info=使用 MoneyGram 時,XMR 買方必須將授權號碼和收據的照片通過電子郵件發送給 XMR 賣方。收據必須清楚地顯示賣方的全名、國家或地區、州和金額。買方將在交易過程中顯示賣方的電子郵件。 +payment.westernUnion.info=使用 Western Union 時,XMR 買方必須通過電子郵件將 MTCN(運單號)和收據照片發送給 XMR 賣方。收據上必須清楚地顯示賣方的全名、城市、國家或地區和金額。買方將在交易過程中顯示賣方的電子郵件。 +payment.halCash.info=使用 HalCash 時,XMR 買方需要通過手機短信向 XMR 賣方發送 HalCash 代碼。\n\n請確保不要超過銀行允許您用半現金匯款的最高金額。每次取款的最低金額是 10 歐元,最高金額是 10 歐元。金額是 600 歐元。對於重複取款,每天每個接收者 3000 歐元,每月每個接收者 6000 歐元。請與您的銀行核對這些限額,以確保它們使用與此處所述相同的限額。\n\n提現金額必須是 10 歐元的倍數,因為您不能從 ATM 機提取其他金額。 創建報價和下單屏幕中的 UI 將調整 XMR 金額,使 EUR 金額正確。你不能使用基於市場的價格,因為歐元的數量會隨着價格的變化而變化。\n # suppress inspection "UnusedMessageFormatParameter" -payment.limits.info=請注意,所有銀行轉賬都有一定的退款風險。為了降低這一風險,Haveno 基於使用的付款方式的退款風險。\n\n對於付款方式,您的每筆交易的出售和購買的限額為{2}\n\n限制只應用在單筆交易,你可以儘可能多的進行交易。\n\n在 Haveno Wiki 查看更多信息[HYPERLINK:https://bisq.wiki/Account_limits]。 +payment.limits.info=請注意,所有銀行轉賬都有一定的退款風險。為了降低這一風險,Haveno 基於使用的付款方式的退款風險。\n\n對於付款方式,您的每筆交易的出售和購買的限額為{2}\n\n限制只應用在單筆交易,你可以儘可能多的進行交易。\n\n在 Haveno Wiki 查看更多信息[HYPERLINK:https://docs.haveno.exchange/the-project/account_limits]。 # suppress inspection "UnusedProperty" -payment.limits.info.withSigning=為了降低這一風險,Haveno 基於兩個因素對該付款方式每筆交易設置了限制:\n\n1. 使用的付款方法的預估退款風險水平\n2. 您的付款方式的賬齡\n\n這個付款賬户還沒有被驗證,所以他每個交易最多購買{0}。在驗證之後,購買限制會以以下規則逐漸增加:\n\n●簽署前,以及簽署後30天內,您的每筆最大交易將限制為{0}\n●簽署後30天,每筆最大交易將限制為{1}\n●簽署後60天,每筆最大交易將限制為{2}\n\n出售限制不會被賬户驗證狀態限制,你可以理科進行單筆為{2}的交易\n\n限制只應用在單筆交易,你可以儘可能多的進行交易。\n\n在 Haveno Wiki 上查看更多:\nhttps://bisq.wiki/Account_limits +payment.limits.info.withSigning=為了降低這一風險,Haveno 基於兩個因素對該付款方式每筆交易設置了限制:\n\n1. 使用的付款方法的預估退款風險水平\n2. 您的付款方式的賬齡\n\n這個付款賬户還沒有被驗證,所以他每個交易最多購買{0}。在驗證之後,購買限制會以以下規則逐漸增加:\n\n●簽署前,以及簽署後30天內,您的每筆最大交易將限制為{0}\n●簽署後30天,每筆最大交易將限制為{1}\n●簽署後60天,每筆最大交易將限制為{2}\n\n出售限制不會被賬户驗證狀態限制,你可以理科進行單筆為{2}的交易\n\n限制只應用在單筆交易,你可以儘可能多的進行交易。\n\n在 Haveno Wiki 上查看更多:\nhttps://docs.haveno.exchange/the-project/account_limits payment.cashDeposit.info=請確認您的銀行允許您將現金存款匯入他人賬户。例如,美國銀行和富國銀行不再允許此類存款。 @@ -1964,7 +1996,7 @@ payment.amazonGiftCard.upgrade=Amazon gift cards payment method requires the cou payment.account.amazonGiftCard.addCountryInfo={0}\nYour existing Amazon Gift Card account ({1}) does not have a Country specified.\nPlease enter your Amazon Gift Card Country to update your account data.\nThis will not affect your account age status. payment.amazonGiftCard.upgrade.headLine=Update Amazon Gift Card account -payment.usPostalMoneyOrder.info=在 Haveno 上交易 US Postal Money Orders (USPMO)您必須理解下述條款:\n\n- BTC 買方必須在發送方和收款人字段中都寫上 BTC 賣方的名稱,並在發送之前對 USPMO 和信封進行高分辨率照片拍照,並帶有跟蹤證明。\n- BTC 買方必須將 USPMO 連同交貨確認書一起發送給 BTC 賣方。\n\n如果需要調解,或有交易糾紛,您將需要將照片連同 USPMO 編號,郵局編號和交易金額一起發送給 Haveno 調解員或退款代理,以便他們進行驗證美國郵局網站上的詳細信息。\n\n如未能提供要求的交易數據將在糾紛中直接判負\n\n在所有爭議案件中,USPMO 發送方在向調解人或仲裁員提供證據/證明時承擔 100% 的責任。\n\n如果您不理解這些要求,請不要在 Haveno 上使用 USPMO 進行交易。 +payment.usPostalMoneyOrder.info=在 Haveno 上交易 US Postal Money Orders (USPMO)您必須理解下述條款:\n\n- XMR 買方必須在發送方和收款人字段中都寫上 XMR 賣方的名稱,並在發送之前對 USPMO 和信封進行高分辨率照片拍照,並帶有跟蹤證明。\n- XMR 買方必須將 USPMO 連同交貨確認書一起發送給 XMR 賣方。\n\n如果需要調解,或有交易糾紛,您將需要將照片連同 USPMO 編號,郵局編號和交易金額一起發送給 Haveno 調解員或退款代理,以便他們進行驗證美國郵局網站上的詳細信息。\n\n如未能提供要求的交易數據將在糾紛中直接判負\n\n在所有爭議案件中,USPMO 發送方在向調解人或仲裁員提供證據/證明時承擔 100% 的責任。\n\n如果您不理解這些要求,請不要在 Haveno 上使用 USPMO 進行交易。 payment.payByMail.contact=聯繫方式 payment.payByMail.contact.prompt=Name or nym envelope should be addressed to @@ -1975,7 +2007,7 @@ payment.f2f.city.prompt=城市將與報價一同顯示 payment.shared.optionalExtra=可選的附加信息 payment.shared.extraInfo=附加信息 payment.shared.extraInfo.prompt=Define any special terms, conditions, or details you would like to be displayed with your offers for this payment account (users will see this info before accepting offers). -payment.f2f.info=與網上交易相比,“面對面”交易有不同的規則,也有不同的風險。\n\n主要區別是:\n●交易夥伴需要使用他們提供的聯繫方式交換關於會面地點和時間的信息。\n●交易雙方需要攜帶筆記本電腦,在會面地點確認“已發送付款”和“已收到付款”。\n●如果交易方有特殊的“條款和條件”,他們必須在賬户的“附加信息”文本框中聲明這些條款和條件。\n●在發生爭議時,調解員或仲裁員不能提供太多幫助,因為通常很難獲得有關會面上所發生情況的篡改證據。在這種情況下,BTC 資金可能會被無限期鎖定,或者直到交易雙方達成協議。\n\n為確保您完全理解“面對面”交易的不同之處,請閲讀以下説明和建議:“https://docs.haveno.exchange/trading-rules.html#f2f-trading” +payment.f2f.info=與網上交易相比,“面對面”交易有不同的規則,也有不同的風險。\n\n主要區別是:\n●交易夥伴需要使用他們提供的聯繫方式交換關於會面地點和時間的信息。\n●交易雙方需要攜帶筆記本電腦,在會面地點確認“已發送付款”和“已收到付款”。\n●如果交易方有特殊的“條款和條件”,他們必須在賬户的“附加信息”文本框中聲明這些條款和條件。\n●在發生爭議時,調解員或仲裁員不能提供太多幫助,因為通常很難獲得有關會面上所發生情況的篡改證據。在這種情況下,XMR 資金可能會被無限期鎖定,或者直到交易雙方達成協議。\n\n為確保您完全理解“面對面”交易的不同之處,請閲讀以下説明和建議:“https://docs.haveno.exchange/trading-rules.html#f2f-trading” payment.f2f.info.openURL=打開網頁 payment.f2f.offerbook.tooltip.countryAndCity=國家或地區及城市:{0} / {1} payment.f2f.offerbook.tooltip.extra=附加信息:{0} @@ -1987,7 +2019,7 @@ payment.japan.recipient=名稱 payment.australia.payid=PayID payment.payid=PayID 需鏈接至金融機構。例如電子郵件地址或手機。 payment.payid.info=PayID,如電話號碼、電子郵件地址或澳大利亞商業號碼(ABN),您可以安全地連接到您的銀行、信用合作社或建立社會帳户。你需要在你的澳大利亞金融機構創建一個 PayID。發送和接收金融機構都必須支持 PayID。更多信息請查看[HYPERLINK:https://payid.com.au/faqs/] -payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the BTC seller via your Amazon account. \n\nHaveno will show the BTC seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://bisq.wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) +payment.amazonGiftCard.info=To pay with Amazon eGift Card, you will need to send an Amazon eGift Card to the XMR seller via your Amazon account. \n\nHaveno will show the XMR seller''s email address or phone number where the gift card should be sent, and you must include the trade ID in the gift card''s message field. Please see the wiki [HYPERLINK:https://haveno.exchange/wiki/Amazon_eGift_card] for further details and best practices. \n\nThree important notes:\n- try to send gift cards with amounts of 100 USD or smaller, as Amazon is known to flag larger gift cards as fraudulent\n- try to use creative, believable text for the gift card''s message (e.g., "Happy birthday Susan!") along with the trade ID (and use trader chat to tell your trading peer the reference text you picked so they can verify your payment)\n- Amazon eGift Cards can only be redeemed on the Amazon website they were purchased on (e.g., a gift card purchased on amazon.it can only be redeemed on amazon.it) # We use constants from the code so we do not use our normal naming convention @@ -2155,10 +2187,10 @@ validation.sortCodeChars={0} 必須由 {1} 個字符構成。 validation.bankIdNumber={0} 必須由 {1} 個數字構成。 validation.accountNr=賬號必須由 {0} 個數字構成。 validation.accountNrChars=賬户必須由 {0} 個字符構成。 -validation.btc.invalidAddress=地址不正確,請檢查地址格式。 +validation.xmr.invalidAddress=地址不正確,請檢查地址格式。 validation.integerOnly=請輸入整數。 validation.inputError=您的輸入引起了錯誤:\n{0} -validation.btc.exceedsMaxTradeLimit=您的交易限額為 {0}。 +validation.xmr.exceedsMaxTradeLimit=您的交易限額為 {0}。 validation.nationalAccountId={0} 必須由{1}個數字組成。 #new diff --git a/core/src/test/java/haveno/core/account/sign/SignedWitnessServiceTest.java b/core/src/test/java/haveno/core/account/sign/SignedWitnessServiceTest.java index 40c991ed1f..9b26def543 100644 --- a/core/src/test/java/haveno/core/account/sign/SignedWitnessServiceTest.java +++ b/core/src/test/java/haveno/core/account/sign/SignedWitnessServiceTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.sign; @@ -353,7 +353,7 @@ public class SignedWitnessServiceTest { when(keyRing.getSignatureKeyPair()).thenReturn(signerKeyPair); AccountAgeWitness accountAgeWitness = new AccountAgeWitness(account1DataHash, accountCreationTime); - signedWitnessService.signAndPublishAccountAgeWitness(BigInteger.valueOf(0), accountAgeWitness, peerKeyPair.getPublic()); + signedWitnessService.signAndPublishAccountAgeWitness(BigInteger.ZERO, accountAgeWitness, peerKeyPair.getPublic()); verify(p2pService, never()).addPersistableNetworkPayload(any(PersistableNetworkPayload.class), anyBoolean()); } diff --git a/core/src/test/java/haveno/core/account/witness/AccountAgeWitnessServiceTest.java b/core/src/test/java/haveno/core/account/witness/AccountAgeWitnessServiceTest.java index 2dd0279432..c60e06cb75 100644 --- a/core/src/test/java/haveno/core/account/witness/AccountAgeWitnessServiceTest.java +++ b/core/src/test/java/haveno/core/account/witness/AccountAgeWitnessServiceTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.account.witness; @@ -192,6 +192,7 @@ public class AccountAgeWitnessServiceTest { 1, DisputeResult.Winner.BUYER, DisputeResult.Reason.OTHER.ordinal(), + DisputeResult.SubtractFeeFrom.BUYER_ONLY, true, true, true, diff --git a/core/src/test/java/haveno/core/app/HavenoHelpFormatterTest.java b/core/src/test/java/haveno/core/app/HavenoHelpFormatterTest.java index fbed2aa567..b2af6bf025 100644 --- a/core/src/test/java/haveno/core/app/HavenoHelpFormatterTest.java +++ b/core/src/test/java/haveno/core/app/HavenoHelpFormatterTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.app; diff --git a/core/src/test/java/haveno/core/arbitration/ArbitratorManagerTest.java b/core/src/test/java/haveno/core/arbitration/ArbitratorManagerTest.java index 184430ce3d..c69ccdc61a 100644 --- a/core/src/test/java/haveno/core/arbitration/ArbitratorManagerTest.java +++ b/core/src/test/java/haveno/core/arbitration/ArbitratorManagerTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.arbitration; diff --git a/core/src/test/java/haveno/core/arbitration/ArbitratorTest.java b/core/src/test/java/haveno/core/arbitration/ArbitratorTest.java index 4b6e16244d..34a775aab0 100644 --- a/core/src/test/java/haveno/core/arbitration/ArbitratorTest.java +++ b/core/src/test/java/haveno/core/arbitration/ArbitratorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.arbitration; diff --git a/core/src/test/java/haveno/core/arbitration/MediatorTest.java b/core/src/test/java/haveno/core/arbitration/MediatorTest.java index 8aba525a14..810be4a61d 100644 --- a/core/src/test/java/haveno/core/arbitration/MediatorTest.java +++ b/core/src/test/java/haveno/core/arbitration/MediatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.arbitration; diff --git a/core/src/test/java/haveno/core/arbitration/TraderDataItemTest.java b/core/src/test/java/haveno/core/arbitration/TraderDataItemTest.java index c6fae6ae38..cec1b838f6 100644 --- a/core/src/test/java/haveno/core/arbitration/TraderDataItemTest.java +++ b/core/src/test/java/haveno/core/arbitration/TraderDataItemTest.java @@ -14,20 +14,20 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.mockito.Mockito.mock; /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ public class TraderDataItemTest { private TraderDataItem traderDataItem1; diff --git a/core/src/test/java/haveno/core/crypto/EncryptionTest.java b/core/src/test/java/haveno/core/crypto/EncryptionTest.java index 493ddbe6f3..d3952f4063 100644 --- a/core/src/test/java/haveno/core/crypto/EncryptionTest.java +++ b/core/src/test/java/haveno/core/crypto/EncryptionTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.crypto; diff --git a/core/src/test/java/haveno/core/crypto/SigTest.java b/core/src/test/java/haveno/core/crypto/SigTest.java index 0df69178b0..9d5e65eff2 100644 --- a/core/src/test/java/haveno/core/crypto/SigTest.java +++ b/core/src/test/java/haveno/core/crypto/SigTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.crypto; diff --git a/core/src/test/java/haveno/core/locale/CurrencyUtilTest.java b/core/src/test/java/haveno/core/locale/CurrencyUtilTest.java index e3e544df69..0152771dd7 100644 --- a/core/src/test/java/haveno/core/locale/CurrencyUtilTest.java +++ b/core/src/test/java/haveno/core/locale/CurrencyUtilTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/test/java/haveno/core/locale/MockTestnetCoin.java b/core/src/test/java/haveno/core/locale/MockTestnetCoin.java index 151c74441d..e6a7c0924b 100644 --- a/core/src/test/java/haveno/core/locale/MockTestnetCoin.java +++ b/core/src/test/java/haveno/core/locale/MockTestnetCoin.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.locale; diff --git a/core/src/test/java/haveno/core/message/MarshallerTest.java b/core/src/test/java/haveno/core/message/MarshallerTest.java index 5d45b81d79..cb7b00fbdf 100644 --- a/core/src/test/java/haveno/core/message/MarshallerTest.java +++ b/core/src/test/java/haveno/core/message/MarshallerTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.message; diff --git a/core/src/test/java/haveno/core/monetary/PriceTest.java b/core/src/test/java/haveno/core/monetary/PriceTest.java index efaf995396..49a32ac09d 100644 --- a/core/src/test/java/haveno/core/monetary/PriceTest.java +++ b/core/src/test/java/haveno/core/monetary/PriceTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.monetary; diff --git a/core/src/test/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java b/core/src/test/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java index 6e72f6d0aa..0644254db7 100644 --- a/core/src/test/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java +++ b/core/src/test/java/haveno/core/network/p2p/seed/DefaultSeedNodeRepositoryTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.network.p2p.seed; diff --git a/core/src/test/java/haveno/core/notifications/MobileModelTest.java b/core/src/test/java/haveno/core/notifications/MobileModelTest.java index 4f3471d60f..45679f3421 100644 --- a/core/src/test/java/haveno/core/notifications/MobileModelTest.java +++ b/core/src/test/java/haveno/core/notifications/MobileModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.notifications; diff --git a/core/src/test/java/haveno/core/offer/OfferMaker.java b/core/src/test/java/haveno/core/offer/OfferMaker.java index 783142148a..52084f209b 100644 --- a/core/src/test/java/haveno/core/offer/OfferMaker.java +++ b/core/src/test/java/haveno/core/offer/OfferMaker.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; @@ -46,6 +46,11 @@ public class OfferMaker { lookup.valueOf(useMarketBasedPrice, false), lookup.valueOf(amount, 100000L), lookup.valueOf(minAmount, 100000L), + 0L, + 0L, + 0L, + 0L, + 0L, lookup.valueOf(baseCurrencyCode, "XMR"), lookup.valueOf(counterCurrencyCode, "USD"), "SEPA", @@ -58,9 +63,6 @@ public class OfferMaker { 0L, 0L, 0L, - 0L, - 0L, - 0L, false, false, 0L, diff --git a/core/src/test/java/haveno/core/offer/OfferTest.java b/core/src/test/java/haveno/core/offer/OfferTest.java index 80b7778d0a..1fceb2e4b1 100644 --- a/core/src/test/java/haveno/core/offer/OfferTest.java +++ b/core/src/test/java/haveno/core/offer/OfferTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer; diff --git a/core/src/test/java/haveno/core/offer/OpenOfferManagerTest.java b/core/src/test/java/haveno/core/offer/OpenOfferManagerTest.java index ed4b85312f..0fcde044a3 100644 --- a/core/src/test/java/haveno/core/offer/OpenOfferManagerTest.java +++ b/core/src/test/java/haveno/core/offer/OpenOfferManagerTest.java @@ -7,7 +7,7 @@ import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.common.persistence.PersistenceManager; import haveno.core.api.CoreContext; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.trade.TradableList; import haveno.network.p2p.P2PService; import haveno.network.p2p.peers.PeerManager; @@ -53,7 +53,7 @@ public class OpenOfferManagerTest { public void testStartEditOfferForActiveOffer() { P2PService p2PService = mock(P2PService.class); OfferBookService offerBookService = mock(OfferBookService.class); - CoreMoneroConnectionsService connectionsService = mock(CoreMoneroConnectionsService.class); + XmrConnectionService xmrConnectionService = mock(XmrConnectionService.class); when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class)); @@ -61,7 +61,7 @@ public class OpenOfferManagerTest { null, null, p2PService, - connectionsService, + xmrConnectionService, null, null, null, @@ -102,14 +102,14 @@ public class OpenOfferManagerTest { public void testStartEditOfferForDeactivatedOffer() { P2PService p2PService = mock(P2PService.class); OfferBookService offerBookService = mock(OfferBookService.class); - CoreMoneroConnectionsService connectionsService = mock(CoreMoneroConnectionsService.class); + XmrConnectionService xmrConnectionService = mock(XmrConnectionService.class); when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class)); final OpenOfferManager manager = new OpenOfferManager(coreContext, null, null, p2PService, - connectionsService, + xmrConnectionService, null, null, null, @@ -142,7 +142,7 @@ public class OpenOfferManagerTest { public void testStartEditOfferForOfferThatIsCurrentlyEdited() { P2PService p2PService = mock(P2PService.class); OfferBookService offerBookService = mock(OfferBookService.class); - CoreMoneroConnectionsService connectionsService = mock(CoreMoneroConnectionsService.class); + XmrConnectionService xmrConnectionService = mock(XmrConnectionService.class); when(p2PService.getPeerManager()).thenReturn(mock(PeerManager.class)); @@ -151,7 +151,7 @@ public class OpenOfferManagerTest { null, null, p2PService, - connectionsService, + xmrConnectionService, null, null, null, diff --git a/core/src/test/java/haveno/core/offer/availability/ArbitratorSelectionTest.java b/core/src/test/java/haveno/core/offer/availability/ArbitratorSelectionTest.java index 89aaa28fd3..c298ce4a6f 100644 --- a/core/src/test/java/haveno/core/offer/availability/ArbitratorSelectionTest.java +++ b/core/src/test/java/haveno/core/offer/availability/ArbitratorSelectionTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.offer.availability; diff --git a/core/src/test/java/haveno/core/payment/PaymentAccountsTest.java b/core/src/test/java/haveno/core/payment/PaymentAccountsTest.java index fb96d74d19..1ed1a9d171 100644 --- a/core/src/test/java/haveno/core/payment/PaymentAccountsTest.java +++ b/core/src/test/java/haveno/core/payment/PaymentAccountsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java b/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java index 9836b0e059..1a0243b1b8 100644 --- a/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java +++ b/core/src/test/java/haveno/core/payment/ReceiptPredicatesTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/test/java/haveno/core/payment/ReceiptValidatorTest.java b/core/src/test/java/haveno/core/payment/ReceiptValidatorTest.java index 4196ea65cd..3dba813ae7 100644 --- a/core/src/test/java/haveno/core/payment/ReceiptValidatorTest.java +++ b/core/src/test/java/haveno/core/payment/ReceiptValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/test/java/haveno/core/payment/TradeLimitsTest.java b/core/src/test/java/haveno/core/payment/TradeLimitsTest.java index 267bbaf0b3..843293af58 100644 --- a/core/src/test/java/haveno/core/payment/TradeLimitsTest.java +++ b/core/src/test/java/haveno/core/payment/TradeLimitsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment; diff --git a/core/src/test/java/haveno/core/payment/validation/CryptoAddressValidatorTest.java b/core/src/test/java/haveno/core/payment/validation/CryptoAddressValidatorTest.java index 97ee875775..aad83f335e 100644 --- a/core/src/test/java/haveno/core/payment/validation/CryptoAddressValidatorTest.java +++ b/core/src/test/java/haveno/core/payment/validation/CryptoAddressValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.payment.validation; diff --git a/core/src/test/java/haveno/core/provider/price/MarketPriceFeedServiceTest.java b/core/src/test/java/haveno/core/provider/price/MarketPriceFeedServiceTest.java index 9effcaa537..805a6141a1 100644 --- a/core/src/test/java/haveno/core/provider/price/MarketPriceFeedServiceTest.java +++ b/core/src/test/java/haveno/core/provider/price/MarketPriceFeedServiceTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.provider.price; diff --git a/core/src/test/java/haveno/core/support/dispute/mediation/FileTransferSessionTest.java b/core/src/test/java/haveno/core/support/dispute/mediation/FileTransferSessionTest.java new file mode 100644 index 0000000000..b34e74e251 --- /dev/null +++ b/core/src/test/java/haveno/core/support/dispute/mediation/FileTransferSessionTest.java @@ -0,0 +1,241 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.core.support.dispute.mediation; + +import haveno.network.p2p.FileTransferPart; +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.network.NetworkNode; + +import haveno.common.config.Config; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class FileTransferSessionTest implements FileTransferSession.FtpCallback { + + double notedProgressPct = -1.0; + int progressInvocations = 0; + boolean ftpCompleteStatus = false; + String testTradeId = "foo"; + int testTraderId = 123; + String testClientId = "bar"; + NetworkNode networkNode; + NodeAddress counterpartyNodeAddress; + + @BeforeEach + public void setUp() throws Exception { + new Config(); // static methods like Config.appDataDir() require config to be created once + networkNode = mock(NetworkNode.class); + when(networkNode.getNodeAddress()).thenReturn(new NodeAddress("null:0000")); + counterpartyNodeAddress = new NodeAddress("null:0000"); + } + + @Test + public void testSendCreate() { + new FileTransferSender(networkNode, counterpartyNodeAddress, testTradeId, testTraderId, testClientId, true, this); + assertEquals(0.0, notedProgressPct, 0.0); + assertEquals(1, progressInvocations); + } + + @Test + public void testCreateZip() { + FileTransferSender sender = new FileTransferSender(networkNode, counterpartyNodeAddress, testTradeId, testTraderId, testClientId, true, this); + assertEquals(0.0, notedProgressPct, 0.0); + assertEquals(1, progressInvocations); + sender.createZipFileToSend(); + File file = new File(sender.zipFilePath); + assertTrue(file.getAbsoluteFile().exists()); + assertTrue(file.getAbsoluteFile().length() > 0); + file.deleteOnExit(); + } + + @Test + public void testSendInitialize() { + // checks that the initial send request packet contains correct information + try { + int testVerifyDataSize = 13; + FileTransferSender session = initializeSession(testVerifyDataSize); + session.initSend(); + FileTransferPart ftp = session.dataAwaitingAck.get(); + assertEquals(ftp.tradeId, testTradeId); + assertTrue(ftp.uid.length() > 0); + assertEquals(0, ftp.messageData.size()); + assertEquals(ftp.seqNumOrFileLength, testVerifyDataSize); + assertEquals(-1, session.currentBlockSeqNum); + return; + } catch (IOException e) { + e.printStackTrace(); + } + fail(); + } + + @Test + public void testSendSmallFile() { + try { + int testVerifyDataSize = 13; + FileTransferSender session = initializeSession(testVerifyDataSize); + // the first block contains zero data, as it is a "request to send" + session.initSend(); + simulateAckFromPeerAndVerify(session, 0, 0, 2); + // the second block contains all the test file data (because it is a small file) + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, testVerifyDataSize, 1, 3); + // the final invocation sends no data, and wraps up the session + session.sendNextBlock(); + assertEquals(1, session.currentBlockSeqNum); + assertEquals(3, progressInvocations); + assertEquals(1.0, notedProgressPct, 0.0); + assertTrue(ftpCompleteStatus); + } catch (IOException ioe) { + ioe.printStackTrace(); + fail(); + } + } + + @Test + public void testSendOneFullBlock() { + try { + int testVerifyDataSize = FileTransferSession.FILE_BLOCK_SIZE; + FileTransferSender session = initializeSession(testVerifyDataSize); + // the first block contains zero data, as it is a "request to send" + session.initSend(); + simulateAckFromPeerAndVerify(session, 0, 0, 2); + // the second block contains all the test file data (because it is a small file) + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, testVerifyDataSize, 1, 3); + // the final invocation sends no data, and wraps up the session + session.sendNextBlock(); + assertEquals(1, session.currentBlockSeqNum); + assertEquals(3, progressInvocations); + assertEquals(1.0, notedProgressPct, 0.0); + assertTrue(ftpCompleteStatus); + } catch (IOException ioe) { + ioe.printStackTrace(); + fail(); + } + } + + @Test + public void testSendTwoFullBlocks() { + try { + int testVerifyDataSize = FileTransferSession.FILE_BLOCK_SIZE * 2; + FileTransferSender session = initializeSession(testVerifyDataSize); + // the first block contains zero data, as it is a "request to send" + session.initSend(); + simulateAckFromPeerAndVerify(session, 0, 0, 2); + // the second block contains half of the test file data + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, testVerifyDataSize / 2, 1, 3); + // the third block contains half of the test file data + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, testVerifyDataSize / 2, 2, 4); + // the final invocation sends no data, and wraps up the session + session.sendNextBlock(); + assertEquals(2, session.currentBlockSeqNum); + assertEquals(4, progressInvocations); + assertEquals(1.0, notedProgressPct, 0.0); + assertTrue(ftpCompleteStatus); + } catch (IOException ioe) { + ioe.printStackTrace(); + fail(); + } + } + + @Test + public void testSendTwoFullBlocksPlusOneByte() { + try { + int testVerifyDataSize = 1 + FileTransferSession.FILE_BLOCK_SIZE * 2; + FileTransferSender session = initializeSession(testVerifyDataSize); + // the first block contains zero data, as it is a "request to send" + session.initSend(); + simulateAckFromPeerAndVerify(session, 0, 0, 2); + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, FileTransferSession.FILE_BLOCK_SIZE, 1, 3); + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, FileTransferSession.FILE_BLOCK_SIZE, 2, 4); + // the fourth block contains one byte + session.sendNextBlock(); + simulateAckFromPeerAndVerify(session, 1, 3, 5); + // the final invocation sends no data, and wraps up the session + session.sendNextBlock(); + assertEquals(3, session.currentBlockSeqNum); + assertEquals(5, progressInvocations); + assertEquals(1.0, notedProgressPct, 0.0); + assertTrue(ftpCompleteStatus); + } catch (IOException ioe) { + ioe.printStackTrace(); + fail(); + } + } + + private FileTransferSender initializeSession(int testSize) { + try { + FileTransferSender session = new FileTransferSender(networkNode, counterpartyNodeAddress, testTradeId, testTraderId, testClientId, true, this); + // simulate a file for sending + FileWriter fileWriter = new FileWriter(session.zipFilePath); + char[] buf = new char[testSize]; + for (int x = 0; x < testSize; x++) + buf[x] = 'A'; + fileWriter.write(buf); + fileWriter.close(); + assertFalse(ftpCompleteStatus); + assertEquals(1, progressInvocations); + assertEquals(0.0, notedProgressPct, 0.0); + assertFalse(session.processAckForFilePart("not_expected_uid")); + return session; + } catch (IOException e) { + e.printStackTrace(); + } + fail(); + return null; + } + + private void simulateAckFromPeerAndVerify(FileTransferSender session, int expectedDataSize, long expectedSeqNum, int expectedProgressInvocations) { + FileTransferPart ftp = session.dataAwaitingAck.get(); + assertEquals(expectedDataSize, ftp.messageData.size()); + assertTrue(session.processAckForFilePart(ftp.uid)); + assertEquals(expectedSeqNum, session.currentBlockSeqNum); + assertEquals(expectedProgressInvocations, progressInvocations); + } + + @Override + public void onFtpProgress(double progressPct) { + notedProgressPct = progressPct; + progressInvocations++; + } + + @Override + public void onFtpComplete(FileTransferSession session) { + ftpCompleteStatus = true; + } + + @Override + public void onFtpTimeout(String status, FileTransferSession session) { + } +} diff --git a/core/src/test/java/haveno/core/trade/TradableListTest.java b/core/src/test/java/haveno/core/trade/TradableListTest.java index 87d3c194ac..7577d6365a 100644 --- a/core/src/test/java/haveno/core/trade/TradableListTest.java +++ b/core/src/test/java/haveno/core/trade/TradableListTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.trade; diff --git a/core/src/test/java/haveno/core/user/PreferencesTest.java b/core/src/test/java/haveno/core/user/PreferencesTest.java index e84ca10023..365d54732b 100644 --- a/core/src/test/java/haveno/core/user/PreferencesTest.java +++ b/core/src/test/java/haveno/core/user/PreferencesTest.java @@ -1,25 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; -import haveno.core.api.LocalMoneroNode; +import haveno.core.api.XmrLocalNode; import haveno.core.locale.CountryUtil; import haveno.core.locale.CryptoCurrency; import haveno.core.locale.CurrencyUtil; @@ -56,9 +56,9 @@ public class PreferencesTest { persistenceManager = mock(PersistenceManager.class); Config config = new Config(); - LocalMoneroNode localMoneroNode = new LocalMoneroNode(config, preferences); + XmrLocalNode xmrLocalNode = new XmrLocalNode(config, preferences); preferences = new Preferences( - persistenceManager, config, null); + persistenceManager, config, null, null); } @Test diff --git a/core/src/test/java/haveno/core/user/UserPayloadModelVOTest.java b/core/src/test/java/haveno/core/user/UserPayloadModelVOTest.java index 83aed0e9e4..445f368545 100644 --- a/core/src/test/java/haveno/core/user/UserPayloadModelVOTest.java +++ b/core/src/test/java/haveno/core/user/UserPayloadModelVOTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.user; diff --git a/core/src/test/java/haveno/core/util/ProtoUtilTest.java b/core/src/test/java/haveno/core/util/ProtoUtilTest.java index edee3c1cdf..ae224f5e00 100644 --- a/core/src/test/java/haveno/core/util/ProtoUtilTest.java +++ b/core/src/test/java/haveno/core/util/ProtoUtilTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; diff --git a/core/src/test/java/haveno/core/util/RegexValidatorTest.java b/core/src/test/java/haveno/core/util/RegexValidatorTest.java index 04c725f0ee..6d015f16bd 100644 --- a/core/src/test/java/haveno/core/util/RegexValidatorTest.java +++ b/core/src/test/java/haveno/core/util/RegexValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util; diff --git a/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java b/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java index 9ff4fdf2ca..eb8e2e124d 100644 --- a/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java +++ b/core/src/test/java/haveno/core/util/coin/CoinUtilTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.util.coin; @@ -31,11 +31,26 @@ import static org.junit.jupiter.api.Assertions.fail; public class CoinUtilTest { @Test - public void testGetFeePerBtc() { - assertEquals(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.xmrToAtomicUnits(1))); - assertEquals(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(1))); - assertEquals(HavenoUtils.xmrToAtomicUnits(0.01), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.xmrToAtomicUnits(0.1))); - assertEquals(HavenoUtils.xmrToAtomicUnits(0.015), HavenoUtils.getFeePerXmr(HavenoUtils.xmrToAtomicUnits(0.3), HavenoUtils.xmrToAtomicUnits(0.05))); + public void testGetPercentOfAmount() { + BigInteger bi = new BigInteger("703100000000"); + assertEquals(new BigInteger("105465000000"), HavenoUtils.multiply(bi, .15)); + } + + @Test + public void testGetFeePerXmr() { + assertEquals(HavenoUtils.xmrToAtomicUnits(1), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(1), 1.0)); + assertEquals(HavenoUtils.xmrToAtomicUnits(0.1), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(0.1), 1.0)); + assertEquals(HavenoUtils.xmrToAtomicUnits(0.01), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(0.1), 0.1)); + assertEquals(HavenoUtils.xmrToAtomicUnits(0.015), HavenoUtils.multiply(HavenoUtils.xmrToAtomicUnits(0.3), 0.05)); + } + + @Test + public void testParseXmr() { + String xmrStr = "0.266394780889"; + BigInteger au = HavenoUtils.parseXmr(xmrStr); + assertEquals(new BigInteger("266394780889"), au); + assertEquals(xmrStr, "" + HavenoUtils.atomicUnitsToXmr(au)); + assertEquals(xmrStr, HavenoUtils.formatXmr(au, false)); } @Test @@ -59,7 +74,7 @@ public class CoinUtilTest { @Test public void testGetAdjustedAmount() { BigInteger result = CoinUtil.getAdjustedAmount( - HavenoUtils.xmrToAtomicUnits(0.001), + HavenoUtils.xmrToAtomicUnits(0.1), Price.valueOf("USD", 1000_0000), HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(), 1); @@ -71,14 +86,14 @@ public class CoinUtilTest { try { CoinUtil.getAdjustedAmount( - BigInteger.valueOf(0), + BigInteger.ZERO, Price.valueOf("USD", 1000_0000), HavenoUtils.xmrToAtomicUnits(0.2).longValueExact(), 1); fail("Expected IllegalArgumentException to be thrown when amount is too low."); } catch (IllegalArgumentException iae) { assertEquals( - "amount needs to be above minimum of 0.0001 xmr", + "amount needs to be above minimum of 0.1 xmr", iae.getMessage(), "Unexpected exception message." ); @@ -112,7 +127,7 @@ public class CoinUtilTest { // 0.05 USD worth, which is below the factor of 1 USD, but does respect the maxTradeLimit. // Basically the given constraints (maxTradeLimit vs factor) are impossible to both fulfill.. result = CoinUtil.getAdjustedAmount( - HavenoUtils.xmrToAtomicUnits(0.001), + HavenoUtils.xmrToAtomicUnits(0.1), Price.valueOf("USD", 1000_0000), HavenoUtils.xmrToAtomicUnits(0.00005).longValueExact(), 1); diff --git a/core/src/test/java/haveno/core/xmr/nodes/BtcNetworkConfigTest.java b/core/src/test/java/haveno/core/xmr/nodes/BtcNetworkConfigTest.java index f247d439ee..e77ef46722 100644 --- a/core/src/test/java/haveno/core/xmr/nodes/BtcNetworkConfigTest.java +++ b/core/src/test/java/haveno/core/xmr/nodes/BtcNetworkConfigTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/test/java/haveno/core/xmr/nodes/XmrNodeConverterTest.java b/core/src/test/java/haveno/core/xmr/nodes/XmrNodeConverterTest.java index 439e68a696..06476ae8eb 100644 --- a/core/src/test/java/haveno/core/xmr/nodes/XmrNodeConverterTest.java +++ b/core/src/test/java/haveno/core/xmr/nodes/XmrNodeConverterTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/test/java/haveno/core/xmr/nodes/XmrNodesRepositoryTest.java b/core/src/test/java/haveno/core/xmr/nodes/XmrNodesRepositoryTest.java index 622b3fd640..3c2ca0034e 100644 --- a/core/src/test/java/haveno/core/xmr/nodes/XmrNodesRepositoryTest.java +++ b/core/src/test/java/haveno/core/xmr/nodes/XmrNodesRepositoryTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/test/java/haveno/core/xmr/nodes/XmrNodesSetupPreferencesTest.java b/core/src/test/java/haveno/core/xmr/nodes/XmrNodesSetupPreferencesTest.java index efbfce52b5..972a98e9e3 100644 --- a/core/src/test/java/haveno/core/xmr/nodes/XmrNodesSetupPreferencesTest.java +++ b/core/src/test/java/haveno/core/xmr/nodes/XmrNodesSetupPreferencesTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.nodes; diff --git a/core/src/test/java/haveno/core/xmr/wallet/RestrictionsTest.java b/core/src/test/java/haveno/core/xmr/wallet/RestrictionsTest.java index a815d506a1..9db323f022 100644 --- a/core/src/test/java/haveno/core/xmr/wallet/RestrictionsTest.java +++ b/core/src/test/java/haveno/core/xmr/wallet/RestrictionsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.core.xmr.wallet; diff --git a/daemon/src/main/java/haveno/daemon/app/HavenoDaemon.java b/daemon/src/main/java/haveno/daemon/app/HavenoDaemon.java index 300573e068..4179655f58 100644 --- a/daemon/src/main/java/haveno/daemon/app/HavenoDaemon.java +++ b/daemon/src/main/java/haveno/daemon/app/HavenoDaemon.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.app; diff --git a/daemon/src/main/java/haveno/daemon/app/HavenoDaemonMain.java b/daemon/src/main/java/haveno/daemon/app/HavenoDaemonMain.java index a4faa5ce40..df92b186c0 100644 --- a/daemon/src/main/java/haveno/daemon/app/HavenoDaemonMain.java +++ b/daemon/src/main/java/haveno/daemon/app/HavenoDaemonMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.app; diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcAccountService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcAccountService.java index 14ce7c2157..d994f500c6 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcAccountService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcAccountService.java @@ -14,17 +14,29 @@ * You should have received a copy of the GNU Affero General Public License * along with Haveno. If not, see <http://www.gnu.org/licenses/>. */ + package haveno.daemon.grpc; import com.google.common.annotations.VisibleForTesting; +import com.google.inject.Inject; import com.google.protobuf.ByteString; import haveno.common.crypto.IncorrectPasswordException; import haveno.core.api.CoreApi; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.AccountExistsReply; import haveno.proto.grpc.AccountExistsRequest; import haveno.proto.grpc.AccountGrpc.AccountImplBase; +import static haveno.proto.grpc.AccountGrpc.getAccountExistsMethod; +import static haveno.proto.grpc.AccountGrpc.getBackupAccountMethod; +import static haveno.proto.grpc.AccountGrpc.getChangePasswordMethod; +import static haveno.proto.grpc.AccountGrpc.getCloseAccountMethod; +import static haveno.proto.grpc.AccountGrpc.getCreateAccountMethod; +import static haveno.proto.grpc.AccountGrpc.getDeleteAccountMethod; +import static haveno.proto.grpc.AccountGrpc.getIsAccountOpenMethod; +import static haveno.proto.grpc.AccountGrpc.getOpenAccountMethod; +import static haveno.proto.grpc.AccountGrpc.getRestoreAccountMethod; import haveno.proto.grpc.BackupAccountReply; import haveno.proto.grpc.BackupAccountRequest; import haveno.proto.grpc.ChangePasswordReply; @@ -45,25 +57,12 @@ import haveno.proto.grpc.RestoreAccountReply; import haveno.proto.grpc.RestoreAccountRequest; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.util.HashMap; import java.util.Optional; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.AccountGrpc.getAccountExistsMethod; -import static haveno.proto.grpc.AccountGrpc.getBackupAccountMethod; -import static haveno.proto.grpc.AccountGrpc.getChangePasswordMethod; -import static haveno.proto.grpc.AccountGrpc.getCloseAccountMethod; -import static haveno.proto.grpc.AccountGrpc.getCreateAccountMethod; -import static haveno.proto.grpc.AccountGrpc.getDeleteAccountMethod; -import static haveno.proto.grpc.AccountGrpc.getIsAccountOpenMethod; -import static haveno.proto.grpc.AccountGrpc.getOpenAccountMethod; -import static haveno.proto.grpc.AccountGrpc.getRestoreAccountMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import lombok.extern.slf4j.Slf4j; @VisibleForTesting @Slf4j diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputeAgentsService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputeAgentsService.java index 99ca4fa868..75d1eef40c 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputeAgentsService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputeAgentsService.java @@ -1,25 +1,23 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; +import static haveno.proto.grpc.DisputeAgentsGrpc.DisputeAgentsImplBase; +import static haveno.proto.grpc.DisputeAgentsGrpc.getRegisterDisputeAgentMethod; +import static haveno.proto.grpc.DisputeAgentsGrpc.getUnregisterDisputeAgentMethod; import haveno.proto.grpc.RegisterDisputeAgentReply; import haveno.proto.grpc.RegisterDisputeAgentRequest; import haveno.proto.grpc.UnregisterDisputeAgentReply; import haveno.proto.grpc.UnregisterDisputeAgentRequest; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.HashMap; import java.util.Optional; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.DisputeAgentsGrpc.DisputeAgentsImplBase; -import static haveno.proto.grpc.DisputeAgentsGrpc.getRegisterDisputeAgentMethod; -import static haveno.proto.grpc.DisputeAgentsGrpc.getUnregisterDisputeAgentMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcDisputeAgentsService extends DisputeAgentsImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputesService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputesService.java index a5dd0978fa..bc7a9a0f74 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputesService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcDisputesService.java @@ -1,5 +1,6 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.common.proto.ProtoUtil; import haveno.core.api.CoreApi; @@ -7,7 +8,13 @@ import haveno.core.support.dispute.Attachment; import haveno.core.support.dispute.DisputeResult; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.DisputesGrpc.DisputesImplBase; +import static haveno.proto.grpc.DisputesGrpc.getGetDisputeMethod; +import static haveno.proto.grpc.DisputesGrpc.getGetDisputesMethod; +import static haveno.proto.grpc.DisputesGrpc.getOpenDisputeMethod; +import static haveno.proto.grpc.DisputesGrpc.getResolveDisputeMethod; +import static haveno.proto.grpc.DisputesGrpc.getSendDisputeChatMessageMethod; import haveno.proto.grpc.GetDisputeReply; import haveno.proto.grpc.GetDisputeRequest; import haveno.proto.grpc.GetDisputesReply; @@ -20,21 +27,12 @@ import haveno.proto.grpc.SendDisputeChatMessageReply; import haveno.proto.grpc.SendDisputeChatMessageRequest; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.HashMap; import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.DisputesGrpc.getGetDisputeMethod; -import static haveno.proto.grpc.DisputesGrpc.getGetDisputesMethod; -import static haveno.proto.grpc.DisputesGrpc.getOpenDisputeMethod; -import static haveno.proto.grpc.DisputesGrpc.getResolveDisputeMethod; -import static haveno.proto.grpc.DisputesGrpc.getSendDisputeChatMessageMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Slf4j public class GrpcDisputesService extends DisputesImplBase { @@ -140,9 +138,9 @@ public class GrpcDisputesService extends DisputesImplBase { new HashMap<>() {{ put(getGetDisputeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 1, SECONDS)); put(getGetDisputesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, SECONDS)); - put(getResolveDisputeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 1, SECONDS)); - put(getOpenDisputeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, SECONDS)); - put(getSendDisputeChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 2, SECONDS)); + put(getResolveDisputeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 40 : 1, SECONDS)); + put(getOpenDisputeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 1, SECONDS)); + put(getSendDisputeChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 40 : 2, SECONDS)); }} ))); } diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcErrorMessageHandler.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcErrorMessageHandler.java index 7bfcc72ef8..a24f6a59fb 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcErrorMessageHandler.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcErrorMessageHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcExceptionHandler.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcExceptionHandler.java index f45bf63587..1d3e4bf17c 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcExceptionHandler.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcExceptionHandler.java @@ -1,34 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; +import com.google.inject.Inject; +import com.google.inject.Singleton; import io.grpc.Status; -import io.grpc.StatusRuntimeException; -import io.grpc.stub.StreamObserver; -import org.slf4j.Logger; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.function.Function; -import java.util.function.Predicate; - import static io.grpc.Status.INVALID_ARGUMENT; import static io.grpc.Status.UNKNOWN; +import io.grpc.StatusRuntimeException; +import io.grpc.stub.StreamObserver; +import java.util.function.Function; +import java.util.function.Predicate; +import org.slf4j.Logger; /** * The singleton instance of this class handles any expected core api Throwable by diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcGetTradeStatisticsService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcGetTradeStatisticsService.java index 459f59f37e..04aefc0872 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcGetTradeStatisticsService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcGetTradeStatisticsService.java @@ -1,24 +1,22 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.core.trade.statistics.TradeStatistics3; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; +import static haveno.proto.grpc.GetTradeStatisticsGrpc.GetTradeStatisticsImplBase; +import static haveno.proto.grpc.GetTradeStatisticsGrpc.getGetTradeStatisticsMethod; import haveno.proto.grpc.GetTradeStatisticsReply; import haveno.proto.grpc.GetTradeStatisticsRequest; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.HashMap; import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.GetTradeStatisticsGrpc.GetTradeStatisticsImplBase; -import static haveno.proto.grpc.GetTradeStatisticsGrpc.getGetTradeStatisticsMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcGetTradeStatisticsService extends GetTradeStatisticsImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcHelpService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcHelpService.java index 2abfc11a97..1a2b880ec1 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcHelpService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcHelpService.java @@ -1,39 +1,37 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.GetMethodHelpReply; import haveno.proto.grpc.GetMethodHelpRequest; -import io.grpc.ServerInterceptor; -import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import java.util.HashMap; -import java.util.Optional; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.HelpGrpc.HelpImplBase; import static haveno.proto.grpc.HelpGrpc.getGetMethodHelpMethod; +import io.grpc.ServerInterceptor; +import io.grpc.stub.StreamObserver; +import java.util.HashMap; +import java.util.Optional; import static java.util.concurrent.TimeUnit.SECONDS; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcHelpService extends HelpImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcNotificationsService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcNotificationsService.java index 23082d0364..410ac270ce 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcNotificationsService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcNotificationsService.java @@ -1,11 +1,15 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.core.api.NotificationListener; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.NotificationMessage; import haveno.proto.grpc.NotificationsGrpc.NotificationsImplBase; +import static haveno.proto.grpc.NotificationsGrpc.getRegisterNotificationListenerMethod; +import static haveno.proto.grpc.NotificationsGrpc.getSendNotificationMethod; import haveno.proto.grpc.RegisterNotificationListenerRequest; import haveno.proto.grpc.SendNotificationReply; import haveno.proto.grpc.SendNotificationRequest; @@ -13,19 +17,13 @@ import io.grpc.Context; import io.grpc.ServerInterceptor; import io.grpc.stub.ServerCallStreamObserver; import io.grpc.stub.StreamObserver; +import java.util.HashMap; +import java.util.Optional; +import static java.util.concurrent.TimeUnit.SECONDS; import lombok.NonNull; import lombok.Value; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import java.util.HashMap; -import java.util.Optional; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.NotificationsGrpc.getRegisterNotificationListenerMethod; -import static haveno.proto.grpc.NotificationsGrpc.getSendNotificationMethod; -import static java.util.concurrent.TimeUnit.SECONDS; - @Slf4j class GrpcNotificationsService extends NotificationsImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java index 5443068c5b..7768522b23 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcOffersService.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.core.api.CoreApi; import haveno.core.api.model.OfferInfo; @@ -24,6 +25,7 @@ import haveno.core.offer.Offer; import haveno.core.offer.OpenOffer; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.CancelOfferReply; import haveno.proto.grpc.CancelOfferRequest; import haveno.proto.grpc.GetMyOfferReply; @@ -34,20 +36,6 @@ import haveno.proto.grpc.GetOfferReply; import haveno.proto.grpc.GetOfferRequest; import haveno.proto.grpc.GetOffersReply; import haveno.proto.grpc.GetOffersRequest; -import haveno.proto.grpc.PostOfferReply; -import haveno.proto.grpc.PostOfferRequest; -import io.grpc.ServerInterceptor; -import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.OffersGrpc.OffersImplBase; import static haveno.proto.grpc.OffersGrpc.getCancelOfferMethod; import static haveno.proto.grpc.OffersGrpc.getGetMyOfferMethod; @@ -55,8 +43,18 @@ import static haveno.proto.grpc.OffersGrpc.getGetMyOffersMethod; import static haveno.proto.grpc.OffersGrpc.getGetOfferMethod; import static haveno.proto.grpc.OffersGrpc.getGetOffersMethod; import static haveno.proto.grpc.OffersGrpc.getPostOfferMethod; +import haveno.proto.grpc.PostOfferReply; +import haveno.proto.grpc.PostOfferRequest; +import io.grpc.ServerInterceptor; +import io.grpc.stub.StreamObserver; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcOffersService extends OffersImplBase { @@ -142,11 +140,7 @@ class GrpcOffersService extends OffersImplBase { @Override public void postOffer(PostOfferRequest req, StreamObserver<PostOfferReply> responseObserver) { - GrpcErrorMessageHandler errorMessageHandler = - new GrpcErrorMessageHandler(getPostOfferMethod().getFullMethodName(), - responseObserver, - exceptionHandler, - log); + GrpcErrorMessageHandler errorMessageHandler = new GrpcErrorMessageHandler(getPostOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log); try { coreApi.postOffer( req.getCurrencyCode(), @@ -156,10 +150,12 @@ class GrpcOffersService extends OffersImplBase { req.getMarketPriceMarginPct(), req.getAmount(), req.getMinAmount(), - req.getBuyerSecurityDepositPct(), + req.getSecurityDepositPct(), req.getTriggerPrice(), req.getReserveExactAmount(), req.getPaymentAccountId(), + req.getIsPrivateOffer(), + req.getBuyerAsTakerWithoutDeposit(), offer -> { // This result handling consumer's accept operation will return // the new offer to the gRPC client after async placement is done. @@ -172,8 +168,7 @@ class GrpcOffersService extends OffersImplBase { responseObserver.onCompleted(); }, errorMessage -> { - if (!errorMessageHandler.isErrorHandled()) - errorMessageHandler.handleErrorMessage(errorMessage); + if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage); }); } catch (Throwable cause) { exceptionHandler.handleException(log, cause, responseObserver); @@ -183,11 +178,15 @@ class GrpcOffersService extends OffersImplBase { @Override public void cancelOffer(CancelOfferRequest req, StreamObserver<CancelOfferReply> responseObserver) { + GrpcErrorMessageHandler errorMessageHandler = new GrpcErrorMessageHandler(getCancelOfferMethod().getFullMethodName(), responseObserver, exceptionHandler, log); try { - coreApi.cancelOffer(req.getId()); - var reply = CancelOfferReply.newBuilder().build(); - responseObserver.onNext(reply); - responseObserver.onCompleted(); + coreApi.cancelOffer(req.getId(), () -> { + var reply = CancelOfferReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + }, errorMessage -> { + if (!errorMessageHandler.isErrorHandled()) errorMessageHandler.handleErrorMessage(errorMessage); + }); } catch (Throwable cause) { exceptionHandler.handleException(log, cause, responseObserver); } @@ -205,9 +204,9 @@ class GrpcOffersService extends OffersImplBase { new HashMap<>() {{ put(getGetOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, SECONDS)); put(getGetMyOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, SECONDS)); - put(getGetOffersMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 1, SECONDS)); - put(getGetMyOffersMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getPostOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 20 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getGetOffersMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 1, SECONDS)); + put(getGetMyOffersMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getPostOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 30 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); put(getCancelOfferMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); }} ))); diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcPaymentAccountsService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcPaymentAccountsService.java index dc87ae5298..ad1acce142 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcPaymentAccountsService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcPaymentAccountsService.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.core.api.CoreApi; import haveno.core.api.model.PaymentAccountForm; @@ -28,10 +29,13 @@ import haveno.core.payment.payload.PaymentMethod; import haveno.core.proto.CoreProtoResolver; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.CreateCryptoCurrencyPaymentAccountReply; import haveno.proto.grpc.CreateCryptoCurrencyPaymentAccountRequest; import haveno.proto.grpc.CreatePaymentAccountReply; import haveno.proto.grpc.CreatePaymentAccountRequest; +import haveno.proto.grpc.DeletePaymentAccountReply; +import haveno.proto.grpc.DeletePaymentAccountRequest; import haveno.proto.grpc.GetCryptoCurrencyPaymentMethodsReply; import haveno.proto.grpc.GetCryptoCurrencyPaymentMethodsRequest; import haveno.proto.grpc.GetPaymentAccountFormReply; @@ -41,25 +45,21 @@ import haveno.proto.grpc.GetPaymentAccountsRequest; import haveno.proto.grpc.GetPaymentMethodsReply; import haveno.proto.grpc.GetPaymentMethodsRequest; import haveno.proto.grpc.PaymentAccountsGrpc.PaymentAccountsImplBase; -import haveno.proto.grpc.ValidateFormFieldReply; -import haveno.proto.grpc.ValidateFormFieldRequest; -import io.grpc.ServerInterceptor; -import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import java.util.HashMap; -import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.PaymentAccountsGrpc.getCreateCryptoCurrencyPaymentAccountMethod; import static haveno.proto.grpc.PaymentAccountsGrpc.getCreatePaymentAccountMethod; import static haveno.proto.grpc.PaymentAccountsGrpc.getGetPaymentAccountFormMethod; import static haveno.proto.grpc.PaymentAccountsGrpc.getGetPaymentAccountsMethod; import static haveno.proto.grpc.PaymentAccountsGrpc.getGetPaymentMethodsMethod; +import haveno.proto.grpc.ValidateFormFieldReply; +import haveno.proto.grpc.ValidateFormFieldRequest; +import io.grpc.ServerInterceptor; +import io.grpc.stub.StreamObserver; +import java.util.HashMap; +import java.util.Optional; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcPaymentAccountsService extends PaymentAccountsImplBase { @@ -162,6 +162,19 @@ class GrpcPaymentAccountsService extends PaymentAccountsImplBase { } } + @Override + public void deletePaymentAccount(DeletePaymentAccountRequest req, + StreamObserver<DeletePaymentAccountReply> responseObserver) { + try { + coreApi.deletePaymentAccount(req.getPaymentAccountId()); + var reply = DeletePaymentAccountReply.newBuilder().build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } catch (Throwable cause) { + exceptionHandler.handleException(log, cause, responseObserver); + } + } + @Override public void getCryptoCurrencyPaymentMethods(GetCryptoCurrencyPaymentMethodsRequest req, StreamObserver<GetCryptoCurrencyPaymentMethodsReply> responseObserver) { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java index dd29b2ce2a..223b1f2874 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcPriceService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,23 +35,24 @@ package haveno.daemon.grpc; import haveno.common.config.Config; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.core.api.model.MarketDepthInfo; import haveno.core.api.model.MarketPriceInfo; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.MarketDepthReply; import haveno.proto.grpc.MarketDepthRequest; import haveno.proto.grpc.MarketPriceReply; import haveno.proto.grpc.MarketPriceRequest; import haveno.proto.grpc.MarketPricesReply; import haveno.proto.grpc.MarketPricesRequest; +import static haveno.proto.grpc.PriceGrpc.PriceImplBase; +import static haveno.proto.grpc.PriceGrpc.getGetMarketPriceMethod; import haveno.proto.grpc.PriceGrpc.PriceImplBase; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.HashMap; import java.util.List; import java.util.Optional; @@ -42,6 +60,7 @@ import java.util.Optional; import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.PriceGrpc.getGetMarketPriceMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcPriceService extends PriceImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcServer.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcServer.java index c1fbd039db..1de4580038 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcServer.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcServer.java @@ -1,35 +1,33 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.config.Config; import haveno.core.api.CoreContext; import haveno.daemon.grpc.interceptor.PasswordAuthInterceptor; import io.grpc.Server; import io.grpc.ServerBuilder; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; +import static io.grpc.ServerInterceptors.interceptForward; import java.io.IOException; import java.io.UncheckedIOException; - -import static io.grpc.ServerInterceptors.interceptForward; +import lombok.extern.slf4j.Slf4j; @Singleton @Slf4j @@ -54,8 +52,8 @@ public class GrpcServer { GrpcTradesService tradesService, GrpcWalletsService walletsService, GrpcNotificationsService notificationsService, - GrpcMoneroConnectionsService moneroConnectionsService, - GrpcMoneroNodeService moneroNodeService) { + GrpcXmrConnectionService moneroConnectionsService, + GrpcXmrNodeService moneroNodeService) { this.server = ServerBuilder.forPort(config.apiPort) .addService(interceptForward(accountService, accountService.interceptors())) .addService(interceptForward(disputeAgentsService, disputeAgentsService.interceptors())) diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcShutdownService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcShutdownService.java index 000ca3aa3e..8956ce8f8e 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcShutdownService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcShutdownService.java @@ -1,33 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.core.app.HavenoHeadlessApp; import haveno.proto.grpc.ShutdownServerGrpc; import haveno.proto.grpc.StopReply; import haveno.proto.grpc.StopRequest; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; - import static java.util.concurrent.TimeUnit.MILLISECONDS; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcShutdownService extends ShutdownServerGrpc.ShutdownServerImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java index 860f718ec4..286fccf51a 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcTradesService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,12 +34,15 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.common.config.Config; import haveno.core.api.CoreApi; import haveno.core.api.model.TradeInfo; +import static haveno.core.api.model.TradeInfo.toTradeInfo; import haveno.core.trade.Trade; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.CompleteTradeReply; import haveno.proto.grpc.CompleteTradeRequest; import haveno.proto.grpc.ConfirmPaymentReceivedReply; @@ -40,18 +60,6 @@ import haveno.proto.grpc.SendChatMessageRequest; import haveno.proto.grpc.TakeOfferReply; import haveno.proto.grpc.TakeOfferRequest; import haveno.proto.grpc.TradesGrpc.TradesImplBase; -import io.grpc.ServerInterceptor; -import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.core.api.model.TradeInfo.toTradeInfo; -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.TradesGrpc.getCompleteTradeMethod; import static haveno.proto.grpc.TradesGrpc.getConfirmPaymentReceivedMethod; import static haveno.proto.grpc.TradesGrpc.getConfirmPaymentSentMethod; @@ -61,8 +69,15 @@ import static haveno.proto.grpc.TradesGrpc.getGetTradesMethod; import static haveno.proto.grpc.TradesGrpc.getSendChatMessageMethod; import static haveno.proto.grpc.TradesGrpc.getTakeOfferMethod; import static haveno.proto.grpc.TradesGrpc.getWithdrawFundsMethod; +import io.grpc.ServerInterceptor; +import io.grpc.stub.StreamObserver; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; import static java.util.concurrent.TimeUnit.MINUTES; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; @Slf4j class GrpcTradesService extends TradesImplBase { @@ -81,9 +96,8 @@ class GrpcTradesService extends TradesImplBase { StreamObserver<GetTradeReply> responseObserver) { try { Trade trade = coreApi.getTrade(req.getTradeId()); - String role = coreApi.getTradeRole(req.getTradeId()); var reply = GetTradeReply.newBuilder() - .setTrade(toTradeInfo(trade, role).toProtoMessage()) + .setTrade(toTradeInfo(trade).toProtoMessage()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -124,6 +138,7 @@ class GrpcTradesService extends TradesImplBase { coreApi.takeOffer(req.getOfferId(), req.getPaymentAccountId(), req.getAmount(), + req.getChallenge(), trade -> { TradeInfo tradeInfo = toTradeInfo(trade); var reply = TakeOfferReply.newBuilder() @@ -243,8 +258,8 @@ class GrpcTradesService extends TradesImplBase { put(getConfirmPaymentReceivedMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); put(getCompleteTradeMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 3, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); put(getWithdrawFundsMethod().getFullMethodName(), new GrpcCallRateMeter(3, MINUTES)); - put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); - put(getSendChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 1, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getGetChatMessagesMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 4, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); + put(getSendChatMessageMethod().getFullMethodName(), new GrpcCallRateMeter(Config.baseCurrencyNetwork().isTestnet() ? 10 : 4, Config.baseCurrencyNetwork().isTestnet() ? SECONDS : MINUTES)); }} ))); } diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcVersionService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcVersionService.java index 432a821fc8..a2897d5267 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcVersionService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcVersionService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc; @@ -20,23 +20,25 @@ package haveno.daemon.grpc; import com.google.common.annotations.VisibleForTesting; import haveno.common.config.Config; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; +import static haveno.proto.grpc.GetVersionGrpc.GetVersionImplBase; +import static haveno.proto.grpc.GetVersionGrpc.getGetVersionMethod; import haveno.proto.grpc.GetVersionGrpc.GetVersionImplBase; import haveno.proto.grpc.GetVersionReply; import haveno.proto.grpc.GetVersionRequest; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.HashMap; import java.util.Optional; import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.GetVersionGrpc.getGetVersionMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import lombok.extern.slf4j.Slf4j; @VisibleForTesting @Slf4j diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcWalletsService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcWalletsService.java index 6453de4f3e..7c3ca22e3b 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcWalletsService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcWalletsService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,12 +34,15 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.core.api.CoreApi; import haveno.core.api.model.AddressBalanceInfo; +import static haveno.core.api.model.XmrTx.toXmrTx; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.CreateXmrTxReply; import haveno.proto.grpc.CreateXmrTxRequest; import haveno.proto.grpc.GetAddressBalanceReply; @@ -50,21 +70,6 @@ import haveno.proto.grpc.SetWalletPasswordRequest; import haveno.proto.grpc.UnlockWalletReply; import haveno.proto.grpc.UnlockWalletRequest; import haveno.proto.grpc.WalletsGrpc.WalletsImplBase; -import io.grpc.ServerInterceptor; -import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; -import monero.wallet.model.MoneroDestination; -import monero.wallet.model.MoneroTxWallet; - -import javax.inject.Inject; -import java.math.BigInteger; -import java.util.HashMap; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.core.api.model.XmrTx.toXmrTx; -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import static haveno.proto.grpc.WalletsGrpc.getGetAddressBalanceMethod; import static haveno.proto.grpc.WalletsGrpc.getGetBalancesMethod; import static haveno.proto.grpc.WalletsGrpc.getGetFundingAddressesMethod; @@ -72,7 +77,17 @@ import static haveno.proto.grpc.WalletsGrpc.getLockWalletMethod; import static haveno.proto.grpc.WalletsGrpc.getRemoveWalletPasswordMethod; import static haveno.proto.grpc.WalletsGrpc.getSetWalletPasswordMethod; import static haveno.proto.grpc.WalletsGrpc.getUnlockWalletMethod; +import io.grpc.ServerInterceptor; +import io.grpc.stub.StreamObserver; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import monero.wallet.model.MoneroDestination; +import monero.wallet.model.MoneroTxWallet; @Slf4j class GrpcWalletsService extends WalletsImplBase { diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcMoneroConnectionsService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcXmrConnectionService.java similarity index 73% rename from daemon/src/main/java/haveno/daemon/grpc/GrpcMoneroConnectionsService.java rename to daemon/src/main/java/haveno/daemon/grpc/GrpcXmrConnectionService.java index 4e85d318aa..a03dc5a73e 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcMoneroConnectionsService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcXmrConnectionService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,15 +34,19 @@ package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.core.api.CoreApi; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; import haveno.proto.grpc.AddConnectionReply; import haveno.proto.grpc.AddConnectionRequest; import haveno.proto.grpc.CheckConnectionReply; import haveno.proto.grpc.CheckConnectionRequest; import haveno.proto.grpc.CheckConnectionsReply; import haveno.proto.grpc.CheckConnectionsRequest; +import haveno.proto.grpc.GetAutoSwitchReply; +import haveno.proto.grpc.GetAutoSwitchRequest; import haveno.proto.grpc.GetBestAvailableConnectionReply; import haveno.proto.grpc.GetBestAvailableConnectionRequest; import haveno.proto.grpc.GetConnectionReply; @@ -38,47 +59,43 @@ import haveno.proto.grpc.SetAutoSwitchReply; import haveno.proto.grpc.SetAutoSwitchRequest; import haveno.proto.grpc.SetConnectionReply; import haveno.proto.grpc.SetConnectionRequest; -import haveno.proto.grpc.StartCheckingConnectionsReply; -import haveno.proto.grpc.StartCheckingConnectionsRequest; -import haveno.proto.grpc.StopCheckingConnectionsReply; -import haveno.proto.grpc.StopCheckingConnectionsRequest; +import haveno.proto.grpc.StartCheckingConnectionReply; +import haveno.proto.grpc.StartCheckingConnectionRequest; +import haveno.proto.grpc.StopCheckingConnectionReply; +import haveno.proto.grpc.StopCheckingConnectionRequest; import haveno.proto.grpc.UrlConnection; +import static haveno.proto.grpc.XmrConnectionsGrpc.XmrConnectionsImplBase; +import static haveno.proto.grpc.XmrConnectionsGrpc.getAddConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getCheckConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getCheckConnectionsMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getGetBestAvailableConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getGetConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getGetConnectionsMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getRemoveConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getSetAutoSwitchMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getSetConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getStartCheckingConnectionMethod; +import static haveno.proto.grpc.XmrConnectionsGrpc.getStopCheckingConnectionMethod; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; -import lombok.extern.slf4j.Slf4j; -import monero.common.MoneroRpcConnection; - -import javax.inject.Inject; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.MoneroConnectionsGrpc.MoneroConnectionsImplBase; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getAddConnectionMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getCheckConnectionMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getCheckConnectionsMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getGetBestAvailableConnectionMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getGetConnectionMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getGetConnectionsMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getRemoveConnectionMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getSetAutoSwitchMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getSetConnectionMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getStartCheckingConnectionsMethod; -import static haveno.proto.grpc.MoneroConnectionsGrpc.getStopCheckingConnectionsMethod; import static java.util.concurrent.TimeUnit.SECONDS; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroRpcConnection; @Slf4j -class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { +class GrpcXmrConnectionService extends XmrConnectionsImplBase { private final CoreApi coreApi; private final GrpcExceptionHandler exceptionHandler; @Inject - public GrpcMoneroConnectionsService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler) { + public GrpcXmrConnectionService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler) { this.coreApi = coreApi; this.exceptionHandler = exceptionHandler; } @@ -87,7 +104,7 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void addConnection(AddConnectionRequest request, StreamObserver<AddConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { - coreApi.addMoneroConnection(toMoneroRpcConnection(request.getConnection())); + coreApi.addXmrConnection(toMoneroRpcConnection(request.getConnection())); return AddConnectionReply.newBuilder().build(); }); } @@ -96,7 +113,7 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void removeConnection(RemoveConnectionRequest request, StreamObserver<RemoveConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { - coreApi.removeMoneroConnection(validateUri(request.getUrl())); + coreApi.removeXmrConnection(validateUri(request.getUrl())); return RemoveConnectionReply.newBuilder().build(); }); } @@ -105,7 +122,7 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void getConnection(GetConnectionRequest request, StreamObserver<GetConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { - UrlConnection replyConnection = toUrlConnection(coreApi.getMoneroConnection()); + UrlConnection replyConnection = toUrlConnection(coreApi.getXmrConnection()); GetConnectionReply.Builder builder = GetConnectionReply.newBuilder(); if (replyConnection != null) { builder.setConnection(replyConnection); @@ -118,9 +135,9 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void getConnections(GetConnectionsRequest request, StreamObserver<GetConnectionsReply> responseObserver) { handleRequest(responseObserver, () -> { - List<MoneroRpcConnection> connections = coreApi.getMoneroConnections(); + List<MoneroRpcConnection> connections = coreApi.getXmrConnections(); List<UrlConnection> replyConnections = connections.stream() - .map(GrpcMoneroConnectionsService::toUrlConnection).collect(Collectors.toList()); + .map(GrpcXmrConnectionService::toUrlConnection).collect(Collectors.toList()); return GetConnectionsReply.newBuilder().addAllConnections(replyConnections).build(); }); } @@ -130,10 +147,10 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { StreamObserver<SetConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { if (request.getUrl() != null && !request.getUrl().isEmpty()) - coreApi.setMoneroConnection(validateUri(request.getUrl())); + coreApi.setXmrConnection(validateUri(request.getUrl())); else if (request.hasConnection()) - coreApi.setMoneroConnection(toMoneroRpcConnection(request.getConnection())); - else coreApi.setMoneroConnection((MoneroRpcConnection) null); // disconnect from client + coreApi.setXmrConnection(toMoneroRpcConnection(request.getConnection())); + else coreApi.setXmrConnection((MoneroRpcConnection) null); // disconnect from client return SetConnectionReply.newBuilder().build(); }); } @@ -142,7 +159,7 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void checkConnection(CheckConnectionRequest request, StreamObserver<CheckConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { - MoneroRpcConnection connection = coreApi.checkMoneroConnection(); + MoneroRpcConnection connection = coreApi.checkXmrConnection(); UrlConnection replyConnection = toUrlConnection(connection); CheckConnectionReply.Builder builder = CheckConnectionReply.newBuilder(); if (replyConnection != null) { @@ -156,30 +173,30 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void checkConnections(CheckConnectionsRequest request, StreamObserver<CheckConnectionsReply> responseObserver) { handleRequest(responseObserver, () -> { - List<MoneroRpcConnection> connections = coreApi.checkMoneroConnections(); + List<MoneroRpcConnection> connections = coreApi.checkXmrConnections(); List<UrlConnection> replyConnections = connections.stream() - .map(GrpcMoneroConnectionsService::toUrlConnection).collect(Collectors.toList()); + .map(GrpcXmrConnectionService::toUrlConnection).collect(Collectors.toList()); return CheckConnectionsReply.newBuilder().addAllConnections(replyConnections).build(); }); } @Override - public void startCheckingConnections(StartCheckingConnectionsRequest request, - StreamObserver<StartCheckingConnectionsReply> responseObserver) { + public void startCheckingConnection(StartCheckingConnectionRequest request, + StreamObserver<StartCheckingConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { int refreshMillis = request.getRefreshPeriod(); Long refreshPeriod = refreshMillis == 0 ? null : (long) refreshMillis; - coreApi.startCheckingMoneroConnection(refreshPeriod); - return StartCheckingConnectionsReply.newBuilder().build(); + coreApi.startCheckingXmrConnection(refreshPeriod); + return StartCheckingConnectionReply.newBuilder().build(); }); } @Override - public void stopCheckingConnections(StopCheckingConnectionsRequest request, - StreamObserver<StopCheckingConnectionsReply> responseObserver) { + public void stopCheckingConnection(StopCheckingConnectionRequest request, + StreamObserver<StopCheckingConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { - coreApi.stopCheckingMoneroConnection(); - return StopCheckingConnectionsReply.newBuilder().build(); + coreApi.stopCheckingXmrConnection(); + return StopCheckingConnectionReply.newBuilder().build(); }); } @@ -187,7 +204,7 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void getBestAvailableConnection(GetBestAvailableConnectionRequest request, StreamObserver<GetBestAvailableConnectionReply> responseObserver) { handleRequest(responseObserver, () -> { - MoneroRpcConnection connection = coreApi.getBestAvailableMoneroConnection(); + MoneroRpcConnection connection = coreApi.getBestAvailableXmrConnection(); UrlConnection replyConnection = toUrlConnection(connection); GetBestAvailableConnectionReply.Builder builder = GetBestAvailableConnectionReply.newBuilder(); if (replyConnection != null) { @@ -201,11 +218,21 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { public void setAutoSwitch(SetAutoSwitchRequest request, StreamObserver<SetAutoSwitchReply> responseObserver) { handleRequest(responseObserver, () -> { - coreApi.setMoneroConnectionAutoSwitch(request.getAutoSwitch()); + coreApi.setXmrConnectionAutoSwitch(request.getAutoSwitch()); return SetAutoSwitchReply.newBuilder().build(); }); } + @Override + public void getAutoSwitch(GetAutoSwitchRequest request, + StreamObserver<GetAutoSwitchReply> responseObserver) { + handleRequest(responseObserver, () -> { + GetAutoSwitchReply.Builder builder = GetAutoSwitchReply.newBuilder(); + builder.setAutoSwitch(coreApi.getXmrConnectionAutoSwitch()); + return builder.build(); + }); + } + private <_Reply> void handleRequest(StreamObserver<_Reply> responseObserver, RpcRequestHandler<_Reply> handler) { try { @@ -285,8 +312,8 @@ class GrpcMoneroConnectionsService extends MoneroConnectionsImplBase { put(getSetConnectionMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); put(getCheckConnectionMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); put(getCheckConnectionsMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); - put(getStartCheckingConnectionsMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); - put(getStopCheckingConnectionsMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); + put(getStartCheckingConnectionMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); + put(getStopCheckingConnectionMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); put(getGetBestAvailableConnectionMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); put(getSetAutoSwitchMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); }} diff --git a/daemon/src/main/java/haveno/daemon/grpc/GrpcMoneroNodeService.java b/daemon/src/main/java/haveno/daemon/grpc/GrpcXmrNodeService.java similarity index 63% rename from daemon/src/main/java/haveno/daemon/grpc/GrpcMoneroNodeService.java rename to daemon/src/main/java/haveno/daemon/grpc/GrpcXmrNodeService.java index b08cbe5188..7df9ae4602 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/GrpcMoneroNodeService.java +++ b/daemon/src/main/java/haveno/daemon/grpc/GrpcXmrNodeService.java @@ -14,55 +14,54 @@ * You should have received a copy of the GNU Affero General Public License * along with Haveno. If not, see <http://www.gnu.org/licenses/>. */ + package haveno.daemon.grpc; +import com.google.inject.Inject; import haveno.core.api.CoreApi; -import haveno.core.xmr.MoneroNodeSettings; +import haveno.core.xmr.XmrNodeSettings; import haveno.daemon.grpc.interceptor.CallRateMeteringInterceptor; import haveno.daemon.grpc.interceptor.GrpcCallRateMeter; -import haveno.proto.grpc.GetMoneroNodeSettingsReply; -import haveno.proto.grpc.GetMoneroNodeSettingsRequest; -import haveno.proto.grpc.IsMoneroNodeOnlineReply; -import haveno.proto.grpc.IsMoneroNodeOnlineRequest; -import haveno.proto.grpc.MoneroNodeGrpc.MoneroNodeImplBase; -import haveno.proto.grpc.StartMoneroNodeReply; -import haveno.proto.grpc.StartMoneroNodeRequest; -import haveno.proto.grpc.StopMoneroNodeReply; -import haveno.proto.grpc.StopMoneroNodeRequest; +import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; +import haveno.proto.grpc.GetXmrNodeSettingsReply; +import haveno.proto.grpc.GetXmrNodeSettingsRequest; +import haveno.proto.grpc.IsXmrNodeOnlineReply; +import haveno.proto.grpc.IsXmrNodeOnlineRequest; +import haveno.proto.grpc.StartXmrNodeReply; +import haveno.proto.grpc.StartXmrNodeRequest; +import haveno.proto.grpc.StopXmrNodeReply; +import haveno.proto.grpc.StopXmrNodeRequest; +import haveno.proto.grpc.XmrNodeGrpc.XmrNodeImplBase; +import static haveno.proto.grpc.XmrNodeGrpc.getGetXmrNodeSettingsMethod; +import static haveno.proto.grpc.XmrNodeGrpc.getIsXmrNodeOnlineMethod; +import static haveno.proto.grpc.XmrNodeGrpc.getStartXmrNodeMethod; +import static haveno.proto.grpc.XmrNodeGrpc.getStopXmrNodeMethod; import io.grpc.ServerInterceptor; import io.grpc.stub.StreamObserver; +import java.util.HashMap; +import java.util.Optional; +import static java.util.concurrent.TimeUnit.SECONDS; import lombok.extern.slf4j.Slf4j; import monero.common.MoneroError; -import javax.inject.Inject; -import java.util.HashMap; -import java.util.Optional; - -import static haveno.daemon.grpc.interceptor.GrpcServiceRateMeteringConfig.getCustomRateMeteringInterceptor; -import static haveno.proto.grpc.MoneroNodeGrpc.getGetMoneroNodeSettingsMethod; -import static haveno.proto.grpc.MoneroNodeGrpc.getIsMoneroNodeOnlineMethod; -import static haveno.proto.grpc.MoneroNodeGrpc.getStartMoneroNodeMethod; -import static haveno.proto.grpc.MoneroNodeGrpc.getStopMoneroNodeMethod; -import static java.util.concurrent.TimeUnit.SECONDS; - @Slf4j -public class GrpcMoneroNodeService extends MoneroNodeImplBase { +public class GrpcXmrNodeService extends XmrNodeImplBase { private final CoreApi coreApi; private final GrpcExceptionHandler exceptionHandler; @Inject - public GrpcMoneroNodeService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler) { + public GrpcXmrNodeService(CoreApi coreApi, GrpcExceptionHandler exceptionHandler) { this.coreApi = coreApi; this.exceptionHandler = exceptionHandler; } @Override - public void isMoneroNodeOnline(IsMoneroNodeOnlineRequest request, - StreamObserver<IsMoneroNodeOnlineReply> responseObserver) { + public void isXmrNodeOnline(IsXmrNodeOnlineRequest request, + StreamObserver<IsXmrNodeOnlineReply> responseObserver) { try { - var reply = IsMoneroNodeOnlineReply.newBuilder() - .setIsRunning(coreApi.isMoneroNodeOnline()) + var reply = IsXmrNodeOnlineReply.newBuilder() + .setIsRunning(coreApi.isXmrNodeOnline()) .build(); responseObserver.onNext(reply); responseObserver.onCompleted(); @@ -72,11 +71,11 @@ public class GrpcMoneroNodeService extends MoneroNodeImplBase { } @Override - public void getMoneroNodeSettings(GetMoneroNodeSettingsRequest request, - StreamObserver<GetMoneroNodeSettingsReply> responseObserver) { + public void getXmrNodeSettings(GetXmrNodeSettingsRequest request, + StreamObserver<GetXmrNodeSettingsReply> responseObserver) { try { - var settings = coreApi.getMoneroNodeSettings(); - var builder = GetMoneroNodeSettingsReply.newBuilder(); + var settings = coreApi.getXmrNodeSettings(); + var builder = GetXmrNodeSettingsReply.newBuilder(); if (settings != null) { builder.setSettings(settings.toProtoMessage()); } @@ -89,12 +88,12 @@ public class GrpcMoneroNodeService extends MoneroNodeImplBase { } @Override - public void startMoneroNode(StartMoneroNodeRequest request, - StreamObserver<StartMoneroNodeReply> responseObserver) { + public void startXmrNode(StartXmrNodeRequest request, + StreamObserver<StartXmrNodeReply> responseObserver) { try { var settings = request.getSettings(); - coreApi.startMoneroNode(MoneroNodeSettings.fromProto(settings)); - var reply = StartMoneroNodeReply.newBuilder().build(); + coreApi.startXmrNode(XmrNodeSettings.fromProto(settings)); + var reply = StartXmrNodeReply.newBuilder().build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } catch (MoneroError me) { @@ -105,11 +104,11 @@ public class GrpcMoneroNodeService extends MoneroNodeImplBase { } @Override - public void stopMoneroNode(StopMoneroNodeRequest request, - StreamObserver<StopMoneroNodeReply> responseObserver) { + public void stopXmrNode(StopXmrNodeRequest request, + StreamObserver<StopXmrNodeReply> responseObserver) { try { - coreApi.stopMoneroNode(); - var reply = StopMoneroNodeReply.newBuilder().build(); + coreApi.stopXmrNode(); + var reply = StopXmrNodeReply.newBuilder().build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } catch (MoneroError me) { @@ -141,10 +140,10 @@ public class GrpcMoneroNodeService extends MoneroNodeImplBase { .or(() -> Optional.of(CallRateMeteringInterceptor.valueOf( new HashMap<>() {{ int allowedCallsPerTimeWindow = 10; - put(getIsMoneroNodeOnlineMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); - put(getGetMoneroNodeSettingsMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); - put(getStartMoneroNodeMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); - put(getStopMoneroNodeMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); + put(getIsXmrNodeOnlineMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); + put(getGetXmrNodeSettingsMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); + put(getStartXmrNodeMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); + put(getStopXmrNodeMethod().getFullMethodName(), new GrpcCallRateMeter(allowedCallsPerTimeWindow, SECONDS)); }} ))); } diff --git a/daemon/src/main/java/haveno/daemon/grpc/interceptor/CallRateMeteringInterceptor.java b/daemon/src/main/java/haveno/daemon/grpc/interceptor/CallRateMeteringInterceptor.java index 7d14086904..850776d48f 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/interceptor/CallRateMeteringInterceptor.java +++ b/daemon/src/main/java/haveno/daemon/grpc/interceptor/CallRateMeteringInterceptor.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc.interceptor; diff --git a/daemon/src/main/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfig.java b/daemon/src/main/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfig.java index 15798f03bf..8ed1698062 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfig.java +++ b/daemon/src/main/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfig.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc.interceptor; diff --git a/daemon/src/main/java/haveno/daemon/grpc/interceptor/PasswordAuthInterceptor.java b/daemon/src/main/java/haveno/daemon/grpc/interceptor/PasswordAuthInterceptor.java index 4eccc52f11..d47b8c83c4 100644 --- a/daemon/src/main/java/haveno/daemon/grpc/interceptor/PasswordAuthInterceptor.java +++ b/daemon/src/main/java/haveno/daemon/grpc/interceptor/PasswordAuthInterceptor.java @@ -1,34 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc.interceptor; +import com.google.inject.Inject; import haveno.common.config.Config; import io.grpc.Metadata; +import static io.grpc.Metadata.ASCII_STRING_MARSHALLER; +import static io.grpc.Metadata.Key; import io.grpc.ServerCall; import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; -import io.grpc.StatusRuntimeException; - -import javax.inject.Inject; - -import static io.grpc.Metadata.ASCII_STRING_MARSHALLER; -import static io.grpc.Metadata.Key; import static io.grpc.Status.UNAUTHENTICATED; +import io.grpc.StatusRuntimeException; import static java.lang.String.format; /** diff --git a/daemon/src/test/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfigTest.java b/daemon/src/test/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfigTest.java index af631dac04..58ab15d2f7 100644 --- a/daemon/src/test/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfigTest.java +++ b/daemon/src/test/java/haveno/daemon/grpc/interceptor/GrpcServiceRateMeteringConfigTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.daemon.grpc.interceptor; diff --git a/desktop/package/README.md b/desktop/package/README.md index f7a1d537b8..3da91d2507 100644 --- a/desktop/package/README.md +++ b/desktop/package/README.md @@ -1,35 +1,41 @@ Follow these instructions to create installers for the Haveno Java desktop application on each platform. -## Build Haveno binaries - -`./gradlew clean build --refresh-keys --refresh-dependencies` (or `make clean && skip-tests` after refreshed) - -## Create installer and install on each platform - > **Note** > These steps will delete the previously built Haveno binaries, so they'll need rebuilt after. -#### Linux +## Linux -1. `./gradlew packageInstallers` -2. Confirm prompts. -3. Path to installer printed at end. Execute to install: `sudo dpkg -i <path>.deb` or open `<path>.deb` with Software Install. +From x86_64 machine: + +1. `sudo apt-get update` +2. `sudo apt install -y rpm libfuse2 flatpak flatpak-builder appstream` +3. `flatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepo` +4. `./gradlew clean build --refresh-keys --refresh-dependencies` (or `make clean && skip-tests` after refreshed) +5. `./gradlew packageInstallers` +6. Confirm prompts. +7. Path to installer is printed at the end. Execute to install, e.g.: `sudo dpkg -i <path>.deb` or open `<path>.deb` with Software Install. + +Note: Please see [flatpak.md](../../docs/flatpak.md) for information on +distributing Haveno via Flatpak. Haveno data folder on Linux: `/home/<username>/.local/share/Haveno/` -#### Mac +## macOS -1. `./gradlew packageInstallers` -2. Confirm prompts. -3. Path to installer printed at end. -4. `open <path>` -5. Open installer and drag Haveno.app to Applications. -6. `sudo xattr -rd com.apple.quarantine /Applications/Haveno.app` -7. Right click /Applications/Haveno.app > Open. Repeat again if necessary, despite being "damaged". +From x86_64 machine: + +1. `./gradlew clean build --refresh-keys --refresh-dependencies` (or `make clean && skip-tests` after refreshed) +2. `./gradlew packageInstallers` +3. Confirm prompts. +4. Path to installer printed at end. +5. `open <path>` +6. Open installer and drag Haveno.app to Applications. +7. `sudo xattr -rd com.apple.quarantine /Applications/Haveno.app` +8. Right click /Applications/Haveno.app > Open. Repeat again if necessary, despite being "damaged". Haveno data folder on Mac: `/Users/<username>/Library/Application Support/Haveno/` -#### Windows +## Windows 1. Enable .NET Framework 3.5: 1. Open the Control Panel on your Windows system. @@ -40,41 +46,42 @@ Haveno data folder on Mac: `/Users/<username>/Library/Application Support/Haveno 6. Click "OK" to save the changes and exit the dialog box. 7. Windows will download and install the required files and components to enable the .NET Framework 3.5. This may take several minutes, depending on your internet connection speed and system configuration. 8. Once the installation is complete, you will need to restart your computer to apply the changes. -2. Install wix: https://wixtoolset.org +2. Install Wix Toolset 3: <https://github.com/wixtoolset/wix3/releases/tag/wix314rtm> 3. Open MSYS2 for the following commands. -4. `export PATH=$PATH:$JAVA_HOME/bin:"C:\Program Files (x86)\WiX Toolset v3.11\bin"` -5. `./gradlew packageInstallers` -6. Confirm prompts. -7. Path to installer printed at end. Execute to install. +4. `export PATH=$PATH:$JAVA_HOME/bin:"C:\Program Files (x86)\WiX Toolset v3.14\bin"` +5. `./gradlew clean build --refresh-keys --refresh-dependencies` (or `make clean && skip-tests` after refreshed) +6. `./gradlew packageInstallers` +7. Confirm prompts. +8. Path to installer is printed at the end. Execute to install. Haveno data folder on Windows: `~\AppData\Roaming\Haveno\` -## Copy installer and rebuild Haveno binaries +## Copying installer and rebuilding Haveno binaries 1. Copy the installer to a safe location because it will be deleted in the next step. 2. `make clean && make` (or `make clean && make skip-tests`) to rebuild Haveno apps. - ## Additional Notes ### Icons -Icons (Haveno.zip) were obtained from https://github.com/haveno-dex/haveno-meta/issues/1#issuecomment-819741689. +Icons (Haveno.zip) were obtained from <https://github.com/haveno-dex/haveno-meta/issues/1#issuecomment-819741689>. -#### Linux +### Building for Linux The linux package requires the correct packaging tools installed. You may run into the following errors: -``` +```sh Error: Invalid or unsupported type: [deb] ``` -``` + +```sh Error: Invalid or unsupported type: [rpm] ``` On Ubuntu, resolve by running `sudo apt install rpm`. For deb, ensure dpkg is installed. -``` +```sh Exception in thread "main" java.io.IOException: Failed to rename /tmp/Haveno-stripped15820156885694375398.tmp to /storage/src/haveno/desktop/build/libs/fatJar/desktop-1.0.0-SNAPSHOT-all.jar at haveno.tools.Utils.renameFile(Utils.java:36) at io.github.zlika.reproducible.StipZipFile.strip(StipZipFile.java:35) @@ -84,20 +91,21 @@ Exception in thread "main" java.io.IOException: Failed to rename /tmp/Haveno-str This may happen if the source folder is on a different hard drive than the system `tmp` folder. The tools-1.0.jar calls renameTo to rename the deterministic jar back to the fat jar location. You can temporarily change your temp directory on linux: -``` +```sh export _JAVA_OPTIONS="-Djava.io.tmpdir=/storage/tmp" ``` -#### MacOs +### Building for macOS -Svg was converted into a 1024x1024 pixel PNG using https://webkul.github.io/myscale/, then converted to icns for macosx -here https://cloudconvert.com/png-to-icns +Svg was converted into a 1024x1024 pixel PNG using +<https://webkul.github.io/myscale/>, then converted to icns for macosx +here <https://cloudconvert.com/png-to-icns> -##### Known Issues +#### Known Issues Signing is not implemented. -#### Windows +### Building for Windows Pngs were resized and pasted into the WixUi images using paint. [CloudConvert](https://cloudconvert.com) was used to convert the Haveno png icon to ico. diff --git a/desktop/package/linux/Haveno.AppDir/.DirIcon b/desktop/package/linux/Haveno.AppDir/.DirIcon new file mode 120000 index 0000000000..37b10e3982 --- /dev/null +++ b/desktop/package/linux/Haveno.AppDir/.DirIcon @@ -0,0 +1 @@ +../haveno.png \ No newline at end of file diff --git a/desktop/package/linux/Haveno.AppDir/exchange.haveno.Haveno.desktop b/desktop/package/linux/Haveno.AppDir/exchange.haveno.Haveno.desktop new file mode 120000 index 0000000000..3507a5b0f0 --- /dev/null +++ b/desktop/package/linux/Haveno.AppDir/exchange.haveno.Haveno.desktop @@ -0,0 +1 @@ +../Haveno.desktop \ No newline at end of file diff --git a/desktop/package/linux/Haveno.AppDir/exchange.haveno.Haveno.svg b/desktop/package/linux/Haveno.AppDir/exchange.haveno.Haveno.svg new file mode 120000 index 0000000000..3fe12c49f8 --- /dev/null +++ b/desktop/package/linux/Haveno.AppDir/exchange.haveno.Haveno.svg @@ -0,0 +1 @@ +../haveno.svg \ No newline at end of file diff --git a/desktop/package/linux/Haveno.desktop b/desktop/package/linux/Haveno.desktop new file mode 100644 index 0000000000..b6d62c222c --- /dev/null +++ b/desktop/package/linux/Haveno.desktop @@ -0,0 +1,14 @@ +[Desktop Entry] +Comment=A decentralized, Tor-based, P2P Monero exchange network. +Exec=sh -c "PATH=\"\\$HOME/.local/bin:\\$PATH\"; bin/Haveno %u" +GenericName[en_US]=Monero Exchange +GenericName=Monero Exchange +Icon=exchange.haveno.Haveno +Categories=Office;Finance;Java;P2P; +Name[en_US]=Haveno +Name=Haveno +Terminal=false +Type=Application +MimeType= +X-AppImage-Name=Haveno +StartupWMClass=Haveno diff --git a/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml b/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml new file mode 100644 index 0000000000..6805134589 --- /dev/null +++ b/desktop/package/linux/exchange.haveno.Haveno.metainfo.xml @@ -0,0 +1,65 @@ +<?xml version="1.0" encoding="UTF-8"?> +<component type="desktop-application"> + <id>exchange.haveno.Haveno</id> + <!-- <icon type="stock">exchange.haveno.Haveno</icon> --> + <launchable type="desktop-id">exchange.haveno.Haveno.desktop</launchable> + <name>Haveno</name> + <summary>Decentralized P2P exchange built on Monero and Tor</summary> + <categories> + <category>Office</category> + <category>Finance</category> + <category>P2P</category> + </categories> + <keywords> + <keyword>cryptocurrency</keyword> + <keyword>monero</keyword> + </keywords> + + <metadata_license>CC-BY-4.0</metadata_license> + <project_license>AGPL-3.0-only</project_license> + <branding> + <color type="primary" scheme_preference="light">#e5a29f</color> + <color type="primary" scheme_preference="dark">#562c63</color> + </branding> + <supports> + <control>pointing</control> + <control>keyboard</control> + <control>touch</control> + </supports> + + <description> + <p>Haveno (pronounced ha‧ve‧no) is a platform for people who want to exchange Monero for fiat currencies like EUR, GBP, and USD or other cryptocurrencies like BTC, ETH, and BCH.</p> + <ul> + <li>All communications are routed through Tor, to preserve your privacy + </li> + <li>Trades are peer-to-peer: trades on Haveno will happen between people only, there is no central authority. + </li> + <li>Trades are non-custodial: Haveno provides arbitration in case something goes wrong during the trade, but we will never have access to your funds. + </li> + <li>There is No token, because we don't need it. Transactions between traders are secured by non-custodial multisignature transactions on the Monero network. + </li> + </ul> + </description> + <screenshots> + <screenshot type="default"> + <image>https://github.com/haveno-dex/haveno/blob/master/desktop/package/linux/preview.png</image> + <caption>Recent Trades page</caption> + </screenshot> + </screenshots> + + <developer id="exchange.haveno"> + <name>woodser</name> + </developer> + <url type="homepage">https://haveno.exchange</url> + <url type="bugtracker">https://github.com/haveno-dex/haveno/issues</url> + <content_rating type="oars-1.1"> + <content_attribute id="social-chat">moderate</content_attribute> + <content_attribute id="social-info">moderate</content_attribute> + <content_attribute id="social-contacts">intense</content_attribute> + <content_attribute id="money-purchasing">intense</content_attribute> + </content_rating> + + <releases> + <release version="1.0.14" date="2024-11-15"/> + </releases> +</component> diff --git a/desktop/package/linux/exchange.haveno.Haveno.yml b/desktop/package/linux/exchange.haveno.Haveno.yml new file mode 100644 index 0000000000..50843f8f75 --- /dev/null +++ b/desktop/package/linux/exchange.haveno.Haveno.yml @@ -0,0 +1,52 @@ +id: exchange.haveno.Haveno +runtime: org.freedesktop.Platform +runtime-version: "23.08" +sdk: org.freedesktop.Sdk +sdk-extensions: + - org.freedesktop.Sdk.Extension.openjdk21 +command: /app/bin/Haveno +modules: + - name: openjdk + buildsystem: simple + build-commands: + - /usr/lib/sdk/openjdk21/install.sh + - name: Haveno + buildsystem: simple + sources: + # - type: git + # url: https://github.com/haveno-dex/haveno + - type: dir + path: build + - type: file + path: package/linux/Haveno.desktop + - type: file + path: package/linux/exchange.haveno.Haveno.metainfo.xml + - type: file + path: package/linux/icon.png + build-commands: + - ls + - pwd + # TODO: consider switching from reading from a deb to reading from jpackage's image + - mv temp-*/binaries/haveno_*.deb haveno.deb + - ar x haveno.deb + - tar xf data.tar.* + - cp -r opt/haveno/lib /app/lib + - install -D opt/haveno/bin/Haveno /app/bin/Haveno + - mkdir -p /app/share/icons/hicolor/128x128/apps/ + - mkdir -p /app/share/applications/ + - mkdir -p /app/share/metainfo/ + - mv icon.png /app/share/icons/hicolor/128x128/apps/exchange.haveno.Haveno.png + - mv Haveno.desktop /app/share/applications/exchange.haveno.Haveno.desktop + - mv exchange.haveno.Haveno.metainfo.xml /app/share/metainfo/ + +# TODO: xdg-open fails +finish-args: + - --env=PATH=/app/jre/bin:/usr/bin:$PATH + # - --env=JAVA_HOME=/app/jre + - --env=JAVA_HOME=/usr/lib/sdk/openjdk21/ + - --device=dri + - --talk-name=org.freedesktop.Notifications + - --talk-name=org.freedesktop.secrets + - --share=network + - --share=ipc + - --socket=x11 diff --git a/desktop/package/linux/haveno.png b/desktop/package/linux/haveno.png new file mode 100644 index 0000000000..681ac6acdb Binary files /dev/null and b/desktop/package/linux/haveno.png differ diff --git a/desktop/package/linux/haveno.svg b/desktop/package/linux/haveno.svg new file mode 100644 index 0000000000..6c94a5b6ea --- /dev/null +++ b/desktop/package/linux/haveno.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800"><defs><style>.cls-1{fill:#f1482d;}.cls-2,.cls-3{fill:#232075;}.cls-2{opacity:0.22;}.cls-3{opacity:0.44;}.cls-4{fill:#fff;}</style></defs><title>haveno_logo_icon</title><g id="Layer_1_copy" data-name="Layer 1 copy"><polygon class="cls-1" points="469.37 155.08 499.53 162.84 511.62 177.19 557.71 207.42 563.75 212.71 576.6 268.62 585.67 276.94 590.96 270.13 638.25 296.94 654.12 312.05 646.12 375.92 630.25 376.68 630.25 386.5 646.12 432.59 584.91 556.51 581.89 568.6 547.89 591.27 504.06 616.96 468.37 618.08 434.54 647.19 358.23 666.08 349.92 639.63 318.18 632.08 170.08 518.73 188.97 501.35 167.06 486.24 149.37 331.08 232.04 173.41 268.31 162.84 275.11 168.13 290.98 168.88 303.07 158.3 329.37 138.08 379.37 125.08 395.37 160.08 422.37 186.08 469.37 155.08"/><path class="cls-2" d="M510.93,216.49c24.31,7.8,36.09,30,57.63,72,23.3,45.44,35,68.16,26.9,88-9.52,23.41-38.88,31.5-35.86,48,1.51,8.27,9.51,9.62,11.52,20,2.61,13.4-7.81,26.12-11.52,30.66-28.3,34.58-68,16.05-103.74,49.32-12.79,11.91-6.63,13.27-32,44-22.74,27.53-34.11,41.29-48.66,44-28.25,5.24-58.53-24.33-73-49.32-18.74-32.38-4-45.06-21.77-78.65-20.61-38.91-46.78-33.88-61.47-70.64-10.55-26.37-6-51.37-2.57-70.65,3.21-17.82,13.66-75.79,52.51-94.64,37.83-18.37,56.84,22.57,110.14,8,33-9,41.66-29.07,89.65-38.65C486.59,214.25,497.55,212.2,510.93,216.49Z"/><path class="cls-3" d="M413.19,283c-32.8.14-104,.43-140.55,35.6-2.81,2.7-31,30.48-16.53,49.39,14,18.27,53.54,9.53,71.1,28.71,14.09,15.39-6,26.91-1.65,58.57,3.33,24.47,21.26,61.11,56.22,66.61,25.76,4.06,50.3-10.45,57.87-14.93,37.64-22.26,41.7-57.59,43-71.2,4.72-49.9-31.83-68.23-11.57-99.92,12.89-20.17,35.64-25.19,31.41-35.61C495.35,282.64,424.89,282.94,413.19,283Z"/><path class="cls-3" d="M342.76,336.08c6.17-12.18,41.43-22.94,66.07-14,14.5,5.26,22.66,16.39,20.94,26-2,11-4.24,13.62-9.77,24.92-7.46,15.25,13.11,19,15,40,1.67,18.59-23.39,40.09-32.62,40.08-60.38-.08.71-46.44-45.12-92C348.72,352.58,338.47,344.52,342.76,336.08Z"/></g><g id="Layer_4" data-name="Layer 4"><path class="cls-4" d="M354.58,380.91h94.33v-97h65.33V535.23H448.91v-103H354.58v103H289.26V283.92h65.32Z"/><circle class="cls-4" cx="402" cy="229" r="33"/></g></svg> \ No newline at end of file diff --git a/desktop/package/linux/icon.png b/desktop/package/linux/icon.png index 681ac6acdb..4a50f0dd75 100644 Binary files a/desktop/package/linux/icon.png and b/desktop/package/linux/icon.png differ diff --git a/desktop/package/linux/preview.png b/desktop/package/linux/preview.png new file mode 100644 index 0000000000..7ead4a92a8 Binary files /dev/null and b/desktop/package/linux/preview.png differ diff --git a/desktop/package/macosx/Haveno-volume.icns b/desktop/package/macosx/Haveno-volume.icns index 2a5b75c734..15595f0c9e 100644 Binary files a/desktop/package/macosx/Haveno-volume.icns and b/desktop/package/macosx/Haveno-volume.icns differ diff --git a/desktop/package/macosx/Haveno.icns b/desktop/package/macosx/Haveno.icns index 2a5b75c734..15595f0c9e 100644 Binary files a/desktop/package/macosx/Haveno.icns and b/desktop/package/macosx/Haveno.icns differ diff --git a/desktop/package/macosx/Info.plist b/desktop/package/macosx/Info.plist index e79d0724ea..31325683fd 100644 --- a/desktop/package/macosx/Info.plist +++ b/desktop/package/macosx/Info.plist @@ -5,10 +5,10 @@ <!-- See: https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html --> <key>CFBundleVersion</key> - <string>1.0.11</string> + <string>1.0.14</string> <key>CFBundleShortVersionString</key> - <string>1.0.11</string> + <string>1.0.14</string> <key>CFBundleExecutable</key> <string>Haveno</string> @@ -26,7 +26,7 @@ <string>public.app-category.finance</string> <key>NSHumanReadableCopyright</key> - <string>Copyright © 2023 - The Haveno developers</string> + <string>Copyright © 2024 - The Haveno developers</string> <!-- Only supported in older OSX versions. See: https://github.com/bitcoin/bitcoin/issues/11896#issuecomment-352148399--> diff --git a/desktop/package/package.gradle b/desktop/package/package.gradle index 766f842448..65e09d554f 100644 --- a/desktop/package/package.gradle +++ b/desktop/package/package.gradle @@ -1,38 +1,46 @@ import org.apache.tools.ant.taskdefs.condition.Os import java.time.LocalDateTime +import java.util.regex.Pattern task jpackageSanityChecks { description 'Interactive sanity checks on the version of the code that will be packaged' doLast { - executeCmd("git --no-pager log -5 --oneline") - ant.input(message: "Above you see the current HEAD and its recent history.\n" + - "Is this the right commit for packaging? (y=continue, n=abort)", - addproperty: "sanity-check-1", - validargs: "y,n") - if (ant.properties['sanity-check-1'] == 'n') { - ant.fail('Aborting') - } + if (!System.getenv("CI")) { + executeCmd("git --no-pager log -5 --oneline") + ant.input(message: "Above you see the current HEAD and its recent history.\n" + + "Is this the right commit for packaging? (y=continue, n=abort)", + addproperty: "sanity-check-1", + validargs: "y,n") + if (ant.properties['sanity-check-1'] == 'n') { + ant.fail('Aborting') + } - executeCmd("git status --short --branch") - ant.input(message: "Above you see any local changes that are not in the remote branch.\n" + - "If you have any local changes, please abort, get them merged, get the latest branch and try again.\n" + - "Continue with packaging? (y=continue, n=abort)", - addproperty: "sanity-check-2", - validargs: "y,n") - if (ant.properties['sanity-check-2'] == 'n') { - ant.fail('Aborting') - } + executeCmd("git status --short --branch") + ant.input(message: "Above you see any local changes that are not in the remote branch.\n" + + "If you have any local changes, please abort, get them merged, get the latest branch and try again.\n" + + "Continue with packaging? (y=continue, n=abort)", + addproperty: "sanity-check-2", + validargs: "y,n") + if (ant.properties['sanity-check-2'] == 'n') { + ant.fail('Aborting') + } - // TODO Evtl check programmatically in gradle (i.e. fail if below v11) - executeCmd("java --version") - ant.input(message: "Above you see the installed java version, which will be used to compile and build Haveno.\n" + - "Is this java version ok for that? (y=continue, n=abort)", - addproperty: "sanity-check-3", - validargs: "y,n") - if (ant.properties['sanity-check-3'] == 'n') { - ant.fail('Aborting') + // TODO Evtl check programmatically in gradle (i.e. fail if below v11) + executeCmd("java --version") + ant.input(message: "Above you see the installed java version, which will be used to compile and build Haveno.\n" + + "Is this java version ok for that? (y=continue, n=abort)", + addproperty: "sanity-check-3", + validargs: "y,n") + if (ant.properties['sanity-check-3'] == 'n') { + ant.fail('Aborting') + } + } else { + println "CI environment detected, skipping interactive sanity checks" + executeCmd("git --no-pager log -5 --oneline") + executeCmd("git status --short --branch") + executeCmd("java --version") } } } @@ -55,9 +63,6 @@ task getJavaBinariesDownloadURLs { binariesFolderPath.mkdirs() ext.binariesFolderPath = binariesFolderPath - // TODO Extend script logic to alternatively allow a local (separate, v14+) JDK for jpackage - // TODO Another option is to use the local JDK for everything: build jars and use jpackage (but then it has to be v14+) - // Define the download URLs (and associated binary hashes) for the JDK used to package the installers // These JDKs are independent of what is installed on the building system // @@ -71,28 +76,48 @@ task getJavaBinariesDownloadURLs { // -- linux ( -> use the tar.gz JDK link) // -- macOS ( -> use the tar.gz JDK link) // -- windows ( -> use the .zip JDK link) - Map jdk15Binaries = [ - 'linux' : 'https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_linux_hotspot_15.0.2_7.tar.gz', - 'linux-sha256' : '94f20ca8ea97773571492e622563883b8869438a015d02df6028180dd9acc24d', - 'mac' : 'https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_mac_hotspot_15.0.2_7.tar.gz', - 'mac-sha256' : 'd358a7ff03905282348c6c80562a4da2e04eb377b60ad2152be4c90f8d580b7f', - 'windows' : 'https://github.com/AdoptOpenJDK/openjdk15-binaries/releases/download/jdk-15.0.2%2B7/OpenJDK15U-jdk_x64_windows_hotspot_15.0.2_7.zip', - 'windows-sha256': 'b80dde2b7f8374eff0f1726c1cbdb48fb095fdde21489046d92f7144baff5741' - - // TODO For some reason, using "--runtime-image jdk-11" does NOT work with a v15 jpackage, but works with v14 + Map jdk21Binaries = [ + 'linux' : 'https://download.bell-sw.com/java/21.0.2+14/bellsoft-jdk21.0.2+14-linux-amd64-full.tar.gz', + 'linux-sha256' : '7eda80851fba1da023e03446c77100f19e7c770491b0d5bc9f893044e1b2b69b', + 'linux-aarch64' : 'https://download.bell-sw.com/java/21.0.2+14/bellsoft-jdk21.0.2+14-linux-aarch64-full.tar.gz', + 'linux-aarch64-sha256' : 'a477fc72085f30b03bf71fbed47923cea3b6f33b5b6a5a74718623b772a3a043', + 'mac' : 'https://download.bell-sw.com/java/21.0.2+14/bellsoft-jdk21.0.2+14-macos-amd64-full.tar.gz', + 'mac-sha256' : '42b528206595e559803b6f9f6bdbbf236ec6d10684058f46bc5261f5498d345c', + 'mac-aarch64' : 'https://download.bell-sw.com/java/21.0.2+14/bellsoft-jdk21.0.2+14-macos-aarch64-full.tar.gz', + 'mac-aarch64-sha256' : 'eba73a9bff7234220dc9a1da7f44b3d7ed2a562663eadc1c53bd74b355839a55', + 'windows' : 'https://download.bell-sw.com/java/21.0.2+14/bellsoft-jdk21.0.2+14-windows-amd64-full.zip', + 'windows-sha256' : 'f823eff0234af5bef095e53e5431191dbee8c2e42ca321eda23148a15cbf8d5b', + 'windows-aarch64' : 'https://download.bell-sw.com/java/21.0.2+14/bellsoft-jdk21.0.2+14-windows-aarch64-full.zip', + 'windows-aarch64-sha256': 'a2e9edecaf9637f83ef1cddab3a74f39ac55f8e1a479f10f3584ad939dfadd0a' ] String osKey + String architecture = System.getProperty("os.arch").toLowerCase() + if (Os.isFamily(Os.FAMILY_WINDOWS)) { - osKey = 'windows' + if (architecture.contains("aarch64") || architecture.contains("arm")) { + osKey = "windows-aarch64" + } else { + osKey = "windows" + } } else if (Os.isFamily(Os.FAMILY_MAC)) { - osKey = 'mac' + if (architecture.contains("aarch64") || architecture.contains("arm")) { + osKey = "mac-aarch64" + } else { + osKey = "mac" + } } else { - osKey = 'linux' + if (architecture.contains("aarch64") || architecture.contains("arm")) { + osKey = "linux-aarch64" + } else { + osKey = "linux" + } } - ext.jdk15Binary_DownloadURL = jdk15Binaries[osKey] - ext.jdk15Binary_SHA256Hash = jdk15Binaries[osKey + '-sha256'] + ext.osKey = osKey + + ext.jdk21Binary_DownloadURL = jdk21Binaries[osKey] + ext.jdk21Binary_SHA256Hash = jdk21Binaries[osKey + '-sha256'] } } @@ -108,8 +133,8 @@ task retrieveAndExtractJavaBinaries { File jdkForJpackageDir = new File(tempRootDir, jdkForJpackageDirName) jdkForJpackageDir.mkdirs() - String jdkForJpackageArchiveURL = getJavaBinariesDownloadURLs.property('jdk15Binary_DownloadURL') - String jdkForJpackageArchiveHash = getJavaBinariesDownloadURLs.property('jdk15Binary_SHA256Hash') + String jdkForJpackageArchiveURL = getJavaBinariesDownloadURLs.property('jdk21Binary_DownloadURL') + String jdkForJpackageArchiveHash = getJavaBinariesDownloadURLs.property('jdk21Binary_SHA256Hash') String jdkForJpackageArchiveFileName = jdkForJpackageArchiveURL.tokenize('/').last() File jdkForJpackageFile = new File(jdkForJpackageDir, jdkForJpackageArchiveFileName) @@ -226,15 +251,15 @@ task packageInstallers { destfile: "${binariesFolderPath}/jar-lib-for-raspberry-pi-${appVersion}.zip") } - String appDescription = 'A decentralized monero exchange network.' - String appCopyright = '© 2023 Haveno' + //String appDescription = 'A decentralized monero exchange network.' + String appCopyright = '© 2024 Haveno' String appNameAndVendor = 'Haveno' String commonOpts = new String( // Generic options " --dest \"${binariesFolderPath}\"" + " --name ${appNameAndVendor}" + - " --description \"${appDescription}\"" + + //" --description \"${appDescription}\"" + // TODO: task managers show app description instead of name, so we disable it " --app-version ${appVersion}" + " --copyright \"${appCopyright}\"" + " --vendor ${appNameAndVendor}" + @@ -248,6 +273,10 @@ task packageInstallers { " --main-class haveno.desktop.app.HavenoAppMain" + " --java-options -Xss1280k" + " --java-options -XX:MaxRAM=4g" + + " --java-options --add-opens=javafx.controls/com.sun.javafx.scene.control.behavior=ALL-UNNAMED" + + " --java-options --add-opens=javafx.controls/com.sun.javafx.scene.control=ALL-UNNAMED" + + " --java-options --add-opens=java.base/java.lang.reflect=ALL-UNNAMED" + + " --java-options --add-opens=javafx.graphics/com.sun.javafx.scene=ALL-UNNAMED" + " --java-options -Djava.net.preferIPv4Stack=true" + " --arguments --baseCurrencyNetwork=XMR_STAGENET" // Warning: this will cause guice reflection exceptions and lead to issues with the guice internal cache @@ -265,7 +294,7 @@ task packageInstallers { " --win-shortcut" ) - executeCmd(jPackageFilePath + commonOpts + windowsOpts + " --type exe") + executeCmd(jPackageFilePath + commonOpts + windowsOpts + " --verbose > desktop/build/output.txt --type exe") } else if (Os.isFamily(Os.FAMILY_MAC)) { // See https://docs.oracle.com/en/java/javase/14/jpackage/override-jpackage-resources.html // for details of "--resource-dir" @@ -295,6 +324,69 @@ task packageInstallers { " --linux-deb-maintainer noreply@haveno.exchange" + " --type deb") + // Clean jpackage temp folder, needs to be empty for the next packaging step (AppImage) + jpackageTempDir.deleteDir() + jpackageTempDir.mkdirs() + + executeCmd(jPackageFilePath + commonOpts + + " --dest \"${jpackageTempDir}\"" + + " --type app-image") + + // Path to the app-image directory: THIS IS NOT THE ACTUAL .AppImage FILE. + // See JPackage documentation on --type app-image for more. + String appImagePath = new String( + "\"${binariesFolderPath}/${appNameAndVendor}\"" + ) + + // Which version of AppImageTool to use + String AppImageToolVersion = "13"; + + // Download AppImageTool + Map AppImageToolBinaries = [ + 'linux' : "https://github.com/AppImage/AppImageKit/releases/download/${AppImageToolVersion}/appimagetool-x86_64.AppImage", + 'linux-aarch64' : "https://github.com/AppImage/AppImageKit/releases/download/${AppImageToolVersion}/appimagetool-aarch64.AppImage", + ] + + String osKey = getJavaBinariesDownloadURLs.property('osKey') + + File appDir = new File("${jpackageTempDir}/Haveno") + File templateAppDir = new File("${project(':desktop').projectDir}/package/linux/Haveno.AppDir") + File jpackDir = appDir + + appDir.mkdirs() + + File AppImageToolBinary = new File("${jpackageTempDir}/appimagetool.AppImage") + + // Adding a platform to the AppImageToolBinaries essentially adds it to the "supported" list of platforms able to make AppImages + // However, be warned that any platform that doesn't support unix `ln` and `chmod` will not work with the current method. + if (AppImageToolBinaries.containsKey(osKey)) { + println "Downloading ${AppImageToolBinaries[osKey]}" + ant.get(src: AppImageToolBinaries[osKey], dest: AppImageToolBinary) + println 'Download saved to ' + jpackageTempDir + + project.exec { + commandLine('chmod', '+x', AppImageToolBinary) + } + + copy { + from templateAppDir + into appDir + boolean includeEmptyDirs = true + } + + project.exec { + workingDir appDir + commandLine 'ln', '-s', 'bin/Haveno', 'AppRun' + } + + project.exec { + commandLine "${AppImageToolBinary}", appDir, "${binariesFolderPath}/haveno_${appVersion}.AppImage" + } + } else { + println "Your platform does not support AppImageTool ${AppImageToolVersion}" + } + + // Clean jpackage temp folder, needs to be empty for the next packaging step (rpm) jpackageTempDir.deleteDir() jpackageTempDir.mkdirs() @@ -303,6 +395,55 @@ task packageInstallers { executeCmd(jPackageFilePath + commonOpts + linuxOpts + " --linux-rpm-license-type AGPLv3" + // https://fedoraproject.org/wiki/Licensing:Main?rd=Licensing#Good_Licenses " --type rpm") + + + + // Define Flatpak-related properties + String flatpakManifestFile = 'package/linux/exchange.haveno.Haveno.yml' + String linuxDir = 'package/linux' + String flatpakOutputDir = 'package/linux/build' + String flatpakExportDir = "${binariesFolderPath}/fpexport" + String flatpakBundleFile = "${binariesFolderPath}/haveno.flatpak" + + // Read the default app name from the HavenoExecutable.java file + def filer = file('../core/src/main/java/haveno/core/app/HavenoExecutable.java') + def content = filer.text + def matcher = Pattern.compile(/public static final String DEFAULT_APP_NAME = "(.*?)";/).matcher(content) + def defaultAppName = "Haveno" + if (matcher.find()) { + defaultAppName = matcher.group(1) + } else { + throw new GradleException("DEFAULT_APP_NAME not found in HavenoExecutable.java") + } + + // Copy the manifest to a new tmp one in the same place + // and add a --filesystem=.local/share/${name} to the flatpak manifest + def manifest = file(flatpakManifestFile) + def newManifest = file('exchange.haveno.Haveno.yaml') + newManifest.write(manifest.text.replace("- --share=network", "- --share=network\n - --filesystem=~/.local/share/${defaultAppName}:create")) + flatpakManifestFile = 'exchange.haveno.Haveno.yaml' + + // Command to build the Flatpak + exec { + commandLine 'flatpak-builder', '--force-clean', flatpakOutputDir, flatpakManifestFile, '--user', '--install-deps-from=flathub' + } + + // Command to export the Flatpak + exec { + commandLine 'flatpak', 'build-export', flatpakExportDir, flatpakOutputDir + } + + // Command to create the Flatpak bundle + exec { + commandLine 'flatpak', 'build-bundle', flatpakExportDir, flatpakBundleFile, 'exchange.haveno.Haveno', '--runtime-repo=https://flathub.org/repo/flathub.flatpakrepo' + } + + // delete the flatpak build directory + delete(flatpakOutputDir) + delete(flatpakExportDir) + delete(flatpakManifestFile) + + println "Flatpak package created at ${flatpakBundleFile}" } // Env variable can be set by calling "export HAVENO_SHARED_FOLDER='Some value'" @@ -319,6 +460,7 @@ task packageInstallers { from binariesFolderPath into envVariableSharedFolder } + executeCmd("open " + envVariableSharedFolder) } } diff --git a/desktop/package/windows/Haveno.ico b/desktop/package/windows/Haveno.ico index 8b3903bb92..03d9fce206 100644 Binary files a/desktop/package/windows/Haveno.ico and b/desktop/package/windows/Haveno.ico differ diff --git a/desktop/package/windows/main.wxs b/desktop/package/windows/main.wxs index 9c04430f2a..58100e428b 100644 --- a/desktop/package/windows/main.wxs +++ b/desktop/package/windows/main.wxs @@ -92,6 +92,23 @@ <WixVariable Id="WixUIDialogBmp" Value="$(var.ImageDir)/WixUIDialogBmp.bmp" /> <UI> + <!-- Run WixUI_InstallDir dialog in the default install directory. --> + <UIRef Id="WixUI_InstallDir" /> + + <?ifndef JpLicenseRtf ?> + <!-- + No license file provided. + Override the dialog sequence in built-in dialog set "WixUI_InstallDir" + to exclude license dialog. + --> + <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="2">1</Publish> + <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">1</Publish> + <?endif?> + + <?ifdef JpLicenseRtf ?> + <UIRef Id="WixUI_Minimal" /> + <?endif?> + <?ifdef JpInstallDirChooser ?> <Dialog Id="JpInvalidInstallDir" Width="300" Height="85" Title="[ProductName] Setup" NoMinimize="yes"> <Control Id="JpInvalidInstallDirYes" Type="PushButton" X="100" Y="55" Width="50" Height="15" Default="no" Cancel="no" Text="Yes"> @@ -104,33 +121,11 @@ <Text>!(loc.message.install.dir.exist)</Text> </Control> </Dialog> - - <!-- - Run WixUI_InstallDir dialog in the default install directory. - --> - <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"/> - <UIRef Id="WixUI_InstallDir" /> - + <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="JpCheckInstallDir" Order="3">1</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="JpInvalidInstallDir" Order="5">INSTALLDIR_VALID="0"</Publish> <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="5">INSTALLDIR_VALID="1"</Publish> - - <?ifndef JpLicenseRtf ?> - <!-- - No license file provided. - Override the dialog sequence in built-in dialog set "WixUI_InstallDir" - to exclude license dialog. - --> - <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="InstallDirDlg" Order="2">1</Publish> - <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">1</Publish> - <?endif?> - - <?else?> - - <?ifdef JpLicenseRtf ?> - <UIRef Id="WixUI_Minimal" /> - <?endif?> - + <?endif?> <!-- Add launch app configuration --> <Publish Dialog="ExitDialog" @@ -139,6 +134,7 @@ Value="LaunchApplication">WIXUI_EXITDIALOGOPTIONALCHECKBOX = 1 and NOT Installed</Publish> </UI> + <Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR"/> <Property Id="WIXUI_EXITDIALOGOPTIONALCHECKBOXTEXT" Value="Launch $(var.JpAppName)" /> <Property Id="WixShellExecTarget" Value="[INSTALLDIR]/$(var.JpAppName).exe" /> <CustomAction Id="LaunchApplication" diff --git a/desktop/src/main/java/haveno/desktop/DesktopModule.java b/desktop/src/main/java/haveno/desktop/DesktopModule.java index 70712ddb0e..c14057258f 100644 --- a/desktop/src/main/java/haveno/desktop/DesktopModule.java +++ b/desktop/src/main/java/haveno/desktop/DesktopModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; diff --git a/desktop/src/main/java/haveno/desktop/Navigation.java b/desktop/src/main/java/haveno/desktop/Navigation.java index 9d049f9bd6..b917f5cb06 100644 --- a/desktop/src/main/java/haveno/desktop/Navigation.java +++ b/desktop/src/main/java/haveno/desktop/Navigation.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.persistence.PersistenceManager; import haveno.common.proto.persistable.NavigationPath; import haveno.common.proto.persistable.PersistedDataHost; @@ -25,17 +26,15 @@ import haveno.desktop.common.view.View; import haveno.desktop.common.view.ViewPath; import haveno.desktop.main.MainView; import haveno.desktop.main.market.MarketView; -import lombok.Getter; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Singleton; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.concurrent.CopyOnWriteArraySet; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton diff --git a/desktop/src/main/java/haveno/desktop/app/HavenoApp.java b/desktop/src/main/java/haveno/desktop/app/HavenoApp.java index 553f78c21e..3e41aa2f8c 100644 --- a/desktop/src/main/java/haveno/desktop/app/HavenoApp.java +++ b/desktop/src/main/java/haveno/desktop/app/HavenoApp.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.app; @@ -89,6 +89,8 @@ public class HavenoApp extends Application implements UncaughtExceptionHandler { private static Consumer<Application> appLaunchedHandler; @Getter private static Runnable shutDownHandler; + @Setter + private static Runnable onGracefulShutDownHandler; @Setter private Injector injector; @@ -145,6 +147,7 @@ public class HavenoApp extends Application implements UncaughtExceptionHandler { new Thread(() -> { gracefulShutDownHandler.gracefulShutDown(() -> { log.info("App shutdown complete"); + if (onGracefulShutDownHandler != null) onGracefulShutDownHandler.run(); }); }).start(); shutDownRequested = true; @@ -380,7 +383,7 @@ public class HavenoApp extends Application implements UncaughtExceptionHandler { // if no warning popup has been shown yet, prompt user if they really intend to shut down String key = "popup.info.shutDownQuery"; if (injector.getInstance(Preferences.class).showAgain(key) && !DevEnv.isDevMode()) { - new Popup().headLine(Res.get("popup.info.shutDownQuery")) + new Popup().headLine(Res.get(key)) .actionButtonText(Res.get("shared.yes")) .onAction(() -> resp.complete(true)) .closeButtonText(Res.get("shared.no")) diff --git a/desktop/src/main/java/haveno/desktop/app/HavenoAppMain.java b/desktop/src/main/java/haveno/desktop/app/HavenoAppMain.java index 5089b8ddc4..a1aee58c4f 100644 --- a/desktop/src/main/java/haveno/desktop/app/HavenoAppMain.java +++ b/desktop/src/main/java/haveno/desktop/app/HavenoAppMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.app; @@ -38,6 +38,7 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Stage; +import javafx.stage.Window; import lombok.extern.slf4j.Slf4j; import java.util.Optional; @@ -47,12 +48,10 @@ import java.util.concurrent.ExecutionException; @Slf4j public class HavenoAppMain extends HavenoExecutable { - public static final String DEFAULT_APP_NAME = "Haveno"; - private HavenoApp application; public HavenoAppMain() { - super("Haveno Desktop", "haveno-desktop", DEFAULT_APP_NAME, Version.VERSION); + super("Haveno Desktop", "haveno-desktop", HavenoExecutable.DEFAULT_APP_NAME, Version.VERSION); } public static void main(String[] args) { @@ -230,6 +229,17 @@ public class HavenoAppMain extends HavenoExecutable { return null; } }); + + // Focus the password field when dialog is shown + Window window = getDialogPane().getScene().getWindow(); + if (window instanceof Stage) { + Stage dialogStage = (Stage) window; + dialogStage.focusedProperty().addListener((observable, oldValue, newValue) -> { + if (newValue) { + passwordField.requestFocus(); + } + }); + } } } } diff --git a/desktop/src/main/java/haveno/desktop/app/HavenoAppModule.java b/desktop/src/main/java/haveno/desktop/app/HavenoAppModule.java index abaded6a49..8928e0147c 100644 --- a/desktop/src/main/java/haveno/desktop/app/HavenoAppModule.java +++ b/desktop/src/main/java/haveno/desktop/app/HavenoAppModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.app; diff --git a/desktop/src/main/java/haveno/desktop/common/UITimer.java b/desktop/src/main/java/haveno/desktop/common/UITimer.java index 708d45d8b4..e8482ea06a 100644 --- a/desktop/src/main/java/haveno/desktop/common/UITimer.java +++ b/desktop/src/main/java/haveno/desktop/common/UITimer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common; diff --git a/desktop/src/main/java/haveno/desktop/common/ViewfxException.java b/desktop/src/main/java/haveno/desktop/common/ViewfxException.java index a6a7f96098..798380e13d 100644 --- a/desktop/src/main/java/haveno/desktop/common/ViewfxException.java +++ b/desktop/src/main/java/haveno/desktop/common/ViewfxException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common; diff --git a/desktop/src/main/java/haveno/desktop/common/fxml/FxmlViewLoader.java b/desktop/src/main/java/haveno/desktop/common/fxml/FxmlViewLoader.java index e1f4e6110c..0679677fa7 100644 --- a/desktop/src/main/java/haveno/desktop/common/fxml/FxmlViewLoader.java +++ b/desktop/src/main/java/haveno/desktop/common/fxml/FxmlViewLoader.java @@ -1,40 +1,38 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.fxml; import com.google.common.base.Joiner; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.util.Utilities; import haveno.desktop.common.ViewfxException; import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.View; import haveno.desktop.common.view.ViewFactory; import haveno.desktop.common.view.ViewLoader; -import javafx.fxml.FXMLLoader; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.io.IOException; import java.lang.annotation.Annotation; import java.net.URL; import java.util.ResourceBundle; - -import static com.google.common.base.Preconditions.checkNotNull; +import javafx.fxml.FXMLLoader; +import lombok.extern.slf4j.Slf4j; @Slf4j @Singleton diff --git a/desktop/src/main/java/haveno/desktop/common/model/Activatable.java b/desktop/src/main/java/haveno/desktop/common/model/Activatable.java index 4bdc495b4b..a3f39d9e1d 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/Activatable.java +++ b/desktop/src/main/java/haveno/desktop/common/model/Activatable.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/ActivatableDataModel.java b/desktop/src/main/java/haveno/desktop/common/model/ActivatableDataModel.java index 36aef90735..53a513566e 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/ActivatableDataModel.java +++ b/desktop/src/main/java/haveno/desktop/common/model/ActivatableDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/ActivatableViewModel.java b/desktop/src/main/java/haveno/desktop/common/model/ActivatableViewModel.java index 6b9e595c1f..f926776a72 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/ActivatableViewModel.java +++ b/desktop/src/main/java/haveno/desktop/common/model/ActivatableViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/ActivatableWithDataModel.java b/desktop/src/main/java/haveno/desktop/common/model/ActivatableWithDataModel.java index f7e449bcdc..6acac969d6 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/ActivatableWithDataModel.java +++ b/desktop/src/main/java/haveno/desktop/common/model/ActivatableWithDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/DataModel.java b/desktop/src/main/java/haveno/desktop/common/model/DataModel.java index 407e2b1925..6bef9bf6de 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/DataModel.java +++ b/desktop/src/main/java/haveno/desktop/common/model/DataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/Model.java b/desktop/src/main/java/haveno/desktop/common/model/Model.java index 820867f03f..5d65c42e50 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/Model.java +++ b/desktop/src/main/java/haveno/desktop/common/model/Model.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/ViewModel.java b/desktop/src/main/java/haveno/desktop/common/model/ViewModel.java index 22223a244e..293e46336d 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/ViewModel.java +++ b/desktop/src/main/java/haveno/desktop/common/model/ViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/model/WithDataModel.java b/desktop/src/main/java/haveno/desktop/common/model/WithDataModel.java index 085047346f..88178753a0 100644 --- a/desktop/src/main/java/haveno/desktop/common/model/WithDataModel.java +++ b/desktop/src/main/java/haveno/desktop/common/model/WithDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.model; diff --git a/desktop/src/main/java/haveno/desktop/common/view/AbstractView.java b/desktop/src/main/java/haveno/desktop/common/view/AbstractView.java index a9aa43e4a1..8fa997e79a 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/AbstractView.java +++ b/desktop/src/main/java/haveno/desktop/common/view/AbstractView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/ActivatableView.java b/desktop/src/main/java/haveno/desktop/common/view/ActivatableView.java index 37d14b2653..e40d56a11f 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/ActivatableView.java +++ b/desktop/src/main/java/haveno/desktop/common/view/ActivatableView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/ActivatableViewAndModel.java b/desktop/src/main/java/haveno/desktop/common/view/ActivatableViewAndModel.java index 60f330c61f..d81b58ee3c 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/ActivatableViewAndModel.java +++ b/desktop/src/main/java/haveno/desktop/common/view/ActivatableViewAndModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/CachingViewLoader.java b/desktop/src/main/java/haveno/desktop/common/view/CachingViewLoader.java index a09de2d3de..1dbd5412f1 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/CachingViewLoader.java +++ b/desktop/src/main/java/haveno/desktop/common/view/CachingViewLoader.java @@ -1,24 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; -import javax.inject.Inject; -import javax.inject.Singleton; +import com.google.inject.Inject; +import com.google.inject.Singleton; import java.util.HashMap; import java.util.Map; diff --git a/desktop/src/main/java/haveno/desktop/common/view/DefaultPathConvention.java b/desktop/src/main/java/haveno/desktop/common/view/DefaultPathConvention.java index 52f172f3ab..6e8c185b1a 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/DefaultPathConvention.java +++ b/desktop/src/main/java/haveno/desktop/common/view/DefaultPathConvention.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/FxmlView.java b/desktop/src/main/java/haveno/desktop/common/view/FxmlView.java index 9821de3907..d858ac9e69 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/FxmlView.java +++ b/desktop/src/main/java/haveno/desktop/common/view/FxmlView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/InitializableView.java b/desktop/src/main/java/haveno/desktop/common/view/InitializableView.java index 6ad2e782b0..af9a5160ea 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/InitializableView.java +++ b/desktop/src/main/java/haveno/desktop/common/view/InitializableView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/View.java b/desktop/src/main/java/haveno/desktop/common/view/View.java index d636982fee..f170b69596 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/View.java +++ b/desktop/src/main/java/haveno/desktop/common/view/View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/ViewFactory.java b/desktop/src/main/java/haveno/desktop/common/view/ViewFactory.java index 7f2dc67727..4849d540ee 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/ViewFactory.java +++ b/desktop/src/main/java/haveno/desktop/common/view/ViewFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/ViewLoader.java b/desktop/src/main/java/haveno/desktop/common/view/ViewLoader.java index 0bdfc7ba19..8cd9f7f35a 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/ViewLoader.java +++ b/desktop/src/main/java/haveno/desktop/common/view/ViewLoader.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/ViewPath.java b/desktop/src/main/java/haveno/desktop/common/view/ViewPath.java index 54217763a9..fbaaaa3c47 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/ViewPath.java +++ b/desktop/src/main/java/haveno/desktop/common/view/ViewPath.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view; diff --git a/desktop/src/main/java/haveno/desktop/common/view/guice/InjectorViewFactory.java b/desktop/src/main/java/haveno/desktop/common/view/guice/InjectorViewFactory.java index 302957ff5e..4ab0ddee74 100644 --- a/desktop/src/main/java/haveno/desktop/common/view/guice/InjectorViewFactory.java +++ b/desktop/src/main/java/haveno/desktop/common/view/guice/InjectorViewFactory.java @@ -1,28 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.view.guice; import com.google.common.base.Preconditions; import com.google.inject.Injector; +import com.google.inject.Singleton; import haveno.desktop.common.view.ViewFactory; -import javax.inject.Singleton; - @Singleton public class InjectorViewFactory implements ViewFactory { diff --git a/desktop/src/main/java/haveno/desktop/components/AccountStatusTooltipLabel.java b/desktop/src/main/java/haveno/desktop/components/AccountStatusTooltipLabel.java index 11f54dabba..8ae0b607f0 100644 --- a/desktop/src/main/java/haveno/desktop/components/AccountStatusTooltipLabel.java +++ b/desktop/src/main/java/haveno/desktop/components/AccountStatusTooltipLabel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; @@ -91,7 +91,7 @@ public class AccountStatusTooltipLabel extends AutoTooltipLabel { infoLabel.getStyleClass().add("small-text"); Label buyLabel = createDetailsItem( - Res.get("offerbook.timeSinceSigning.tooltip.checkmark.buyBtc"), + Res.get("offerbook.timeSinceSigning.tooltip.checkmark.buyXmr"), witnessAgeData.isAccountSigned() ); Label waitLabel = createDetailsItem( @@ -106,7 +106,7 @@ public class AccountStatusTooltipLabel extends AutoTooltipLabel { learnMoreLink.setWrapText(true); learnMoreLink.setPadding(new Insets(10, 10, 2, 10)); learnMoreLink.getStyleClass().addAll("very-small-text"); - learnMoreLink.setOnAction((e) -> GUIUtil.openWebPage("https://bisq.wiki/Account_limits")); + learnMoreLink.setOnAction((e) -> GUIUtil.openWebPage("https://docs.haveno.exchange/the-project/account_limits")); VBox vBox = new VBox(2, titleLabel, infoLabel, buyLabel, waitLabel, learnMoreLink); vBox.setPadding(new Insets(2, 0, 2, 0)); diff --git a/desktop/src/main/java/haveno/desktop/components/AddressTextField.java b/desktop/src/main/java/haveno/desktop/components/AddressTextField.java index 94faa4153e..ec6f284379 100644 --- a/desktop/src/main/java/haveno/desktop/components/AddressTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/AddressTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; @@ -22,7 +22,6 @@ import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; import haveno.common.util.Utilities; import haveno.core.locale.Res; -import haveno.core.trade.HavenoUtils; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.GUIUtil; import javafx.beans.property.ObjectProperty; @@ -151,14 +150,13 @@ public class AddressTextField extends AnchorPane { /////////////////////////////////////////////////////////////////////////////////////////// private String getMoneroURI() { - if (amount.get().compareTo(BigInteger.valueOf(0)) < 0) { + if (amount.get().compareTo(BigInteger.ZERO) < 0) { log.warn("Amount must not be negative"); - setAmount(BigInteger.valueOf(0)); + setAmount(BigInteger.ZERO); } return GUIUtil.getMoneroURI( address.get(), amount.get(), - paymentLabel.get(), - HavenoUtils.havenoSetup.getXmrWalletService().getWallet()); + paymentLabel.get()); } } diff --git a/desktop/src/main/java/haveno/desktop/components/AddressWithIconAndDirection.java b/desktop/src/main/java/haveno/desktop/components/AddressWithIconAndDirection.java index b4fe63c518..2e095b889f 100644 --- a/desktop/src/main/java/haveno/desktop/components/AddressWithIconAndDirection.java +++ b/desktop/src/main/java/haveno/desktop/components/AddressWithIconAndDirection.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipButton.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipButton.java index a9a04b2edc..83261ba212 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutoTooltipButton.java +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipButton.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipCheckBox.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipCheckBox.java index 1d7d50f04a..3f3eb40c51 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutoTooltipCheckBox.java +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipCheckBox.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipLabel.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipLabel.java index 84ee4931bc..4cd70d91c6 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutoTooltipLabel.java +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipLabel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipRadioButton.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipRadioButton.java index c2da4a509f..d301b98945 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutoTooltipRadioButton.java +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipRadioButton.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipTableColumn.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipTableColumn.java index 201344c547..3cc56c69a0 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutoTooltipTableColumn.java +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipTableColumn.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipTextField.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipTextField.java new file mode 100644 index 0000000000..1473ed0940 --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipTextField.java @@ -0,0 +1,45 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.components; + +import com.jfoenix.controls.JFXTextField; +import com.jfoenix.skins.JFXTextFieldSkin; +import javafx.scene.control.Skin; +import javafx.scene.control.TextField; + +public class AutoTooltipTextField extends JFXTextField { + + public AutoTooltipTextField() { + super(); + } + + public AutoTooltipTextField(String text) { + super(text); + } + + @Override + protected Skin<?> createDefaultSkin() { + return new AutoTooltipTextFieldSkin(this); + } + + private class AutoTooltipTextFieldSkin extends JFXTextFieldSkin { + public AutoTooltipTextFieldSkin(TextField textField) { + super(textField); + } + } +} diff --git a/desktop/src/main/java/haveno/desktop/components/AutoTooltipToggleButton.java b/desktop/src/main/java/haveno/desktop/components/AutoTooltipToggleButton.java index 071ed7fec7..207dc4440d 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutoTooltipToggleButton.java +++ b/desktop/src/main/java/haveno/desktop/components/AutoTooltipToggleButton.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/AutocompleteComboBox.java b/desktop/src/main/java/haveno/desktop/components/AutocompleteComboBox.java index 0bf4dd1a72..2b1adc5769 100644 --- a/desktop/src/main/java/haveno/desktop/components/AutocompleteComboBox.java +++ b/desktop/src/main/java/haveno/desktop/components/AutocompleteComboBox.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/BalanceTextField.java b/desktop/src/main/java/haveno/desktop/components/BalanceTextField.java index 97387bf666..4e00789dc8 100644 --- a/desktop/src/main/java/haveno/desktop/components/BalanceTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/BalanceTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/BusyAnimation.java b/desktop/src/main/java/haveno/desktop/components/BusyAnimation.java index 80cb34baec..a1abdee765 100644 --- a/desktop/src/main/java/haveno/desktop/components/BusyAnimation.java +++ b/desktop/src/main/java/haveno/desktop/components/BusyAnimation.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosText.java b/desktop/src/main/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosText.java index 2875ac2b56..910114dbb2 100644 --- a/desktop/src/main/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosText.java +++ b/desktop/src/main/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosText.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/ExplorerAddressTextField.java b/desktop/src/main/java/haveno/desktop/components/ExplorerAddressTextField.java index ce76137e44..7dff009b9e 100644 --- a/desktop/src/main/java/haveno/desktop/components/ExplorerAddressTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/ExplorerAddressTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/ExternalHyperlink.java b/desktop/src/main/java/haveno/desktop/components/ExternalHyperlink.java index c2d85e4271..0ade0810d6 100644 --- a/desktop/src/main/java/haveno/desktop/components/ExternalHyperlink.java +++ b/desktop/src/main/java/haveno/desktop/components/ExternalHyperlink.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/FundsTextField.java b/desktop/src/main/java/haveno/desktop/components/FundsTextField.java index 21506f25f5..0804750972 100644 --- a/desktop/src/main/java/haveno/desktop/components/FundsTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/FundsTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/HyperlinkWithIcon.java b/desktop/src/main/java/haveno/desktop/components/HyperlinkWithIcon.java index 764b504b58..28d89251fd 100644 --- a/desktop/src/main/java/haveno/desktop/components/HyperlinkWithIcon.java +++ b/desktop/src/main/java/haveno/desktop/components/HyperlinkWithIcon.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/InfoAutoTooltipLabel.java b/desktop/src/main/java/haveno/desktop/components/InfoAutoTooltipLabel.java index efbbf4cf9c..de4f019a80 100644 --- a/desktop/src/main/java/haveno/desktop/components/InfoAutoTooltipLabel.java +++ b/desktop/src/main/java/haveno/desktop/components/InfoAutoTooltipLabel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/InfoDisplay.java b/desktop/src/main/java/haveno/desktop/components/InfoDisplay.java index 3d98f435e7..a19569e9e0 100644 --- a/desktop/src/main/java/haveno/desktop/components/InfoDisplay.java +++ b/desktop/src/main/java/haveno/desktop/components/InfoDisplay.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/InfoInputTextField.java b/desktop/src/main/java/haveno/desktop/components/InfoInputTextField.java index 12c023666c..cf818aad00 100644 --- a/desktop/src/main/java/haveno/desktop/components/InfoInputTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/InfoInputTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/InfoTextField.java b/desktop/src/main/java/haveno/desktop/components/InfoTextField.java index 819e24c125..beafcf9494 100644 --- a/desktop/src/main/java/haveno/desktop/components/InfoTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/InfoTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/InputTextField.java b/desktop/src/main/java/haveno/desktop/components/InputTextField.java index 888573d997..8c4ace02b8 100644 --- a/desktop/src/main/java/haveno/desktop/components/InputTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/InputTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/JFXRadioButtonSkinHavenoStyle.java b/desktop/src/main/java/haveno/desktop/components/JFXRadioButtonSkinHavenoStyle.java index 6a58647c53..4ab09a7cda 100644 --- a/desktop/src/main/java/haveno/desktop/components/JFXRadioButtonSkinHavenoStyle.java +++ b/desktop/src/main/java/haveno/desktop/components/JFXRadioButtonSkinHavenoStyle.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/MenuItem.java b/desktop/src/main/java/haveno/desktop/components/MenuItem.java index 5d8f45b307..c32eab65c3 100644 --- a/desktop/src/main/java/haveno/desktop/components/MenuItem.java +++ b/desktop/src/main/java/haveno/desktop/components/MenuItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/PasswordTextField.java b/desktop/src/main/java/haveno/desktop/components/PasswordTextField.java index 94b1fc84b8..7297ef6b47 100644 --- a/desktop/src/main/java/haveno/desktop/components/PasswordTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/PasswordTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/PeerInfoIcon.java b/desktop/src/main/java/haveno/desktop/components/PeerInfoIcon.java index e6d86cd826..da8dcb4a70 100644 --- a/desktop/src/main/java/haveno/desktop/components/PeerInfoIcon.java +++ b/desktop/src/main/java/haveno/desktop/components/PeerInfoIcon.java @@ -1,56 +1,62 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; -import com.google.common.base.Charsets; +import haveno.desktop.main.overlays.editor.PeerInfoWithTagEditor; +import haveno.desktop.util.DisplayUtils; + import haveno.core.alert.PrivateNotificationManager; import haveno.core.locale.Res; import haveno.core.offer.Offer; import haveno.core.trade.Trade; import haveno.core.user.Preferences; -import haveno.desktop.main.overlays.editor.PeerInfoWithTagEditor; -import haveno.desktop.util.DisplayUtils; + import haveno.network.p2p.NodeAddress; -import javafx.geometry.Point2D; + +import com.google.common.base.Charsets; + import javafx.scene.Group; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.control.Label; import javafx.scene.control.Tooltip; import javafx.scene.image.ImageView; +import javafx.scene.input.MouseButton; import javafx.scene.layout.Pane; import javafx.scene.paint.Color; -import lombok.Setter; + +import javafx.geometry.Point2D; + +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import java.util.Map; + import lombok.extern.slf4j.Slf4j; import javax.annotation.Nullable; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Map; @Slf4j public class PeerInfoIcon extends Group { - public interface notify { - void avatarTagUpdated(); - } - @Setter - private notify callback; protected Preferences preferences; protected final String fullAddress; protected String tooltipText; @@ -59,10 +65,12 @@ public class PeerInfoIcon extends Group { protected Pane tagPane; protected Pane numTradesPane; protected int numTrades = 0; + private final StringProperty tag; public PeerInfoIcon(NodeAddress nodeAddress, Preferences preferences) { this.preferences = preferences; this.fullAddress = nodeAddress != null ? nodeAddress.getFullAddress() : ""; + this.tag = new SimpleStringProperty(""); } protected void createAvatar(Color ringColor) { @@ -162,23 +170,24 @@ public class PeerInfoIcon extends Group { Res.get("peerInfo.unknownAge") : null; - setOnMouseClicked(e -> new PeerInfoWithTagEditor(privateNotificationManager, trade, offer, preferences, useDevPrivilegeKeys) - .fullAddress(fullAddress) - .numTrades(numTrades) - .accountAge(accountAgeFormatted) - .signAge(signAgeFormatted) - .accountAgeInfo(peersAccountAgeInfo) - .signAgeInfo(peersSignAgeInfo) - .accountSigningState(accountSigningState) - .position(localToScene(new Point2D(0, 0))) - .onSave(newTag -> { - preferences.setTagForPeer(fullAddress, newTag); - updatePeerInfoIcon(); - if (callback != null) { - callback.avatarTagUpdated(); - } - }) - .show()); + setOnMouseClicked(e -> { + if (e.getButton().equals(MouseButton.PRIMARY)) { + new PeerInfoWithTagEditor(privateNotificationManager, trade, offer, preferences, useDevPrivilegeKeys) + .fullAddress(fullAddress) + .numTrades(numTrades) + .accountAge(accountAgeFormatted) + .signAge(signAgeFormatted) + .accountAgeInfo(peersAccountAgeInfo) + .signAgeInfo(peersSignAgeInfo) + .accountSigningState(accountSigningState) + .position(localToScene(new Point2D(0, 0))) + .onSave(newTag -> { + preferences.setTagForPeer(fullAddress, newTag); + tag.set(newTag); + }) + .show(); + } + }); } protected double getScaleFactor() { @@ -192,20 +201,6 @@ public class PeerInfoIcon extends Group { } protected void updatePeerInfoIcon() { - String tag; - Map<String, String> peerTagMap = preferences.getPeerTagMap(); - if (peerTagMap.containsKey(fullAddress)) { - tag = peerTagMap.get(fullAddress); - final String text = !tag.isEmpty() ? Res.get("peerInfoIcon.tooltip", tooltipText, tag) : tooltipText; - Tooltip.install(this, new Tooltip(text)); - } else { - tag = ""; - Tooltip.install(this, new Tooltip(tooltipText)); - } - - if (!tag.isEmpty()) - tagLabel.setText(tag.substring(0, 1)); - if (numTrades > 0) { numTradesLabel.setText(numTrades > 99 ? "*" : String.valueOf(numTrades)); @@ -216,9 +211,27 @@ public class PeerInfoIcon extends Group { numTradesLabel.relocate(scaleFactor * 5, scaleFactor * 1); } } - numTradesPane.setVisible(numTrades > 0); - tagPane.setVisible(!tag.isEmpty()); + refreshTag(); + } + + protected void refreshTag() { + Map<String, String> peerTagMap = preferences.getPeerTagMap(); + if (peerTagMap.containsKey(fullAddress)) { + tag.set(peerTagMap.get(fullAddress)); + } + + Tooltip.install(this, new Tooltip(!tag.get().isEmpty() ? + Res.get("peerInfoIcon.tooltip", tooltipText, tag.get()) : tooltipText)); + + if (!tag.get().isEmpty()) { + tagLabel.setText(tag.get().substring(0, 1)); + } + tagPane.setVisible(!tag.get().isEmpty()); + } + + protected StringProperty tagProperty() { + return tag; } } diff --git a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconDispute.java b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconDispute.java index c81e73836a..cb1e6fc7e3 100644 --- a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconDispute.java +++ b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconDispute.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; @@ -40,8 +40,4 @@ public class PeerInfoIconDispute extends PeerInfoIcon { addMouseListener(numTrades, null, null, null, preferences, false, false, accountAge, 0L, null, null, null); } - - public void refreshTag() { - updatePeerInfoIcon(); - } } diff --git a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconMap.java b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconMap.java new file mode 100644 index 0000000000..e59fa538c3 --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconMap.java @@ -0,0 +1,48 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.components; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; + +import java.util.HashMap; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class PeerInfoIconMap extends HashMap<String, PeerInfoIcon> implements ChangeListener<String> { + + @Override + public PeerInfoIcon put(String key, PeerInfoIcon icon) { + icon.tagProperty().addListener(this); + return super.put(key, icon); + } + + @Override + public void changed(ObservableValue<? extends String> o, String oldVal, String newVal) { + log.info("Updating avatar tags, the avatar map size is {}", size()); + forEach((key, icon) -> { + // We update all avatars, as some could be sharing the same tag. + // We also temporarily remove listeners to prevent firing of + // events while each icon's tagProperty is being reset. + icon.tagProperty().removeListener(this); + icon.refreshTag(); + icon.tagProperty().addListener(this); + }); + } +} diff --git a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java index 2791e637d7..6a9f1344d6 100644 --- a/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java +++ b/desktop/src/main/java/haveno/desktop/components/PeerInfoIconTrading.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/PopOverWrapper.java b/desktop/src/main/java/haveno/desktop/components/PopOverWrapper.java index 804b72b7cc..1f60fbe55f 100644 --- a/desktop/src/main/java/haveno/desktop/components/PopOverWrapper.java +++ b/desktop/src/main/java/haveno/desktop/components/PopOverWrapper.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/SimpleMarkdownLabel.java b/desktop/src/main/java/haveno/desktop/components/SimpleMarkdownLabel.java index 7c0413410d..d8cfd66402 100644 --- a/desktop/src/main/java/haveno/desktop/components/SimpleMarkdownLabel.java +++ b/desktop/src/main/java/haveno/desktop/components/SimpleMarkdownLabel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/TableGroupHeadline.java b/desktop/src/main/java/haveno/desktop/components/TableGroupHeadline.java index 7767bdae52..22ce1f6d8e 100644 --- a/desktop/src/main/java/haveno/desktop/components/TableGroupHeadline.java +++ b/desktop/src/main/java/haveno/desktop/components/TableGroupHeadline.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/TextFieldWithCopyIcon.java b/desktop/src/main/java/haveno/desktop/components/TextFieldWithCopyIcon.java index 876dd27b7e..d337916da3 100644 --- a/desktop/src/main/java/haveno/desktop/components/TextFieldWithCopyIcon.java +++ b/desktop/src/main/java/haveno/desktop/components/TextFieldWithCopyIcon.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/TextFieldWithIcon.java b/desktop/src/main/java/haveno/desktop/components/TextFieldWithIcon.java index 27aafe3300..2e66a0e026 100644 --- a/desktop/src/main/java/haveno/desktop/components/TextFieldWithIcon.java +++ b/desktop/src/main/java/haveno/desktop/components/TextFieldWithIcon.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/TitledGroupBg.java b/desktop/src/main/java/haveno/desktop/components/TitledGroupBg.java index c28f102fc5..2487a763ec 100644 --- a/desktop/src/main/java/haveno/desktop/components/TitledGroupBg.java +++ b/desktop/src/main/java/haveno/desktop/components/TitledGroupBg.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/TooltipUtil.java b/desktop/src/main/java/haveno/desktop/components/TooltipUtil.java index 5ccd161054..1b37f3829e 100644 --- a/desktop/src/main/java/haveno/desktop/components/TooltipUtil.java +++ b/desktop/src/main/java/haveno/desktop/components/TooltipUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java b/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java index 360b0f5af1..e9ced56cdf 100644 --- a/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java +++ b/desktop/src/main/java/haveno/desktop/components/TxIdTextField.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; @@ -23,11 +23,13 @@ import de.jensd.fx.fontawesome.AwesomeIcon; import haveno.common.UserThread; import haveno.common.util.Utilities; import haveno.core.locale.Res; +import haveno.core.trade.Trade; import haveno.core.user.BlockChainExplorer; import haveno.core.user.Preferences; import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.components.indicator.TxConfidenceIndicator; import haveno.desktop.util.GUIUtil; +import javafx.beans.value.ChangeListener; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.control.Tooltip; @@ -51,7 +53,9 @@ public class TxIdTextField extends AnchorPane { private final TxConfidenceIndicator txConfidenceIndicator; private final Label copyIcon, blockExplorerIcon, missingTxWarningIcon; - private MoneroWalletListener txUpdater; + private MoneroWalletListener walletListener; + private ChangeListener<Number> tradeListener; + private Trade trade; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -108,9 +112,18 @@ public class TxIdTextField extends AnchorPane { } public void setup(@Nullable String txId) { - if (txUpdater != null) { - xmrWalletService.removeWalletListener(txUpdater); - txUpdater = null; + setup(txId, null); + } + + public void setup(@Nullable String txId, Trade trade) { + this.trade = trade; + if (walletListener != null) { + xmrWalletService.removeWalletListener(walletListener); + walletListener = null; + } + if (tradeListener != null) { + trade.getDepositTxsUpdateCounter().removeListener(tradeListener); + tradeListener = null; } if (txId == null) { @@ -126,15 +139,21 @@ public class TxIdTextField extends AnchorPane { return; } - // listen for tx updates - // TODO: this only listens for new blocks, listen for double spend - txUpdater = new MoneroWalletListener() { - @Override - public void onNewBlock(long lastBlockHeight) { - updateConfidence(txId, false, lastBlockHeight + 1); - } - }; - xmrWalletService.addWalletListener(txUpdater); + // subscribe for tx updates + if (trade == null) { + walletListener = new MoneroWalletListener() { + @Override + public void onNewBlock(long height) { + updateConfidence(txId, trade, false, height); + } + }; + xmrWalletService.addWalletListener(walletListener); // TODO: this only listens for new blocks, listen for double spend + } else { + tradeListener = (observable, oldValue, newValue) -> { + updateConfidence(txId, trade, null, null); + }; + trade.getDepositTxsUpdateCounter().addListener(tradeListener); + } textField.setText(txId); textField.setOnMouseClicked(mouseEvent -> openBlockExplorer(txId)); @@ -143,14 +162,19 @@ public class TxIdTextField extends AnchorPane { txConfidenceIndicator.setVisible(true); // update off main thread - new Thread(() -> updateConfidence(txId, true, null)).start(); + new Thread(() -> updateConfidence(txId, trade, true, null)).start(); } public void cleanup() { - if (xmrWalletService != null && txUpdater != null) { - xmrWalletService.removeWalletListener(txUpdater); - txUpdater = null; + if (xmrWalletService != null && walletListener != null) { + xmrWalletService.removeWalletListener(walletListener); + walletListener = null; } + if (tradeListener != null) { + trade.getDepositTxsUpdateCounter().removeListener(tradeListener); + tradeListener = null; + } + trade = null; textField.setOnMouseClicked(null); blockExplorerIcon.setOnMouseClicked(null); copyIcon.setOnMouseClicked(null); @@ -168,26 +192,31 @@ public class TxIdTextField extends AnchorPane { } } - private synchronized void updateConfidence(String txId, boolean useCache, Long height) { + private synchronized void updateConfidence(String txId, Trade trade, Boolean useCache, Long height) { MoneroTx tx = null; try { - tx = useCache ? xmrWalletService.getTxWithCache(txId) : xmrWalletService.getTx(txId); - tx.setNumConfirmations(tx.isConfirmed() ? (height == null ? xmrWalletService.getConnectionsService().getLastInfo().getHeight() : height) - tx.getHeight(): 0l); // TODO: don't set if tx.getNumConfirmations() works reliably on non-local testnet + if (trade == null) { + tx = useCache ? xmrWalletService.getDaemonTxWithCache(txId) : xmrWalletService.getDaemonTx(txId); + tx.setNumConfirmations(tx.isConfirmed() ? (height == null ? xmrWalletService.getXmrConnectionService().getLastInfo().getHeight() : height) - tx.getHeight(): 0l); // TODO: don't set if tx.getNumConfirmations() works reliably on non-local testnet + } else { + if (txId.equals(trade.getMaker().getDepositTxHash())) tx = trade.getMakerDepositTx(); + else if (txId.equals(trade.getTaker().getDepositTxHash())) tx = trade.getTakerDepositTx(); + } } catch (Exception e) { // do nothing } - updateConfidence(tx); + updateConfidence(tx, trade); } - private void updateConfidence(MoneroTx tx) { + private void updateConfidence(MoneroTx tx, Trade trade) { UserThread.execute(() -> { - GUIUtil.updateConfidence(tx, progressIndicatorTooltip, txConfidenceIndicator); + GUIUtil.updateConfidence(tx, trade, progressIndicatorTooltip, txConfidenceIndicator); if (txConfidenceIndicator.getProgress() != 0) { AnchorPane.setRightAnchor(txConfidenceIndicator, 0.0); } - if (txConfidenceIndicator.getProgress() >= 1.0 && txUpdater != null) { - xmrWalletService.removeWalletListener(txUpdater); // unregister listener - txUpdater = null; + if (txConfidenceIndicator.getProgress() >= 1.0 && walletListener != null) { + xmrWalletService.removeWalletListener(walletListener); // unregister listener + walletListener = null; } }); } diff --git a/desktop/src/main/java/haveno/desktop/components/chart/ChartDataModel.java b/desktop/src/main/java/haveno/desktop/components/chart/ChartDataModel.java index 6e8120ccf4..3b676540a0 100644 --- a/desktop/src/main/java/haveno/desktop/components/chart/ChartDataModel.java +++ b/desktop/src/main/java/haveno/desktop/components/chart/ChartDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.chart; diff --git a/desktop/src/main/java/haveno/desktop/components/chart/ChartView.java b/desktop/src/main/java/haveno/desktop/components/chart/ChartView.java index fed25ed7d1..bb68fdd78a 100644 --- a/desktop/src/main/java/haveno/desktop/components/chart/ChartView.java +++ b/desktop/src/main/java/haveno/desktop/components/chart/ChartView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.chart; diff --git a/desktop/src/main/java/haveno/desktop/components/chart/ChartViewModel.java b/desktop/src/main/java/haveno/desktop/components/chart/ChartViewModel.java index 04035ad9a3..fc2bcb0849 100644 --- a/desktop/src/main/java/haveno/desktop/components/chart/ChartViewModel.java +++ b/desktop/src/main/java/haveno/desktop/components/chart/ChartViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.chart; diff --git a/desktop/src/main/java/haveno/desktop/components/chart/TemporalAdjusterModel.java b/desktop/src/main/java/haveno/desktop/components/chart/TemporalAdjusterModel.java index f6f48f79e6..fdf79afb15 100644 --- a/desktop/src/main/java/haveno/desktop/components/chart/TemporalAdjusterModel.java +++ b/desktop/src/main/java/haveno/desktop/components/chart/TemporalAdjusterModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.chart; diff --git a/desktop/src/main/java/haveno/desktop/components/controlsfx/control/PopOver.java b/desktop/src/main/java/haveno/desktop/components/controlsfx/control/PopOver.java index 88515ab92d..f04dee5960 100644 --- a/desktop/src/main/java/haveno/desktop/components/controlsfx/control/PopOver.java +++ b/desktop/src/main/java/haveno/desktop/components/controlsfx/control/PopOver.java @@ -507,19 +507,30 @@ public class PopOver extends PopupControl { } if (isShowing()) { - if (isAnimated()) { - // Fade Out - Node skinNode = getSkin().getNode(); + super.hide(); - FadeTransition fadeOut = new FadeTransition(fadeOutDuration, - skinNode); - fadeOut.setFromValue(skinNode.getOpacity()); - fadeOut.setToValue(0); - fadeOut.setOnFinished(evt -> { if (super.isShowing()) super.hide(); }); - fadeOut.play(); - } else { - super.hide(); - } + // TODO: getting error "The window has already been closed" with animation which freezes application. + // To recreate: create multiple payment methods, edit offer, go to payment method drop down, hover over info box, then quickly select another payment method + // if (isAnimated()) { + // // Fade Out + // Node skinNode = getSkin().getNode(); + + // FadeTransition fadeOut = new FadeTransition(fadeOutDuration, + // skinNode); + // fadeOut.setFromValue(skinNode.getOpacity()); + // fadeOut.setToValue(0); + // fadeOut.setOnFinished(evt -> { + // try { + // super.hide(); + // } catch (IllegalStateException e) { + // log.warn("Error hiding PopOver: " + e.getMessage()); + // e.printStackTrace(); + // } + // }); + // fadeOut.play(); + // } else { + // super.hide(); + // } } } diff --git a/desktop/src/main/java/haveno/desktop/components/indicator/TxConfidenceIndicator.java b/desktop/src/main/java/haveno/desktop/components/indicator/TxConfidenceIndicator.java index d02817353e..d0cf0ad377 100644 --- a/desktop/src/main/java/haveno/desktop/components/indicator/TxConfidenceIndicator.java +++ b/desktop/src/main/java/haveno/desktop/components/indicator/TxConfidenceIndicator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/desktop/src/main/java/haveno/desktop/components/indicator/skin/StaticProgressIndicatorSkin.java b/desktop/src/main/java/haveno/desktop/components/indicator/skin/StaticProgressIndicatorSkin.java index 1302f9469c..09587ef086 100644 --- a/desktop/src/main/java/haveno/desktop/components/indicator/skin/StaticProgressIndicatorSkin.java +++ b/desktop/src/main/java/haveno/desktop/components/indicator/skin/StaticProgressIndicatorSkin.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/desktop/src/main/java/haveno/desktop/components/list/FilterBox.java b/desktop/src/main/java/haveno/desktop/components/list/FilterBox.java index 4b3f1436a7..9bed491f49 100644 --- a/desktop/src/main/java/haveno/desktop/components/list/FilterBox.java +++ b/desktop/src/main/java/haveno/desktop/components/list/FilterBox.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.list; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AchTransferForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AchTransferForm.java index f8cbbffed1..b566c7b681 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AchTransferForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AchTransferForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AdvancedCashForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AdvancedCashForm.java index db138ab2f0..7d19265349 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AdvancedCashForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AdvancedCashForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AliPayForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AliPayForm.java index c7316b2d11..f4d7cce695 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AliPayForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AliPayForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AmazonGiftCardForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AmazonGiftCardForm.java index 4d976c7cc7..3bcdc44075 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AmazonGiftCardForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AmazonGiftCardForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AssetsForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AssetsForm.java index 5038afd3c9..f57c3f154f 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AssetsForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AssetsForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AustraliaPayidForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AustraliaPayidForm.java index 3f4a3a5392..234b5e88b0 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/AustraliaPayidForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/AustraliaPayidForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; @@ -29,12 +29,17 @@ import haveno.core.util.coin.CoinFormatter; import haveno.core.util.validation.InputValidator; import haveno.desktop.components.InputTextField; import haveno.desktop.util.FormBuilder; +import javafx.scene.control.TextArea; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextArea; import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; +import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; import static haveno.desktop.util.FormBuilder.addTopLabelTextField; +import com.jfoenix.controls.JFXTextArea; + public class AustraliaPayidForm extends PaymentMethodForm { private final AustraliaPayidAccount australiaPayidAccount; private final AustraliaPayidValidator australiaPayidValidator; @@ -42,8 +47,15 @@ public class AustraliaPayidForm extends PaymentMethodForm { public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), ((AustraliaPayidAccountPayload) paymentAccountPayload).getBankAccountName()); - addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.payid"), + + addCompactTopLabelTextField(gridPane, gridRow, 1, Res.get("payment.payid"), ((AustraliaPayidAccountPayload) paymentAccountPayload).getPayid()); + + AustraliaPayidAccountPayload payId = (AustraliaPayidAccountPayload) paymentAccountPayload; + TextArea textExtraInfo = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textExtraInfo.setMinHeight(70); + textExtraInfo.setEditable(false); + textExtraInfo.setText(payId.getExtraInfo()); return gridRow; } @@ -78,6 +90,15 @@ public class AustraliaPayidForm extends PaymentMethodForm { updateFromInputs(); }); + TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow, + Res.get("payment.shared.optionalExtra"), Res.get("payment.shared.extraInfo.prompt")).second; + extraTextArea.setMinHeight(70); + ((JFXTextArea) extraTextArea).setLabelFloat(false); + extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + australiaPayidAccount.setExtraInfo(newValue); + updateFromInputs(); + }); + TradeCurrency singleTradeCurrency = australiaPayidAccount.getSingleTradeCurrency(); String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null"; addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), nameAndCode); @@ -96,11 +117,19 @@ public class AustraliaPayidForm extends PaymentMethodForm { addAccountNameTextFieldWithAutoFillToggleButton(); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), Res.get(australiaPayidAccount.getPaymentMethod().getId())); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.payid"), australiaPayidAccount.getPayid()); + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), australiaPayidAccount.getBankAccountName()).second; field.setMouseTransparent(false); + + TextArea textAreaExtra = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textAreaExtra.setText(australiaPayidAccount.getExtraInfo()); + textAreaExtra.setMinHeight(70); + textAreaExtra.setEditable(false); + TradeCurrency singleTradeCurrency = australiaPayidAccount.getSingleTradeCurrency(); String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : "null"; addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), nameAndCode); diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/BankForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/BankForm.java index 1ba7e5d0d3..ae268620c9 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/BankForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/BankForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/BizumForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/BizumForm.java index 3b11eb9bb9..667f6937b4 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/BizumForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/BizumForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CapitualForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CapitualForm.java index bd75eecc80..0a02b243c9 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CapitualForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CapitualForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAppForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAppForm.java new file mode 100644 index 0000000000..60fe712709 --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAppForm.java @@ -0,0 +1,137 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.components.paymentmethods; + +import com.jfoenix.controls.JFXTextArea; +import haveno.core.account.witness.AccountAgeWitnessService; +import haveno.core.locale.Res; +import haveno.core.payment.CashAppAccount; +import haveno.core.payment.PaymentAccount; +import haveno.core.payment.payload.CashAppAccountPayload; +import haveno.core.payment.payload.PaymentAccountPayload; +import haveno.core.payment.validation.EmailOrMobileNrOrCashtagValidator; +import haveno.core.util.coin.CoinFormatter; +import haveno.core.util.validation.InputValidator; +import haveno.desktop.components.InputTextField; +import haveno.desktop.util.FormBuilder; +import haveno.desktop.util.Layout; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.GridPane; + +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon; +import static haveno.desktop.util.FormBuilder.addTopLabelFlowPane; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextArea; +import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; + +public class CashAppForm extends PaymentMethodForm { + private final CashAppAccount cashAppAccount; + private final EmailOrMobileNrOrCashtagValidator cashAppValidator; + + public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.email.mobile.cashtag"), ((CashAppAccountPayload) paymentAccountPayload).getEmailOrMobileNrOrCashtag()); + + CashAppAccountPayload payId = (CashAppAccountPayload) paymentAccountPayload; + TextArea textExtraInfo = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textExtraInfo.setMinHeight(70); + textExtraInfo.setEditable(false); + textExtraInfo.setText(payId.getExtraInfo()); + + return gridRow; + } + + public CashAppForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, + EmailOrMobileNrOrCashtagValidator cashAppValidator, InputValidator inputValidator, GridPane gridPane, + int gridRow, + CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.cashAppAccount = (CashAppAccount) paymentAccount; + this.cashAppValidator = cashAppValidator; + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + InputTextField mobileNrInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, + Res.get("payment.email.mobile.cashtag")); + mobileNrInputTextField.setValidator(cashAppValidator); + mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + cashAppAccount.setEmailOrMobileNrOrCashtag(newValue.trim()); + updateFromInputs(); + }); + + TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow, + Res.get("payment.shared.optionalExtra"), Res.get("payment.shared.extraInfo.prompt")).second; + extraTextArea.setMinHeight(70); + ((JFXTextArea) extraTextArea).setLabelFloat(false); + extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + cashAppAccount.setExtraInfo(newValue); + updateFromInputs(); + }); + + addCurrenciesGrid(true); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + private void addCurrenciesGrid(boolean isEditable) { + FlowPane flowPane = addTopLabelFlowPane(gridPane, ++gridRow, + Res.get("payment.supportedCurrencies"), Layout.FLOATING_LABEL_DISTANCE * 3, + Layout.FLOATING_LABEL_DISTANCE * 3).second; + + if (isEditable) + flowPane.setId("flow-pane-checkboxes-bg"); + else + flowPane.setId("flow-pane-checkboxes-non-editable-bg"); + + cashAppAccount.getSupportedCurrencies().forEach(e -> + fillUpFlowPaneWithCurrencies(isEditable, flowPane, e, cashAppAccount)); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(cashAppAccount.getEmailOrMobileNrOrCashtag()); + } + + @Override + public void addFormForEditAccount() { + gridRowFrom = gridRow; + addAccountNameTextFieldWithAutoFillToggleButton(); + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.email.mobile.cashtag"), + cashAppAccount.getEmailOrMobileNrOrCashtag()).second; + + TextArea textAreaExtra = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textAreaExtra.setText(cashAppAccount.getExtraInfo()); + textAreaExtra.setMinHeight(70); + textAreaExtra.setEditable(false); + + field.setMouseTransparent(false); + addLimitations(true); + addCurrenciesGrid(false); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && cashAppValidator.validate(cashAppAccount.getEmailOrMobileNrOrCashtag()).isValid + && cashAppAccount.getTradeCurrencies().size() > 0); + } +} diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAtAtmForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAtAtmForm.java index dcbe9fbcb4..339dce099e 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAtAtmForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashAtAtmForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashDepositForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashDepositForm.java index f708d3aee9..d4f1795cdc 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashDepositForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CashDepositForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CelPayForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CelPayForm.java index 855919355a..e883888945 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/CelPayForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/CelPayForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/ChaseQuickPayForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/ChaseQuickPayForm.java index 31bf606f09..4dc8618e42 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/ChaseQuickPayForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/ChaseQuickPayForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/DomesticWireTransferForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/DomesticWireTransferForm.java index 1c6dca1181..995eb4b920 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/DomesticWireTransferForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/DomesticWireTransferForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/F2FForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/F2FForm.java index 3ec594ea27..ada24a71d4 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/F2FForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/F2FForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/FasterPaymentsForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/FasterPaymentsForm.java index f1f6255291..a19f4fb0cb 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/FasterPaymentsForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/FasterPaymentsForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/GeneralUsBankForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/GeneralUsBankForm.java index 2758e0f49a..514cb27a9b 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/GeneralUsBankForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/GeneralUsBankForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/HalCashForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/HalCashForm.java index 719fa6a497..e3e663ac5e 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/HalCashForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/HalCashForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/IfscBankForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/IfscBankForm.java index 3fbfb72b88..f35a839bcf 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/IfscBankForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/IfscBankForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/ImpsForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/ImpsForm.java index 0fa676d096..2794f071d4 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/ImpsForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/ImpsForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java index 55cf4e9ea4..8447a1a01a 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/InteracETransferForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/JapanBankTransferForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/JapanBankTransferForm.java index 37056583bb..118d5580cc 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/JapanBankTransferForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/JapanBankTransferForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneseForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneseForm.java index 76a365780a..66ed3d43ce 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneseForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneseForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyBeamForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyBeamForm.java index dbf6137818..ff9b50220f 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyBeamForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyBeamForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyGramForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyGramForm.java index 6f1513333c..46579d5c87 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyGramForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/MoneyGramForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/NationalBankForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/NationalBankForm.java index 53e56b27dc..132f9e2d4c 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/NationalBankForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/NationalBankForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/NeftForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/NeftForm.java index e671bb07b7..edd8c826d9 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/NeftForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/NeftForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/NequiForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/NequiForm.java index c1b6aecb2b..46f0b7cf8e 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/NequiForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/NequiForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaxumForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaxumForm.java index f59a12ae77..7c7510824a 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaxumForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaxumForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayByMailForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayByMailForm.java index 7305cd5856..c8b9053e83 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayByMailForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayByMailForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayPalForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayPalForm.java new file mode 100644 index 0000000000..8e0d48ee6e --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayPalForm.java @@ -0,0 +1,140 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.components.paymentmethods; + +import com.jfoenix.controls.JFXTextArea; +import haveno.core.account.witness.AccountAgeWitnessService; +import haveno.core.locale.Res; +import haveno.core.payment.PayPalAccount; +import haveno.core.payment.PaymentAccount; +import haveno.core.payment.payload.PayPalAccountPayload; +import haveno.core.payment.payload.PaymentAccountPayload; +import haveno.core.payment.validation.EmailOrMobileNrOrUsernameValidator; +import haveno.core.util.coin.CoinFormatter; +import haveno.core.util.validation.InputValidator; +import haveno.desktop.components.InputTextField; +import haveno.desktop.util.FormBuilder; +import haveno.desktop.util.Layout; +import javafx.scene.control.TextArea; +import javafx.scene.control.TextField; +import javafx.scene.layout.FlowPane; +import javafx.scene.layout.GridPane; + +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextArea; +import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; +import static haveno.desktop.util.FormBuilder.addTopLabelFlowPane; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; + +public class PayPalForm extends PaymentMethodForm { + private final PayPalAccount paypalAccount; + private final EmailOrMobileNrOrUsernameValidator paypalValidator; + + public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.email.mobile.username"), ((PayPalAccountPayload) paymentAccountPayload).getEmailOrMobileNrOrUsername()); + + PayPalAccountPayload payId = (PayPalAccountPayload) paymentAccountPayload; + TextArea textExtraInfo = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textExtraInfo.setMinHeight(70); + textExtraInfo.setEditable(false); + textExtraInfo.setText(payId.getExtraInfo()); + + return gridRow; + } + + public PayPalForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, + EmailOrMobileNrOrUsernameValidator paypalValidator, InputValidator inputValidator, GridPane gridPane, + int gridRow, + CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.paypalAccount = (PayPalAccount) paymentAccount; + this.paypalValidator = paypalValidator; + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + InputTextField mobileNrInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, + Res.get("payment.email.mobile.username")); + mobileNrInputTextField.setValidator(paypalValidator); + mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + paypalAccount.setEmailOrMobileNrOrUsername(newValue.trim()); + updateFromInputs(); + }); + + TextArea extraTextArea = addTopLabelTextArea(gridPane, ++gridRow, + Res.get("payment.shared.optionalExtra"), Res.get("payment.shared.extraInfo.prompt")).second; + extraTextArea.setMinHeight(70); + ((JFXTextArea) extraTextArea).setLabelFloat(false); + extraTextArea.textProperty().addListener((ov, oldValue, newValue) -> { + paypalAccount.setExtraInfo(newValue); + updateFromInputs(); + }); + + addCurrenciesGrid(true); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + private void addCurrenciesGrid(boolean isEditable) { + FlowPane flowPane = addTopLabelFlowPane(gridPane, ++gridRow, + Res.get("payment.supportedCurrencies"), Layout.FLOATING_LABEL_DISTANCE * 3, + Layout.FLOATING_LABEL_DISTANCE * 3).second; + + if (isEditable) + flowPane.setId("flow-pane-checkboxes-bg"); + else + flowPane.setId("flow-pane-checkboxes-non-editable-bg"); + + paypalAccount.getSupportedCurrencies().forEach(e -> + fillUpFlowPaneWithCurrencies(isEditable, flowPane, e, paypalAccount)); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(paypalAccount.getEmailOrMobileNrOrUsername()); + } + + @Override + public void addFormForEditAccount() { + gridRowFrom = gridRow; + addAccountNameTextFieldWithAutoFillToggleButton(); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(paypalAccount.getPaymentMethod().getId())); + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, + Res.get("payment.email.mobile.username"), + paypalAccount.getEmailOrMobileNrOrUsername()).second; + + TextArea textAreaExtra = addCompactTopLabelTextArea(gridPane, ++gridRow, Res.get("payment.shared.extraInfo"), "").second; + textAreaExtra.setText(paypalAccount.getExtraInfo()); + textAreaExtra.setMinHeight(70); + textAreaExtra.setEditable(false); + + field.setMouseTransparent(false); + addLimitations(true); + addCurrenciesGrid(false); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && paypalValidator.validate(paypalAccount.getEmailOrMobileNrOrUsername()).isValid + && paypalAccount.getTradeCurrencies().size() > 0); + } +} diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaymentMethodForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaymentMethodForm.java index 3fa7755cfe..5abdee0d61 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaymentMethodForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaymentMethodForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; @@ -184,14 +184,14 @@ public abstract class PaymentMethodForm { Res.get("payment.maxPeriodAndLimitCrypto", getTimeText(hours), HavenoUtils.formatXmr(accountAgeWitnessService.getMyTradeLimit( - paymentAccount, tradeCurrency.getCode(), OfferDirection.BUY), true)) + paymentAccount, tradeCurrency.getCode(), OfferDirection.BUY, false), true)) : Res.get("payment.maxPeriodAndLimit", getTimeText(hours), HavenoUtils.formatXmr(accountAgeWitnessService.getMyTradeLimit( - paymentAccount, tradeCurrency.getCode(), OfferDirection.BUY), true), + paymentAccount, tradeCurrency.getCode(), OfferDirection.BUY, false), true), HavenoUtils.formatXmr(accountAgeWitnessService.getMyTradeLimit( - paymentAccount, tradeCurrency.getCode(), OfferDirection.SELL), true), + paymentAccount, tradeCurrency.getCode(), OfferDirection.SELL, false), true), DisplayUtils.formatAccountAge(accountAge)); return limitationsText; } diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayseraForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayseraForm.java index 6519561114..140472f8ed 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayseraForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PayseraForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaytmForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaytmForm.java index 481c2cb138..4491076248 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaytmForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PaytmForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PerfectMoneyForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PerfectMoneyForm.java index a1f8a16396..2b60ee9f95 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PerfectMoneyForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PerfectMoneyForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PixForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PixForm.java index 66f20ec3b3..291fa5e0b2 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PixForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PixForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PopmoneyForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PopmoneyForm.java index 8a3119cdf7..daac87ece1 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PopmoneyForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PopmoneyForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PromptPayForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PromptPayForm.java index 5b76d5472d..0ef9f5b16c 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/PromptPayForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/PromptPayForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/RevolutForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/RevolutForm.java index 97fb85ad9c..e11d06fca7 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/RevolutForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/RevolutForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; @@ -63,10 +63,10 @@ public class RevolutForm extends PaymentMethodForm { public void addFormForAddAccount() { gridRowFrom = gridRow + 1; - InputTextField userNameInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.userName")); + InputTextField userNameInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.username")); userNameInputTextField.setValidator(validator); userNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { - account.setUserName(newValue.trim()); + account.setUsername(newValue.trim()); updateFromInputs(); }); @@ -91,7 +91,7 @@ public class RevolutForm extends PaymentMethodForm { @Override protected void autoFillNameTextField() { - setAccountNameWithString(account.getUserName()); + setAccountNameWithString(account.getUsername()); } @Override @@ -101,8 +101,8 @@ public class RevolutForm extends PaymentMethodForm { addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), Res.get(account.getPaymentMethod().getId())); - String userName = account.getUserName(); - TextField userNameTf = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.userName"), userName).second; + String userName = account.getUsername(); + TextField userNameTf = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.username"), userName).second; userNameTf.setMouseTransparent(false); addLimitations(true); @@ -112,7 +112,7 @@ public class RevolutForm extends PaymentMethodForm { @Override public void updateAllInputsValid() { allInputsValid.set(isAccountNameValid() - && validator.validate(account.getUserName()).isValid + && validator.validate(account.getUsername()).isValid && account.getTradeCurrencies().size() > 0); } } diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/RtgsForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/RtgsForm.java index 34bbc50839..0a33650ca7 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/RtgsForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/RtgsForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SameBankForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SameBankForm.java index ff0625d4a0..2052942628 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SameBankForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SameBankForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SatispayForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SatispayForm.java index 8de3edcc76..2198cc65c7 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SatispayForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SatispayForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaForm.java index 2ade62f79f..526d9d37ff 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaInstantForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaInstantForm.java index 4c1b2ff9a4..380f31accb 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaInstantForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SepaInstantForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SpecificBankForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SpecificBankForm.java index 1c4ef58c04..0c3eda1aba 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SpecificBankForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SpecificBankForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/StrikeForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/StrikeForm.java index b4dc9030b0..f496e1de93 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/StrikeForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/StrikeForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; @@ -41,7 +41,7 @@ public class StrikeForm extends PaymentMethodForm { public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { - addTopLabelTextFieldWithCopyIcon(gridPane, gridRow, 1, Res.get("payment.account.userName"), + addTopLabelTextFieldWithCopyIcon(gridPane, gridRow, 1, Res.get("payment.account.username"), ((StrikeAccountPayload) paymentAccountPayload).getHolderName(), Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE); return gridRow; } @@ -60,7 +60,7 @@ public class StrikeForm extends PaymentMethodForm { gridRowFrom = gridRow + 1; - InputTextField holderNameField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.userName")); + InputTextField holderNameField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.username")); holderNameField.setValidator(inputValidator); holderNameField.textProperty().addListener((ov, oldValue, newValue) -> { account.setHolderName(newValue.trim()); @@ -84,7 +84,7 @@ public class StrikeForm extends PaymentMethodForm { addAccountNameTextFieldWithAutoFillToggleButton(); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), Res.get(account.getPaymentMethod().getId())); - TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.userName"), + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.username"), account.getHolderName()).second; field.setMouseTransparent(false); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), account.getSingleTradeCurrency().getNameAndCode()); diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwiftForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwiftForm.java index a0b057c31d..7b7d50b3dd 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwiftForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwiftForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwishForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwishForm.java index 5a55bad09d..916c4f41b5 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwishForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/SwishForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/TikkieForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/TikkieForm.java index eb449c7cdd..1254f40ca6 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/TikkieForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/TikkieForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseForm.java index a85ce0c243..8de2eae567 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseUsdForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseUsdForm.java index 7c8c1251e7..922b5aec75 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseUsdForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/TransferwiseUsdForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/USPostalMoneyOrderForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/USPostalMoneyOrderForm.java index d3fee57fe8..9f7b0eec47 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/USPostalMoneyOrderForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/USPostalMoneyOrderForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpholdForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpholdForm.java index 146248a7f3..5443139dbc 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpholdForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpholdForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; @@ -112,7 +112,7 @@ public class UpholdForm extends PaymentMethodForm { addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), Res.get(upholdAccount.getPaymentMethod().getId())); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.owner"), - Res.get(upholdAccount.getAccountOwner())); + upholdAccount.getAccountOwner()); TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.uphold.accountId"), upholdAccount.getAccountId()).second; field.setMouseTransparent(false); diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpiForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpiForm.java index 167c8078d9..05703c8094 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpiForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/UpiForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/VenmoForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/VenmoForm.java new file mode 100644 index 0000000000..0414eed883 --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/VenmoForm.java @@ -0,0 +1,104 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.components.paymentmethods; + +import haveno.core.account.witness.AccountAgeWitnessService; +import haveno.core.locale.Res; +import haveno.core.locale.TradeCurrency; +import haveno.core.payment.VenmoAccount; +import haveno.core.payment.PaymentAccount; +import haveno.core.payment.payload.VenmoAccountPayload; +import haveno.core.payment.payload.PaymentAccountPayload; +import haveno.core.payment.validation.EmailOrMobileNrOrUsernameValidator; +import haveno.core.util.coin.CoinFormatter; +import haveno.core.util.validation.InputValidator; +import haveno.desktop.components.InputTextField; +import haveno.desktop.util.FormBuilder; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; + +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextFieldWithCopyIcon; +import static haveno.desktop.util.FormBuilder.addTopLabelTextField; + +public class VenmoForm extends PaymentMethodForm { + private final VenmoAccount venmoAccount; + private final EmailOrMobileNrOrUsernameValidator venmoValidator; + + public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.email.mobile.username"), ((VenmoAccountPayload) paymentAccountPayload).getEmailOrMobileNrOrUsername()); + return gridRow; + } + + public VenmoForm(PaymentAccount paymentAccount, AccountAgeWitnessService accountAgeWitnessService, + EmailOrMobileNrOrUsernameValidator venmoValidator, InputValidator inputValidator, GridPane gridPane, + int gridRow, + CoinFormatter formatter) { + super(paymentAccount, accountAgeWitnessService, inputValidator, gridPane, gridRow, formatter); + this.venmoAccount = (VenmoAccount) paymentAccount; + this.venmoValidator = venmoValidator; + } + + @Override + public void addFormForAddAccount() { + gridRowFrom = gridRow + 1; + + InputTextField mobileNrInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, + Res.get("payment.email.mobile.username")); + mobileNrInputTextField.setValidator(venmoValidator); + mobileNrInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { + venmoAccount.setNameOrUsernameOrEmailOrMobileNr(newValue.trim()); + updateFromInputs(); + }); + final TradeCurrency singleTradeCurrency = venmoAccount.getSingleTradeCurrency(); + final String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : ""; + addTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), + nameAndCode); + addLimitations(false); + addAccountNameTextFieldWithAutoFillToggleButton(); + } + + @Override + protected void autoFillNameTextField() { + setAccountNameWithString(venmoAccount.getNameOrUsernameOrEmailOrMobileNr()); + } + + @Override + public void addFormForEditAccount() { + gridRowFrom = gridRow; + addAccountNameTextFieldWithAutoFillToggleButton(); + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), + Res.get(venmoAccount.getPaymentMethod().getId())); + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, + Res.get("payment.email.mobile.username"), + venmoAccount.getNameOrUsernameOrEmailOrMobileNr()).second; + field.setMouseTransparent(false); + final TradeCurrency singleTradeCurrency = venmoAccount.getSingleTradeCurrency(); + final String nameAndCode = singleTradeCurrency != null ? singleTradeCurrency.getNameAndCode() : ""; + addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.currency"), + nameAndCode); + addLimitations(true); + } + + @Override + public void updateAllInputsValid() { + allInputsValid.set(isAccountNameValid() + && venmoValidator.validate(venmoAccount.getNameOrUsernameOrEmailOrMobileNr()).isValid + && venmoAccount.getTradeCurrencies().size() > 0); + } +} diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/VerseForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/VerseForm.java index 8b5e3c9470..823ea81615 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/VerseForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/VerseForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; @@ -39,7 +39,7 @@ public class VerseForm extends PaymentMethodForm { public static int addFormForBuyer(GridPane gridPane, int gridRow, PaymentAccountPayload paymentAccountPayload) { - addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.account.userName"), + addCompactTopLabelTextFieldWithCopyIcon(gridPane, ++gridRow, Res.get("payment.account.username"), ((VerseAccountPayload) paymentAccountPayload).getHolderName()); return gridRow; } @@ -55,7 +55,7 @@ public class VerseForm extends PaymentMethodForm { public void addFormForAddAccount() { gridRowFrom = gridRow + 1; - InputTextField holderNameInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.userName")); + InputTextField holderNameInputTextField = FormBuilder.addInputTextField(gridPane, ++gridRow, Res.get("payment.account.username")); holderNameInputTextField.setValidator(inputValidator); holderNameInputTextField.textProperty().addListener((ov, oldValue, newValue) -> { account.setHolderName(newValue.trim()); @@ -92,7 +92,7 @@ public class VerseForm extends PaymentMethodForm { addAccountNameTextFieldWithAutoFillToggleButton(); addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("shared.paymentMethod"), Res.get(account.getPaymentMethod().getId())); - TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.userName"), + TextField field = addCompactTopLabelTextField(gridPane, ++gridRow, Res.get("payment.account.username"), account.getHolderName()).second; field.setMouseTransparent(false); addLimitations(true); diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/WeChatPayForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/WeChatPayForm.java index 9a75d9af24..eb384687f2 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/WeChatPayForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/WeChatPayForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/WesternUnionForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/WesternUnionForm.java index 2e10d2a156..82cea4ba7b 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/WesternUnionForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/WesternUnionForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/components/paymentmethods/ZelleForm.java b/desktop/src/main/java/haveno/desktop/components/paymentmethods/ZelleForm.java index ac4fa400e3..79dab45ee2 100644 --- a/desktop/src/main/java/haveno/desktop/components/paymentmethods/ZelleForm.java +++ b/desktop/src/main/java/haveno/desktop/components/paymentmethods/ZelleForm.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components.paymentmethods; diff --git a/desktop/src/main/java/haveno/desktop/haveno.css b/desktop/src/main/java/haveno/desktop/haveno.css index c78b9e5b69..fc92b1c308 100644 --- a/desktop/src/main/java/haveno/desktop/haveno.css +++ b/desktop/src/main/java/haveno/desktop/haveno.css @@ -262,7 +262,6 @@ .table-view .table-cell:selected { -fx-background: -fx-accent; -fx-background-color: -fx-selection-bar; - -fx-border-color: -fx-selection-bar; } .number-column.table-cell { @@ -1201,6 +1200,19 @@ textfield */ -fx-border-color: -bs-background-gray; } +.text-area-no-border { + -fx-border-color: -bs-background-color; +} + +.text-area-no-border .content { + -fx-background-color: -bs-background-color; +} + +.text-area-no-border:focused { + -fx-focus-color: -bs-background-color; + -fx-faint-focus-color: -bs-background-color; +} + /******************************************************************************* * * * Tab pane * @@ -1225,6 +1237,14 @@ textfield */ -jfx-rippler-fill: -fx-accent; } +.tab:disabled .jfx-rippler { + -jfx-rippler-fill: none !important; +} + +.tab:disabled .tab-label { + -fx-cursor: default !important; +} + .jfx-tab-pane .headers-region .tab .tab-container .tab-close-button > .jfx-svg-glyph { -fx-shape: "M810 274l-238 238 238 238-60 60-238-238-238 238-60-60 238-238-238-238 60-60 238 238 238-238z"; -jfx-size: 9; @@ -1255,6 +1275,7 @@ textfield */ -fx-padding: 14; -fx-font-size: 0.769em; -fx-font-weight: normal; + -fx-cursor: hand; } .jfx-tab-pane .depth-container { diff --git a/desktop/src/main/java/haveno/desktop/images.css b/desktop/src/main/java/haveno/desktop/images.css index 28887daaab..39f0c7e806 100644 --- a/desktop/src/main/java/haveno/desktop/images.css +++ b/desktop/src/main/java/haveno/desktop/images.css @@ -59,6 +59,10 @@ -fx-image: url("../../images/sell_red.png"); } +#image-lock2x { + -fx-image: url("../../images/lock@2x.png"); +} + #image-expand { -fx-image: url("../../images/expand.png"); } diff --git a/desktop/src/main/java/haveno/desktop/main/MainView.java b/desktop/src/main/java/haveno/desktop/main/MainView.java index a3966492ba..9bf5f378e7 100644 --- a/desktop/src/main/java/haveno/desktop/main/MainView.java +++ b/desktop/src/main/java/haveno/desktop/main/MainView.java @@ -1,25 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main; +import com.google.inject.Inject; import com.jfoenix.controls.JFXBadge; import com.jfoenix.controls.JFXComboBox; -import com.jfoenix.controls.JFXProgressBar; import haveno.common.HavenoException; import haveno.common.Timer; import haveno.common.UserThread; @@ -55,6 +55,10 @@ import haveno.desktop.main.shared.PriceFeedComboBoxItem; import haveno.desktop.main.support.SupportView; import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.Transitions; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Date; +import java.util.Locale; import javafx.animation.Animation; import javafx.animation.KeyFrame; import javafx.animation.Timeline; @@ -81,6 +85,10 @@ import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; +import static javafx.scene.layout.AnchorPane.setBottomAnchor; +import static javafx.scene.layout.AnchorPane.setLeftAnchor; +import static javafx.scene.layout.AnchorPane.setRightAnchor; +import static javafx.scene.layout.AnchorPane.setTopAnchor; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; @@ -93,17 +101,6 @@ import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.Date; -import java.util.Locale; - -import static javafx.scene.layout.AnchorPane.setBottomAnchor; -import static javafx.scene.layout.AnchorPane.setLeftAnchor; -import static javafx.scene.layout.AnchorPane.setRightAnchor; -import static javafx.scene.layout.AnchorPane.setTopAnchor; - @FxmlView @Slf4j public class MainView extends InitializableView<StackPane, MainViewModel> { @@ -168,8 +165,8 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { MainView.rootContainer.setNodeOrientation(NodeOrientation.RIGHT_TO_LEFT); ToggleButton marketButton = new NavButton(MarketView.class, Res.get("mainView.menu.market").toUpperCase()); - ToggleButton buyButton = new NavButton(BuyOfferView.class, Res.get("mainView.menu.buy").toUpperCase()); - ToggleButton sellButton = new NavButton(SellOfferView.class, Res.get("mainView.menu.sell").toUpperCase()); + ToggleButton buyButton = new NavButton(BuyOfferView.class, Res.get("mainView.menu.buyXmr").toUpperCase()); + ToggleButton sellButton = new NavButton(SellOfferView.class, Res.get("mainView.menu.sellXmr").toUpperCase()); ToggleButton portfolioButton = new NavButton(PortfolioView.class, Res.get("mainView.menu.portfolio").toUpperCase()); ToggleButton fundsButton = new NavButton(FundsView.class, Res.get("mainView.menu.funds").toUpperCase()); @@ -226,7 +223,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { Tuple2<Label, VBox> availableBalanceBox = getBalanceBox(Res.get("mainView.balance.available")); availableBalanceBox.first.textProperty().bind(model.getAvailableBalance()); - availableBalanceBox.first.setPrefWidth(105); + availableBalanceBox.first.setPrefWidth(112); availableBalanceBox.first.tooltipProperty().bind(new ObjectBinding<>() { { bind(model.getAvailableBalance()); @@ -355,23 +352,24 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { settingsButtonWithBadge.getStyleClass().add("new"); navigation.addListener((viewPath, data) -> { - if (viewPath.size() != 2 || viewPath.indexOf(MainView.class) != 0) - return; + UserThread.await(() -> { + if (viewPath.size() != 2 || viewPath.indexOf(MainView.class) != 0) return; - Class<? extends View> viewClass = viewPath.tip(); - View view = viewLoader.load(viewClass); - contentContainer.getChildren().setAll(view.getRoot()); + Class<? extends View> viewClass = viewPath.tip(); + View view = viewLoader.load(viewClass); + contentContainer.getChildren().setAll(view.getRoot()); - try { - navButtons.getToggles().stream() - .filter(toggle -> toggle instanceof NavButton) - .filter(button -> viewClass == ((NavButton) button).viewClass) - .findFirst() - .orElseThrow(() -> new HavenoException("No button matching %s found", viewClass)) - .setSelected(true); - } catch (HavenoException e) { - navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class); - } + try { + navButtons.getToggles().stream() + .filter(toggle -> toggle instanceof NavButton) + .filter(button -> viewClass == ((NavButton) button).viewClass) + .findFirst() + .orElseThrow(() -> new HavenoException("No button matching %s found", viewClass)) + .setSelected(true); + } catch (HavenoException e) { + navigation.navigateTo(MainView.class, MarketView.class, OfferBookChartView.class); + } + }); }); VBox splashScreen = createSplashScreen(); @@ -429,14 +427,12 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { return new ListCell<>() { @Override protected void updateItem(PriceFeedComboBoxItem item, boolean empty) { - UserThread.execute(() -> { - super.updateItem(item, empty); - if (!empty && item != null) { - textProperty().bind(item.displayStringProperty); - } else { - textProperty().unbind(); - } - }); + super.updateItem(item, empty); + if (!empty && item != null) { + textProperty().bind(item.displayStringProperty); + } else { + textProperty().unbind(); + } } }; } @@ -521,9 +517,9 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { xmrSplashInfo.setId("splash-error-state-msg"); xmrSplashInfo.getStyleClass().add("error-text"); }; - model.getWalletServiceErrorMsg().addListener(walletServiceErrorMsgListener); + model.getConnectionServiceErrorMsg().addListener(walletServiceErrorMsgListener); - xmrSyncIndicator = new JFXProgressBar(); + xmrSyncIndicator = new ProgressBar(); xmrSyncIndicator.setPrefWidth(305); xmrSyncIndicator.progressProperty().bind(model.getCombinedSyncProgress()); @@ -536,8 +532,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { xmrSyncIcon.setVisible(true); xmrSyncIcon.setManaged(true); - xmrSyncIndicator.setVisible(false); - xmrSyncIndicator.setManaged(false); + // show progress bar until we have checkmark id + boolean inProgress = "".equals(newValue); + xmrSyncIndicator.setVisible(inProgress); + xmrSyncIndicator.setManaged(inProgress); }; model.getXmrSplashSyncIconId().addListener(xmrSyncIconIdListener); @@ -628,7 +626,7 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { } private void disposeSplashScreen() { - model.getWalletServiceErrorMsg().removeListener(walletServiceErrorMsgListener); + model.getConnectionServiceErrorMsg().removeListener(walletServiceErrorMsgListener); model.getXmrSplashSyncIconId().removeListener(xmrSyncIconIdListener); model.getP2pNetworkWarnMsg().removeListener(splashP2PNetworkErrorMsgListener); @@ -666,18 +664,26 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { //blockchainSyncIndicator.setMaxHeight(10); //blockchainSyncIndicator.progressProperty().bind(model.getCombinedSyncProgress()); - model.getWalletServiceErrorMsg().addListener((ov, oldValue, newValue) -> { + model.getConnectionServiceErrorMsg().addListener((ov, oldValue, newValue) -> { if (newValue != null) { xmrInfoLabel.setId("splash-error-state-msg"); xmrInfoLabel.getStyleClass().add("error-text"); - // if (xmrNetworkWarnMsgPopup == null) { - // xmrNetworkWarnMsgPopup = new Popup().warning(newValue); - // xmrNetworkWarnMsgPopup.show(); - // } + if (xmrNetworkWarnMsgPopup == null) { + xmrNetworkWarnMsgPopup = new Popup().warning(newValue); + xmrNetworkWarnMsgPopup.show(); + } } else { xmrInfoLabel.setId("footer-pane"); - // if (xmrNetworkWarnMsgPopup != null) - // xmrNetworkWarnMsgPopup.hide(); + xmrInfoLabel.getStyleClass().remove("error-text"); + if (xmrNetworkWarnMsgPopup != null) + xmrNetworkWarnMsgPopup.hide(); + } + }); + + model.getTopErrorMsg().addListener((ov, oldValue, newValue) -> { + log.warn("Top level warning: " + newValue); + if (newValue != null) { + new Popup().warning(newValue).show(); } }); @@ -770,14 +776,12 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { } }); - model.getUpdatedDataReceived().addListener((observable, oldValue, newValue) -> { - UserThread.execute(() -> { - p2PNetworkIcon.setOpacity(1); - p2pNetworkProgressBar.setProgress(0); - }); - }); + model.getUpdatedDataReceived().addListener((observable, oldValue, newValue) -> UserThread.execute(() -> { + p2PNetworkIcon.setOpacity(1); + p2pNetworkProgressBar.setProgress(0); + })); - p2pNetworkProgressBar = new JFXProgressBar(-1); + p2pNetworkProgressBar = new ProgressBar(-1); p2pNetworkProgressBar.setMaxHeight(2); p2pNetworkProgressBar.prefWidthProperty().bind(p2PNetworkLabel.widthProperty()); @@ -797,12 +801,10 @@ public class MainView extends InitializableView<StackPane, MainViewModel> { private void setupBadge(JFXBadge buttonWithBadge, StringProperty badgeNumber, BooleanProperty badgeEnabled) { buttonWithBadge.textProperty().bind(badgeNumber); buttonWithBadge.setEnabled(badgeEnabled.get()); - badgeEnabled.addListener((observable, oldValue, newValue) -> { - UserThread.execute(() -> { - buttonWithBadge.setEnabled(newValue); - buttonWithBadge.refreshBadge(); - }); - }); + badgeEnabled.addListener((observable, oldValue, newValue) -> UserThread.execute(() -> { + buttonWithBadge.setEnabled(newValue); + buttonWithBadge.refreshBadge(); + })); buttonWithBadge.setPosition(Pos.TOP_RIGHT); buttonWithBadge.setMinHeight(34); diff --git a/desktop/src/main/java/haveno/desktop/main/MainViewModel.java b/desktop/src/main/java/haveno/desktop/main/MainViewModel.java index 3af48666e1..f120b794e7 100644 --- a/desktop/src/main/java/haveno/desktop/main/MainViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/MainViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main; @@ -29,7 +29,7 @@ import haveno.common.util.Tuple2; import haveno.core.account.sign.SignedWitnessService; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.alert.PrivateNotificationManager; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.app.HavenoSetup; import haveno.core.locale.CryptoCurrency; import haveno.core.locale.CurrencyUtil; @@ -44,6 +44,8 @@ import haveno.core.presentation.BalancePresentation; import haveno.core.presentation.SupportTicketsPresentation; import haveno.core.presentation.TradePresentation; import haveno.core.provider.price.PriceFeedService; +import haveno.core.trade.ArbitratorTrade; +import haveno.core.trade.HavenoUtils; import haveno.core.trade.TradeManager; import haveno.core.user.DontShowAgainLookup; import haveno.core.user.Preferences; @@ -102,7 +104,7 @@ import java.util.concurrent.TimeUnit; @Slf4j public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener { private final HavenoSetup havenoSetup; - private final CoreMoneroConnectionsService connectionService; + private final XmrConnectionService xmrConnectionService; private final User user; private final BalancePresentation balancePresentation; private final TradePresentation tradePresentation; @@ -138,6 +140,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener @SuppressWarnings("FieldCanBeLocal") private MonadicBinding<Boolean> tradesAndUIReady; private final Queue<Overlay<?>> popupQueue = new PriorityQueue<>(Comparator.comparing(Overlay::getDisplayOrderPriority)); + private Popup moneroConnectionFallbackPopup; /////////////////////////////////////////////////////////////////////////////////////////// @@ -146,7 +149,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener @Inject public MainViewModel(HavenoSetup havenoSetup, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, XmrWalletService xmrWalletService, User user, BalancePresentation balancePresentation, @@ -170,7 +173,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener CorruptedStorageFileHandler corruptedStorageFileHandler, Navigation navigation) { this.havenoSetup = havenoSetup; - this.connectionService = connectionService; + this.xmrConnectionService = xmrConnectionService; this.user = user; this.balancePresentation = balancePresentation; this.tradePresentation = tradePresentation; @@ -217,7 +220,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener if (newValue) { tradeManager.applyTradePeriodState(); - tradeManager.getObservableList().forEach(trade -> { + tradeManager.getOpenTrades().forEach(trade -> { // check initialization error if (trade.getInitError() != null) { @@ -236,6 +239,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener key = "displayHalfTradePeriodOver" + trade.getId(); if (DontShowAgainLookup.showAgain(key)) { DontShowAgainLookup.dontShowAgain(key, true); + if (trade instanceof ArbitratorTrade) break; // skip popup if arbitrator trade new Popup().warning(Res.get("popup.warning.tradePeriod.halfReached", trade.getShortId(), DisplayUtils.formatDateTime(maxTradePeriodDate))) @@ -246,6 +250,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener key = "displayTradePeriodOver" + trade.getId(); if (DontShowAgainLookup.showAgain(key)) { DontShowAgainLookup.dontShowAgain(key, true); + if (trade instanceof ArbitratorTrade) break; // skip popup if arbitrator trade new Popup().warning(Res.get("popup.warning.tradePeriod.ended", trade.getShortId(), DisplayUtils.formatDateTime(maxTradePeriodDate))) @@ -270,12 +275,23 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener UserThread.execute(() -> getShowAppScreen().set(true)); - // show welcome message if not mainnet + // show welcome message if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_STAGENET) { - String key = "welcome.test"; + String key = "welcome.stagenet"; if (DontShowAgainLookup.showAgain(key)) { UserThread.runAfter(() -> { - new Popup().attention(Res.get("popup.attention.welcome.test")). + new Popup().attention(Res.get("popup.attention.welcome.stagenet")). + dontShowAgainId(key) + .closeButtonText(Res.get("shared.iUnderstand")) + .show(); + }, 1); + } + } else if (Config.baseCurrencyNetwork() == BaseCurrencyNetwork.XMR_MAINNET) { + String key = "welcome.mainnet"; + boolean isReleaseLimited = HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS); + if (DontShowAgainLookup.showAgain(key)) { + UserThread.runAfter(() -> { + new Popup().attention(Res.get(isReleaseLimited ? "popup.attention.welcome.mainnet.test" : "popup.attention.welcome.mainnet")). dontShowAgainId(key) .closeButtonText(Res.get("shared.iUnderstand")) .show(); @@ -319,9 +335,38 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener tacWindow.onAction(acceptedHandler::run).show(); }, 1)); + havenoSetup.setDisplayMoneroConnectionFallbackHandler(show -> { + if (moneroConnectionFallbackPopup == null) { + moneroConnectionFallbackPopup = new Popup() + .headLine(Res.get("connectionFallback.headline")) + .warning(Res.get("connectionFallback.msg")) + .closeButtonText(Res.get("shared.no")) + .actionButtonText(Res.get("shared.yes")) + .onAction(() -> { + havenoSetup.getConnectionServiceFallbackHandlerActive().set(false); + new Thread(() -> HavenoUtils.xmrConnectionService.fallbackToBestConnection()).start(); + }) + .onClose(() -> { + log.warn("User has declined to fallback to the next best available Monero node."); + havenoSetup.getConnectionServiceFallbackHandlerActive().set(false); + }); + } + if (show) { + moneroConnectionFallbackPopup.show(); + } else if (moneroConnectionFallbackPopup.isDisplayed()) { + moneroConnectionFallbackPopup.hide(); + } + }); + havenoSetup.setDisplayTorNetworkSettingsHandler(show -> { if (show) { torNetworkSettingsWindow.show(); + + // bring connection fallback popup to front if displayed + if (moneroConnectionFallbackPopup != null && moneroConnectionFallbackPopup.isDisplayed()) { + moneroConnectionFallbackPopup.hide(); + moneroConnectionFallbackPopup.show(); + } } else if (torNetworkSettingsWindow.isDisplayed()) { torNetworkSettingsWindow.hide(); } @@ -330,7 +375,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener havenoSetup.setChainFileLockedExceptionHandler(msg -> new Popup().warning(msg) .useShutDownButton() .show()); - havenoSetup.setLockedUpFundsHandler(msg -> new Popup().width(850).warning(msg).show()); + tradeManager.setLockedUpFundsHandler(msg -> new Popup().width(850).warning(msg).show()); havenoSetup.setDisplayUpdateHandler((alert, key) -> new DisplayUpdateDownloadWindow(alert, config) .actionButtonText(Res.get("displayUpdateDownloadWindow.button.downloadLater")) @@ -356,7 +401,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener havenoSetup.setDisplaySecurityRecommendationHandler(key -> {}); havenoSetup.setDisplayLocalhostHandler(key -> { if (!DevEnv.isDevMode()) { - Popup popup = new Popup().backgroundInfo(Res.get("popup.moneroLocalhostNode.msg")) + Popup popup = new Popup().backgroundInfo(Res.get("popup.xmrLocalNode.msg")) .dontShowAgainId(key); popup.setDisplayOrderPriority(5); popupQueue.add(popup); @@ -415,11 +460,8 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener .useShutDownButton() .show()); - tradeManager.setTakeOfferRequestErrorMessageHandler(errorMessage -> new Popup() - .warning(Res.get("popup.error.takeOfferRequestFailed", errorMessage)) - .show()); - - havenoSetup.getXmrSyncProgress().addListener((observable, oldValue, newValue) -> updateXmrSyncProgress()); + havenoSetup.getXmrDaemonSyncProgress().addListener((observable, oldValue, newValue) -> updateXmrDaemonSyncProgress()); + havenoSetup.getXmrWalletSyncProgress().addListener((observable, oldValue, newValue) -> updateXmrWalletSyncProgress()); havenoSetup.setFilterWarningHandler(warning -> new Popup().warning(warning).show()); @@ -437,7 +479,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { setupInvalidOpenOffersHandler(); } }); @@ -496,7 +538,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener private void showPopupIfInvalidBtcConfig() { preferences.setMoneroNodesOptionOrdinal(0); - new Popup().warning(Res.get("settings.net.warn.invalidBtcConfig")) + new Popup().warning(Res.get("settings.net.warn.invalidXmrConfig")) .hideCloseButton() .useShutDownButton() .show(); @@ -515,7 +557,7 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener } else { p2PService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { accountAgeWitnessService.publishMyAccountAgeWitness(aliPayAccount.getPaymentAccountPayload()); } }); @@ -532,10 +574,18 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener } } - private void updateXmrSyncProgress() { - final DoubleProperty xmrSyncProgress = havenoSetup.getXmrSyncProgress(); - - combinedSyncProgress.set(xmrSyncProgress.doubleValue()); + private void updateXmrDaemonSyncProgress() { + final DoubleProperty xmrDaemonSyncProgress = havenoSetup.getXmrDaemonSyncProgress(); + UserThread.execute(() -> { + combinedSyncProgress.set(xmrDaemonSyncProgress.doubleValue()); + }); + } + + private void updateXmrWalletSyncProgress() { + final DoubleProperty xmrWalletSyncProgress = havenoSetup.getXmrWalletSyncProgress(); + UserThread.execute(() -> { + combinedSyncProgress.set(xmrWalletSyncProgress.doubleValue()); + }); } private void setupInvalidOpenOffersHandler() { @@ -621,8 +671,12 @@ public class MainViewModel implements ViewModel, HavenoSetup.HavenoSetupListener return combinedSyncProgress; } - StringProperty getWalletServiceErrorMsg() { - return havenoSetup.getWalletServiceErrorMsg(); + StringProperty getConnectionServiceErrorMsg() { + return havenoSetup.getConnectionServiceErrorMsg(); + } + + StringProperty getTopErrorMsg() { + return havenoSetup.getTopErrorMsg(); } StringProperty getXmrSplashSyncIconId() { diff --git a/desktop/src/main/java/haveno/desktop/main/SharedPresentation.java b/desktop/src/main/java/haveno/desktop/main/SharedPresentation.java index 6f736c63bc..b26bb6a3e2 100644 --- a/desktop/src/main/java/haveno/desktop/main/SharedPresentation.java +++ b/desktop/src/main/java/haveno/desktop/main/SharedPresentation.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main; diff --git a/desktop/src/main/java/haveno/desktop/main/account/AccountView.java b/desktop/src/main/java/haveno/desktop/main/account/AccountView.java index 65bab37394..30c434cccd 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/AccountView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/AccountView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account; +import com.google.inject.Inject; import haveno.common.util.Utilities; import haveno.core.locale.Res; import haveno.core.user.DontShowAgainLookup; @@ -38,6 +39,7 @@ import haveno.desktop.main.account.register.mediator.MediatorRegistrationView; import haveno.desktop.main.account.register.refundagent.RefundAgentRegistrationView; import haveno.desktop.main.account.register.signing.SigningView; import haveno.desktop.main.presentation.AccountPresentation; +import java.util.List; import javafx.beans.value.ChangeListener; import javafx.collections.ListChangeListener; import javafx.event.EventHandler; @@ -49,9 +51,6 @@ import javafx.scene.control.TabPane; import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; -import javax.inject.Inject; -import java.util.List; - @FxmlView public class AccountView extends ActivatableView<TabPane, Void> { diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/backup/BackupView.java b/desktop/src/main/java/haveno/desktop/main/account/content/backup/BackupView.java index bc14e1d6f6..d8d3eea770 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/backup/BackupView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/backup/BackupView.java @@ -1,51 +1,55 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.backup; +import com.google.inject.Inject; +import haveno.common.UserThread; import haveno.common.config.Config; import haveno.common.file.FileUtil; import haveno.common.persistence.PersistenceManager; import haveno.common.util.Tuple2; import haveno.common.util.Utilities; +import haveno.core.api.XmrLocalNode; import haveno.core.locale.Res; import haveno.core.user.Preferences; +import haveno.core.xmr.wallet.XmrWalletService; +import haveno.desktop.app.HavenoApp; import haveno.desktop.common.view.ActivatableView; import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.add2Buttons; +import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import haveno.desktop.util.Layout; -import javafx.beans.value.ChangeListener; -import javafx.scene.control.Button; -import javafx.scene.control.TextField; -import javafx.scene.layout.GridPane; -import javafx.stage.DirectoryChooser; - -import javax.annotation.Nullable; -import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.nio.file.Paths; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.concurrent.TimeUnit; -import static haveno.desktop.util.FormBuilder.add2Buttons; -import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import javafx.beans.value.ChangeListener; +import javafx.scene.control.Button; +import javafx.scene.control.TextField; +import javafx.scene.layout.GridPane; +import javafx.stage.DirectoryChooser; +import javax.annotation.Nullable; @FxmlView public class BackupView extends ActivatableView<GridPane, Void> { @@ -125,24 +129,56 @@ public class BackupView extends ActivatableView<GridPane, Void> { openFileOrShowWarning(openLogsButton, logFile); backupNow.setOnAction(event -> { - String backupDirectory = preferences.getBackupDirectory(); - if (backupDirectory != null && backupDirectory.length() > 0) { // We need to flush data to disk - PersistenceManager.flushAllDataToDiskAtBackup(() -> { - try { - String dateString = new SimpleDateFormat("yyyy-MM-dd-HHmmss").format(new Date()); - String destination = Paths.get(backupDirectory, "haveno_backup_" + dateString).toString(); - FileUtil.copyDirectory(dataDir, new File(destination)); - new Popup().feedback(Res.get("account.backup.success", destination)).show(); - } catch (IOException e) { - e.printStackTrace(); - log.error(e.getMessage()); - showWrongPathWarningAndReset(e); - } - }); + + // windows requires closing wallets for read access + if (Utilities.isWindows()) { + new Popup().information(Res.get("settings.net.needRestart")) + .actionButtonText(Res.get("shared.applyAndShutDown")) + .onAction(() -> { + UserThread.runAfter(() -> { + HavenoApp.setOnGracefulShutDownHandler(() -> doBackup()); + HavenoApp.getShutDownHandler().run(); + }, 500, TimeUnit.MILLISECONDS); + }) + .closeButtonText(Res.get("shared.cancel")) + .onClose(() -> { + // nothing to do + }) + .show(); + } else { + doBackup(); } }); } + private void doBackup() { + log.info("Backing up data directory"); + String backupDirectory = preferences.getBackupDirectory(); + if (backupDirectory != null && backupDirectory.length() > 0) { // We need to flush data to disk + PersistenceManager.flushAllDataToDiskAtBackup(() -> { + try { + + // copy data directory to backup directory + String dateString = new SimpleDateFormat("yyyy-MM-dd-HHmmss").format(new Date()); + String destination = Paths.get(backupDirectory, "haveno_backup_" + dateString).toString(); + File destinationFile = new File(destination); + FileUtil.copyDirectory(dataDir, new File(destination)); + + // delete monerod and monero-wallet-rpc binaries from backup so they're reinstalled with permissions + File monerod = new File(destinationFile, XmrLocalNode.MONEROD_NAME); + if (monerod.exists()) monerod.delete(); + File moneroWalletRpc = new File(destinationFile, XmrWalletService.MONERO_WALLET_RPC_NAME); + if (moneroWalletRpc.exists()) moneroWalletRpc.delete(); + new Popup().feedback(Res.get("account.backup.success", destination)).show(); + } catch (IOException e) { + e.printStackTrace(); + log.error(e.getMessage()); + showWrongPathWarningAndReset(e); + } + }); + } + } + private void openFileOrShowWarning(Button button, File dataDir) { button.setOnAction(event -> { try { diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsDataModel.java b/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsDataModel.java index 943c5e9951..95fa4bbd63 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsDataModel.java @@ -1,24 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.cryptoaccounts; import com.google.inject.Inject; -import haveno.common.crypto.KeyRing; import haveno.common.file.CorruptedStorageFileHandler; import haveno.common.proto.persistable.PersistenceProtoResolver; import haveno.core.account.witness.AccountAgeWitnessService; @@ -55,7 +54,6 @@ class CryptoAccountsDataModel extends ActivatableDataModel { private final String accountsFileName = "CryptoPaymentAccounts"; private final PersistenceProtoResolver persistenceProtoResolver; private final CorruptedStorageFileHandler corruptedStorageFileHandler; - private final KeyRing keyRing; @Inject public CryptoAccountsDataModel(User user, @@ -64,8 +62,7 @@ class CryptoAccountsDataModel extends ActivatableDataModel { TradeManager tradeManager, AccountAgeWitnessService accountAgeWitnessService, PersistenceProtoResolver persistenceProtoResolver, - CorruptedStorageFileHandler corruptedStorageFileHandler, - KeyRing keyRing) { + CorruptedStorageFileHandler corruptedStorageFileHandler) { this.user = user; this.preferences = preferences; this.openOfferManager = openOfferManager; @@ -73,7 +70,6 @@ class CryptoAccountsDataModel extends ActivatableDataModel { this.accountAgeWitnessService = accountAgeWitnessService; this.persistenceProtoResolver = persistenceProtoResolver; this.corruptedStorageFileHandler = corruptedStorageFileHandler; - this.keyRing = keyRing; setChangeListener = change -> fillAndSortPaymentAccounts(); } @@ -119,13 +115,16 @@ class CryptoAccountsDataModel extends ActivatableDataModel { }); } + if (paymentAccount.getAccountName() == null) throw new IllegalStateException("Account name cannot be null"); user.addPaymentAccount(paymentAccount); + paymentAccount.onPersistChanges(); if (!(paymentAccount instanceof AssetAccount)) accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); } public void onUpdateAccount(PaymentAccount paymentAccount) { + if (paymentAccount.getAccountName() == null) throw new IllegalStateException("Account name cannot be null"); paymentAccount.onPersistChanges(); user.requestPersistence(); } @@ -154,12 +153,12 @@ class CryptoAccountsDataModel extends ActivatableDataModel { ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream() .filter(paymentAccount -> paymentAccount instanceof AssetAccount) .collect(Collectors.toList())); - GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing); + GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler); } } public void importAccounts(Stage stage) { - GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing); + GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler); } public int getNumPaymentAccounts() { diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsView.java b/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsView.java index 4dde7eed03..8abcd98a9d 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsView.java @@ -1,24 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.cryptoaccounts; -import haveno.asset.CryptoAccountDisclaimer; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.asset.Asset; +import haveno.asset.CryptoAccountDisclaimer; import haveno.asset.coins.Monero; import haveno.common.util.Tuple2; import haveno.common.util.Tuple3; @@ -39,11 +41,17 @@ import haveno.core.util.validation.InputValidator; import haveno.desktop.common.view.FxmlView; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.components.paymentmethods.AssetsForm; +import static haveno.desktop.components.paymentmethods.AssetsForm.INSTANT_TRADE_NEWS; import haveno.desktop.components.paymentmethods.PaymentMethodForm; import haveno.desktop.main.account.content.PaymentAccountsView; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.FormBuilder; +import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.add3ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelListView; import haveno.desktop.util.Layout; +import java.util.Optional; import javafx.collections.ObservableList; import javafx.scene.control.Button; import javafx.scene.control.Label; @@ -52,16 +60,6 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.Optional; - -import static haveno.desktop.components.paymentmethods.AssetsForm.INSTANT_TRADE_NEWS; -import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.add3ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelListView; - @FxmlView public class CryptoAccountsView extends PaymentAccountsView<GridPane, CryptoAccountsViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsViewModel.java b/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsViewModel.java index 74ac3a40fb..9043c9cd37 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/cryptoaccounts/CryptoAccountsViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.cryptoaccounts; diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/notifications/ManageMarketAlertsWindow.java b/desktop/src/main/java/haveno/desktop/main/account/content/notifications/ManageMarketAlertsWindow.java index 9638b995a7..9ac8a97d47 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/notifications/ManageMarketAlertsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/notifications/ManageMarketAlertsWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.notifications; diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/notifications/MobileNotificationsView.java b/desktop/src/main/java/haveno/desktop/main/account/content/notifications/MobileNotificationsView.java index ba20aa9c53..255558ab22 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/notifications/MobileNotificationsView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/notifications/MobileNotificationsView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.notifications; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.common.util.Tuple2; import haveno.common.util.Tuple3; @@ -47,8 +48,16 @@ import haveno.desktop.components.InfoInputTextField; import haveno.desktop.components.InputTextField; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.FormBuilder; +import static haveno.desktop.util.FormBuilder.addButton; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addSlideToggleButton; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelButton; import haveno.desktop.util.GUIUtil; import haveno.desktop.util.Layout; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.collections.SetChangeListener; @@ -64,17 +73,6 @@ import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; import javafx.util.StringConverter; -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static haveno.desktop.util.FormBuilder.addButton; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addSlideToggleButton; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelButton; - @FxmlView public class MobileNotificationsView extends ActivatableView<GridPane, Void> { private final Preferences preferences; diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/notifications/NoWebCamFoundException.java b/desktop/src/main/java/haveno/desktop/main/account/content/notifications/NoWebCamFoundException.java index c78ea84d8b..8f30b91872 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/notifications/NoWebCamFoundException.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/notifications/NoWebCamFoundException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.notifications; diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/password/PasswordView.java b/desktop/src/main/java/haveno/desktop/main/account/content/password/PasswordView.java index 332170d3d7..e59309c75f 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/password/PasswordView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/password/PasswordView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.password; +import static com.google.common.base.Preconditions.checkArgument; +import com.google.inject.Inject; import com.jfoenix.validation.RequiredFieldValidator; import haveno.common.util.Tuple4; import haveno.core.api.CoreAccountService; @@ -33,6 +35,11 @@ import haveno.desktop.main.MainView; import haveno.desktop.main.account.AccountView; import haveno.desktop.main.account.content.backup.BackupView; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabel; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addPasswordTextField; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import org.apache.commons.lang3.exception.ExceptionUtils; import haveno.desktop.util.Layout; import haveno.desktop.util.validation.PasswordValidator; import javafx.beans.value.ChangeListener; @@ -41,14 +48,6 @@ import javafx.scene.control.Label; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; -import javax.inject.Inject; - -import static com.google.common.base.Preconditions.checkArgument; -import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabel; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; -import static haveno.desktop.util.FormBuilder.addPasswordTextField; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; - @FxmlView public class PasswordView extends ActivatableView<GridPane, Void> { @@ -159,8 +158,9 @@ public class PasswordView extends ActivatableView<GridPane, Void> { backupWalletAndResetFields(); walletsManager.clearBackup(); } catch (Throwable t) { + log.error("Error applying password: {}\n", t.getMessage(), t); new Popup() - .warning(Res.get("password.walletEncryptionFailed")) + .warning(Res.get("password.walletEncryptionFailed") + "\n\n" + ExceptionUtils.getStackTrace(t)) .show(); } } diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/seedwords/SeedWordsView.java b/desktop/src/main/java/haveno/desktop/main/account/content/seedwords/SeedWordsView.java index 6cac3ee56a..9d90994029 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/seedwords/SeedWordsView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/seedwords/SeedWordsView.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,6 +35,8 @@ package haveno.desktop.main.account.content.seedwords; import com.google.common.base.Splitter; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.locale.Res; import haveno.core.offer.OpenOfferManager; @@ -29,7 +48,19 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.SharedPresentation; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.WalletPasswordWindow; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelDatePicker; +import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; import haveno.desktop.util.Layout; +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.TimeZone; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; @@ -40,23 +71,7 @@ import javafx.scene.layout.GridPane; import org.bitcoinj.crypto.MnemonicCode; import org.bitcoinj.crypto.MnemonicException; import org.bitcoinj.wallet.DeterministicSeed; - -import javax.inject.Inject; -import javax.inject.Named; -import java.io.File; -import java.io.IOException; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.ZoneOffset; -import java.util.TimeZone; - -import static haveno.desktop.util.FormBuilder.addMultilineLabel; -import static haveno.desktop.util.FormBuilder.addPrimaryActionButtonAFterGroup; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelDatePicker; -import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; -import static javafx.beans.binding.Bindings.createBooleanBinding; +//import static javafx.beans.binding.Bindings.createBooleanBinding; @FxmlView public class SeedWordsView extends ActivatableView<GridPane, Void> { @@ -108,14 +123,21 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> { datePicker = addTopLabelDatePicker(root, ++gridRow, Res.get("seed.date"), 10).second; datePicker.setMouseTransparent(true); - addTitledGroupBg(root, ++gridRow, 3, Res.get("seed.restore.title"), Layout.GROUP_DISTANCE); - seedWordsTextArea = addTopLabelTextArea(root, gridRow, Res.get("seed.seedWords"), "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; - seedWordsTextArea.getStyleClass().add("wallet-seed-words"); - seedWordsTextArea.setPrefHeight(40); - seedWordsTextArea.setMaxHeight(40); + // TODO: to re-enable restore functionality: + // - uncomment code throughout this file + // - support getting wallet's restore height + // - support translating between date and restore height + // - clear XmrAddressEntries which are incompatible with new wallet and other tests + // - update mnemonic validation and restore calls - restoreDatePicker = addTopLabelDatePicker(root, ++gridRow, Res.get("seed.date"), 10).second; - restoreButton = addPrimaryActionButtonAFterGroup(root, ++gridRow, Res.get("seed.restore")); + // addTitledGroupBg(root, ++gridRow, 3, Res.get("seed.restore.title"), Layout.GROUP_DISTANCE); + // seedWordsTextArea = addTopLabelTextArea(root, gridRow, Res.get("seed.seedWords"), "", Layout.FIRST_ROW_AND_GROUP_DISTANCE).second; + // seedWordsTextArea.getStyleClass().add("wallet-seed-words"); + // seedWordsTextArea.setPrefHeight(40); + // seedWordsTextArea.setMaxHeight(40); + + // restoreDatePicker = addTopLabelDatePicker(root, ++gridRow, Res.get("seed.date"), 10).second; + // restoreButton = addPrimaryActionButtonAFterGroup(root, ++gridRow, Res.get("seed.restore")); addTitledGroupBg(root, ++gridRow, 1, Res.get("shared.information"), Layout.GROUP_DISTANCE); addMultilineLabel(root, gridRow, Res.get("account.seed.info"), @@ -143,21 +165,21 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> { @Override public void activate() { - seedWordsValid.addListener(seedWordsValidChangeListener); - seedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener); - restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !seedWordsEdited.get(), - seedWordsValid, seedWordsEdited)); + // seedWordsValid.addListener(seedWordsValidChangeListener); + // seedWordsTextArea.textProperty().addListener(seedWordsTextAreaChangeListener); + // restoreButton.disableProperty().bind(createBooleanBinding(() -> !seedWordsValid.get() || !seedWordsEdited.get(), + // seedWordsValid, seedWordsEdited)); - restoreButton.setOnAction(e -> { - new Popup().information(Res.get("account.seed.restore.info")) - .closeButtonText(Res.get("shared.cancel")) - .actionButtonText(Res.get("account.seed.restore.ok")) - .onAction(this::onRestore) - .show(); - }); + // restoreButton.setOnAction(e -> { + // new Popup().information(Res.get("account.seed.restore.info")) + // .closeButtonText(Res.get("shared.cancel")) + // .actionButtonText(Res.get("account.seed.restore.ok")) + // .onAction(this::onRestore) + // .show(); + // }); - seedWordsTextArea.getStyleClass().remove("validation-error"); - restoreDatePicker.getStyleClass().remove("validation-error"); + // seedWordsTextArea.getStyleClass().remove("validation-error"); + // restoreDatePicker.getStyleClass().remove("validation-error"); String key = "showBackupWarningAtSeedPhrase"; if (DontShowAgainLookup.showAgain(key)) { @@ -197,19 +219,20 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> { @Override protected void deactivate() { - seedWordsValid.removeListener(seedWordsValidChangeListener); - seedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener); - restoreButton.disableProperty().unbind(); - restoreButton.setOnAction(null); - displaySeedWordsTextArea.setText(""); - seedWordsTextArea.setText(""); - - restoreDatePicker.setValue(null); datePicker.setValue(null); - seedWordsTextArea.getStyleClass().remove("validation-error"); - restoreDatePicker.getStyleClass().remove("validation-error"); + // seedWordsValid.removeListener(seedWordsValidChangeListener); + // seedWordsTextArea.textProperty().removeListener(seedWordsTextAreaChangeListener); + // restoreButton.disableProperty().unbind(); + // restoreButton.setOnAction(null); + + // seedWordsTextArea.setText(""); + + // restoreDatePicker.setValue(null); + + // seedWordsTextArea.getStyleClass().remove("validation-error"); + // restoreDatePicker.getStyleClass().remove("validation-error"); } private void askForPassword() { @@ -225,6 +248,7 @@ public class SeedWordsView extends ActivatableView<GridPane, Void> { private void showSeedScreen() { displaySeedWordsTextArea.setText(seedWordText); + walletCreationDate = Instant.ofEpochSecond(xmrWalletService.getWalletCreationDate()).atZone(ZoneId.systemDefault()).toLocalDate(); datePicker.setValue(walletCreationDate); } diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsDataModel.java b/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsDataModel.java index 7010cb1785..909aa945dc 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsDataModel.java @@ -1,24 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.traditionalaccounts; import com.google.inject.Inject; -import haveno.common.crypto.KeyRing; import haveno.common.file.CorruptedStorageFileHandler; import haveno.common.proto.persistable.PersistenceProtoResolver; import haveno.core.account.witness.AccountAgeWitnessService; @@ -56,7 +55,6 @@ class TraditionalAccountsDataModel extends ActivatableDataModel { private final String accountsFileName = "FiatPaymentAccounts"; private final PersistenceProtoResolver persistenceProtoResolver; private final CorruptedStorageFileHandler corruptedStorageFileHandler; - private final KeyRing keyRing; @Inject public TraditionalAccountsDataModel(User user, @@ -65,8 +63,7 @@ class TraditionalAccountsDataModel extends ActivatableDataModel { TradeManager tradeManager, AccountAgeWitnessService accountAgeWitnessService, PersistenceProtoResolver persistenceProtoResolver, - CorruptedStorageFileHandler corruptedStorageFileHandler, - KeyRing keyRing) { + CorruptedStorageFileHandler corruptedStorageFileHandler) { this.user = user; this.preferences = preferences; this.openOfferManager = openOfferManager; @@ -74,7 +71,6 @@ class TraditionalAccountsDataModel extends ActivatableDataModel { this.accountAgeWitnessService = accountAgeWitnessService; this.persistenceProtoResolver = persistenceProtoResolver; this.corruptedStorageFileHandler = corruptedStorageFileHandler; - this.keyRing = keyRing; setChangeListener = change -> fillAndSortPaymentAccounts(); } @@ -108,6 +104,7 @@ class TraditionalAccountsDataModel extends ActivatableDataModel { TradeCurrency singleTradeCurrency = paymentAccount.getSingleTradeCurrency(); List<TradeCurrency> tradeCurrencies = paymentAccount.getTradeCurrencies(); if (singleTradeCurrency != null) { + paymentAccount.setSelectedTradeCurrency(singleTradeCurrency); if (singleTradeCurrency instanceof TraditionalCurrency) preferences.addTraditionalCurrency((TraditionalCurrency) singleTradeCurrency); else @@ -127,6 +124,7 @@ class TraditionalAccountsDataModel extends ActivatableDataModel { } user.addPaymentAccount(paymentAccount); + paymentAccount.onPersistChanges(); accountAgeWitnessService.publishMyAccountAgeWitness(paymentAccount.getPaymentAccountPayload()); accountAgeWitnessService.signAndPublishSameNameAccounts(); @@ -157,12 +155,12 @@ class TraditionalAccountsDataModel extends ActivatableDataModel { ArrayList<PaymentAccount> accounts = new ArrayList<>(user.getPaymentAccounts().stream() .filter(paymentAccount -> !(paymentAccount instanceof AssetAccount)) .collect(Collectors.toList())); - GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing); + GUIUtil.exportAccounts(accounts, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler); } } public void importAccounts(Stage stage) { - GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler, keyRing); + GUIUtil.importAccounts(user, accountsFileName, preferences, stage, persistenceProtoResolver, corruptedStorageFileHandler); } public int getNumPaymentAccounts() { diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsView.java b/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsView.java index 1f108b817a..6ed91e956b 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.traditionalaccounts; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.util.Tuple2; import haveno.common.util.Tuple3; @@ -26,18 +28,21 @@ import haveno.core.locale.Res; import haveno.core.offer.OfferRestrictions; import haveno.core.payment.AmazonGiftCardAccount; import haveno.core.payment.AustraliaPayidAccount; +import haveno.core.payment.CashAppAccount; import haveno.core.payment.CashAtAtmAccount; -import haveno.core.payment.PayByMailAccount; import haveno.core.payment.CashDepositAccount; -import haveno.core.payment.ZelleAccount; import haveno.core.payment.F2FAccount; import haveno.core.payment.HalCashAccount; import haveno.core.payment.MoneyGramAccount; +import haveno.core.payment.PayByMailAccount; +import haveno.core.payment.PayPalAccount; import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccountFactory; import haveno.core.payment.RevolutAccount; import haveno.core.payment.USPostalMoneyOrderAccount; +import haveno.core.payment.VenmoAccount; import haveno.core.payment.WesternUnionAccount; +import haveno.core.payment.ZelleAccount; import haveno.core.payment.payload.PaymentMethod; import haveno.core.payment.validation.AdvancedCashValidator; import haveno.core.payment.validation.AliPayValidator; @@ -46,6 +51,8 @@ import haveno.core.payment.validation.BICValidator; import haveno.core.payment.validation.CapitualValidator; import haveno.core.payment.validation.ChaseQuickPayValidator; import haveno.core.payment.validation.EmailOrMobileNrValidator; +import haveno.core.payment.validation.EmailOrMobileNrOrCashtagValidator; +import haveno.core.payment.validation.EmailOrMobileNrOrUsernameValidator; import haveno.core.payment.validation.F2FValidator; import haveno.core.payment.validation.HalCashValidator; import haveno.core.payment.validation.InteracETransferValidator; @@ -65,6 +72,7 @@ import haveno.core.trade.HavenoUtils; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; import haveno.desktop.common.view.FxmlView; +import haveno.desktop.components.AutocompleteComboBox; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.components.paymentmethods.AchTransferForm; import haveno.desktop.components.paymentmethods.AdvancedCashForm; @@ -73,12 +81,11 @@ import haveno.desktop.components.paymentmethods.AmazonGiftCardForm; import haveno.desktop.components.paymentmethods.AustraliaPayidForm; import haveno.desktop.components.paymentmethods.BizumForm; import haveno.desktop.components.paymentmethods.CapitualForm; +import haveno.desktop.components.paymentmethods.CashAppForm; import haveno.desktop.components.paymentmethods.CashAtAtmForm; -import haveno.desktop.components.paymentmethods.PayByMailForm; import haveno.desktop.components.paymentmethods.CashDepositForm; import haveno.desktop.components.paymentmethods.CelPayForm; import haveno.desktop.components.paymentmethods.ChaseQuickPayForm; -import haveno.desktop.components.paymentmethods.ZelleForm; import haveno.desktop.components.paymentmethods.DomesticWireTransferForm; import haveno.desktop.components.paymentmethods.F2FForm; import haveno.desktop.components.paymentmethods.FasterPaymentsForm; @@ -93,6 +100,8 @@ import haveno.desktop.components.paymentmethods.NationalBankForm; import haveno.desktop.components.paymentmethods.NeftForm; import haveno.desktop.components.paymentmethods.NequiForm; import haveno.desktop.components.paymentmethods.PaxumForm; +import haveno.desktop.components.paymentmethods.PayByMailForm; +import haveno.desktop.components.paymentmethods.PayPalForm; import haveno.desktop.components.paymentmethods.PaymentMethodForm; import haveno.desktop.components.paymentmethods.PayseraForm; import haveno.desktop.components.paymentmethods.PaytmForm; @@ -116,18 +125,27 @@ import haveno.desktop.components.paymentmethods.TransferwiseUsdForm; import haveno.desktop.components.paymentmethods.USPostalMoneyOrderForm; import haveno.desktop.components.paymentmethods.UpholdForm; import haveno.desktop.components.paymentmethods.UpiForm; +import haveno.desktop.components.paymentmethods.VenmoForm; import haveno.desktop.components.paymentmethods.VerseForm; import haveno.desktop.components.paymentmethods.WeChatPayForm; import haveno.desktop.components.paymentmethods.WesternUnionForm; +import haveno.desktop.components.paymentmethods.ZelleForm; import haveno.desktop.main.account.content.PaymentAccountsView; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.FormBuilder; +import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.add3ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addLabel; +import static haveno.desktop.util.FormBuilder.addTopLabelListView; import haveno.desktop.util.GUIUtil; import haveno.desktop.util.Layout; +import java.math.BigInteger; +import java.util.List; +import java.util.stream.Collectors; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.control.Button; -import javafx.scene.control.ComboBox; import javafx.scene.control.Label; import javafx.scene.control.ListView; import javafx.scene.layout.GridPane; @@ -135,17 +153,6 @@ import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.StringConverter; -import javax.inject.Inject; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.List; -import java.util.stream.Collectors; - -import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.add3ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelListView; - @FxmlView public class TraditionalAccountsView extends PaymentAccountsView<GridPane, TraditionalAccountsViewModel> { @@ -160,6 +167,9 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi private final PerfectMoneyValidator perfectMoneyValidator; private final SwishValidator swishValidator; private final EmailOrMobileNrValidator zelleValidator; + private final EmailOrMobileNrOrUsernameValidator paypalValidator; + private final EmailOrMobileNrOrUsernameValidator venmoValidator; + private final EmailOrMobileNrOrCashtagValidator cashAppValidator; private final ChaseQuickPayValidator chaseQuickPayValidator; private final InteracETransferValidator interacETransferValidator; private final JapanBankTransferValidator japanBankTransferValidator; @@ -172,7 +182,7 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi private final AdvancedCashValidator advancedCashValidator; private final TransferwiseValidator transferwiseValidator; private final CoinFormatter formatter; - private ComboBox<PaymentMethod> paymentMethodComboBox; + private AutocompleteComboBox<PaymentMethod> paymentMethodComboBox; private PaymentMethodForm paymentMethodForm; private TitledGroupBg accountTitledGroupBg; private Button saveNewAccountButton; @@ -191,6 +201,8 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi PerfectMoneyValidator perfectMoneyValidator, SwishValidator swishValidator, EmailOrMobileNrValidator zelleValidator, + EmailOrMobileNrOrCashtagValidator cashAppValidator, + EmailOrMobileNrOrUsernameValidator emailMobileUsernameValidator, ChaseQuickPayValidator chaseQuickPayValidator, InteracETransferValidator interacETransferValidator, JapanBankTransferValidator japanBankTransferValidator, @@ -219,6 +231,9 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi this.perfectMoneyValidator = perfectMoneyValidator; this.swishValidator = swishValidator; this.zelleValidator = zelleValidator; + this.paypalValidator = emailMobileUsernameValidator; + this.venmoValidator = emailMobileUsernameValidator; + this.cashAppValidator = cashAppValidator; this.chaseQuickPayValidator = chaseQuickPayValidator; this.interacETransferValidator = interacETransferValidator; this.japanBankTransferValidator = japanBankTransferValidator; @@ -260,7 +275,7 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi new Popup().information(Res.get("payment.f2f.info")) .width(700) .closeButtonText(Res.get("payment.f2f.info.openURL")) - .onClose(() -> GUIUtil.openWebPage("https://bisq.wiki/Face-to-face_(payment_method)")) + .onClose(() -> GUIUtil.openWebPage("https://docs.haveno.exchange/the-project/payment_methods/F2F")) .actionButtonText(Res.get("shared.iUnderstand")) .onAction(() -> doSaveNewAccount(paymentAccount)) .show(); @@ -364,6 +379,27 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi .actionButtonText(Res.get("shared.iUnderstand")) .onAction(() -> doSaveNewAccount(paymentAccount)) .show(); + } else if (paymentAccount instanceof CashAppAccount) { + new Popup().warning(Res.get("payment.cashapp.info")) + .width(700) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); + } else if (paymentAccount instanceof VenmoAccount) { + new Popup().warning(Res.get("payment.venmo.info")) + .width(700) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); + } else if (paymentAccount instanceof PayPalAccount) { + new Popup().warning(Res.get("payment.paypal.info")) + .width(700) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.iUnderstand")) + .onAction(() -> doSaveNewAccount(paymentAccount)) + .show(); } else { doSaveNewAccount(paymentAccount); } @@ -428,14 +464,17 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi removeAccountRows(); addAccountButton.setDisable(true); accountTitledGroupBg = addTitledGroupBg(root, ++gridRow, 2, Res.get("shared.createNewAccount"), Layout.GROUP_DISTANCE); - paymentMethodComboBox = FormBuilder.addComboBox(root, gridRow, Res.get("shared.selectPaymentMethod"), Layout.FIRST_ROW_AND_GROUP_DISTANCE); - paymentMethodComboBox.setVisibleRowCount(11); + addLabel(root, gridRow, Res.get("shared.createNewAccountDescription"), Layout.COMPACT_FIRST_ROW_DISTANCE); + paymentMethodComboBox = FormBuilder.addAutocompleteComboBox( + root, gridRow, Res.get("shared.selectPaymentMethod"), Layout.TWICE_FIRST_ROW_AND_GROUP_DISTANCE + Layout.PADDING + ); + paymentMethodComboBox.setVisibleRowCount(Math.min(paymentMethodComboBox.getItems().size(), 10)); paymentMethodComboBox.setPrefWidth(250); List<PaymentMethod> list = PaymentMethod.paymentMethods.stream() .filter(PaymentMethod::isTraditional) .sorted() .collect(Collectors.toList()); - paymentMethodComboBox.setItems(FXCollections.observableArrayList(list)); + paymentMethodComboBox.setAutocompleteItems(FXCollections.observableArrayList(list)); paymentMethodComboBox.setConverter(new StringConverter<>() { @Override public String toString(PaymentMethod paymentMethod) { @@ -444,10 +483,15 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi @Override public PaymentMethod fromString(String s) { - return null; + if (s.isEmpty()) + return null; + + return paymentMethodComboBox.getItems().stream() + .filter(item -> Res.get(item.getId()).equals(s)) + .findAny().orElse(null); } }); - paymentMethodComboBox.setOnAction(e -> { + paymentMethodComboBox.setOnChangeConfirmed(e -> { if (paymentMethodForm != null) { FormBuilder.removeRowsFromGridPane(root, 3, paymentMethodForm.getGridRow() + 1); GridPane.setRowSpan(accountTitledGroupBg, paymentMethodForm.getRowSpan() + 1); @@ -515,6 +559,7 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi } private PaymentMethodForm getPaymentMethodForm(PaymentMethod paymentMethod) { + if (paymentMethod == null) return null; final PaymentAccount paymentAccount = PaymentAccountFactory.getPaymentAccount(paymentMethod); paymentAccount.init(); return getPaymentMethodForm(paymentMethod, paymentAccount); @@ -626,6 +671,12 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi return new AchTransferForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); case PaymentMethod.DOMESTIC_WIRE_TRANSFER_ID: return new DomesticWireTransferForm(paymentAccount, accountAgeWitnessService, inputValidator, root, gridRow, formatter); + case PaymentMethod.PAYPAL_ID: + return new PayPalForm(paymentAccount, accountAgeWitnessService, paypalValidator, inputValidator, root, gridRow, formatter); + case PaymentMethod.VENMO_ID: + return new VenmoForm(paymentAccount, accountAgeWitnessService, venmoValidator, inputValidator, root, gridRow, formatter); + case PaymentMethod.CASH_APP_ID: + return new CashAppForm(paymentAccount, accountAgeWitnessService, cashAppValidator, inputValidator, root, gridRow, formatter); default: log.error("Not supported PaymentMethod: " + paymentMethod); return null; @@ -671,4 +722,3 @@ public class TraditionalAccountsView extends PaymentAccountsView<GridPane, Tradi } } - diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsViewModel.java b/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsViewModel.java index 737b4ffae5..21eb83a3ba 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/traditionalaccounts/TraditionalAccountsViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.traditionalaccounts; diff --git a/desktop/src/main/java/haveno/desktop/main/account/content/walletinfo/WalletInfoView.java b/desktop/src/main/java/haveno/desktop/main/account/content/walletinfo/WalletInfoView.java index 2d4f624340..d761ffec51 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/content/walletinfo/WalletInfoView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/content/walletinfo/WalletInfoView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.content.walletinfo; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.locale.Res; import haveno.core.util.FormattingUtils; @@ -29,6 +31,10 @@ import haveno.desktop.common.view.ActivatableView; import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.ShowWalletDataWindow; +import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelTextField; import haveno.desktop.util.Layout; import javafx.scene.control.Button; import javafx.scene.control.TextField; @@ -37,14 +43,6 @@ import org.bitcoinj.core.Coin; import org.bitcoinj.core.Transaction; import org.bitcoinj.script.Script; import org.bitcoinj.wallet.DeterministicKeyChain; - -import javax.inject.Inject; -import javax.inject.Named; - -import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelTextField; import static org.bitcoinj.wallet.Wallet.BalanceType.ESTIMATED_SPENDABLE; @FxmlView diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationView.java b/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationView.java index 5c62603c15..4f51a634da 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register; diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationViewModel.java b/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationViewModel.java index 8259472139..47fcbc5257 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/AgentRegistrationViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register; diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationView.java b/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationView.java index 81aa0d88f1..8a0350762f 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationView.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.arbitrator; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.locale.Res; import haveno.core.support.dispute.arbitration.arbitrator.Arbitrator; import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.account.register.AgentRegistrationView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class ArbitratorRegistrationView extends AgentRegistrationView<Arbitrator, ArbitratorRegistrationViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationViewModel.java b/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationViewModel.java index 138d00372c..080446f882 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/arbitrator/ArbitratorRegistrationViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.arbitrator; diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationView.java b/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationView.java index 0cfa2524cf..b2fe9b8908 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationView.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.mediator; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.locale.Res; import haveno.core.support.dispute.mediation.mediator.Mediator; import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.account.register.AgentRegistrationView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class MediatorRegistrationView extends AgentRegistrationView<Mediator, MediatorRegistrationViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationViewModel.java b/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationViewModel.java index 23ec857c24..8b7656714f 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/mediator/MediatorRegistrationViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.mediator; diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationView.java b/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationView.java index 1f1ff3512a..80a445f60b 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationView.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.refundagent; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.locale.Res; import haveno.core.support.dispute.refund.refundagent.RefundAgent; import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.account.register.AgentRegistrationView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class RefundAgentRegistrationView extends AgentRegistrationView<RefundAgent, RefundAgentRegistrationViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationViewModel.java b/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationViewModel.java index 9de55eedd5..4c008d09f9 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/refundagent/RefundAgentRegistrationViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.refundagent; diff --git a/desktop/src/main/java/haveno/desktop/main/account/register/signing/SigningView.java b/desktop/src/main/java/haveno/desktop/main/account/register/signing/SigningView.java index ec611af0a3..f127975bc5 100644 --- a/desktop/src/main/java/haveno/desktop/main/account/register/signing/SigningView.java +++ b/desktop/src/main/java/haveno/desktop/main/account/register/signing/SigningView.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.account.register.signing; +import com.google.inject.Inject; import haveno.common.util.Utilities; import haveno.desktop.common.view.ActivatableView; import haveno.desktop.common.view.FxmlView; @@ -30,8 +31,6 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; -import javax.inject.Inject; - @FxmlView public class SigningView extends ActivatableView<AnchorPane, Void> { diff --git a/desktop/src/main/java/haveno/desktop/main/debug/DebugView.java b/desktop/src/main/java/haveno/desktop/main/debug/DebugView.java index 9a3319d485..00ab2680b5 100644 --- a/desktop/src/main/java/haveno/desktop/main/debug/DebugView.java +++ b/desktop/src/main/java/haveno/desktop/main/debug/DebugView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.debug; +import com.google.inject.Inject; import haveno.common.taskrunner.Task; import haveno.common.util.Tuple2; import haveno.core.offer.availability.tasks.ProcessOfferAvailabilityResponse; @@ -30,15 +31,14 @@ import haveno.core.trade.protocol.tasks.BuyerSendPaymentSentMessage; import haveno.core.trade.protocol.tasks.MakerSetLockTime; import haveno.core.trade.protocol.tasks.ProcessPaymentReceivedMessage; import haveno.core.trade.protocol.tasks.ProcessPaymentSentMessage; -import haveno.core.trade.protocol.tasks.RemoveOffer; import haveno.core.trade.protocol.tasks.SellerPreparePaymentReceivedMessage; -import haveno.core.trade.protocol.tasks.SellerPublishDepositTx; -import haveno.core.trade.protocol.tasks.SellerPublishTradeStatistics; import haveno.core.trade.protocol.tasks.SellerSendPaymentReceivedMessageToBuyer; import haveno.core.trade.protocol.tasks.VerifyPeersAccountAgeWitness; import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.InitializableView; import haveno.desktop.components.TitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelComboBox; +import java.util.Arrays; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; @@ -47,11 +47,6 @@ import javafx.scene.control.Label; import javafx.scene.layout.GridPane; import javafx.util.StringConverter; -import javax.inject.Inject; -import java.util.Arrays; - -import static haveno.desktop.util.FormBuilder.addTopLabelComboBox; - // Not maintained anymore with new trade protocol, but leave it...If used needs to be adopted to current protocol. @FxmlView public class DebugView extends InitializableView<GridPane, Void> { @@ -88,10 +83,6 @@ public class DebugView extends InitializableView<GridPane, Void> { ApplyFilter.class, VerifyPeersAccountAgeWitness.class, - //SellerSendsDepositTxAndDelayedPayoutTxMessage.class, - SellerPublishDepositTx.class, - SellerPublishTradeStatistics.class, - ProcessPaymentSentMessage.class, ApplyFilter.class, @@ -108,8 +99,6 @@ public class DebugView extends InitializableView<GridPane, Void> { VerifyPeersAccountAgeWitness.class, MakerSetLockTime.class, - RemoveOffer.class, - ApplyFilter.class, BuyerPreparePaymentSentMessage.class, BuyerSendPaymentSentMessage.class, @@ -138,19 +127,11 @@ public class DebugView extends InitializableView<GridPane, Void> { VerifyPeersAccountAgeWitness.class, MakerSetLockTime.class, - //SellerAsMakerProcessDepositTxMessage.class, - RemoveOffer.class, - - //SellerSendsDepositTxAndDelayedPayoutTxMessage.class, - SellerPublishDepositTx.class, - SellerPublishTradeStatistics.class, - ProcessPaymentSentMessage.class, ApplyFilter.class, ApplyFilter.class, SellerPreparePaymentReceivedMessage.class, - //SellerBroadcastPayoutTx.class, // TODO (woodser): removed from main pipeline; debug view? SellerSendPaymentReceivedMessageToBuyer.class ) )); diff --git a/desktop/src/main/java/haveno/desktop/main/funds/FundsView.java b/desktop/src/main/java/haveno/desktop/main/funds/FundsView.java index 988660bb97..588f3eb299 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/FundsView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/FundsView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.desktop.Navigation; import haveno.desktop.common.view.ActivatableView; @@ -33,8 +34,6 @@ import javafx.fxml.FXML; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; -import javax.inject.Inject; - @FxmlView public class FundsView extends ActivatableView<TabPane, Void> { diff --git a/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositListItem.java b/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositListItem.java index c7de866dd9..180b883d61 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.deposit; @@ -23,7 +23,6 @@ import com.google.common.base.Suppliers; import haveno.core.locale.Res; import haveno.core.trade.HavenoUtils; import haveno.core.util.coin.CoinFormatter; -import haveno.core.xmr.listeners.XmrBalanceListener; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.components.indicator.TxConfidenceIndicator; @@ -45,7 +44,6 @@ class DepositListItem { private final XmrWalletService xmrWalletService; private BigInteger balanceAsBI; private String usage = "-"; - private XmrBalanceListener balanceListener; private int numTxsWithOutputs = 0; private final Supplier<LazyFields> lazyFieldsSupplier; @@ -58,24 +56,14 @@ class DepositListItem { return lazyFieldsSupplier.get(); } - DepositListItem(XmrAddressEntry addressEntry, XmrWalletService xmrWalletService, CoinFormatter formatter, List<MoneroTxWallet> cachedTxs) { + DepositListItem(XmrAddressEntry addressEntry, XmrWalletService xmrWalletService, CoinFormatter formatter) { this.xmrWalletService = xmrWalletService; this.addressEntry = addressEntry; - balanceListener = new XmrBalanceListener(addressEntry.getSubaddressIndex()) { - @Override - public void onBalanceChanged(BigInteger balance) { - DepositListItem.this.balanceAsBI = balance; - DepositListItem.this.balance.set(HavenoUtils.formatXmr(balanceAsBI)); - updateUsage(addressEntry.getSubaddressIndex(), null); - } - }; - xmrWalletService.addBalanceListener(balanceListener); - balanceAsBI = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex()); balance.set(HavenoUtils.formatXmr(balanceAsBI)); - updateUsage(addressEntry.getSubaddressIndex(), cachedTxs); + updateUsage(addressEntry.getSubaddressIndex()); // confidence lazyFieldsSupplier = Suppliers.memoize(() -> new LazyFields() {{ @@ -84,7 +72,7 @@ class DepositListItem { tooltip = new Tooltip(Res.get("shared.notUsedYet")); txConfidenceIndicator.setProgress(0); txConfidenceIndicator.setTooltip(tooltip); - MoneroTx tx = getTxWithFewestConfirmations(cachedTxs); + MoneroTx tx = getTxWithFewestConfirmations(); if (tx == null) { txConfidenceIndicator.setVisible(false); } else { @@ -94,8 +82,8 @@ class DepositListItem { }}); } - private void updateUsage(int subaddressIndex, List<MoneroTxWallet> cachedTxs) { - numTxsWithOutputs = xmrWalletService.getNumTxsWithIncomingOutputs(addressEntry.getSubaddressIndex(), cachedTxs); + private void updateUsage(int subaddressIndex) { + numTxsWithOutputs = xmrWalletService.getNumTxsWithIncomingOutputs(addressEntry.getSubaddressIndex()); switch (addressEntry.getContext()) { case BASE_ADDRESS: usage = Res.get("funds.deposit.baseAddress"); @@ -115,7 +103,6 @@ class DepositListItem { } public void cleanup() { - xmrWalletService.removeBalanceListener(balanceListener); } public TxConfidenceIndicator getTxConfidenceIndicator() { @@ -150,15 +137,15 @@ class DepositListItem { return numTxsWithOutputs; } - public long getNumConfirmationsSinceFirstUsed(List<MoneroTxWallet> incomingTxs) { - MoneroTx tx = getTxWithFewestConfirmations(incomingTxs); + public long getNumConfirmationsSinceFirstUsed() { + MoneroTx tx = getTxWithFewestConfirmations(); return tx == null ? 0 : tx.getNumConfirmations(); } - private MoneroTxWallet getTxWithFewestConfirmations(List<MoneroTxWallet> allIncomingTxs) { + private MoneroTxWallet getTxWithFewestConfirmations() { // get txs with incoming outputs to subaddress index - List<MoneroTxWallet> txs = xmrWalletService.getTxsWithIncomingOutputs(addressEntry.getSubaddressIndex(), allIncomingTxs); + List<MoneroTxWallet> txs = xmrWalletService.getTxsWithIncomingOutputs(addressEntry.getSubaddressIndex()); // get tx with fewest confirmations MoneroTxWallet highestTx = null; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositView.java b/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositView.java index 0818aaf510..e7c4c89ab9 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/deposit/DepositView.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,10 @@ package haveno.desktop.main.funds.deposit; +import com.google.inject.Inject; +import com.google.inject.name.Named; + +import haveno.common.ThreadUtils; import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.util.Tuple3; @@ -38,8 +59,18 @@ import haveno.desktop.components.InputTextField; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.QRCodeWindow; +import static haveno.desktop.util.FormBuilder.addAddressTextField; +import static haveno.desktop.util.FormBuilder.addButtonCheckBoxWithBox; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import haveno.desktop.util.GUIUtil; import haveno.desktop.util.Layout; +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.TimeUnit; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; @@ -49,6 +80,7 @@ import javafx.fxml.FXML; import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; +import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; @@ -59,8 +91,8 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.util.Callback; +import monero.common.MoneroUtils; import monero.wallet.model.MoneroTxConfig; -import monero.wallet.model.MoneroTxWallet; import monero.wallet.model.MoneroWalletListener; import net.glxn.qrgen.QRCode; import net.glxn.qrgen.image.ImageType; @@ -69,19 +101,6 @@ import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; -import javax.inject.Named; -import java.io.ByteArrayInputStream; -import java.math.BigInteger; -import java.util.Comparator; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import static haveno.desktop.util.FormBuilder.addAddressTextField; -import static haveno.desktop.util.FormBuilder.addButtonCheckBoxWithBox; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; - @FxmlView public class DepositView extends ActivatableView<VBox, Void> { @@ -96,6 +115,7 @@ public class DepositView extends ActivatableView<VBox, Void> { private Button generateNewAddressButton; private TitledGroupBg titledGroupBg; private InputTextField amountTextField; + private static final String THREAD_ID = DepositView.class.getName(); private final XmrWalletService xmrWalletService; private final Preferences preferences; @@ -108,7 +128,6 @@ public class DepositView extends ActivatableView<VBox, Void> { private Subscription amountTextFieldSubscription; private ChangeListener<DepositListItem> tableViewSelectionListener; private int gridRow = 0; - List<MoneroTxWallet> txsWithIncomingOutputs; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -132,145 +151,155 @@ public class DepositView extends ActivatableView<VBox, Void> { confirmationsColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.confirmations"))); usageColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.usage"))); - // try to initialize with wallet txs - try { + // set loading placeholder + Label placeholderLabel = new Label("Loading..."); + tableView.setPlaceholder(placeholderLabel); - // prefetch all incoming txs to avoid query per subaddress - txsWithIncomingOutputs = xmrWalletService.getTxsWithIncomingOutputs(); + ThreadUtils.execute(() -> { // trigger creation of at least 1 address - xmrWalletService.getFreshAddressEntry(txsWithIncomingOutputs); - } catch (Exception e) { - log.warn("Failed to get wallet txs to initialize DepositView"); - e.printStackTrace(); - } - - tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); - tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.deposit.noAddresses"))); - tableViewSelectionListener = (observableValue, oldValue, newValue) -> { - if (newValue != null) { - fillForm(newValue.getAddressString()); - GUIUtil.requestFocus(amountTextField); + try { + xmrWalletService.getFreshAddressEntry(); + } catch (Exception e) { + log.warn("Failed to create fresh address entry to initialize DepositView"); + e.printStackTrace(); } - }; - setAddressColumnCellFactory(); - setBalanceColumnCellFactory(); - setUsageColumnCellFactory(); - setConfidenceColumnCellFactory(); - - addressColumn.setComparator(Comparator.comparing(DepositListItem::getAddressString)); - balanceColumn.setComparator(Comparator.comparing(DepositListItem::getBalanceAsBI)); - confirmationsColumn.setComparator(Comparator.comparingLong(o -> o.getNumConfirmationsSinceFirstUsed(txsWithIncomingOutputs))); - usageColumn.setComparator(Comparator.comparing(DepositListItem::getUsage)); - tableView.getSortOrder().add(usageColumn); - tableView.setItems(sortedList); - - titledGroupBg = addTitledGroupBg(gridPane, gridRow, 4, Res.get("funds.deposit.fundWallet")); - titledGroupBg.getStyleClass().add("last"); - - qrCodeImageView = new ImageView(); - qrCodeImageView.setFitHeight(150); - qrCodeImageView.setFitWidth(150); - qrCodeImageView.getStyleClass().add("qr-code"); - Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow"))); - qrCodeImageView.setOnMouseClicked(e -> UserThread.runAfter( - () -> new QRCodeWindow(getPaymentUri()).show(), - 200, TimeUnit.MILLISECONDS)); - GridPane.setRowIndex(qrCodeImageView, gridRow); - GridPane.setRowSpan(qrCodeImageView, 4); - GridPane.setColumnIndex(qrCodeImageView, 1); - GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 10)); - gridPane.getChildren().add(qrCodeImageView); - - addressTextField = addAddressTextField(gridPane, ++gridRow, Res.get("shared.address"), Layout.FIRST_ROW_DISTANCE); - addressTextField.setPaymentLabel(paymentLabelString); - - - amountTextField = addInputTextField(gridPane, ++gridRow, Res.get("funds.deposit.amount")); - amountTextField.setMaxWidth(380); - if (DevEnv.isDevMode()) - amountTextField.setText("10"); - - titledGroupBg.setVisible(false); - titledGroupBg.setManaged(false); - qrCodeImageView.setVisible(false); - qrCodeImageView.setManaged(false); - addressTextField.setVisible(false); - addressTextField.setManaged(false); - amountTextField.setManaged(false); - - Tuple3<Button, CheckBox, HBox> buttonCheckBoxHBox = addButtonCheckBoxWithBox(gridPane, ++gridRow, - Res.get("funds.deposit.generateAddress"), - null, - 15); - buttonCheckBoxHBox.third.setSpacing(25); - generateNewAddressButton = buttonCheckBoxHBox.first; - - generateNewAddressButton.setOnAction(event -> { - boolean hasUnusedAddress = !xmrWalletService.getUnusedAddressEntries().isEmpty(); - if (hasUnusedAddress) { - new Popup().warning(Res.get("funds.deposit.selectUnused")).show(); - } else { - XmrAddressEntry newSavingsAddressEntry = xmrWalletService.getNewAddressEntry(); - updateList(); - observableList.stream() - .filter(depositListItem -> depositListItem.getAddressString().equals(newSavingsAddressEntry.getAddressString())) - .findAny() - .ifPresent(depositListItem -> tableView.getSelectionModel().select(depositListItem)); - } - }); - - balanceListener = new XmrBalanceListener() { - @Override - public void onBalanceChanged(BigInteger balance) { - updateList(); - } - }; - - walletListener = new MoneroWalletListener() { - @Override - public void onNewBlock(long height) { - updateList(); - } - }; - - GUIUtil.focusWhenAddedToScene(amountTextField); + UserThread.execute(() -> { + tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.deposit.noAddresses"))); + tableViewSelectionListener = (observableValue, oldValue, newValue) -> { + if (newValue != null) { + fillForm(newValue.getAddressString()); + GUIUtil.requestFocus(amountTextField); + } + }; + + setAddressColumnCellFactory(); + setBalanceColumnCellFactory(); + setUsageColumnCellFactory(); + setConfidenceColumnCellFactory(); + + addressColumn.setComparator(Comparator.comparing(DepositListItem::getAddressString)); + balanceColumn.setComparator(Comparator.comparing(DepositListItem::getBalanceAsBI)); + confirmationsColumn.setComparator(Comparator.comparingLong(o -> o.getNumConfirmationsSinceFirstUsed())); + usageColumn.setComparator(Comparator.comparing(DepositListItem::getUsage)); + tableView.getSortOrder().add(usageColumn); + tableView.setItems(sortedList); + + titledGroupBg = addTitledGroupBg(gridPane, gridRow, 4, Res.get("funds.deposit.fundWallet")); + titledGroupBg.getStyleClass().add("last"); + + qrCodeImageView = new ImageView(); + qrCodeImageView.setFitHeight(150); + qrCodeImageView.setFitWidth(150); + qrCodeImageView.getStyleClass().add("qr-code"); + Tooltip.install(qrCodeImageView, new Tooltip(Res.get("shared.openLargeQRWindow"))); + qrCodeImageView.setOnMouseClicked(e -> UserThread.runAfter( + () -> new QRCodeWindow(getPaymentUri()).show(), + 200, TimeUnit.MILLISECONDS)); + GridPane.setRowIndex(qrCodeImageView, gridRow); + GridPane.setRowSpan(qrCodeImageView, 4); + GridPane.setColumnIndex(qrCodeImageView, 1); + GridPane.setMargin(qrCodeImageView, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 10)); + gridPane.getChildren().add(qrCodeImageView); + + addressTextField = addAddressTextField(gridPane, ++gridRow, Res.get("shared.address"), Layout.FIRST_ROW_DISTANCE); + addressTextField.setPaymentLabel(paymentLabelString); + amountTextField = addInputTextField(gridPane, ++gridRow, Res.get("funds.deposit.amount")); + amountTextField.setMaxWidth(380); + if (DevEnv.isDevMode()) + amountTextField.setText("10"); + + titledGroupBg.setVisible(false); + titledGroupBg.setManaged(false); + qrCodeImageView.setVisible(false); + qrCodeImageView.setManaged(false); + addressTextField.setVisible(false); + addressTextField.setManaged(false); + amountTextField.setManaged(false); + + Tuple3<Button, CheckBox, HBox> buttonCheckBoxHBox = addButtonCheckBoxWithBox(gridPane, ++gridRow, + Res.get("funds.deposit.generateAddress"), + null, + 15); + buttonCheckBoxHBox.third.setSpacing(25); + generateNewAddressButton = buttonCheckBoxHBox.first; + + generateNewAddressButton.setOnAction(event -> { + boolean hasUnusedAddress = !xmrWalletService.getUnusedAddressEntries().isEmpty(); + if (hasUnusedAddress) { + new Popup().warning(Res.get("funds.deposit.selectUnused")).show(); + } else { + XmrAddressEntry newSavingsAddressEntry = xmrWalletService.getNewAddressEntry(); + updateList(); + UserThread.execute(() -> { + observableList.stream() + .filter(depositListItem -> depositListItem.getAddressString().equals(newSavingsAddressEntry.getAddressString())) + .findAny() + .ifPresent(depositListItem -> tableView.getSelectionModel().select(depositListItem)); + }); + } + }); + + balanceListener = new XmrBalanceListener() { + @Override + public void onBalanceChanged(BigInteger balance) { + updateList(); + } + }; + + walletListener = new MoneroWalletListener() { + @Override + public void onNewBlock(long height) { + updateList(); + } + }; + + GUIUtil.focusWhenAddedToScene(amountTextField); + }); + }, THREAD_ID); } @Override protected void activate() { - tableView.getSelectionModel().selectedItemProperty().addListener(tableViewSelectionListener); - sortedList.comparatorProperty().bind(tableView.comparatorProperty()); - - // try to update deposits list - try { - updateList(); - } catch (Exception e) { - log.warn("Could not update deposits list"); - e.printStackTrace(); - } - - xmrWalletService.addBalanceListener(balanceListener); - xmrWalletService.addWalletListener(walletListener); - - amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> { - addressTextField.setAmount(HavenoUtils.parseXmr(t)); - updateQRCode(); - }); - - if (tableView.getSelectionModel().getSelectedItem() == null && !sortedList.isEmpty()) - tableView.getSelectionModel().select(0); + ThreadUtils.execute(() -> { + UserThread.execute(() -> { + tableView.getSelectionModel().selectedItemProperty().addListener(tableViewSelectionListener); + sortedList.comparatorProperty().bind(tableView.comparatorProperty()); + + // try to update deposits list + try { + updateList(); + } catch (Exception e) { + log.warn("Could not update deposits list"); + e.printStackTrace(); + } + + xmrWalletService.addBalanceListener(balanceListener); + xmrWalletService.addWalletListener(walletListener); + + amountTextFieldSubscription = EasyBind.subscribe(amountTextField.textProperty(), t -> { + addressTextField.setAmount(HavenoUtils.parseXmr(t)); + updateQRCode(); + }); + + if (tableView.getSelectionModel().getSelectedItem() == null && !sortedList.isEmpty()) + tableView.getSelectionModel().select(0); + }); + }, THREAD_ID); } @Override protected void deactivate() { - tableView.getSelectionModel().selectedItemProperty().removeListener(tableViewSelectionListener); - sortedList.comparatorProperty().unbind(); - observableList.forEach(DepositListItem::cleanup); - xmrWalletService.removeBalanceListener(balanceListener); - xmrWalletService.removeWalletListener(walletListener); - amountTextFieldSubscription.unsubscribe(); + ThreadUtils.execute(() -> { + tableView.getSelectionModel().selectedItemProperty().removeListener(tableViewSelectionListener); + sortedList.comparatorProperty().unbind(); + observableList.forEach(DepositListItem::cleanup); + xmrWalletService.removeBalanceListener(balanceListener); + xmrWalletService.removeWalletListener(walletListener); + amountTextFieldSubscription.unsubscribe(); + }, THREAD_ID); } @@ -313,16 +342,22 @@ public class DepositView extends ActivatableView<VBox, Void> { private void updateList() { - // cache incoming txs - txsWithIncomingOutputs = xmrWalletService.getTxsWithIncomingOutputs(); + // create deposit list items + List<XmrAddressEntry> addressEntries = xmrWalletService.getAddressEntries(); + List<DepositListItem> items = new ArrayList<>(); + for (XmrAddressEntry addressEntry : addressEntries) { + if (addressEntry.isTrade()) continue; // skip reserved for trade + items.add(new DepositListItem(addressEntry, xmrWalletService, formatter)); + } - // clear existing items - observableList.forEach(DepositListItem::cleanup); - observableList.clear(); - - // add address entries - xmrWalletService.getAddressEntries() - .forEach(e -> observableList.add(new DepositListItem(e, xmrWalletService, formatter, txsWithIncomingOutputs))); + // update list + UserThread.execute(() -> { + observableList.forEach(DepositListItem::cleanup); + observableList.clear(); + for (DepositListItem item : items) { + observableList.add(item); + } + }); } private Coin getAmount() { @@ -331,7 +366,7 @@ public class DepositView extends ActivatableView<VBox, Void> { @NotNull private String getPaymentUri() { - return xmrWalletService.getWallet().getPaymentUri(new MoneroTxConfig() + return MoneroUtils.getPaymentUri(new MoneroTxConfig() .setAddress(addressTextField.getAddress()) .setAmount(HavenoUtils.coinToAtomicUnits(getAmount())) .setNote(paymentLabelString)); diff --git a/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedListItem.java b/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedListItem.java index 7cb441d91b..7ffd4651ce 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.locked; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java b/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java index af82228ca7..0a986b5505 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/locked/LockedView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.locked; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.googlecode.jcsv.writer.CSVEntryConverter; import de.jensd.fx.fontawesome.AwesomeIcon; import haveno.core.locale.Res; @@ -39,6 +41,11 @@ import haveno.desktop.components.HyperlinkWithIcon; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.util.GUIUtil; +import java.util.Comparator; +import java.util.Date; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; @@ -60,14 +67,6 @@ import javafx.util.Callback; import org.bitcoinj.core.Coin; import org.bitcoinj.core.Transaction; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - @FxmlView public class LockedView extends ActivatableView<VBox, Void> { @FXML diff --git a/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedListItem.java b/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedListItem.java index eb4f7dc42f..a6f0a1e41e 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.reserved; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java b/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java index 921e056f1a..bfa8bd26b0 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/reserved/ReservedView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.reserved; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.googlecode.jcsv.writer.CSVEntryConverter; import de.jensd.fx.fontawesome.AwesomeIcon; import haveno.core.locale.Res; @@ -39,6 +41,11 @@ import haveno.desktop.components.HyperlinkWithIcon; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.util.GUIUtil; +import java.util.Comparator; +import java.util.Date; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; @@ -60,14 +67,6 @@ import javafx.util.Callback; import org.bitcoinj.core.Coin; import org.bitcoinj.core.Transaction; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.Comparator; -import java.util.Date; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Collectors; - @FxmlView public class ReservedView extends ActivatableView<VBox, Void> { @FXML diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactions.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactions.java index bee147581c..4400bfbadd 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactions.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactions.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; +import haveno.common.UserThread; import haveno.core.trade.Tradable; import haveno.core.xmr.wallet.XmrWalletService; import monero.wallet.model.MoneroTxWallet; @@ -42,13 +43,14 @@ class DisplayedTransactions extends ObservableListDecorator<TransactionsListItem void update() { List<TransactionsListItem> transactionsListItems = getTransactionListItems(); - // are sorted by getRecentTransactions - forEach(TransactionsListItem::cleanup); - setAll(transactionsListItems); + UserThread.execute(() -> { + forEach(TransactionsListItem::cleanup); + setAll(transactionsListItems); + }); } private List<TransactionsListItem> getTransactionListItems() { - List<MoneroTxWallet> transactions = xmrWalletService.getTransactions(false); + List<MoneroTxWallet> transactions = xmrWalletService.getTxs(false); return transactions.stream() .map(this::convertTransactionToListItem) .collect(Collectors.toList()); diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsFactory.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsFactory.java index 77b58b7430..7b83bbb157 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsFactory.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsFactory.java @@ -1,27 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.xmr.wallet.XmrWalletService; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public class DisplayedTransactionsFactory { private final XmrWalletService xmrWalletService; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/DummyTransactionAwareTradable.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/DummyTransactionAwareTradable.java index ba3dfc2693..9814f52b25 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/DummyTransactionAwareTradable.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/DummyTransactionAwareTradable.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/ObservableListDecorator.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/ObservableListDecorator.java index e9f6976df6..f6cf2dc960 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/ObservableListDecorator.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/ObservableListDecorator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TradableRepository.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TradableRepository.java index 871c0271cb..a46a18f624 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TradableRepository.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TradableRepository.java @@ -1,31 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; import com.google.common.collect.ImmutableSet; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.offer.OpenOfferManager; import haveno.core.trade.ClosedTradableManager; import haveno.core.trade.Tradable; import haveno.core.trade.TradeManager; import haveno.core.trade.failed.FailedTradesManager; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.Set; @Singleton diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareOpenOffer.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareOpenOffer.java index 27b7990c37..d8862b8506 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareOpenOffer.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareOpenOffer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradable.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradable.java index 892e045ff5..c8c58e557a 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradable.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradable.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactory.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactory.java index 5f6334c1b9..c07e548032 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactory.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactory.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.crypto.PubKeyRingProvider; import haveno.core.offer.OpenOffer; import haveno.core.support.dispute.arbitration.ArbitrationManager; @@ -25,9 +27,6 @@ import haveno.core.trade.Tradable; import haveno.core.trade.Trade; import haveno.core.xmr.wallet.XmrWalletService; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public class TransactionAwareTradableFactory { diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTrade.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTrade.java index 0d398936d4..fe5bdb0d2e 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTrade.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionAwareTrade.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionListItemFactory.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionListItemFactory.java index 6bd896acd9..996a9f7a73 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionListItemFactory.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionListItemFactory.java @@ -1,32 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; import haveno.core.xmr.wallet.XmrWalletService; -import monero.wallet.model.MoneroTxWallet; - import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; +import monero.wallet.model.MoneroTxWallet; @Singleton diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsListItem.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsListItem.java index 8bf772ba1c..b325b04efa 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; @@ -42,7 +42,7 @@ import java.util.Date; import java.util.Optional; @Slf4j -class TransactionsListItem { +public class TransactionsListItem { private String dateString; private final Date date; private final String txId; @@ -53,13 +53,16 @@ class TransactionsListItem { private String direction = ""; private boolean received; private boolean detailsAvailable; - private BigInteger amount = BigInteger.valueOf(0); + private BigInteger amount = BigInteger.ZERO; + private BigInteger txFee = BigInteger.ZERO; private String memo = ""; private long confirmations = 0; @Getter private boolean initialTxConfidenceVisibility = true; private final Supplier<LazyFields> lazyFieldsSupplier; private XmrWalletService xmrWalletService; + @Getter + private MoneroTxWallet tx; private static class LazyFields { TxConfidenceIndicator txConfidenceIndicator; @@ -80,6 +83,7 @@ class TransactionsListItem { TransactionsListItem(MoneroTxWallet tx, XmrWalletService xmrWalletService, TransactionAwareTradable transactionAwareTradable) { + this.tx = tx; this.memo = tx.getNote(); this.txId = tx.getHash(); this.xmrWalletService = xmrWalletService; @@ -88,8 +92,8 @@ class TransactionsListItem { Optional<Tradable> optionalTradable = Optional.ofNullable(transactionAwareTradable) .map(TransactionAwareTradable::asTradable); - BigInteger valueSentToMe = tx.getIncomingAmount() == null ? BigInteger.valueOf(0) : tx.getIncomingAmount(); - BigInteger valueSentFromMe = tx.getOutgoingAmount() == null ? BigInteger.valueOf(0) : tx.getOutgoingAmount(); + BigInteger valueSentToMe = tx.getIncomingAmount() == null ? BigInteger.ZERO : tx.getIncomingAmount(); + BigInteger valueSentFromMe = tx.getOutgoingAmount() == null ? BigInteger.ZERO : tx.getOutgoingAmount(); if (tx.getTransfers().get(0).isIncoming()) { addressString = ((MoneroIncomingTransfer) tx.getTransfers().get(0)).getAddress(); @@ -99,7 +103,7 @@ class TransactionsListItem { else addressString = "unavailable"; } - if (valueSentFromMe.compareTo(BigInteger.valueOf(0)) == 0) { + if (valueSentFromMe.compareTo(BigInteger.ZERO) == 0) { amount = valueSentToMe; direction = Res.get("funds.tx.direction.receivedWith"); received = true; @@ -107,6 +111,7 @@ class TransactionsListItem { amount = valueSentFromMe.multiply(BigInteger.valueOf(-1)); received = false; direction = Res.get("funds.tx.direction.sentTo"); + txFee = tx.getFee().multiply(BigInteger.valueOf(-1)); } if (optionalTradable.isPresent()) { @@ -122,16 +127,17 @@ class TransactionsListItem { if (trade.getSelf().getDepositTxHash() != null && trade.getSelf().getDepositTxHash().equals(txId)) { details = Res.get("funds.tx.multiSigDeposit", tradeId); + addressString = trade.getProcessModel().getMultisigAddress(); } else if (trade.getPayoutTxId() != null && trade.getPayoutTxId().equals(txId)) { details = Res.get("funds.tx.multiSigPayout", tradeId); - if (amount.compareTo(BigInteger.valueOf(0)) == 0) { + if (amount.compareTo(BigInteger.ZERO) == 0) { initialTxConfidenceVisibility = false; } } else { Trade.DisputeState disputeState = trade.getDisputeState(); if (disputeState == Trade.DisputeState.DISPUTE_CLOSED) { - if (valueSentToMe.compareTo(BigInteger.valueOf(0)) > 0) { + if (valueSentToMe.compareTo(BigInteger.ZERO) > 0) { details = Res.get("funds.tx.disputePayout", tradeId); } else { details = Res.get("funds.tx.disputeLost", tradeId); @@ -139,7 +145,7 @@ class TransactionsListItem { } else if (disputeState == Trade.DisputeState.REFUND_REQUEST_CLOSED || disputeState == Trade.DisputeState.REFUND_REQUESTED || disputeState == Trade.DisputeState.REFUND_REQUEST_STARTED_BY_PEER) { - if (valueSentToMe.compareTo(BigInteger.valueOf(0)) > 0) { + if (valueSentToMe.compareTo(BigInteger.ZERO) > 0) { details = Res.get("funds.tx.refund", tradeId); } else { // We have spent the deposit tx outputs to the Haveno donation address to enable @@ -147,7 +153,7 @@ class TransactionsListItem { // already when funding the deposit tx we show 0 BTC as amount. // Confirmation is not known from the BitcoinJ side (not 100% clear why) as no funds // left our wallet nor we received funds. So we set indicator invisible. - amount = BigInteger.valueOf(0); + amount = BigInteger.ZERO; details = Res.get("funds.tx.collateralForRefund", tradeId); initialTxConfidenceVisibility = false; } @@ -157,7 +163,7 @@ class TransactionsListItem { } } } else { - if (amount.compareTo(BigInteger.valueOf(0)) == 0) { + if (amount.compareTo(BigInteger.ZERO) == 0) { details = Res.get("funds.tx.noFundsFromDispute"); } } @@ -200,6 +206,14 @@ class TransactionsListItem { return amount; } + public BigInteger getTxFee() { + return txFee; + } + + public String getTxFeeStr() { + return txFee.equals(BigInteger.ZERO) ? "" : HavenoUtils.formatXmr(txFee); + } + public String getAddressString() { return addressString; } diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml index 8cd53a17e3..7c5da97808 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.fxml @@ -36,7 +36,8 @@ <TableColumn fx:id="detailsColumn" minWidth="220" maxWidth="220"/> <TableColumn fx:id="addressColumn" minWidth="260"/> <TableColumn fx:id="transactionColumn" minWidth="180"/> - <TableColumn fx:id="amountColumn" minWidth="130" maxWidth="130"/> + <TableColumn fx:id="amountColumn" minWidth="110" maxWidth="110"/> + <TableColumn fx:id="txFeeColumn" minWidth="110" maxWidth="110"/> <TableColumn fx:id="memoColumn" minWidth="40"/> <TableColumn fx:id="confidenceColumn" minWidth="120" maxWidth="130"/> <TableColumn fx:id="revertTxColumn" sortable="false" minWidth="110" maxWidth="110" visible="false"/> diff --git a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java index bc7253bf85..9544f50748 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/transactions/TransactionsView.java @@ -1,26 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; +import com.google.inject.Inject; import com.googlecode.jcsv.writer.CSVEntryConverter; import de.jensd.fx.fontawesome.AwesomeIcon; import haveno.common.util.Utilities; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.locale.Res; import haveno.core.offer.OpenOffer; import haveno.core.trade.Trade; @@ -31,12 +32,14 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.components.AddressWithIconAndDirection; import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.AutoTooltipLabel; -import haveno.desktop.components.ExternalHyperlink; import haveno.desktop.components.HyperlinkWithIcon; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; +import haveno.desktop.main.overlays.windows.TxDetailsWindow; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; +import java.math.BigInteger; +import java.util.Comparator; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.ObservableList; import javafx.collections.transformation.SortedList; @@ -60,10 +63,6 @@ import javafx.stage.Stage; import javafx.util.Callback; import monero.wallet.model.MoneroWalletListener; -import javax.inject.Inject; -import java.math.BigInteger; -import java.util.Comparator; - @FxmlView public class TransactionsView extends ActivatableView<VBox, Void> { @@ -71,7 +70,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> { @FXML TableView<TransactionsListItem> tableView; @FXML - TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, memoColumn, confidenceColumn, revertTxColumn; + TableColumn<TransactionsListItem, TransactionsListItem> dateColumn, detailsColumn, addressColumn, transactionColumn, amountColumn, txFeeColumn, memoColumn, confidenceColumn, revertTxColumn; @FXML Label numItems; @FXML @@ -86,11 +85,12 @@ public class TransactionsView extends ActivatableView<VBox, Void> { private final Preferences preferences; private final TradeDetailsWindow tradeDetailsWindow; private final OfferDetailsWindow offerDetailsWindow; + private final TxDetailsWindow txDetailsWindow; private EventHandler<KeyEvent> keyEventEventHandler; private Scene scene; - private TransactionsUpdater transactionsUpdater = new TransactionsUpdater(); + private final TransactionsUpdater transactionsUpdater = new TransactionsUpdater(); private class TransactionsUpdater extends MoneroWalletListener { @Override @@ -110,15 +110,17 @@ public class TransactionsView extends ActivatableView<VBox, Void> { @Inject private TransactionsView(XmrWalletService xmrWalletService, P2PService p2PService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, Preferences preferences, TradeDetailsWindow tradeDetailsWindow, OfferDetailsWindow offerDetailsWindow, + TxDetailsWindow txDetailsWindow, DisplayedTransactionsFactory displayedTransactionsFactory) { this.xmrWalletService = xmrWalletService; this.preferences = preferences; this.tradeDetailsWindow = tradeDetailsWindow; this.offerDetailsWindow = offerDetailsWindow; + this.txDetailsWindow = txDetailsWindow; this.displayedTransactions = displayedTransactionsFactory.create(); this.sortedDisplayedTransactions = displayedTransactions.asSortedList(); } @@ -130,11 +132,12 @@ public class TransactionsView extends ActivatableView<VBox, Void> { addressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address"))); transactionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txId", Res.getBaseCurrencyCode()))); amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountWithCur", Res.getBaseCurrencyCode()))); + txFeeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.txFee", Res.getBaseCurrencyCode()))); memoColumn.setGraphic(new AutoTooltipLabel(Res.get("funds.tx.memo"))); confidenceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.confirmations", Res.getBaseCurrencyCode()))); revertTxColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.revert", Res.getBaseCurrencyCode()))); - tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY_FLEX_LAST_COLUMN); tableView.setPlaceholder(new AutoTooltipLabel(Res.get("funds.tx.noTxAvailable"))); setDateColumnCellFactory(); @@ -142,6 +145,7 @@ public class TransactionsView extends ActivatableView<VBox, Void> { setAddressColumnCellFactory(); setTransactionColumnCellFactory(); setAmountColumnCellFactory(); + setTxFeeColumnCellFactory(); setMemoColumnCellFactory(); setConfidenceColumnCellFactory(); setRevertTxColumnCellFactory(); @@ -157,9 +161,8 @@ public class TransactionsView extends ActivatableView<VBox, Void> { addressColumn.setComparator(Comparator.comparing(item -> item.getDirection() + item.getAddressString())); transactionColumn.setComparator(Comparator.comparing(TransactionsListItem::getTxId)); amountColumn.setComparator(Comparator.comparing(TransactionsListItem::getAmount)); - confidenceColumn.setComparator(Comparator.comparingLong(item -> item.getNumConfirmations())); - memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo)); - + confidenceColumn.setComparator(Comparator.comparingLong(TransactionsListItem::getNumConfirmations)); + memoColumn.setComparator(Comparator.comparing(TransactionsListItem::getMemo, Comparator.nullsLast(Comparator.naturalOrder()))); dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); @@ -217,8 +220,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> { columns[2] = item.getDirection() + " " + item.getAddressString(); columns[3] = item.getTxId(); columns[4] = item.getAmountStr(); - columns[5] = item.getMemo() == null ? "" : item.getMemo(); - columns[6] = String.valueOf(item.getNumConfirmations()); + columns[5] = item.getTxFeeStr(); + columns[6] = item.getMemo() == null ? "" : item.getMemo(); + columns[7] = String.valueOf(item.getNumConfirmations()); return columns; }; @@ -251,6 +255,10 @@ public class TransactionsView extends ActivatableView<VBox, Void> { tradeDetailsWindow.show((Trade) item.getTradable()); } + private void openTxDetailPopup(TransactionsListItem item) { + txDetailsWindow.show(item); + } + /////////////////////////////////////////////////////////////////////////////////////////// // ColumnCellFactories @@ -374,9 +382,9 @@ public class TransactionsView extends ActivatableView<VBox, Void> { //noinspection Duplicates if (item != null && !empty) { String transactionId = item.getTxId(); - hyperlinkWithIcon = new ExternalHyperlink(transactionId); - hyperlinkWithIcon.setOnAction(event -> openTxInBlockExplorer(item)); - hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("tooltip.openBlockchainForTx", transactionId))); + hyperlinkWithIcon = new HyperlinkWithIcon(transactionId, AwesomeIcon.INFO_SIGN); + hyperlinkWithIcon.setOnAction(event -> openTxDetailPopup(item)); + hyperlinkWithIcon.setTooltip(new Tooltip(Res.get("txDetailsWindow.headline"))); setGraphic(hyperlinkWithIcon); } else { setGraphic(null); @@ -415,6 +423,33 @@ public class TransactionsView extends ActivatableView<VBox, Void> { }); } + + private void setTxFeeColumnCellFactory() { + txFeeColumn.setCellValueFactory((addressListItem) -> + new ReadOnlyObjectWrapper<>(addressListItem.getValue())); + txFeeColumn.setCellFactory( + new Callback<>() { + + @Override + public TableCell<TransactionsListItem, TransactionsListItem> call(TableColumn<TransactionsListItem, + TransactionsListItem> column) { + return new TableCell<>() { + + @Override + public void updateItem(final TransactionsListItem item, boolean empty) { + super.updateItem(item, empty); + + if (item != null && !empty) { + setGraphic(new AutoTooltipLabel(item.getTxFeeStr())); + } else { + setGraphic(null); + } + } + }; + } + }); + } + private void setMemoColumnCellFactory() { memoColumn.setCellValueFactory((addressListItem) -> new ReadOnlyObjectWrapper<>(addressListItem.getValue())); diff --git a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalListItem.java b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalListItem.java index 5cafb3304d..ed9a0f0a7d 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalListItem.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.withdrawal; +import haveno.common.UserThread; import haveno.core.locale.Res; import haveno.core.trade.HavenoUtils; import haveno.core.util.coin.CoinFormatter; @@ -68,8 +69,9 @@ class WithdrawalListItem { private void updateBalance() { balance = walletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex()); - if (balance != null) - balanceLabel.setText(HavenoUtils.formatXmr(this.balance)); + if (balance != null) { + UserThread.execute(() -> balanceLabel.setText(HavenoUtils.formatXmr(this.balance))); + } } public final String getLabel() { diff --git a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java index 61b49614d8..53b3d70bbf 100644 --- a/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java +++ b/desktop/src/main/java/haveno/desktop/main/funds/withdrawal/WithdrawalView.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,71 +34,73 @@ package haveno.desktop.main.funds.withdrawal; -import haveno.common.util.Tuple4; +import com.google.inject.Inject; +import haveno.common.util.Tuple3; import haveno.core.locale.Res; import haveno.core.trade.HavenoUtils; -import haveno.core.trade.Trade; import haveno.core.trade.TradeManager; +import haveno.core.trade.protocol.TradeProtocol; import haveno.core.user.DontShowAgainLookup; import haveno.core.util.validation.BtcAddressValidator; import haveno.core.xmr.listeners.XmrBalanceListener; -import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.setup.WalletsSetup; import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.common.view.ActivatableView; import haveno.desktop.common.view.FxmlView; +import haveno.desktop.components.BusyAnimation; +import haveno.desktop.components.HyperlinkWithIcon; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.main.overlays.popups.Popup; -import haveno.desktop.main.overlays.windows.TxDetails; +import haveno.desktop.main.overlays.windows.TxWithdrawWindow; import haveno.desktop.main.overlays.windows.WalletPasswordWindow; import haveno.desktop.util.FormBuilder; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; +import javafx.application.Platform; import javafx.beans.value.ChangeListener; import javafx.fxml.FXML; -import javafx.scene.control.Button; import javafx.scene.control.Label; -import javafx.scene.control.RadioButton; import javafx.scene.control.TextField; -import javafx.scene.control.Toggle; -import javafx.scene.control.ToggleGroup; +import javafx.scene.control.Button; import javafx.scene.layout.GridPane; +import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import monero.common.MoneroRpcConnection; +import monero.common.MoneroUtils; import monero.wallet.model.MoneroTxConfig; import monero.wallet.model.MoneroTxWallet; -import javax.inject.Inject; import java.math.BigInteger; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; -import static haveno.desktop.util.FormBuilder.addButton; import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import static haveno.desktop.util.FormBuilder.addTopLabelInputTextField; +import static haveno.desktop.util.FormBuilder.addButton; @FxmlView public class WithdrawalView extends ActivatableView<VBox, Void> { @FXML - GridPane gridPane; + private GridPane gridPane; + + private BusyAnimation spinningWheel; + + + private StackPane overlayPane; private Label amountLabel; private TextField amountTextField, withdrawToTextField, withdrawMemoTextField; - private RadioButton feeExcludedRadioButton, feeIncludedRadioButton; private final XmrWalletService xmrWalletService; private final TradeManager tradeManager; private final P2PService p2PService; private final WalletPasswordWindow walletPasswordWindow; private XmrBalanceListener balanceListener; - private BigInteger amount = BigInteger.valueOf(0); + private BigInteger amount = BigInteger.ZERO; private ChangeListener<String> amountListener; private ChangeListener<Boolean> amountFocusListener; - private ChangeListener<Toggle> feeToggleGroupListener; - private ToggleGroup feeToggleGroup; - private boolean feeExcluded; private int rowIndex = 0; + boolean sendMax = false; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, lifecycle @@ -103,33 +122,55 @@ public class WithdrawalView extends ActivatableView<VBox, Void> { @Override public void initialize() { + spinningWheel = new BusyAnimation(); + overlayPane = new StackPane(); + overlayPane.setStyle("-fx-background-color: transparent;"); // Adjust opacity as needed + overlayPane.setVisible(false); + overlayPane.getChildren().add(spinningWheel); + + // Add overlay pane to root VBox + root.getChildren().add(overlayPane); + final TitledGroupBg titledGroupBg = addTitledGroupBg(gridPane, rowIndex, 4, Res.get("funds.deposit.withdrawFromWallet")); titledGroupBg.getStyleClass().add("last"); withdrawToTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("funds.withdrawal.toLabel", Res.getBaseCurrencyCode())).second; - feeToggleGroup = new ToggleGroup(); - - final Tuple4<Label, TextField, RadioButton, RadioButton> feeTuple3 = FormBuilder.addTopLabelTextFieldRadioButtonRadioButton(gridPane, ++rowIndex, feeToggleGroup, + final Tuple3<Label, TextField, HyperlinkWithIcon> feeTuple3 = FormBuilder.addTopLabelTextFieldHyperLink(gridPane, ++rowIndex, "", Res.get("funds.withdrawal.receiverAmount", Res.getBaseCurrencyCode()), - "", - Res.get("funds.withdrawal.feeExcluded"), - Res.get("funds.withdrawal.feeIncluded"), + Res.get("funds.withdrawal.sendMax"), 0); amountLabel = feeTuple3.first; amountTextField = feeTuple3.second; amountTextField.setMinWidth(180); - feeExcludedRadioButton = feeTuple3.third; - feeIncludedRadioButton = feeTuple3.fourth; + HyperlinkWithIcon sendMaxLink = feeTuple3.third; withdrawMemoTextField = addTopLabelInputTextField(gridPane, ++rowIndex, Res.get("funds.withdrawal.memoLabel", Res.getBaseCurrencyCode())).second; final Button withdrawButton = addButton(gridPane, ++rowIndex, Res.get("funds.withdrawal.withdrawButton"), 15); - withdrawButton.setOnAction(event -> onWithdraw()); + withdrawButton.setOnAction(event -> { + // Show the spinning wheel (progress indicator) + showLoadingIndicator(); + + // Execute onWithdraw() method on a separate thread + new Thread(() -> { + // Call the method that performs the withdrawal + onWithdraw(); + + // Hide the spinning wheel (progress indicator) after withdrawal is complete + Platform.runLater(() -> hideLoadingIndicator()); + }).start(); + }); + + sendMaxLink.setOnAction(event -> { + sendMax = true; + amount = null; // set amount when tx created + amountTextField.setText(Res.get("funds.withdrawal.maximum")); + }); balanceListener = new XmrBalanceListener() { @Override @@ -139,6 +180,7 @@ public class WithdrawalView extends ActivatableView<VBox, Void> { }; amountListener = (observable, oldValue, newValue) -> { if (amountTextField.focusedProperty().get()) { + sendMax = false; // disable max if amount changed while focused try { amount = HavenoUtils.parseXmr(amountTextField.getText()); } catch (Throwable t) { @@ -147,22 +189,29 @@ public class WithdrawalView extends ActivatableView<VBox, Void> { } }; amountFocusListener = (observable, oldValue, newValue) -> { - if (oldValue && !newValue) { - if (amount.compareTo(BigInteger.valueOf(0)) > 0) + + // parse amount on focus out unless sending max + if (oldValue && !newValue && !sendMax) { + if (amount.compareTo(BigInteger.ZERO) > 0) amountTextField.setText(HavenoUtils.formatXmr(amount)); else amountTextField.setText(""); } }; amountLabel.setText(Res.get("funds.withdrawal.receiverAmount")); - feeExcludedRadioButton.setToggleGroup(feeToggleGroup); - feeIncludedRadioButton.setToggleGroup(feeToggleGroup); - feeToggleGroupListener = (observable, oldValue, newValue) -> { - feeExcluded = newValue == feeExcludedRadioButton; - amountLabel.setText(feeExcluded ? - Res.get("funds.withdrawal.receiverAmount") : - Res.get("funds.withdrawal.senderAmount")); - }; + } + + + private void showLoadingIndicator() { + overlayPane.setVisible(true); + spinningWheel.play(); + root.setDisable(true); + } + + private void hideLoadingIndicator() { + overlayPane.setVisible(false); + spinningWheel.stop(); + root.setDisable(false); } @Override @@ -172,19 +221,16 @@ public class WithdrawalView extends ActivatableView<VBox, Void> { amountTextField.textProperty().addListener(amountListener); amountTextField.focusedProperty().addListener(amountFocusListener); xmrWalletService.addBalanceListener(balanceListener); - feeToggleGroup.selectedToggleProperty().addListener(feeToggleGroupListener); - - if (feeToggleGroup.getSelectedToggle() == null) feeToggleGroup.selectToggle(feeExcludedRadioButton); GUIUtil.requestFocus(withdrawToTextField); } @Override protected void deactivate() { + spinningWheel.stop(); xmrWalletService.removeBalanceListener(balanceListener); amountTextField.textProperty().removeListener(amountListener); amountTextField.focusedProperty().removeListener(amountFocusListener); - feeToggleGroup.selectedToggleProperty().removeListener(feeToggleGroupListener); } @@ -193,80 +239,108 @@ public class WithdrawalView extends ActivatableView<VBox, Void> { /////////////////////////////////////////////////////////////////////////////////////////// private void onWithdraw() { - if (GUIUtil.isReadyForTxBroadcastOrShowPopup(xmrWalletService.getConnectionsService())) { + if (GUIUtil.isReadyForTxBroadcastOrShowPopup(xmrWalletService)) { try { - // get withdraw address - final String withdrawToAddress = withdrawToTextField.getText(); + // collect tx fields to local variables + String withdrawToAddress = withdrawToTextField.getText(); + boolean sendMax = this.sendMax; + BigInteger amount = this.amount; + + // validate address + if (!MoneroUtils.isValidAddress(withdrawToAddress, XmrWalletService.getMoneroNetworkType())) { + throw new IllegalArgumentException(Res.get("validation.xmr.invalidAddress")); + } + + // set max amount if requested + if (sendMax) amount = xmrWalletService.getAvailableBalance(); + + // check sufficient available balance + if (amount.compareTo(BigInteger.ZERO) <= 0) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow")); // create tx - if (amount.compareTo(BigInteger.valueOf(0)) <= 0) throw new RuntimeException(Res.get("portfolio.pending.step5_buyer.amountTooLow")); - MoneroTxWallet tx = xmrWalletService.getWallet().createTx(new MoneroTxConfig() - .setAccountIndex(0) - .setAmount(amount) - .setAddress(withdrawToAddress) - .setSubtractFeeFrom(feeExcluded ? null : Arrays.asList(0))); - - // create confirmation message - BigInteger receiverAmount = tx.getOutgoingTransfer().getDestinations().get(0).getAmount(); - BigInteger fee = tx.getFee(); - String messageText = Res.get("shared.sendFundsDetailsWithFee", - HavenoUtils.formatXmr(amount, true), - withdrawToAddress, - HavenoUtils.formatXmr(fee, true), - HavenoUtils.formatXmr(receiverAmount, true)); + MoneroTxWallet tx = null; + for (int i = 0; i < TradeProtocol.MAX_ATTEMPTS; i++) { + MoneroRpcConnection sourceConnection = xmrWalletService.getXmrConnectionService().getConnection(); + try { + log.info("Creating withdraw tx"); + long startTime = System.currentTimeMillis(); + tx = xmrWalletService.createTx(new MoneroTxConfig() + .setAccountIndex(0) + .setAmount(amount) + .setAddress(withdrawToAddress) + .setSubtractFeeFrom(sendMax ? Arrays.asList(0) : null)); + log.info("Done creating withdraw tx in {} ms", System.currentTimeMillis() - startTime); + break; + } catch (Exception e) { + if (isNotEnoughMoney(e.getMessage())) throw e; + log.warn("Error creating creating withdraw tx, attempt={}/{}, error={}", i + 1, TradeProtocol.MAX_ATTEMPTS, e.getMessage()); + if (i == TradeProtocol.MAX_ATTEMPTS - 1) throw e; + if (xmrWalletService.getXmrConnectionService().isConnected()) xmrWalletService.requestSwitchToNextBestConnection(sourceConnection); + HavenoUtils.waitFor(TradeProtocol.REPROCESS_DELAY_MS); // wait before retrying + } + } // popup confirmation message - Popup popup = new Popup(); - popup.headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest")) - .confirmation(messageText) - .actionButtonText(Res.get("shared.yes")) - .onAction(() -> { - if (xmrWalletService.isWalletEncrypted()) { - walletPasswordWindow.headLine(Res.get("walletPasswordWindow.headline")).onSuccess(() -> { - relayTx(tx, withdrawToAddress, amount, fee); - }).onClose(() -> { - popup.hide(); - }).hideForgotPasswordButton().show(); - } else { - relayTx(tx, withdrawToAddress, amount, fee); - } - }) - .closeButtonText(Res.get("shared.cancel")) - .show(); + popupConfirmationMessage(tx); } catch (Throwable e) { - if (e.getMessage().contains("enough")) new Popup().warning(Res.get("funds.withdrawal.warn.amountExceeds")).show(); - else { - e.printStackTrace(); - new Popup().warning(e.getMessage()).show(); - } + e.printStackTrace(); + if (isNotEnoughMoney(e.getMessage())) new Popup().warning(Res.get("funds.withdrawal.notEnoughFunds")).show(); + else new Popup().warning(e.getMessage()).show(); } } } + private static boolean isNotEnoughMoney(String errorMsg) { + return errorMsg.contains("not enough"); + } + + private void popupConfirmationMessage(MoneroTxWallet tx) { + + // create confirmation message + String withdrawToAddress = tx.getOutgoingTransfer().getDestinations().get(0).getAddress(); + BigInteger receiverAmount = tx.getOutgoingTransfer().getDestinations().get(0).getAmount(); + BigInteger fee = tx.getFee(); + String messageText = Res.get("shared.sendFundsDetailsWithFee", + HavenoUtils.formatXmr(receiverAmount.add(fee), true), + withdrawToAddress, + HavenoUtils.formatXmr(fee, true), + HavenoUtils.formatXmr(receiverAmount, true)); + + // popup confirmation message + Popup popup = new Popup(); + popup.headLine(Res.get("funds.withdrawal.confirmWithdrawalRequest")) + .confirmation(messageText) + .actionButtonText(Res.get("shared.yes")) + .onAction(() -> { + if (xmrWalletService.isWalletEncrypted()) { + walletPasswordWindow.headLine(Res.get("walletPasswordWindow.headline")).onSuccess(() -> { + relayTx(tx, withdrawToAddress, receiverAmount, fee); + }).onClose(() -> { + popup.hide(); + }).hideForgotPasswordButton().show(); + } else { + relayTx(tx, withdrawToAddress, receiverAmount, fee); + } + }) + .closeButtonText(Res.get("shared.cancel")) + .show(); + } + private void relayTx(MoneroTxWallet tx, String withdrawToAddress, BigInteger receiverAmount, BigInteger fee) { try { xmrWalletService.getWallet().relayTx(tx); xmrWalletService.getWallet().setTxNote(tx.getHash(), withdrawMemoTextField.getText()); // TODO (monero-java): tx note does not persist when tx created then relayed String key = "showTransactionSent"; if (DontShowAgainLookup.showAgain(key)) { - new TxDetails(tx.getHash(), withdrawToAddress, HavenoUtils.formatXmr(receiverAmount, true), HavenoUtils.formatXmr(fee, true), xmrWalletService.getWallet().getTxNote(tx.getHash())) + new TxWithdrawWindow(tx.getHash(), withdrawToAddress, HavenoUtils.formatXmr(receiverAmount, true), HavenoUtils.formatXmr(fee, true), xmrWalletService.getWallet().getTxNote(tx.getHash())) .dontShowAgainId(key) .show(); } log.debug("onWithdraw onSuccess tx ID:{}", tx.getHash()); - - // TODO: remove this? - List<Trade> trades = new ArrayList<>(tradeManager.getObservableList()); - trades.stream() - .filter(Trade::isPayoutPublished) - .forEach(trade -> xmrWalletService.getAddressEntry(trade.getId(), XmrAddressEntry.Context.TRADE_PAYOUT) - .ifPresent(addressEntry -> { - if (xmrWalletService.getBalanceForAddress(addressEntry.getAddressString()).compareTo(BigInteger.valueOf(0)) == 0) - tradeManager.onTradeCompleted(trade); - })); } catch (Exception e) { e.printStackTrace(); + new Popup().warning(e.getMessage()).show(); } } @@ -276,7 +350,8 @@ public class WithdrawalView extends ActivatableView<VBox, Void> { /////////////////////////////////////////////////////////////////////////////////////////// private void reset() { - amount = BigInteger.valueOf(0); + sendMax = false; + amount = BigInteger.ZERO; amountTextField.setText(""); amountTextField.setPromptText(Res.get("funds.withdrawal.setAmount")); diff --git a/desktop/src/main/java/haveno/desktop/main/market/MarketView.java b/desktop/src/main/java/haveno/desktop/main/market/MarketView.java index c50bc16f63..98f5e75490 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/MarketView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/MarketView.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market; import com.google.common.base.Joiner; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.util.Utilities; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -43,6 +45,8 @@ import haveno.desktop.main.offer.offerbook.OfferBook; import haveno.desktop.main.offer.offerbook.OfferBookListItem; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.DisplayUtils; +import java.util.List; +import java.util.stream.Collectors; import javafx.beans.value.ChangeListener; import javafx.event.EventHandler; import javafx.fxml.FXML; @@ -54,11 +58,6 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import org.apache.commons.lang3.StringUtils; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.List; -import java.util.stream.Collectors; - @FxmlView public class MarketView extends ActivatableView<TabPane, Void> { @FXML @@ -201,22 +200,24 @@ public class MarketView extends ActivatableView<TabPane, Void> { } private String getAllOffersWithReferralId() { - List<String> list = offerBook.getOfferBookListItems().stream() - .map(OfferBookListItem::getOffer) - .filter(offer -> offer.getExtraDataMap() != null) - .filter(offer -> offer.getExtraDataMap().get(OfferPayload.REFERRAL_ID) != null) - .map(offer -> { - StringBuilder sb = new StringBuilder(); - sb.append("Offer ID: ").append(offer.getId()).append("\n") - .append("Type: ").append(offer.getDirection().name()).append("\n") - .append("Market: ").append(CurrencyUtil.getCurrencyPair(offer.getCurrencyCode())).append("\n") - .append("Price: ").append(FormattingUtils.formatPrice(offer.getPrice())).append("\n") - .append("Amount: ").append(DisplayUtils.formatAmount(offer, formatter)).append(" BTC\n") - .append("Payment method: ").append(Res.get(offer.getPaymentMethod().getId())).append("\n") - .append("ReferralID: ").append(offer.getExtraDataMap().get(OfferPayload.REFERRAL_ID)); - return sb.toString(); - }) - .collect(Collectors.toList()); - return Joiner.on("\n\n").join(list); + synchronized (offerBook.getOfferBookListItems()) { + List<String> list = offerBook.getOfferBookListItems().stream() + .map(OfferBookListItem::getOffer) + .filter(offer -> offer.getExtraDataMap() != null) + .filter(offer -> offer.getExtraDataMap().get(OfferPayload.REFERRAL_ID) != null) + .map(offer -> { + StringBuilder sb = new StringBuilder(); + sb.append("Offer ID: ").append(offer.getId()).append("\n") + .append("Type: ").append(offer.getDirection().name()).append("\n") + .append("Market: ").append(CurrencyUtil.getCurrencyPair(offer.getCurrencyCode())).append("\n") + .append("Price: ").append(FormattingUtils.formatPrice(offer.getPrice())).append("\n") + .append("Amount: ").append(DisplayUtils.formatAmount(offer, formatter)).append(" BTC\n") + .append("Payment method: ").append(Res.get(offer.getPaymentMethod().getId())).append("\n") + .append("ReferralID: ").append(offer.getExtraDataMap().get(OfferPayload.REFERRAL_ID)); + return sb.toString(); + }) + .collect(Collectors.toList()); + return Joiner.on("\n\n").join(list); + } } } diff --git a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java index 134fddf50c..3d2ec6d884 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.offerbook; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.jfoenix.controls.JFXTabPane; import haveno.common.UserThread; import haveno.common.config.Config; @@ -40,8 +42,15 @@ import haveno.desktop.components.PeerInfoIconSmall; import haveno.desktop.main.offer.offerbook.OfferBookListItem; import haveno.desktop.util.CurrencyListItem; import haveno.desktop.util.DisplayUtils; +import static haveno.desktop.util.FormBuilder.addTopLabelAutocompleteComboBox; import haveno.desktop.util.GUIUtil; +import static haveno.desktop.util.Layout.INITIAL_WINDOW_HEIGHT; import haveno.network.p2p.NodeAddress; +import java.text.DecimalFormat; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -73,17 +82,6 @@ import javafx.util.StringConverter; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import javax.inject.Inject; -import javax.inject.Named; -import java.text.DecimalFormat; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static haveno.desktop.util.FormBuilder.addTopLabelAutocompleteComboBox; -import static haveno.desktop.util.Layout.INITIAL_WINDOW_HEIGHT; - @FxmlView public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookChartViewModel> { private final boolean useDevPrivilegeKeys; @@ -209,16 +207,21 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC @Override public String toString(Number object) { - final double doubleValue = (double) object; - if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) { - final String withCryptoPrecision = FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision); - if (withCryptoPrecision.startsWith("0.0")) { - return FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, 8).replaceFirst("0+$", ""); + try { + final double doubleValue = (double) object; + if (CurrencyUtil.isCryptoCurrency(model.getCurrencyCode())) { + final String withCryptoPrecision = FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, cryptoPrecision); + if (withCryptoPrecision.startsWith("0.0")) { + return FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, 8).replaceFirst("0+$", ""); + } else { + return withCryptoPrecision.replaceFirst("0+$", ""); + } } else { - return withCryptoPrecision.replaceFirst("0+$", ""); + return df.format(Double.parseDouble(FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, 0))); } - } else { - return df.format(Double.parseDouble(FormattingUtils.formatRoundedDoubleWithPrecision(doubleValue, 0))); + } catch (IllegalArgumentException e) { + log.error("Error converting number to string, tradeCurrency={}, number={}\n", code, object, e); + return "NaN"; // TODO: occasionally getting invalid number } } @@ -543,7 +546,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC }); // amount - TableColumn<OfferListItem, OfferListItem> amountColumn = new AutoTooltipTableColumn<>(Res.get("shared.BTCMinMax")); + TableColumn<OfferListItem, OfferListItem> amountColumn = new AutoTooltipTableColumn<>(Res.get("shared.XMRMinMax")); amountColumn.setMinWidth(115); amountColumn.setSortable(false); amountColumn.getStyleClass().add("number-column"); diff --git a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java index 0df8b45538..c7d0c91277 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModel.java @@ -1,24 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.offerbook; import com.google.common.math.LongMath; import com.google.inject.Inject; + +import haveno.common.UserThread; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.GlobalSettings; @@ -135,10 +137,12 @@ class OfferBookChartViewModel extends ActivatableViewModel { currenciesUpdatedListener = (observable, oldValue, newValue) -> { if (!isAnyPriceAbsent()) { - offerBook.fillOfferBookListItems(); - updateChartData(); - var self = this; - priceFeedService.updateCounterProperty().removeListener(self.currenciesUpdatedListener); + UserThread.execute(() -> { + offerBook.fillOfferBookListItems(); + updateChartData(); + var self = this; + priceFeedService.updateCounterProperty().removeListener(self.currenciesUpdatedListener); + }); } }; @@ -147,16 +151,18 @@ class OfferBookChartViewModel extends ActivatableViewModel { private void fillTradeCurrencies() { // Don't use a set as we need all entries - List<TradeCurrency> tradeCurrencyList = offerBookListItems.stream() - .map(e -> { - String currencyCode = e.getOffer().getCurrencyCode(); - Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(currencyCode); - return tradeCurrencyOptional.orElse(null); - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); + synchronized (offerBookListItems) { + List<TradeCurrency> tradeCurrencyList = offerBookListItems.stream() + .map(e -> { + String currencyCode = e.getOffer().getCurrencyCode(); + Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(currencyCode); + return tradeCurrencyOptional.orElse(null); + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); - currencyListItems.updateWithCurrencies(tradeCurrencyList, null); + currencyListItems.updateWithCurrencies(tradeCurrencyList, null); + } } @Override @@ -206,7 +212,10 @@ class OfferBookChartViewModel extends ActivatableViewModel { } public boolean isSellOffer(OfferDirection direction) { - return direction == OfferDirection.SELL; + // for cryptocurrency, buy direction is to buy XMR, so we need sell offers + // for traditional currency, buy direction is to sell XMR, so we need buy offers + boolean isCryptoCurrency = CurrencyUtil.isCryptoCurrency(getCurrencyCode()); + return isCryptoCurrency ? direction == OfferDirection.BUY : direction == OfferDirection.SELL; } public boolean isMyOffer(Offer offer) { @@ -417,16 +426,20 @@ class OfferBookChartViewModel extends ActivatableViewModel { private void updateScreenCurrencyInPreferences(OfferDirection direction) { if (isSellOffer(direction)) { - if (CurrencyUtil.isTraditionalCurrency(getCurrencyCode())) { + if (CurrencyUtil.isFiatCurrency(getCurrencyCode())) { preferences.setBuyScreenCurrencyCode(getCurrencyCode()); - } else if (!getCurrencyCode().equals(GUIUtil.TOP_CRYPTO.getCode())) { + } else if (CurrencyUtil.isCryptoCurrency(getCurrencyCode())) { preferences.setBuyScreenCryptoCurrencyCode(getCurrencyCode()); + } else if (CurrencyUtil.isTraditionalCurrency(getCurrencyCode())) { + preferences.setBuyScreenOtherCurrencyCode(getCurrencyCode()); } } else { - if (CurrencyUtil.isTraditionalCurrency(getCurrencyCode())) { + if (CurrencyUtil.isFiatCurrency(getCurrencyCode())) { preferences.setSellScreenCurrencyCode(getCurrencyCode()); - } else if (!getCurrencyCode().equals(GUIUtil.TOP_CRYPTO.getCode())) { + } else if (CurrencyUtil.isCryptoCurrency(getCurrencyCode())) { preferences.setSellScreenCryptoCurrencyCode(getCurrencyCode()); + } else if (CurrencyUtil.isTraditionalCurrency(getCurrencyCode())) { + preferences.setSellScreenOtherCurrencyCode(getCurrencyCode()); } } } diff --git a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferListItem.java b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferListItem.java index fc993ceaec..527b01ee4d 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/market/offerbook/OfferListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.offerbook; diff --git a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadItem.java b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadItem.java index 00e76371e9..01cec6609b 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadItem.java +++ b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.spread; diff --git a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadView.java b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadView.java index 7a680a68c2..9adf595ad4 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.spread; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -29,6 +31,8 @@ import haveno.desktop.components.AutoTooltipLabel; import haveno.desktop.components.AutoTooltipTableColumn; import haveno.desktop.components.ColoredDecimalPlacesWithZerosText; import haveno.desktop.util.GUIUtil; +import java.math.BigInteger; +import java.util.Comparator; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.collections.ListChangeListener; import javafx.collections.transformation.SortedList; @@ -40,11 +44,6 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.Priority; import javafx.util.Callback; -import javax.inject.Inject; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.Comparator; - @FxmlView public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewModel> { private final CoinFormatter formatter; @@ -123,7 +122,7 @@ public class SpreadView extends ActivatableViewAndModel<GridPane, SpreadViewMode int numberOfBuyOffers = sortedList.stream().mapToInt(item -> item.numberOfBuyOffers).sum(); int numberOfSellOffers = sortedList.stream().mapToInt(item -> item.numberOfSellOffers).sum(); - BigInteger totalAmount = BigInteger.valueOf(0); + BigInteger totalAmount = BigInteger.ZERO; for (SpreadItem item : sortedList) totalAmount = totalAmount.add(item.totalAmount); String total = HavenoUtils.formatXmr(totalAmount); diff --git a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java index 3529cb94c4..2ca1d3e743 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.spread; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.core.locale.Res; import haveno.core.monetary.CryptoMoney; @@ -35,15 +36,6 @@ import haveno.desktop.main.offer.offerbook.OfferBook; import haveno.desktop.main.offer.offerbook.OfferBookListItem; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.GUIUtil; -import javafx.beans.property.IntegerProperty; -import javafx.beans.property.SimpleIntegerProperty; -import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import lombok.Getter; -import lombok.Setter; - -import javax.inject.Named; import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; @@ -56,6 +48,13 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.collections.FXCollections; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import lombok.Getter; +import lombok.Setter; class SpreadViewModel extends ActivatableViewModel { @@ -114,22 +113,24 @@ class SpreadViewModel extends ActivatableViewModel { private void update(ObservableList<OfferBookListItem> offerBookListItems) { Map<String, List<Offer>> offersByCurrencyMap = new HashMap<>(); - for (OfferBookListItem offerBookListItem : offerBookListItems) { - Offer offer = offerBookListItem.getOffer(); - String key = offer.getCurrencyCode(); - if (includePaymentMethod) { - key = offer.getPaymentMethod().getShortName(); - if (expandedView) { - key += ":" + offer.getCurrencyCode(); + synchronized (offerBookListItems) { + for (OfferBookListItem offerBookListItem : offerBookListItems) { + Offer offer = offerBookListItem.getOffer(); + String key = offer.getCurrencyCode(); + if (includePaymentMethod) { + key = offer.getPaymentMethod().getShortName(); + if (expandedView) { + key += ":" + offer.getCurrencyCode(); + } } + if (!offersByCurrencyMap.containsKey(key)) + offersByCurrencyMap.put(key, new ArrayList<>()); + offersByCurrencyMap.get(key).add(offer); } - if (!offersByCurrencyMap.containsKey(key)) - offersByCurrencyMap.put(key, new ArrayList<>()); - offersByCurrencyMap.get(key).add(offer); } spreadItems.clear(); - BigInteger totalAmount = BigInteger.valueOf(0); + BigInteger totalAmount = BigInteger.ZERO; for (String key : offersByCurrencyMap.keySet()) { List<Offer> offers = offersByCurrencyMap.get(key); @@ -229,9 +230,13 @@ class SpreadViewModel extends ActivatableViewModel { } } - for (Offer offer : offers) totalAmount = totalAmount.add(offer.getAmount()); + BigInteger totalAmountForCurrency = BigInteger.ZERO; + for (Offer offer : offers) { + totalAmount = totalAmount.add(offer.getAmount()); + totalAmountForCurrency = totalAmountForCurrency.add(offer.getAmount()); + } spreadItems.add(new SpreadItem(key, buyOffers.size(), sellOffers.size(), - uniqueOffers.size(), spread, percentage, percentageValue, totalAmount)); + uniqueOffers.size(), spread, percentage, percentageValue, totalAmountForCurrency)); } maxPlacesForAmount.set(formatAmount(totalAmount, false).length()); diff --git a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewPaymentMethod.java b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewPaymentMethod.java index 7832ed7d60..39933c24c7 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewPaymentMethod.java +++ b/desktop/src/main/java/haveno/desktop/main/market/spread/SpreadViewPaymentMethod.java @@ -1,32 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.spread; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.locale.Res; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; import haveno.desktop.common.view.FxmlView; -import javafx.scene.control.ToggleButton; - -import javax.inject.Inject; -import javax.inject.Named; - import static haveno.desktop.util.FormBuilder.addSlideToggleButton; +import javafx.scene.control.ToggleButton; @FxmlView public class SpreadViewPaymentMethod extends SpreadView { diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java b/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java index 0a2e8f1a52..c8ba1af3af 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/ChartCalculations.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades; diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/TradeStatistics3ListItem.java b/desktop/src/main/java/haveno/desktop/main/market/trades/TradeStatistics3ListItem.java index 8bbf7b0672..f69ae31e53 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/TradeStatistics3ListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/TradeStatistics3ListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades; diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsView.java b/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsView.java index 4553380ee1..dee3591bc8 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsView.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.googlecode.jcsv.writer.CSVEntryConverter; import com.jfoenix.controls.JFXTabPane; import haveno.common.UserThread; @@ -41,11 +43,20 @@ import haveno.desktop.components.AutoTooltipTableColumn; import haveno.desktop.components.AutoTooltipToggleButton; import haveno.desktop.components.AutocompleteComboBox; import haveno.desktop.components.ColoredDecimalPlacesWithZerosText; +import static haveno.desktop.main.market.trades.TradesChartsViewModel.MAX_TICKS; import haveno.desktop.main.market.trades.charts.price.CandleStickChart; import haveno.desktop.main.market.trades.charts.volume.VolumeChart; import haveno.desktop.util.CurrencyListItem; import haveno.desktop.util.DisplayUtils; +import static haveno.desktop.util.FormBuilder.addTopLabelAutocompleteComboBox; +import static haveno.desktop.util.FormBuilder.getTopLabelWithVBox; import haveno.desktop.util.GUIUtil; +import java.text.DecimalFormat; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; @@ -84,19 +95,6 @@ import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.monadic.MonadicBinding; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; -import javax.inject.Named; -import java.text.DecimalFormat; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import java.util.stream.Collectors; - -import static haveno.desktop.main.market.trades.TradesChartsViewModel.MAX_TICKS; -import static haveno.desktop.util.FormBuilder.addTopLabelAutocompleteComboBox; -import static haveno.desktop.util.FormBuilder.getTopLabelWithVBox; - @FxmlView public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesChartsViewModel> { private static final int SHOW_ALL = 0; diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java b/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java index d88ea04e0d..665f25aa3e 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/TradesChartsViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades; diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/CandleData.java b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/CandleData.java index ceedae601d..59a0611c52 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/CandleData.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/CandleData.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades.charts; diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/Candle.java b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/Candle.java index 8087a70b93..4cb2d36737 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/Candle.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/Candle.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleStickChart.java b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleStickChart.java index 7397bdca98..215619150b 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleStickChart.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleStickChart.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleTooltip.java b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleTooltip.java index e38a1c341a..0d4da8a424 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleTooltip.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/price/CandleTooltip.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ /* diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeBar.java b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeBar.java index acb0c079c7..9e0ce60ea3 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeBar.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeBar.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades.charts.volume; diff --git a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeChart.java b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeChart.java index ad0af1eba7..f9fc70da1c 100644 --- a/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeChart.java +++ b/desktop/src/main/java/haveno/desktop/main/market/trades/charts/volume/VolumeChart.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades.charts.volume; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/BuyOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/BuyOfferView.java index 5ae1de3268..67591cbce4 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/BuyOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/BuyOfferView.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; +import com.google.inject.Inject; + +import haveno.core.locale.Res; import haveno.core.offer.OfferDirection; import haveno.core.user.Preferences; import haveno.core.user.User; @@ -25,8 +28,6 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.ViewLoader; import haveno.network.p2p.P2PService; -import javax.inject.Inject; - @FxmlView public class BuyOfferView extends OfferView { @@ -43,4 +44,9 @@ public class BuyOfferView extends OfferView { p2PService, OfferDirection.BUY); } + + @Override + protected String getOfferLabel() { + return Res.get("offerbook.buyXmrWith"); + } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/ClosableView.java b/desktop/src/main/java/haveno/desktop/main/offer/ClosableView.java index 9f88fb6091..1fbd9af629 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/ClosableView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/ClosableView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/InitializableViewWithTakeOfferData.java b/desktop/src/main/java/haveno/desktop/main/offer/InitializableViewWithTakeOfferData.java index d4abfe787d..6832e58dbe 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/InitializableViewWithTakeOfferData.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/InitializableViewWithTakeOfferData.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java index 871b6af883..bad2ee75f8 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferDataModel.java @@ -1,23 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Inject; +import com.google.inject.name.Named; + +import haveno.common.UserThread; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.util.MathUtils; import haveno.common.util.Utilities; @@ -48,9 +52,17 @@ import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.Restrictions; import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.Navigation; -import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; +import java.math.BigInteger; +import java.util.Comparator; +import static java.util.Comparator.comparing; +import java.util.Date; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; import javafx.beans.property.BooleanProperty; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ObjectProperty; @@ -69,20 +81,6 @@ import javafx.collections.SetChangeListener; import lombok.Getter; import org.jetbrains.annotations.NotNull; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.Comparator; -import java.util.Date; -import java.util.HashSet; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static java.util.Comparator.comparing; - public abstract class MutableOfferDataModel extends OfferDataModel { private final CreateOfferService createOfferService; protected final OpenOfferManager openOfferManager; @@ -96,7 +94,6 @@ public abstract class MutableOfferDataModel extends OfferDataModel { private final CoinFormatter btcFormatter; private final Navigation navigation; private final String offerId; - private final XmrBalanceListener xmrBalanceListener; private final SetChangeListener<PaymentAccount> paymentAccountsChangeListener; protected OfferDirection direction; @@ -110,7 +107,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel { protected final ObjectProperty<Volume> minVolume = new SimpleObjectProperty<>(); // Percentage value of buyer security deposit. E.g. 0.01 means 1% of trade amount - protected final DoubleProperty buyerSecurityDepositPct = new SimpleDoubleProperty(); + protected final DoubleProperty securityDepositPct = new SimpleDoubleProperty(); + protected final BooleanProperty buyerAsTakerWithoutDeposit = new SimpleBooleanProperty(); protected final ObservableList<PaymentAccount> paymentAccounts = FXCollections.observableArrayList(); @@ -122,13 +120,14 @@ public abstract class MutableOfferDataModel extends OfferDataModel { protected boolean allowAmountUpdate = true; private final TradeStatisticsManager tradeStatisticsManager; - private final Predicate<ObjectProperty<BigInteger>> isNonZeroAmount = (c) -> c.get() != null && c.get().compareTo(BigInteger.valueOf(0)) != 0; + private final Predicate<ObjectProperty<BigInteger>> isNonZeroAmount = (c) -> c.get() != null && c.get().compareTo(BigInteger.ZERO) != 0; private final Predicate<ObjectProperty<Price>> isNonZeroPrice = (p) -> p.get() != null && !p.get().isZero(); private final Predicate<ObjectProperty<Volume>> isNonZeroVolume = (v) -> v.get() != null && !v.get().isZero(); @Getter protected long triggerPrice; @Getter protected boolean reserveExactAmount; + private XmrBalanceListener xmrBalanceListener; /////////////////////////////////////////////////////////////////////////////////////////// @@ -164,19 +163,11 @@ public abstract class MutableOfferDataModel extends OfferDataModel { offerId = OfferUtil.getRandomOfferId(); shortOfferId = Utilities.getShortId(offerId); - addressEntry = xmrWalletService.getOrCreateAddressEntry(offerId, XmrAddressEntry.Context.OFFER_FUNDING); reserveExactAmount = preferences.getSplitOfferOutput(); useMarketBasedPrice.set(preferences.isUsePercentageBasedPrice()); - buyerSecurityDepositPct.set(Restrictions.getMinBuyerSecurityDepositAsPercent()); - - xmrBalanceListener = new XmrBalanceListener(getAddressEntry().getSubaddressIndex()) { - @Override - public void onBalanceChanged(BigInteger balance) { - updateBalance(); - } - }; + securityDepositPct.set(Restrictions.getMinSecurityDepositAsPercent()); paymentAccountsChangeListener = change -> fillPaymentAccounts(); } @@ -188,7 +179,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { if (isTabSelected) priceFeedService.setCurrencyCode(tradeCurrencyCode.get()); - updateBalance(); + updateBalances(); } @Override @@ -213,6 +204,14 @@ public abstract class MutableOfferDataModel extends OfferDataModel { // called before activate() public boolean initWithData(OfferDirection direction, TradeCurrency tradeCurrency) { + addressEntry = xmrWalletService.getOrCreateAddressEntry(offerId, XmrAddressEntry.Context.OFFER_FUNDING); + xmrBalanceListener = new XmrBalanceListener(getAddressEntry().getSubaddressIndex()) { + @Override + public void onBalanceChanged(BigInteger balance) { + updateBalances(); + } + }; + this.direction = direction; this.tradeCurrency = tradeCurrency; @@ -250,7 +249,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { calculateVolume(); calculateTotalToPay(); - updateBalance(); + updateBalances(); setSuggestedSecurityDeposit(getPaymentAccount()); return true; @@ -260,10 +259,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel { private Optional<PaymentAccount> getAnyPaymentAccount() { if (CurrencyUtil.isFiatCurrency(tradeCurrency.getCode())) { return paymentAccounts.stream().filter(paymentAccount1 -> paymentAccount1.isFiat()).findAny(); + } else if (CurrencyUtil.isCryptoCurrency(tradeCurrency.getCode())) { + return paymentAccounts.stream().filter(paymentAccount1 -> paymentAccount1.isCryptoCurrency()).findAny(); } else { - return paymentAccounts.stream().filter(paymentAccount1 -> !paymentAccount1.isFiat() && - paymentAccount1.getTradeCurrency().isPresent() && - !Objects.equals(paymentAccount1.getTradeCurrency().get().getCode(), GUIUtil.TOP_CRYPTO.getCode())).findAny(); + return paymentAccounts.stream().filter(paymentAccount1 -> paymentAccount1.getTradeCurrency().isPresent()).findAny(); } } @@ -277,6 +276,19 @@ public abstract class MutableOfferDataModel extends OfferDataModel { priceFeedService.setCurrencyCode(tradeCurrencyCode.get()); } + protected void updateBalances() { + super.updateBalances(); + + // update remaining balance + UserThread.await(() -> { + missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), balance.get())); + isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), balance.get())); + if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) { + showWalletFundedNotification.set(true); + } + }); + } + /////////////////////////////////////////////////////////////////////////////////////////// // UI actions /////////////////////////////////////////////////////////////////////////////////////////// @@ -290,8 +302,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel { useMarketBasedPrice.get() ? null : price.get(), useMarketBasedPrice.get(), useMarketBasedPrice.get() ? marketPriceMargin : 0, - buyerSecurityDepositPct.get(), - paymentAccount); + securityDepositPct.get(), + paymentAccount, + buyerAsTakerWithoutDeposit.get(), // private offer if buyer as taker without deposit + buyerAsTakerWithoutDeposit.get()); } void onPlaceOffer(Offer offer, TransactionResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { @@ -299,6 +313,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { useSavingsWallet, triggerPrice, reserveExactAmount, + false, // desktop ui resets address entries on cancel resultHandler, errorMessageHandler); } @@ -317,10 +332,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel { } private void setSuggestedSecurityDeposit(PaymentAccount paymentAccount) { - var minSecurityDeposit = Restrictions.getMinBuyerSecurityDepositAsPercent(); + var minSecurityDeposit = Restrictions.getMinSecurityDepositAsPercent(); try { if (getTradeCurrency() == null) { - setBuyerSecurityDeposit(minSecurityDeposit); + setSecurityDepositPct(minSecurityDeposit); return; } // Get average historic prices over for the prior trade period equaling the lock time @@ -343,16 +358,16 @@ public abstract class MutableOfferDataModel extends OfferDataModel { var min = extremes[0]; var max = extremes[1]; if (min == 0d || max == 0d) { - setBuyerSecurityDeposit(minSecurityDeposit); + setSecurityDepositPct(minSecurityDeposit); return; } // Suggested deposit is double the trade range over the previous lock time period, bounded by min/max deposit var suggestedSecurityDeposit = - Math.min(2 * (max - min) / max, Restrictions.getMaxBuyerSecurityDepositAsPercent()); - buyerSecurityDepositPct.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit)); + Math.min(2 * (max - min) / max, Restrictions.getMaxSecurityDepositAsPercent()); + securityDepositPct.set(Math.max(suggestedSecurityDeposit, minSecurityDeposit)); } catch (Throwable t) { log.error(t.toString()); - buyerSecurityDepositPct.set(minSecurityDeposit); + securityDepositPct.set(minSecurityDeposit); } } @@ -396,11 +411,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { void fundFromSavingsWallet() { this.useSavingsWallet = true; - updateBalance(); - if (!isXmrWalletFunded.get()) { - this.useSavingsWallet = false; - updateBalance(); - } + updateBalances(); } protected void setMarketPriceMarginPct(double marketPriceMargin) { @@ -447,6 +458,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel { preferences.setUsePercentageBasedPrice(useMarketBasedPrice); } + protected void setBuyerAsTakerWithoutDeposit(boolean buyerAsTakerWithoutDeposit) { + this.buyerAsTakerWithoutDeposit.set(buyerAsTakerWithoutDeposit); + } + public ObservableList<PaymentAccount> getPaymentAccounts() { return paymentAccounts; } @@ -456,18 +471,19 @@ public abstract class MutableOfferDataModel extends OfferDataModel { } long getMaxTradeLimit() { + + // disallow offers which no buyer can take due to trade limits on release + if (HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS)) { + return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), OfferDirection.BUY, buyerAsTakerWithoutDeposit.get()); + } + if (paymentAccount != null) { - return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction); + return accountAgeWitnessService.getMyTradeLimit(paymentAccount, tradeCurrencyCode.get(), direction, buyerAsTakerWithoutDeposit.get()); } else { return 0; } } - public boolean hasAvailableSplitOutput() { - BigInteger reserveAmount = totalToPay.get(); - return openOfferManager.hasAvailableOutput(reserveAmount); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Utils /////////////////////////////////////////////////////////////////////////////////////////// @@ -494,7 +510,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel { } } - updateBalance(); + updateBalances(); } void calculateMinVolume() { @@ -519,12 +535,18 @@ public abstract class MutableOfferDataModel extends OfferDataModel { void calculateAmount() { if (isNonZeroPrice.test(price) && isNonZeroVolume.test(volume) && allowAmountUpdate) { try { - BigInteger value = HavenoUtils.coinToAtomicUnits(DisplayUtils.reduceTo4Decimals(HavenoUtils.atomicUnitsToCoin(price.get().getAmountByVolume(volume.get())), btcFormatter)); - value = CoinUtil.getRoundedAmount(value, price.get(), getMaxTradeLimit(), tradeCurrencyCode.get(), paymentAccount.getPaymentMethod().getId()); - + Volume volumeBefore = volume.get(); calculateVolume(); - amount.set(value); + // if the volume != amount * price, we need to adjust the amount + if (amount.get() == null || !volumeBefore.equals(price.get().getVolumeByAmount(amount.get()))) { + BigInteger value = price.get().getAmountByVolume(volumeBefore); + value = value.min(BigInteger.valueOf(getMaxTradeLimit())); // adjust if above maximum + value = value.max(Restrictions.getMinTradeAmount()); // adjust if below minimum + value = CoinUtil.getRoundedAmount(value, price.get(), getMaxTradeLimit(), tradeCurrencyCode.get(), paymentAccount.getPaymentMethod().getId()); + amount.set(value); + } + calculateTotalToPay(); } catch (Throwable t) { log.error(t.toString()); @@ -536,19 +558,15 @@ public abstract class MutableOfferDataModel extends OfferDataModel { // Maker does not pay the mining fee for the trade txs because the mining fee might be different when maker // created the offer and reserved his funds, so that would not work well with dynamic fees. // The mining fee for the createOfferFee tx is deducted from the createOfferFee and not visible to the trader - final BigInteger makerFee = getMakerFee(); + final BigInteger makerFee = getMaxMakerFee(); if (direction != null && amount.get() != null && makerFee != null) { BigInteger feeAndSecDeposit = getSecurityDeposit().add(makerFee); BigInteger total = isBuyOffer() ? feeAndSecDeposit : feeAndSecDeposit.add(amount.get()); totalToPay.set(total); - updateBalance(); + updateBalances(); } } - BigInteger getSecurityDeposit() { - return isBuyOffer() ? getBuyerSecurityDeposit() : getSellerSecurityDeposit(); - } - void swapTradeToSavings() { xmrWalletService.resetAddressEntriesForOpenOffer(offerId); } @@ -573,14 +591,18 @@ public abstract class MutableOfferDataModel extends OfferDataModel { this.volume.set(volume); } - protected void setBuyerSecurityDeposit(double value) { - this.buyerSecurityDepositPct.set(value); + protected void setSecurityDepositPct(double value) { + this.securityDepositPct.set(value); } /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// + public BigInteger getMaxUnsignedBuyLimit() { + return BigInteger.valueOf(accountAgeWitnessService.getUnsignedTradeLimit(paymentAccount.getPaymentMethod(), tradeCurrencyCode.get(), OfferDirection.BUY)); + } + protected ReadOnlyObjectProperty<BigInteger> getAmount() { return amount; } @@ -601,6 +623,10 @@ public abstract class MutableOfferDataModel extends OfferDataModel { return minVolume; } + public ReadOnlyBooleanProperty getBuyerAsTakerWithoutDeposit() { + return buyerAsTakerWithoutDeposit; + } + protected void setMinAmount(BigInteger minAmount) { this.minAmount.set(minAmount); } @@ -625,35 +651,19 @@ public abstract class MutableOfferDataModel extends OfferDataModel { return useMarketBasedPrice; } - ReadOnlyDoubleProperty getBuyerSecurityDepositPct() { - return buyerSecurityDepositPct; + ReadOnlyDoubleProperty getSecurityDepositPct() { + return securityDepositPct; } - protected BigInteger getBuyerSecurityDeposit() { - BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(buyerSecurityDepositPct.get(), amount.get()); - return getBoundedBuyerSecurityDeposit(percentOfAmount); - } - - private BigInteger getSellerSecurityDeposit() { + protected BigInteger getSecurityDeposit() { BigInteger amount = this.amount.get(); - if (amount == null) - amount = BigInteger.valueOf(0); - - BigInteger percentOfAmount = CoinUtil.getPercentOfAmount( - createOfferService.getSellerSecurityDepositAsDouble(buyerSecurityDepositPct.get()), amount); - return getBoundedSellerSecurityDeposit(percentOfAmount); + if (amount == null) amount = BigInteger.ZERO; + BigInteger percentOfAmount = CoinUtil.getPercentOfAmount(securityDepositPct.get(), amount); + return getBoundedSecurityDeposit(percentOfAmount); } - protected BigInteger getBoundedBuyerSecurityDeposit(BigInteger value) { - // We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the - // MinBuyerSecurityDeposit from Restrictions. - return Restrictions.getMinBuyerSecurityDeposit().max(value); - } - - private BigInteger getBoundedSellerSecurityDeposit(BigInteger value) { - // We need to ensure that for small amount values we don't get a too low BTC amount. We limit it with using the - // MinSellerSecurityDeposit from Restrictions. - return Restrictions.getMinSellerSecurityDeposit().max(value); + protected BigInteger getBoundedSecurityDeposit(BigInteger value) { + return Restrictions.getMinSecurityDeposit().max(value); } ReadOnlyObjectProperty<BigInteger> totalToPayAsProperty() { @@ -664,8 +674,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel { this.marketPriceAvailable = marketPriceAvailable; } - public BigInteger getMakerFee() { - return HavenoUtils.getMakerFee(amount.get()); + public BigInteger getMaxMakerFee() { + return HavenoUtils.multiply(amount.get(), buyerAsTakerWithoutDeposit.get() ? HavenoUtils.MAKER_FEE_FOR_TAKER_WITHOUT_DEPOSIT_PCT : HavenoUtils.MAKER_FEE_PCT); } boolean canPlaceOffer() { @@ -673,8 +683,8 @@ public abstract class MutableOfferDataModel extends OfferDataModel { GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation); } - public boolean isMinBuyerSecurityDeposit() { - return getBuyerSecurityDeposit().compareTo(Restrictions.getMinBuyerSecurityDeposit()) <= 0; + public boolean isMinSecurityDeposit() { + return getSecurityDeposit().compareTo(Restrictions.getMinSecurityDeposit()) <= 0; } public void setTriggerPrice(long triggerPrice) { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java index 342819bae5..9115c64491 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; @@ -77,6 +77,7 @@ import javafx.scene.control.Label; import javafx.scene.control.ScrollPane; import javafx.scene.control.Separator; import javafx.scene.control.TextField; +import javafx.scene.control.ToggleButton; import javafx.scene.control.Tooltip; import javafx.scene.image.Image; import javafx.scene.image.ImageView; @@ -132,16 +133,17 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten private AutoTooltipButton nextButton, cancelButton1, cancelButton2, placeOfferButton, fundFromSavingsWalletButton; private Button priceTypeToggleButton; private InputTextField fixedPriceTextField, marketBasedPriceTextField, triggerPriceInputTextField; - protected InputTextField amountTextField, minAmountTextField, volumeTextField, buyerSecurityDepositInputTextField; + protected InputTextField amountTextField, minAmountTextField, volumeTextField, securityDepositInputTextField; private TextField currencyTextField; private AddressTextField addressTextField; private BalanceTextField balanceTextField; private CheckBox reserveExactAmountCheckbox; + private ToggleButton buyerAsTakerWithoutDepositSlider; private FundsTextField totalToPayTextField; private Label amountDescriptionLabel, priceCurrencyLabel, priceDescriptionLabel, volumeDescriptionLabel, waitingForFundsLabel, marketBasedPriceLabel, percentagePriceDescriptionLabel, tradeFeeDescriptionLabel, - resultLabel, tradeFeeInXmrLabel, xLabel, fakeXLabel, buyerSecurityDepositLabel, - buyerSecurityDepositPercentageLabel, triggerPriceCurrencyLabel, triggerPriceDescriptionLabel; + resultLabel, tradeFeeInXmrLabel, xLabel, fakeXLabel, securityDepositLabel, + securityDepositPercentageLabel, triggerPriceCurrencyLabel, triggerPriceDescriptionLabel; protected Label amountBtcLabel, volumeCurrencyLabel, minAmountBtcLabel; private ComboBox<PaymentAccount> paymentAccountsComboBox; private ComboBox<TradeCurrency> currencyComboBox; @@ -149,16 +151,16 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten private VBox currencySelection, fixedPriceBox, percentagePriceBox, currencyTextFieldBox, triggerPriceVBox; private HBox fundingHBox, firstRowHBox, secondRowHBox, placeOfferBox, amountValueCurrencyBox, priceAsPercentageValueCurrencyBox, volumeValueCurrencyBox, priceValueCurrencyBox, - minAmountValueCurrencyBox, advancedOptionsBox, triggerPriceHBox; + minAmountValueCurrencyBox, securityDepositAndFeeBox, triggerPriceHBox; private Subscription isWaitingForFundsSubscription, balanceSubscription; private ChangeListener<Boolean> amountFocusedListener, minAmountFocusedListener, volumeFocusedListener, - buyerSecurityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener, + securityDepositFocusedListener, priceFocusedListener, placeOfferCompletedListener, priceAsPercentageFocusedListener, getShowWalletFundedNotificationListener, - isMinBuyerSecurityDepositListener, triggerPriceFocusedListener; + isMinSecurityDepositListener, buyerAsTakerWithoutDepositListener, triggerPriceFocusedListener; private ChangeListener<BigInteger> missingCoinListener; private ChangeListener<String> tradeCurrencyCodeListener, errorMessageListener, - marketPriceMarginListener, volumeListener, buyerSecurityDepositInBTCListener; + marketPriceMarginListener, volumeListener, securityDepositInXMRListener; private ChangeListener<Number> marketPriceAvailableListener; private EventHandler<ActionEvent> currencyComboBoxSelectionHandler, paymentAccountsComboBoxSelectionHandler; private OfferView.CloseHandler closeHandler; @@ -168,7 +170,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten private final HashMap<String, Boolean> paymentAccountWarningDisplayed = new HashMap<>(); private boolean zelleWarningDisplayed, fasterPaymentsWarningDisplayed, isActivated; private InfoInputTextField marketBasedPriceInfoInputTextField, volumeInfoInputTextField, - buyerSecurityDepositInfoInputTextField, triggerPriceInfoInputTextField; + securityDepositInfoInputTextField, triggerPriceInfoInputTextField; private Text xIcon, fakeXIcon; @Setter @@ -252,6 +254,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten Label popOverLabel = OfferViewUtil.createPopOverLabel(Res.get("createOffer.triggerPrice.tooltip")); triggerPriceInfoInputTextField.setContentForPopOver(popOverLabel, AwesomeIcon.SHIELD); + + buyerAsTakerWithoutDepositSlider.setSelected(model.dataModel.getBuyerAsTakerWithoutDeposit().get()); } } @@ -308,7 +312,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { placeOfferButtonLabel = Res.get("createOffer.placeOfferButton", Res.get("shared.buy")); } else { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), tradeCurrency.getCode()); + placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), tradeCurrency.getCode()); } nextButton.setId("buy-button"); fundFromSavingsWalletButton.setId("buy-button"); @@ -317,12 +321,15 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { placeOfferButtonLabel = Res.get("createOffer.placeOfferButton", Res.get("shared.sell")); } else { - placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), tradeCurrency.getCode()); + placeOfferButtonLabel = Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), tradeCurrency.getCode()); } nextButton.setId("sell-button"); fundFromSavingsWalletButton.setId("sell-button"); } + buyerAsTakerWithoutDepositSlider.setVisible(model.isSellOffer()); + buyerAsTakerWithoutDepositSlider.setManaged(model.isSellOffer()); + placeOfferButton.updateText(placeOfferButtonLabel); updatePriceToggle(); } @@ -330,7 +337,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten // called from parent as the view does not get notified when the tab is closed public void onClose() { // we use model.placeOfferCompleted to not react on close which was triggered by a successful placeOffer - if (model.getDataModel().getBalance().get().compareTo(BigInteger.valueOf(0)) > 0 && !model.placeOfferCompleted.get()) { + if (model.getDataModel().getBalance().get().compareTo(BigInteger.ZERO) > 0 && !model.placeOfferCompleted.get()) { model.getDataModel().swapTradeToSavings(); } } @@ -348,9 +355,12 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten if (model.getDataModel().canPlaceOffer()) { Offer offer = model.createAndGetOffer(); if (!DevEnv.isDevMode()) { - offerDetailsWindow.onPlaceOffer(() -> - model.onPlaceOffer(offer, offerDetailsWindow::hide)) - .show(offer); + offerDetailsWindow.onPlaceOffer(() -> { + model.onPlaceOffer(offer, offerDetailsWindow::hide); + }).show(offer); + offerDetailsWindow.onClose(() -> { + model.onCancelOffer(null, null); + }); } else { balanceSubscription.unsubscribe(); model.onPlaceOffer(offer, () -> { @@ -372,8 +382,13 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten setDepositTitledGroupBg.setVisible(false); setDepositTitledGroupBg.setManaged(false); - advancedOptionsBox.setVisible(false); - advancedOptionsBox.setManaged(false); + securityDepositAndFeeBox.setVisible(false); + securityDepositAndFeeBox.setManaged(false); + + buyerAsTakerWithoutDepositSlider.setVisible(false); + buyerAsTakerWithoutDepositSlider.setManaged(false); + + updateQrCode(); model.onShowPayFundsScreen(() -> { if (!DevEnv.isDevMode()) { @@ -551,8 +566,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten volumeTextField.promptTextProperty().bind(model.volumePromptLabel); totalToPayTextField.textProperty().bind(model.totalToPay); addressTextField.amountAsProperty().bind(model.getDataModel().getMissingCoin()); - buyerSecurityDepositInputTextField.textProperty().bindBidirectional(model.buyerSecurityDeposit); - buyerSecurityDepositLabel.textProperty().bind(model.buyerSecurityDepositLabel); + securityDepositInputTextField.textProperty().bindBidirectional(model.securityDeposit); + securityDepositLabel.textProperty().bind(model.securityDepositLabel); tradeFeeInXmrLabel.textProperty().bind(model.tradeFeeInXmrWithFiat); tradeFeeDescriptionLabel.textProperty().bind(model.tradeFeeDescription); @@ -562,7 +577,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten fixedPriceTextField.validationResultProperty().bind(model.priceValidationResult); triggerPriceInputTextField.validationResultProperty().bind(model.triggerPriceValidationResult); volumeTextField.validationResultProperty().bind(model.volumeValidationResult); - buyerSecurityDepositInputTextField.validationResultProperty().bind(model.buyerSecurityDepositValidationResult); + securityDepositInputTextField.validationResultProperty().bind(model.securityDepositValidationResult); // funding fundingHBox.visibleProperty().bind(model.getDataModel().getIsXmrWalletFunded().not().and(model.showPayFundsScreenDisplayed)); @@ -599,8 +614,8 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten volumeTextField.promptTextProperty().unbindBidirectional(model.volume); totalToPayTextField.textProperty().unbind(); addressTextField.amountAsProperty().unbind(); - buyerSecurityDepositInputTextField.textProperty().unbindBidirectional(model.buyerSecurityDeposit); - buyerSecurityDepositLabel.textProperty().unbind(); + securityDepositInputTextField.textProperty().unbindBidirectional(model.securityDeposit); + securityDepositLabel.textProperty().unbind(); tradeFeeInXmrLabel.textProperty().unbind(); tradeFeeDescriptionLabel.textProperty().unbind(); tradeFeeInXmrLabel.visibleProperty().unbind(); @@ -612,7 +627,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten fixedPriceTextField.validationResultProperty().unbind(); triggerPriceInputTextField.validationResultProperty().unbind(); volumeTextField.validationResultProperty().unbind(); - buyerSecurityDepositInputTextField.validationResultProperty().unbind(); + securityDepositInputTextField.validationResultProperty().unbind(); // funding fundingHBox.visibleProperty().unbind(); @@ -674,9 +689,9 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten model.onFocusOutVolumeTextField(oldValue, newValue); volumeTextField.setText(model.volume.get()); }; - buyerSecurityDepositFocusedListener = (o, oldValue, newValue) -> { - model.onFocusOutBuyerSecurityDepositTextField(oldValue, newValue); - buyerSecurityDepositInputTextField.setText(model.buyerSecurityDeposit.get()); + securityDepositFocusedListener = (o, oldValue, newValue) -> { + model.onFocusOutSecurityDepositTextField(oldValue, newValue); + securityDepositInputTextField.setText(model.securityDeposit.get()); }; triggerPriceFocusedListener = (o, oldValue, newValue) -> { @@ -685,9 +700,11 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten }; errorMessageListener = (o, oldValue, newValue) -> { - if (newValue != null) + if (model.createOfferCanceled) return; + if (newValue != null) { UserThread.runAfter(() -> new Popup().error(Res.get("createOffer.amountPriceBox.error.message", model.errorMessage.get())) - .show(), 100, TimeUnit.MILLISECONDS); + .show(), 100, TimeUnit.MILLISECONDS); + } }; paymentAccountsComboBoxSelectionHandler = e -> onPaymentAccountsComboBoxSelected(); @@ -700,10 +717,10 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten triggerPriceInputTextField.clear(); if (!CurrencyUtil.isTraditionalCurrency(newValue)) { if (model.isShownAsBuyOffer()) { - placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), + placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), model.getTradeCurrency().getCode())); } else { - placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.sell"), + placeOfferButton.updateText(Res.get("createOffer.placeOfferButtonCrypto", Res.get("shared.buy"), model.getTradeCurrency().getCode())); } } @@ -743,12 +760,11 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten } }; - buyerSecurityDepositInBTCListener = (observable, oldValue, newValue) -> { + securityDepositInXMRListener = (observable, oldValue, newValue) -> { if (!newValue.equals("")) { - Label depositInBTCInfo = OfferViewUtil.createPopOverLabel(model.getSecurityDepositPopOverLabel(newValue)); - buyerSecurityDepositInfoInputTextField.setContentForInfoPopOver(depositInBTCInfo); + updateSecurityDepositLabels(); } else { - buyerSecurityDepositInfoInputTextField.setContentForInfoPopOver(null); + securityDepositInfoInputTextField.setContentForInfoPopOver(null); } }; @@ -763,14 +779,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten missingCoinListener = (observable, oldValue, newValue) -> { if (!newValue.toString().equals("")) { - final byte[] imageBytes = QRCode - .from(getMoneroURI()) - .withSize(300, 300) - .to(ImageType.PNG) - .stream() - .toByteArray(); - Image qrImage = new Image(new ByteArrayInputStream(imageBytes)); - qrCodeImageView.setImage(qrImage); + updateQrCode(); } }; @@ -805,17 +814,40 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten } }; - isMinBuyerSecurityDepositListener = ((observable, oldValue, newValue) -> { - if (newValue) { - // show BTC - buyerSecurityDepositPercentageLabel.setText(Res.getBaseCurrencyCode()); - buyerSecurityDepositInputTextField.setDisable(true); - } else { - // show % - buyerSecurityDepositPercentageLabel.setText("%"); - buyerSecurityDepositInputTextField.setDisable(false); - } + isMinSecurityDepositListener = ((observable, oldValue, newValue) -> { + updateSecurityDepositLabels(); }); + + buyerAsTakerWithoutDepositListener = ((observable, oldValue, newValue) -> { + updateSecurityDepositLabels(); + }); + } + + private void updateSecurityDepositLabels() { + if (model.isMinSecurityDeposit.get()) { + // show XMR + securityDepositPercentageLabel.setText(Res.getBaseCurrencyCode()); + securityDepositInputTextField.setDisable(true); + } else { + // show % + securityDepositPercentageLabel.setText("%"); + securityDepositInputTextField.setDisable(model.getDataModel().buyerAsTakerWithoutDeposit.get()); + } + if (model.securityDepositInXMR.get() != null && !model.securityDepositInXMR.get().equals("")) { + Label depositInBTCInfo = OfferViewUtil.createPopOverLabel(model.getSecurityDepositPopOverLabel(model.securityDepositInXMR.get())); + securityDepositInfoInputTextField.setContentForInfoPopOver(depositInBTCInfo); + } + } + + private void updateQrCode() { + final byte[] imageBytes = QRCode + .from(getMoneroURI()) + .withSize(300, 300) + .to(ImageType.PNG) + .stream() + .toByteArray(); + Image qrImage = new Image(new ByteArrayInputStream(imageBytes)); + qrCodeImageView.setImage(qrImage); } private void closeAndGoToOpenOffers() { @@ -845,8 +877,9 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten model.marketPriceMargin.addListener(marketPriceMarginListener); model.volume.addListener(volumeListener); model.getDataModel().missingCoin.addListener(missingCoinListener); - model.buyerSecurityDepositInBTC.addListener(buyerSecurityDepositInBTCListener); - model.isMinBuyerSecurityDeposit.addListener(isMinBuyerSecurityDepositListener); + model.securityDepositInXMR.addListener(securityDepositInXMRListener); + model.isMinSecurityDeposit.addListener(isMinSecurityDepositListener); + model.getDataModel().buyerAsTakerWithoutDeposit.addListener(buyerAsTakerWithoutDepositListener); // focus out amountTextField.focusedProperty().addListener(amountFocusedListener); @@ -855,7 +888,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten triggerPriceInputTextField.focusedProperty().addListener(triggerPriceFocusedListener); marketBasedPriceTextField.focusedProperty().addListener(priceAsPercentageFocusedListener); volumeTextField.focusedProperty().addListener(volumeFocusedListener); - buyerSecurityDepositInputTextField.focusedProperty().addListener(buyerSecurityDepositFocusedListener); + securityDepositInputTextField.focusedProperty().addListener(securityDepositFocusedListener); // notifications model.getDataModel().getShowWalletFundedNotification().addListener(getShowWalletFundedNotificationListener); @@ -877,8 +910,9 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten model.marketPriceMargin.removeListener(marketPriceMarginListener); model.volume.removeListener(volumeListener); model.getDataModel().missingCoin.removeListener(missingCoinListener); - model.buyerSecurityDepositInBTC.removeListener(buyerSecurityDepositInBTCListener); - model.isMinBuyerSecurityDeposit.removeListener(isMinBuyerSecurityDepositListener); + model.securityDepositInXMR.removeListener(securityDepositInXMRListener); + model.isMinSecurityDeposit.removeListener(isMinSecurityDepositListener); + model.getDataModel().buyerAsTakerWithoutDeposit.removeListener(buyerAsTakerWithoutDepositListener); // focus out amountTextField.focusedProperty().removeListener(amountFocusedListener); @@ -887,7 +921,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten triggerPriceInputTextField.focusedProperty().removeListener(triggerPriceFocusedListener); marketBasedPriceTextField.focusedProperty().removeListener(priceAsPercentageFocusedListener); volumeTextField.focusedProperty().removeListener(volumeFocusedListener); - buyerSecurityDepositInputTextField.focusedProperty().removeListener(buyerSecurityDepositFocusedListener); + securityDepositInputTextField.focusedProperty().removeListener(securityDepositFocusedListener); // notifications model.getDataModel().getShowWalletFundedNotification().removeListener(getShowWalletFundedNotificationListener); @@ -986,22 +1020,46 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten } private void addOptionsGroup() { - setDepositTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 1, + setDepositTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 2, Res.get("shared.advancedOptions"), Layout.COMPACT_GROUP_DISTANCE); - advancedOptionsBox = new HBox(); - advancedOptionsBox.setSpacing(40); + securityDepositAndFeeBox = new HBox(); + securityDepositAndFeeBox.setSpacing(40); - GridPane.setRowIndex(advancedOptionsBox, gridRow); - GridPane.setColumnSpan(advancedOptionsBox, GridPane.REMAINING); - GridPane.setColumnIndex(advancedOptionsBox, 0); - GridPane.setHalignment(advancedOptionsBox, HPos.LEFT); - GridPane.setMargin(advancedOptionsBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); - gridPane.getChildren().add(advancedOptionsBox); + GridPane.setRowIndex(securityDepositAndFeeBox, gridRow); + GridPane.setColumnSpan(securityDepositAndFeeBox, GridPane.REMAINING); + GridPane.setColumnIndex(securityDepositAndFeeBox, 0); + GridPane.setHalignment(securityDepositAndFeeBox, HPos.LEFT); + GridPane.setMargin(securityDepositAndFeeBox, new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); + gridPane.getChildren().add(securityDepositAndFeeBox); VBox tradeFeeFieldsBox = getTradeFeeFieldsBox(); tradeFeeFieldsBox.setMinWidth(240); - advancedOptionsBox.getChildren().addAll(getBuyerSecurityDepositBox(), tradeFeeFieldsBox); + securityDepositAndFeeBox.getChildren().addAll(getSecurityDepositBox(), tradeFeeFieldsBox); + + buyerAsTakerWithoutDepositSlider = FormBuilder.addSlideToggleButton(gridPane, ++gridRow, Res.get("createOffer.buyerAsTakerWithoutDeposit")); + buyerAsTakerWithoutDepositSlider.setOnAction(event -> { + + // popup info box + String key = "popup.info.buyerAsTakerWithoutDeposit"; + if (buyerAsTakerWithoutDepositSlider.isSelected() && DontShowAgainLookup.showAgain(key)) { + new Popup().headLine(Res.get(key + ".headline")) + .information(Res.get(key)) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.ok")) + .onAction(() -> model.dataModel.setBuyerAsTakerWithoutDeposit(true)) + .onClose(() -> { + buyerAsTakerWithoutDepositSlider.setSelected(false); + model.dataModel.setBuyerAsTakerWithoutDeposit(false); + }) + .dontShowAgainId(key) + .show(); + } else { + model.dataModel.setBuyerAsTakerWithoutDeposit(buyerAsTakerWithoutDepositSlider.isSelected()); + } + }); + GridPane.setHalignment(buyerAsTakerWithoutDepositSlider, HPos.LEFT); + GridPane.setMargin(buyerAsTakerWithoutDepositSlider, new Insets(0, 0, 0, 0)); Tuple2<Button, Button> tuple = add2ButtonsAfterGroup(gridPane, ++gridRow, Res.get("shared.nextStep"), Res.get("shared.cancel")); @@ -1020,7 +1078,24 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten nextButton.setOnAction(e -> { if (model.isPriceInRange()) { - onShowPayFundsScreen(); + + // warn if sell offer exceeds unsigned buy limit within release window + boolean isSellOffer = model.getDataModel().isSellOffer(); + boolean exceedsUnsignedBuyLimit = model.getDataModel().getAmount().get().compareTo(model.getDataModel().getMaxUnsignedBuyLimit()) > 0; + String key = "popup.warning.tradeLimitDueAccountAgeRestriction.seller.exceedsUnsignedBuyLimit"; + if (isSellOffer && exceedsUnsignedBuyLimit && DontShowAgainLookup.showAgain(key) && HavenoUtils.isReleasedWithinDays(HavenoUtils.WARN_ON_OFFER_EXCEEDS_UNSIGNED_BUY_LIMIT_DAYS)) { + new Popup().information(Res.get(key, + HavenoUtils.formatXmr(model.getDataModel().getMaxUnsignedBuyLimit(), true), + Res.get("offerbook.warning.newVersionAnnouncement"))) + .closeButtonText(Res.get("shared.cancel")) + .actionButtonText(Res.get("shared.ok")) + .onAction(this::onShowPayFundsScreen) + .width(900) + .dontShowAgainId(key) + .show(); + } else { + onShowPayFundsScreen(); + } } }); } @@ -1032,26 +1107,28 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten nextButton.setManaged(false); cancelButton1.setVisible(false); cancelButton1.setManaged(false); - advancedOptionsBox.setVisible(false); - advancedOptionsBox.setManaged(false); + securityDepositAndFeeBox.setVisible(false); + securityDepositAndFeeBox.setManaged(false); + buyerAsTakerWithoutDepositSlider.setVisible(false); + buyerAsTakerWithoutDepositSlider.setManaged(false); } - private VBox getBuyerSecurityDepositBox() { + private VBox getSecurityDepositBox() { Tuple3<HBox, InfoInputTextField, Label> tuple = getEditableValueBoxWithInfo( Res.get("createOffer.securityDeposit.prompt")); - buyerSecurityDepositInfoInputTextField = tuple.second; - buyerSecurityDepositInputTextField = buyerSecurityDepositInfoInputTextField.getInputTextField(); - buyerSecurityDepositPercentageLabel = tuple.third; + securityDepositInfoInputTextField = tuple.second; + securityDepositInputTextField = securityDepositInfoInputTextField.getInputTextField(); + securityDepositPercentageLabel = tuple.third; // getEditableValueBox delivers BTC, so we overwrite it with % - buyerSecurityDepositPercentageLabel.setText("%"); + securityDepositPercentageLabel.setText("%"); Tuple2<Label, VBox> tradeInputBoxTuple = getTradeInputBox(tuple.first, model.getSecurityDepositLabel()); VBox depositBox = tradeInputBoxTuple.second; - buyerSecurityDepositLabel = tradeInputBoxTuple.first; + securityDepositLabel = tradeInputBoxTuple.first; depositBox.setMaxWidth(310); - editOfferElements.add(buyerSecurityDepositInputTextField); - editOfferElements.add(buyerSecurityDepositPercentageLabel); + editOfferElements.add(securityDepositInputTextField); + editOfferElements.add(securityDepositPercentageLabel); return depositBox; } @@ -1199,8 +1276,7 @@ public abstract class MutableOfferView<M extends MutableOfferViewModel<?>> exten return GUIUtil.getMoneroURI( addressTextField.getAddress(), model.getDataModel().getMissingCoin().get(), - model.getPaymentLabel(), - model.dataModel.getXmrWalletService().getWallet()); + model.getPaymentLabel()); } private void addAmountPriceFields() { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java index d2521d9b8a..8ededde35c 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/MutableOfferViewModel.java @@ -1,24 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.app.DevEnv; +import haveno.common.handlers.ErrorMessageHandler; +import haveno.common.handlers.ResultHandler; import haveno.common.util.MathUtils; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.locale.CurrencyUtil; @@ -32,6 +36,8 @@ import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; import haveno.core.offer.OfferRestrictions; import haveno.core.offer.OfferUtil; +import haveno.core.offer.OpenOffer; +import haveno.core.offer.OpenOfferManager; import haveno.core.payment.PaymentAccount; import haveno.core.payment.payload.PaymentMethod; import haveno.core.payment.validation.FiatVolumeValidator; @@ -47,8 +53,8 @@ import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; import haveno.core.util.coin.CoinFormatter; import haveno.core.util.coin.CoinUtil; -import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.AmountValidator4Decimals; +import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.InputValidator; import haveno.core.util.validation.MonetaryValidator; import haveno.core.xmr.wallet.Restrictions; @@ -62,6 +68,13 @@ import haveno.desktop.main.settings.SettingsView; import haveno.desktop.main.settings.preferences.PreferencesView; import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.GUIUtil; +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import static javafx.beans.binding.Bindings.createStringBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; @@ -78,13 +91,6 @@ import javafx.util.Callback; import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.Coin; -import javax.inject.Inject; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.concurrent.TimeUnit; - -import static javafx.beans.binding.Bindings.createStringBinding; - @Slf4j public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> extends ActivatableWithDataModel<M> { private final XmrValidator xmrValidator; @@ -103,12 +109,13 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext private String addressAsString; private final String paymentLabel; private boolean createOfferRequested; + public boolean createOfferCanceled; public final StringProperty amount = new SimpleStringProperty(); public final StringProperty minAmount = new SimpleStringProperty(); - protected final StringProperty buyerSecurityDeposit = new SimpleStringProperty(); - final StringProperty buyerSecurityDepositInBTC = new SimpleStringProperty(); - final StringProperty buyerSecurityDepositLabel = new SimpleStringProperty(); + protected final StringProperty securityDeposit = new SimpleStringProperty(); + final StringProperty securityDepositInXMR = new SimpleStringProperty(); + final StringProperty securityDepositLabel = new SimpleStringProperty(); // Price in the viewModel is always dependent on fiat/crypto: Fiat Fiat/BTC, for cryptos we use inverted price. // The domain (dataModel) uses always the same price model (otherCurrencyBTC) @@ -144,14 +151,14 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext final BooleanProperty showPayFundsScreenDisplayed = new SimpleBooleanProperty(); private final BooleanProperty showTransactionPublishedScreen = new SimpleBooleanProperty(); final BooleanProperty isWaitingForFunds = new SimpleBooleanProperty(); - final BooleanProperty isMinBuyerSecurityDeposit = new SimpleBooleanProperty(); + final BooleanProperty isMinSecurityDeposit = new SimpleBooleanProperty(); final ObjectProperty<InputValidator.ValidationResult> amountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty<InputValidator.ValidationResult> minAmountValidationResult = new SimpleObjectProperty<>(); final ObjectProperty<InputValidator.ValidationResult> priceValidationResult = new SimpleObjectProperty<>(); final ObjectProperty<InputValidator.ValidationResult> triggerPriceValidationResult = new SimpleObjectProperty<>(new InputValidator.ValidationResult(true)); final ObjectProperty<InputValidator.ValidationResult> volumeValidationResult = new SimpleObjectProperty<>(); - final ObjectProperty<InputValidator.ValidationResult> buyerSecurityDepositValidationResult = new SimpleObjectProperty<>(); + final ObjectProperty<InputValidator.ValidationResult> securityDepositValidationResult = new SimpleObjectProperty<>(); private ChangeListener<String> amountStringListener; private ChangeListener<String> minAmountStringListener; @@ -164,6 +171,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext private ChangeListener<Price> priceListener; private ChangeListener<Volume> volumeListener; private ChangeListener<Number> securityDepositAsDoubleListener; + private ChangeListener<Boolean> buyerAsTakerWithoutDepositListener; private ChangeListener<Boolean> isWalletFundedListener; private ChangeListener<String> errorMessageListener; @@ -210,9 +218,6 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext paymentLabel = Res.get("createOffer.fundsBox.paymentLabel", dataModel.shortOfferId); - if (dataModel.getAddressEntry() != null) { - addressAsString = dataModel.getAddressEntry().getAddressString(); - } createListeners(); } @@ -264,7 +269,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext dataModel.getTradeCurrencyCode())); } volumePromptLabel.bind(createStringBinding( - () -> Res.get("createOffer.volume.prompt", dataModel.getTradeCurrencyCode().get()), + () -> Res.get("createOffer.volume.prompt", CurrencyUtil.getCurrencyCodeBase(dataModel.getTradeCurrencyCode().get())), dataModel.getTradeCurrencyCode())); totalToPay.bind(createStringBinding(() -> HavenoUtils.formatXmr(dataModel.totalToPayAsProperty().get(), true), @@ -299,7 +304,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext dataModel.calculateVolume(); dataModel.calculateTotalToPay(); } - updateBuyerSecurityDeposit(); + updateSecurityDeposit(); updateButtonDisableState(); } }; @@ -415,34 +420,36 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext updateButtonDisableState(); } }; + securityDepositStringListener = (ov, oldValue, newValue) -> { if (!ignoreSecurityDepositStringListener) { if (securityDepositValidator.validate(newValue).isValid) { - setBuyerSecurityDepositToModel(); + setSecurityDepositToModel(); dataModel.calculateTotalToPay(); } updateButtonDisableState(); } }; - amountListener = (ov, oldValue, newValue) -> { if (newValue != null) { amount.set(HavenoUtils.formatXmr(newValue)); - buyerSecurityDepositInBTC.set(HavenoUtils.formatXmr(dataModel.getBuyerSecurityDeposit(), true)); + securityDepositInXMR.set(HavenoUtils.formatXmr(dataModel.getSecurityDeposit(), true)); } else { amount.set(""); - buyerSecurityDepositInBTC.set(""); + securityDepositInXMR.set(""); } applyMakerFee(); }; + minAmountListener = (ov, oldValue, newValue) -> { if (newValue != null) minAmount.set(HavenoUtils.formatXmr(newValue)); else minAmount.set(""); }; + priceListener = (ov, oldValue, newValue) -> { ignorePriceStringListener = true; if (newValue != null) @@ -453,6 +460,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext ignorePriceStringListener = false; applyMakerFee(); }; + volumeListener = (ov, oldValue, newValue) -> { ignoreVolumeStringListener = true; if (newValue != null) @@ -466,17 +474,26 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext securityDepositAsDoubleListener = (ov, oldValue, newValue) -> { if (newValue != null) { - buyerSecurityDeposit.set(FormattingUtils.formatToPercent((double) newValue)); + securityDeposit.set(FormattingUtils.formatToPercent((double) newValue)); if (dataModel.getAmount().get() != null) { - buyerSecurityDepositInBTC.set(HavenoUtils.formatXmr(dataModel.getBuyerSecurityDeposit(), true)); + securityDepositInXMR.set(HavenoUtils.formatXmr(dataModel.getSecurityDeposit(), true)); } - updateBuyerSecurityDeposit(); + updateSecurityDeposit(); } else { - buyerSecurityDeposit.set(""); - buyerSecurityDepositInBTC.set(""); + securityDeposit.set(""); + securityDepositInXMR.set(""); } }; + buyerAsTakerWithoutDepositListener = (ov, oldValue, newValue) -> { + if (dataModel.paymentAccount != null) xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); + xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); + if (amount.get() != null) amountValidationResult.set(isXmrInputValid(amount.get())); + updateSecurityDeposit(); + applyMakerFee(); + dataModel.calculateTotalToPay(); + updateButtonDisableState(); + }; isWalletFundedListener = (ov, oldValue, newValue) -> updateButtonDisableState(); /* feeFromFundingTxListener = (ov, oldValue, newValue) -> { @@ -491,9 +508,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext private void applyMakerFee() { tradeFeeCurrencyCode.set(Res.getBaseCurrencyCode()); - tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly")); + tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionXMROnly")); - BigInteger makerFee = dataModel.getMakerFee(); + BigInteger makerFee = dataModel.getMaxMakerFee(); if (makerFee == null) { return; } @@ -501,7 +518,7 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext isTradeFeeVisible.setValue(true); tradeFee.set(HavenoUtils.formatXmr(makerFee)); tradeFeeInXmrWithFiat.set(OfferViewModelUtil.getTradeFeeWithFiatEquivalent(offerUtil, - dataModel.getMakerFee(), + dataModel.getMaxMakerFee(), btcFormatter)); } @@ -521,14 +538,15 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext marketPriceMargin.addListener(marketPriceMarginStringListener); dataModel.getUseMarketBasedPrice().addListener(useMarketBasedPriceListener); volume.addListener(volumeStringListener); - buyerSecurityDeposit.addListener(securityDepositStringListener); + securityDeposit.addListener(securityDepositStringListener); // Binding with Bindings.createObjectBinding does not work because of bi-directional binding dataModel.getAmount().addListener(amountListener); dataModel.getMinAmount().addListener(minAmountListener); dataModel.getPrice().addListener(priceListener); dataModel.getVolume().addListener(volumeListener); - dataModel.getBuyerSecurityDepositPct().addListener(securityDepositAsDoubleListener); + dataModel.getSecurityDepositPct().addListener(securityDepositAsDoubleListener); + dataModel.getBuyerAsTakerWithoutDeposit().addListener(buyerAsTakerWithoutDepositListener); // dataModel.feeFromFundingTxProperty.addListener(feeFromFundingTxListener); dataModel.getIsXmrWalletFunded().addListener(isWalletFundedListener); @@ -543,14 +561,15 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext marketPriceMargin.removeListener(marketPriceMarginStringListener); dataModel.getUseMarketBasedPrice().removeListener(useMarketBasedPriceListener); volume.removeListener(volumeStringListener); - buyerSecurityDeposit.removeListener(securityDepositStringListener); + securityDeposit.removeListener(securityDepositStringListener); // Binding with Bindings.createObjectBinding does not work because of bi-directional binding dataModel.getAmount().removeListener(amountListener); dataModel.getMinAmount().removeListener(minAmountListener); dataModel.getPrice().removeListener(priceListener); dataModel.getVolume().removeListener(volumeListener); - dataModel.getBuyerSecurityDepositPct().removeListener(securityDepositAsDoubleListener); + dataModel.getSecurityDepositPct().removeListener(securityDepositAsDoubleListener); + dataModel.getBuyerAsTakerWithoutDeposit().removeListener(buyerAsTakerWithoutDepositListener); //dataModel.feeFromFundingTxProperty.removeListener(feeFromFundingTxListener); dataModel.getIsXmrWalletFunded().removeListener(isWalletFundedListener); @@ -568,6 +587,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext boolean initWithData(OfferDirection direction, TradeCurrency tradeCurrency) { boolean result = dataModel.initWithData(direction, tradeCurrency); + if (dataModel.getAddressEntry() != null) { + addressAsString = dataModel.getAddressEntry().getAddressString(); + } if (dataModel.paymentAccount != null) xmrValidator.setMaxValue(dataModel.paymentAccount.getPaymentMethod().getMaxTradeLimit(dataModel.getTradeCurrencyCode().get())); xmrValidator.setMaxTradeLimit(BigInteger.valueOf(dataModel.getMaxTradeLimit())); @@ -586,9 +608,9 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext } securityDepositValidator.setPaymentAccount(dataModel.paymentAccount); - validateAndSetBuyerSecurityDepositToModel(); - buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get())); - buyerSecurityDepositLabel.set(getSecurityDepositLabel()); + validateAndSetSecurityDepositToModel(); + securityDeposit.set(FormattingUtils.formatToPercent(dataModel.getSecurityDepositPct().get())); + securityDepositLabel.set(getSecurityDepositLabel()); applyMakerFee(); return result; @@ -602,26 +624,53 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext void onPlaceOffer(Offer offer, Runnable resultHandler) { errorMessage.set(null); createOfferRequested = true; + createOfferCanceled = false; dataModel.onPlaceOffer(offer, transaction -> { resultHandler.run(); - placeOfferCompleted.set(true); + if (!createOfferCanceled) placeOfferCompleted.set(true); errorMessage.set(null); }, errMessage -> { createOfferRequested = false; if (offer.getState() == Offer.State.OFFER_FEE_RESERVED) errorMessage.set(errMessage + Res.get("createOffer.errorInfo")); else errorMessage.set(errMessage); - updateButtonDisableState(); - updateSpinnerInfo(); - - resultHandler.run(); + UserThread.execute(() -> { + updateButtonDisableState(); + updateSpinnerInfo(); + resultHandler.run(); + }); }); updateButtonDisableState(); updateSpinnerInfo(); } + public void onCancelOffer(ResultHandler resultHandler, ErrorMessageHandler errorMessageHandler) { + createOfferRequested = false; + createOfferCanceled = true; + OpenOfferManager openOfferManager = HavenoUtils.openOfferManager; + Optional<OpenOffer> openOffer = openOfferManager.getOpenOfferById(offer.getId()); + if (openOffer.isPresent()) { + openOfferManager.cancelOpenOffer(openOffer.get(), () -> { + UserThread.execute(() -> { + updateButtonDisableState(); + updateSpinnerInfo(); + }); + if (resultHandler != null) resultHandler.handleResult(); + }, errorMessage -> { + UserThread.execute(() -> { + updateButtonDisableState(); + updateSpinnerInfo(); + if (errorMessageHandler != null) errorMessageHandler.handleErrorMessage(errorMessage); + }); + }); + } else { + if (resultHandler != null) resultHandler.handleResult(); + return; + } + } + public void onPaymentAccountSelected(PaymentAccount paymentAccount) { dataModel.onPaymentAccountSelected(paymentAccount); if (amount.get() != null) @@ -687,16 +736,37 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext if (minAmount.get() != null) minAmountValidationResult.set(isXmrInputValid(minAmount.get())); } else if (amount.get() != null && xmrValidator.getMaxTradeLimit() != null && xmrValidator.getMaxTradeLimit().longValueExact() == OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT.longValueExact()) { - if (Double.parseDouble(amount.get()) < HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount())) { + if (ParsingUtils.parseNumberStringToDouble(amount.get()) < HavenoUtils.atomicUnitsToXmr(Restrictions.getMinTradeAmount())) { amountValidationResult.set(result); } else { amount.set(HavenoUtils.formatXmr(xmrValidator.getMaxTradeLimit())); boolean isBuy = dataModel.getDirection() == OfferDirection.BUY; - new Popup().information(Res.get(isBuy ? "popup.warning.tradeLimitDueAccountAgeRestriction.buyer" : "popup.warning.tradeLimitDueAccountAgeRestriction.seller", - HavenoUtils.formatXmr(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT, true), - Res.get("offerbook.warning.newVersionAnnouncement"))) - .width(900) - .show(); + boolean isSellerWithinReleaseWindow = !isBuy && HavenoUtils.isReleasedWithinDays(HavenoUtils.RELEASE_LIMIT_DAYS); + if (isSellerWithinReleaseWindow) { + + // format release date plus days + Date releaseDate = HavenoUtils.getReleaseDate(); + Calendar c = Calendar.getInstance(); + c.setTime(releaseDate); + c.add(Calendar.DATE, HavenoUtils.RELEASE_LIMIT_DAYS); + Date releaseDatePlusDays = c.getTime(); + SimpleDateFormat formatter = new SimpleDateFormat("MMMM d, yyyy"); + String releaseDatePlusDaysAsString = formatter.format(releaseDatePlusDays); + + // popup temporary restriction + new Popup().information(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.seller.releaseLimit", + HavenoUtils.formatXmr(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT, true), + releaseDatePlusDaysAsString, + Res.get("offerbook.warning.newVersionAnnouncement"))) + .width(900) + .show(); + } else { + new Popup().information(Res.get(isBuy ? "popup.warning.tradeLimitDueAccountAgeRestriction.buyer" : "popup.warning.tradeLimitDueAccountAgeRestriction.seller", + HavenoUtils.formatXmr(OfferRestrictions.TOLERATED_SMALL_TRADE_AMOUNT, true), + Res.get("offerbook.warning.newVersionAnnouncement"))) + .width(900) + .show(); + } } } // We want to trigger a recalculation of the volume @@ -877,14 +947,14 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext } } - void onFocusOutBuyerSecurityDepositTextField(boolean oldValue, boolean newValue) { + void onFocusOutSecurityDepositTextField(boolean oldValue, boolean newValue) { if (oldValue && !newValue) { - InputValidator.ValidationResult result = securityDepositValidator.validate(buyerSecurityDeposit.get()); - buyerSecurityDepositValidationResult.set(result); + InputValidator.ValidationResult result = securityDepositValidator.validate(securityDeposit.get()); + securityDepositValidationResult.set(result); if (result.isValid) { - double defaultSecurityDeposit = Restrictions.getDefaultBuyerSecurityDepositAsPercent(); + double defaultSecurityDeposit = Restrictions.getDefaultSecurityDepositAsPercent(); String key = "buyerSecurityDepositIsLowerAsDefault"; - double depositAsDouble = ParsingUtils.parsePercentStringToDouble(buyerSecurityDeposit.get()); + double depositAsDouble = ParsingUtils.parsePercentStringToDouble(securityDeposit.get()); if (preferences.showAgain(key) && depositAsDouble < defaultSecurityDeposit) { String postfix = dataModel.isBuyOffer() ? Res.get("createOffer.tooLowSecDeposit.makerIsBuyer") : @@ -895,26 +965,26 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext .width(800) .actionButtonText(Res.get("createOffer.resetToDefault")) .onAction(() -> { - dataModel.setBuyerSecurityDeposit(defaultSecurityDeposit); + dataModel.setSecurityDepositPct(defaultSecurityDeposit); ignoreSecurityDepositStringListener = true; - buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get())); + securityDeposit.set(FormattingUtils.formatToPercent(dataModel.getSecurityDepositPct().get())); ignoreSecurityDepositStringListener = false; }) .closeButtonText(Res.get("createOffer.useLowerValue")) - .onClose(this::applyBuyerSecurityDepositOnFocusOut) + .onClose(this::applySecurityDepositOnFocusOut) .dontShowAgainId(key) .show(); } else { - applyBuyerSecurityDepositOnFocusOut(); + applySecurityDepositOnFocusOut(); } } } } - private void applyBuyerSecurityDepositOnFocusOut() { - setBuyerSecurityDepositToModel(); + private void applySecurityDepositOnFocusOut() { + setSecurityDepositToModel(); ignoreSecurityDepositStringListener = true; - buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get())); + securityDeposit.set(FormattingUtils.formatToPercent(dataModel.getSecurityDepositPct().get())); ignoreSecurityDepositStringListener = false; } @@ -969,21 +1039,22 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext } public String getSecurityDepositLabel() { - return Preferences.USE_SYMMETRIC_SECURITY_DEPOSIT ? Res.get("createOffer.setDepositForBothTraders") : + return dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer() ? Res.get("createOffer.myDeposit") : + Preferences.USE_SYMMETRIC_SECURITY_DEPOSIT ? Res.get("createOffer.setDepositForBothTraders") : dataModel.isBuyOffer() ? Res.get("createOffer.setDepositAsBuyer") : Res.get("createOffer.setDeposit"); } - public String getSecurityDepositPopOverLabel(String depositInBTC) { - return dataModel.isBuyOffer() ? Res.get("createOffer.securityDepositInfoAsBuyer", depositInBTC) : - Res.get("createOffer.securityDepositInfo", depositInBTC); + public String getSecurityDepositPopOverLabel(String depositInXMR) { + return dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer() ? Res.get("createOffer.myDepositInfo", depositInXMR) : + dataModel.isBuyOffer() ? Res.get("createOffer.securityDepositInfoAsBuyer", depositInXMR) : + Res.get("createOffer.securityDepositInfo", depositInXMR); } public String getSecurityDepositInfo() { return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, dataModel.getSecurityDeposit(), dataModel.getAmount().get(), - btcFormatter, - Restrictions.getMinBuyerSecurityDeposit() + btcFormatter ); } @@ -994,14 +1065,13 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext public String getTradeFee() { return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, - dataModel.getMakerFee(), + dataModel.getMaxMakerFee(), dataModel.getAmount().get(), - btcFormatter, - HavenoUtils.getMinMakerFee()); + btcFormatter); } public String getMakerFeePercentage() { - final BigInteger makerFee = dataModel.getMakerFee(); + final BigInteger makerFee = dataModel.getMaxMakerFee(); return GUIUtil.getPercentage(makerFee, dataModel.getAmount().get()); } @@ -1140,19 +1210,19 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext } } - private void setBuyerSecurityDepositToModel() { - if (buyerSecurityDeposit.get() != null && !buyerSecurityDeposit.get().isEmpty()) { - dataModel.setBuyerSecurityDeposit(ParsingUtils.parsePercentStringToDouble(buyerSecurityDeposit.get())); + private void setSecurityDepositToModel() { + if (!(dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer()) && securityDeposit.get() != null && !securityDeposit.get().isEmpty()) { + dataModel.setSecurityDepositPct(ParsingUtils.parsePercentStringToDouble(securityDeposit.get())); } else { - dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()); + dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositAsPercent()); } } - private void validateAndSetBuyerSecurityDepositToModel() { + private void validateAndSetSecurityDepositToModel() { // If the security deposit in the model is not valid percent - String value = FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get()); + String value = FormattingUtils.formatToPercent(dataModel.getSecurityDepositPct().get()); if (!securityDepositValidator.validate(value).isValid) { - dataModel.setBuyerSecurityDeposit(Restrictions.getDefaultBuyerSecurityDepositAsPercent()); + dataModel.setSecurityDepositPct(Restrictions.getDefaultSecurityDepositAsPercent()); } } @@ -1210,15 +1280,17 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext isWaitingForFunds.set(!waitingForFundsText.get().isEmpty()); } - private void updateBuyerSecurityDeposit() { - isMinBuyerSecurityDeposit.set(dataModel.isMinBuyerSecurityDeposit()); - - if (dataModel.isMinBuyerSecurityDeposit()) { - buyerSecurityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed")); - buyerSecurityDeposit.set(HavenoUtils.formatXmr(Restrictions.getMinBuyerSecurityDeposit())); + private void updateSecurityDeposit() { + isMinSecurityDeposit.set(dataModel.isMinSecurityDeposit()); + if (dataModel.isMinSecurityDeposit()) { + securityDepositLabel.set(Res.get("createOffer.minSecurityDepositUsed")); + securityDeposit.set(HavenoUtils.formatXmr(Restrictions.getMinSecurityDeposit())); } else { - buyerSecurityDepositLabel.set(getSecurityDepositLabel()); - buyerSecurityDeposit.set(FormattingUtils.formatToPercent(dataModel.getBuyerSecurityDepositPct().get())); + securityDepositLabel.set(getSecurityDepositLabel()); + boolean hasBuyerAsTakerWithoutDeposit = dataModel.buyerAsTakerWithoutDeposit.get() && dataModel.isSellOffer(); + securityDeposit.set(FormattingUtils.formatToPercent(hasBuyerAsTakerWithoutDeposit ? + Restrictions.getDefaultSecurityDepositAsPercent() : // use default percent if no deposit from buyer + dataModel.getSecurityDepositPct().get())); } } @@ -1240,8 +1312,8 @@ public abstract class MutableOfferViewModel<M extends MutableOfferDataModel> ext } // validating the percentage deposit value only makes sense if it is actually used - if (!dataModel.isMinBuyerSecurityDeposit()) { - inputDataValid = inputDataValid && securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid; + if (!dataModel.isMinSecurityDeposit()) { + inputDataValid = inputDataValid && securityDepositValidator.validate(securityDeposit.get()).isValid; } isNextButtonDisabled.set(!inputDataValid); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferDataModel.java index f41bab09db..71a827ffa3 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferDataModel.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; +import haveno.common.UserThread; import haveno.core.offer.OfferUtil; import haveno.core.xmr.model.XmrAddressEntry; import haveno.core.xmr.wallet.XmrWalletService; @@ -49,7 +50,7 @@ public abstract class OfferDataModel extends ActivatableDataModel { @Getter protected final ObjectProperty<BigInteger> availableBalance = new SimpleObjectProperty<>(); @Getter - protected final ObjectProperty<BigInteger> missingCoin = new SimpleObjectProperty<>(BigInteger.valueOf(0)); + protected final ObjectProperty<BigInteger> missingCoin = new SimpleObjectProperty<>(BigInteger.ZERO); @Getter protected final BooleanProperty showWalletFundedNotification = new SimpleBooleanProperty(); @Getter @@ -64,43 +65,30 @@ public abstract class OfferDataModel extends ActivatableDataModel { this.offerUtil = offerUtil; } - protected void updateBalance() { - updateBalances(); - if (useSavingsWallet) { - if (totalToPay.get() != null) { - balance.set(totalToPay.get().min(totalBalance)); - } - } - missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), balance.get())); - isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), balance.get())); - if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) { - showWalletFundedNotification.set(true); - } - } - - protected void updateAvailableBalance() { - updateBalances(); - if (useSavingsWallet) { - if (totalToPay.get() != null) { - availableBalance.set(totalToPay.get().min(totalAvailableBalance)); - } - } - missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), availableBalance.get())); - isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), availableBalance.get())); - if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) { - showWalletFundedNotification.set(true); - } - } - - private void updateBalances() { + protected void updateBalances() { BigInteger tradeWalletBalance = xmrWalletService.getBalanceForSubaddress(addressEntry.getSubaddressIndex()); BigInteger tradeWalletAvailableBalance = xmrWalletService.getAvailableBalanceForSubaddress(addressEntry.getSubaddressIndex()); - if (useSavingsWallet) { - totalBalance = xmrWalletService.getBalance();; - totalAvailableBalance = xmrWalletService.getAvailableBalance(); - } else { - balance.set(tradeWalletBalance); - availableBalance.set(tradeWalletAvailableBalance); - } + BigInteger walletBalance = xmrWalletService.getBalance(); + BigInteger walletAvailableBalance = xmrWalletService.getAvailableBalance(); + UserThread.await(() -> { + if (useSavingsWallet) { + totalBalance = walletBalance; + totalAvailableBalance = walletAvailableBalance; + if (totalToPay.get() != null) { + balance.set(totalToPay.get().min(totalBalance)); + availableBalance.set(totalToPay.get().min(totalAvailableBalance)); + } + } else { + totalBalance = tradeWalletBalance; + totalAvailableBalance = tradeWalletAvailableBalance; + balance.set(tradeWalletBalance); + availableBalance.set(tradeWalletAvailableBalance); + } + }); + + } + + public boolean hasTotalToPay() { + return totalToPay.get() != null && totalToPay.get().compareTo(BigInteger.ZERO) > 0; } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java index 1e5b8a478d..6f6aba7cbc 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; @@ -33,14 +33,15 @@ import haveno.desktop.common.view.View; import haveno.desktop.common.view.ViewLoader; import haveno.desktop.main.MainView; import haveno.desktop.main.offer.createoffer.CreateOfferView; -import haveno.desktop.main.offer.offerbook.XmrOfferBookView; +import haveno.desktop.main.offer.offerbook.FiatOfferBookView; import haveno.desktop.main.offer.offerbook.OfferBookView; +import haveno.desktop.main.offer.offerbook.CryptoOfferBookView; import haveno.desktop.main.offer.offerbook.OtherOfferBookView; -import haveno.desktop.main.offer.offerbook.TopCryptoOfferBookView; import haveno.desktop.main.offer.takeoffer.TakeOfferView; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; import javafx.beans.value.ChangeListener; +import javafx.scene.control.Label; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import org.jetbrains.annotations.NotNull; @@ -50,9 +51,9 @@ import java.util.Optional; public abstract class OfferView extends ActivatableView<TabPane, Void> { - private OfferBookView<?, ?> xmrOfferBookView, topCryptoOfferBookView, otherOfferBookView; + private OfferBookView<?, ?> fiatOfferBookView, cryptoOfferBookView, otherOfferBookView; - private Tab xmrOfferBookTab, topCryptoOfferBookTab, otherOfferBookTab; + private Tab labelTab, fiatOfferBookTab, cryptoOfferBookTab, otherOfferBookTab; private final ViewLoader viewLoader; private final Navigation navigation; @@ -95,17 +96,17 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { tabChangeListener = (observableValue, oldValue, newValue) -> { UserThread.execute(() -> { if (newValue != null) { - if (newValue.equals(xmrOfferBookTab)) { - if (xmrOfferBookView != null) { - xmrOfferBookView.onTabSelected(true); + if (newValue.equals(fiatOfferBookTab)) { + if (fiatOfferBookView != null) { + fiatOfferBookView.onTabSelected(true); } else { - loadView(XmrOfferBookView.class, null, null); + loadView(FiatOfferBookView.class, null, null); } - } else if (newValue.equals(topCryptoOfferBookTab)) { - if (topCryptoOfferBookView != null) { - topCryptoOfferBookView.onTabSelected(true); + } else if (newValue.equals(cryptoOfferBookTab)) { + if (cryptoOfferBookView != null) { + cryptoOfferBookView.onTabSelected(true); } else { - loadView(TopCryptoOfferBookView.class, null, null); + loadView(CryptoOfferBookView.class, null, null); } } else if (newValue.equals(otherOfferBookTab)) { if (otherOfferBookView != null) { @@ -116,10 +117,10 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { } } if (oldValue != null) { - if (oldValue.equals(xmrOfferBookTab) && xmrOfferBookView != null) { - xmrOfferBookView.onTabSelected(false); - } else if (oldValue.equals(topCryptoOfferBookTab) && topCryptoOfferBookView != null) { - topCryptoOfferBookView.onTabSelected(false); + if (oldValue.equals(fiatOfferBookTab) && fiatOfferBookView != null) { + fiatOfferBookView.onTabSelected(false); + } else if (oldValue.equals(cryptoOfferBookTab) && cryptoOfferBookView != null) { + cryptoOfferBookView.onTabSelected(false); } else if (oldValue.equals(otherOfferBookTab) && otherOfferBookView != null) { otherOfferBookView.onTabSelected(false); } @@ -154,14 +155,8 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { root.getSelectionModel().selectedItemProperty().addListener(tabChangeListener); navigation.addListener(navigationListener); - if (xmrOfferBookView == null) { - navigation.navigateTo(MainView.class, this.getClass(), XmrOfferBookView.class); - } - - GUIUtil.updateTopCrypto(preferences); - - if (topCryptoOfferBookTab != null) { - topCryptoOfferBookTab.setText(GUIUtil.TOP_CRYPTO.getName().toUpperCase()); + if (fiatOfferBookView == null) { + navigation.navigateTo(MainView.class, this.getClass(), FiatOfferBookView.class); } } @@ -171,6 +166,8 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { root.getSelectionModel().selectedItemProperty().removeListener(tabChangeListener); } + protected abstract String getOfferLabel(); + private void loadView(Class<? extends View> viewClass, Class<? extends View> childViewClass, @Nullable Object data) { @@ -179,66 +176,75 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { if (OfferBookView.class.isAssignableFrom(viewClass)) { - if (viewClass == XmrOfferBookView.class && xmrOfferBookTab != null && xmrOfferBookView != null) { + if (viewClass == FiatOfferBookView.class && fiatOfferBookTab != null && fiatOfferBookView != null) { if (childViewClass == null) { - xmrOfferBookTab.setContent(xmrOfferBookView.getRoot()); + fiatOfferBookTab.setContent(fiatOfferBookView.getRoot()); } else if (childViewClass == TakeOfferView.class) { - loadTakeViewClass(viewClass, childViewClass, xmrOfferBookTab); + loadTakeViewClass(viewClass, childViewClass, fiatOfferBookTab); } else { - loadCreateViewClass(xmrOfferBookView, viewClass, childViewClass, xmrOfferBookTab, (PaymentMethod) data); + loadCreateViewClass(fiatOfferBookView, viewClass, childViewClass, fiatOfferBookTab, (PaymentMethod) data); } - tabPane.getSelectionModel().select(xmrOfferBookTab); - } else if (viewClass == TopCryptoOfferBookView.class && topCryptoOfferBookTab != null && topCryptoOfferBookView != null) { + tabPane.getSelectionModel().select(fiatOfferBookTab); + } else if (viewClass == CryptoOfferBookView.class && cryptoOfferBookTab != null && cryptoOfferBookView != null) { if (childViewClass == null) { - topCryptoOfferBookTab.setContent(topCryptoOfferBookView.getRoot()); + cryptoOfferBookTab.setContent(cryptoOfferBookView.getRoot()); } else if (childViewClass == TakeOfferView.class) { - loadTakeViewClass(viewClass, childViewClass, topCryptoOfferBookTab); + loadTakeViewClass(viewClass, childViewClass, cryptoOfferBookTab); } else { - tradeCurrency = GUIUtil.TOP_CRYPTO; - loadCreateViewClass(topCryptoOfferBookView, viewClass, childViewClass, topCryptoOfferBookTab, (PaymentMethod) data); - } - tabPane.getSelectionModel().select(topCryptoOfferBookTab); - } else if (viewClass == OtherOfferBookView.class && otherOfferBookTab != null && otherOfferBookView != null) { - if (childViewClass == null) { - otherOfferBookTab.setContent(otherOfferBookView.getRoot()); - } else if (childViewClass == TakeOfferView.class) { - loadTakeViewClass(viewClass, childViewClass, otherOfferBookTab); - } else { - //add sanity check in case of app restart + // add sanity check in case of app restart if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { Optional<TradeCurrency> tradeCurrencyOptional = (this.direction == OfferDirection.SELL) ? CurrencyUtil.getTradeCurrency(preferences.getSellScreenCryptoCurrencyCode()) : CurrencyUtil.getTradeCurrency(preferences.getBuyScreenCryptoCurrencyCode()); tradeCurrency = tradeCurrencyOptional.isEmpty() ? OfferViewUtil.getAnyOfMainCryptoCurrencies() : tradeCurrencyOptional.get(); } + loadCreateViewClass(cryptoOfferBookView, viewClass, childViewClass, cryptoOfferBookTab, (PaymentMethod) data); + } + tabPane.getSelectionModel().select(cryptoOfferBookTab); + } else if (viewClass == OtherOfferBookView.class && otherOfferBookTab != null && otherOfferBookView != null) { + if (childViewClass == null) { + otherOfferBookTab.setContent(otherOfferBookView.getRoot()); + } else if (childViewClass == TakeOfferView.class) { + loadTakeViewClass(viewClass, childViewClass, otherOfferBookTab); + } else { loadCreateViewClass(otherOfferBookView, viewClass, childViewClass, otherOfferBookTab, (PaymentMethod) data); } tabPane.getSelectionModel().select(otherOfferBookTab); } else { - if (xmrOfferBookTab == null) { - xmrOfferBookTab = new Tab(Res.getBaseCurrencyName().toUpperCase()); - xmrOfferBookTab.setClosable(false); - topCryptoOfferBookTab = new Tab(GUIUtil.TOP_CRYPTO.getName().toUpperCase()); - topCryptoOfferBookTab.setClosable(false); + if (fiatOfferBookTab == null) { + + // add preceding label tab + labelTab = new Tab(); + labelTab.setDisable(true); + labelTab.setContent(new Label()); + labelTab.setClosable(false); + Label offerLabel = new Label(getOfferLabel()); // use overlay for label for custom formatting + offerLabel.getStyleClass().add("titled-group-bg-label"); + offerLabel.setStyle("-fx-font-size: 1.4em;"); + labelTab.setGraphic(offerLabel); + + fiatOfferBookTab = new Tab(Res.get("shared.fiat").toUpperCase()); + fiatOfferBookTab.setClosable(false); + cryptoOfferBookTab = new Tab(Res.get("shared.crypto").toUpperCase()); + cryptoOfferBookTab.setClosable(false); otherOfferBookTab = new Tab(Res.get("shared.other").toUpperCase()); otherOfferBookTab.setClosable(false); - - tabPane.getTabs().addAll(xmrOfferBookTab, topCryptoOfferBookTab, otherOfferBookTab); + tabPane.getTabs().addAll(labelTab, fiatOfferBookTab, cryptoOfferBookTab, otherOfferBookTab); } - if (viewClass == XmrOfferBookView.class) { - xmrOfferBookView = (XmrOfferBookView) viewLoader.load(XmrOfferBookView.class); - xmrOfferBookView.setOfferActionHandler(offerActionHandler); - xmrOfferBookView.setDirection(direction); - xmrOfferBookView.onTabSelected(true); - tabPane.getSelectionModel().select(xmrOfferBookTab); - xmrOfferBookTab.setContent(xmrOfferBookView.getRoot()); - } else if (viewClass == TopCryptoOfferBookView.class) { - topCryptoOfferBookView = (TopCryptoOfferBookView) viewLoader.load(TopCryptoOfferBookView.class); - topCryptoOfferBookView.setOfferActionHandler(offerActionHandler); - topCryptoOfferBookView.setDirection(direction); - topCryptoOfferBookView.onTabSelected(true); - tabPane.getSelectionModel().select(topCryptoOfferBookTab); - topCryptoOfferBookTab.setContent(topCryptoOfferBookView.getRoot()); + if (viewClass == FiatOfferBookView.class) { + fiatOfferBookView = (FiatOfferBookView) viewLoader.load(FiatOfferBookView.class); + fiatOfferBookView.setOfferActionHandler(offerActionHandler); + fiatOfferBookView.setDirection(direction); + fiatOfferBookView.onTabSelected(true); + tabPane.getSelectionModel().select(fiatOfferBookTab); + fiatOfferBookTab.setContent(fiatOfferBookView.getRoot()); + } else if (viewClass == CryptoOfferBookView.class) { + cryptoOfferBookView = (CryptoOfferBookView) viewLoader.load(CryptoOfferBookView.class); + cryptoOfferBookView.setOfferActionHandler(offerActionHandler); + cryptoOfferBookView.setDirection(direction); + cryptoOfferBookView.onTabSelected(true); + tabPane.getSelectionModel().select(cryptoOfferBookTab); + cryptoOfferBookTab.setContent(cryptoOfferBookView.getRoot()); } else if (viewClass == OtherOfferBookView.class) { otherOfferBookView = (OtherOfferBookView) viewLoader.load(OtherOfferBookView.class); otherOfferBookView.setOfferActionHandler(offerActionHandler); @@ -264,6 +270,7 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { // CreateOffer and TakeOffer must not be cached by ViewLoader as we cannot use a view multiple times // in different graphs view = viewLoader.load(childViewClass); + ((CreateOfferView) view).initWithData(direction, tradeCurrency, offerActionHandler); ((SelectableView) view).onTabSelected(true); @@ -324,9 +331,9 @@ public abstract class OfferView extends ActivatableView<TabPane, Void> { private Class<? extends OfferBookView<?, ?>> getOfferBookViewClassFor(String currencyCode) { Class<? extends OfferBookView<?, ?>> offerBookViewClass; if (CurrencyUtil.isFiatCurrency(currencyCode)) { - offerBookViewClass = XmrOfferBookView.class; - } else if (currencyCode.equals(GUIUtil.TOP_CRYPTO.getCode())) { - offerBookViewClass = TopCryptoOfferBookView.class; + offerBookViewClass = FiatOfferBookView.class; + } else if (CurrencyUtil.isCryptoCurrency(currencyCode)) { + offerBookViewClass = CryptoOfferBookView.class; } else { offerBookViewClass = OtherOfferBookView.class; } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java index 095a86db34..cab7008d74 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewModelUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; @@ -44,22 +44,14 @@ public class OfferViewModelUtil { public static String getTradeFeeWithFiatEquivalentAndPercentage(OfferUtil offerUtil, BigInteger tradeFee, BigInteger tradeAmount, - CoinFormatter formatter, - BigInteger minTradeFee) { - String feeAsBtc = HavenoUtils.formatXmr(tradeFee, true); + CoinFormatter formatter) { + String feeAsXmr = HavenoUtils.formatXmr(tradeFee, true); String percentage; - if (tradeFee.compareTo(minTradeFee) <= 0) { - percentage = Res.get("guiUtil.requiredMinimum") - .replace("(", "") - .replace(")", ""); - } else { - percentage = GUIUtil.getPercentage(tradeFee, tradeAmount) + - " " + Res.get("guiUtil.ofTradeAmount"); - } + percentage = GUIUtil.getPercentage(tradeFee, tradeAmount) + " " + Res.get("guiUtil.ofTradeAmount"); return offerUtil.getFeeInUserFiatCurrency(tradeFee, formatter) .map(VolumeUtil::formatAverageVolumeWithCode) - .map(feeInFiat -> Res.get("feeOptionWindow.btcFeeWithFiatAndPercentage", feeAsBtc, feeInFiat, percentage)) - .orElseGet(() -> Res.get("feeOptionWindow.btcFeeWithPercentage", feeAsBtc, percentage)); + .map(feeInFiat -> Res.get("feeOptionWindow.xmrFeeWithFiatAndPercentage", feeAsXmr, feeInFiat, percentage)) + .orElseGet(() -> Res.get("feeOptionWindow.xmrFeeWithPercentage", feeAsXmr, percentage)); } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java index f62f001323..a01f2f3e96 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/OfferViewUtil.java @@ -1,56 +1,49 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; import haveno.common.UserThread; -import haveno.common.util.Tuple2; import haveno.core.locale.CryptoCurrency; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.locale.TradeCurrency; +import haveno.core.locale.TraditionalCurrency; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; import haveno.core.xmr.wallet.XmrWalletService; -import haveno.desktop.Navigation; -import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.AutoTooltipLabel; -import haveno.desktop.components.HyperlinkWithIcon; -import haveno.desktop.main.offer.offerbook.XmrOfferBookView; +import haveno.desktop.main.offer.offerbook.FiatOfferBookView; import haveno.desktop.main.offer.offerbook.OfferBookView; +import haveno.desktop.main.offer.offerbook.CryptoOfferBookView; import haveno.desktop.main.offer.offerbook.OtherOfferBookView; -import haveno.desktop.main.offer.offerbook.TopCryptoOfferBookView; import haveno.desktop.main.overlays.popups.Popup; -import haveno.desktop.util.GUIUtil; import javafx.geometry.HPos; import javafx.geometry.Insets; -import javafx.geometry.Pos; import javafx.geometry.VPos; import javafx.scene.control.Label; import javafx.scene.control.TableView; import javafx.scene.control.TextField; import javafx.scene.layout.GridPane; -import javafx.scene.layout.HBox; import lombok.extern.slf4j.Slf4j; import monero.daemon.model.MoneroSubmitTxResult; import org.jetbrains.annotations.NotNull; import java.util.HashMap; -import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -94,42 +87,12 @@ public class OfferViewUtil { infoGridPane.getChildren().addAll(label, textField); } - public static Tuple2<AutoTooltipButton, HBox> createBuyBsqButtonBox(Navigation navigation) { - String buyBsqText = Res.get("shared.buyCurrency", "BSQ"); - var buyBsqButton = new AutoTooltipButton(buyBsqText); - buyBsqButton.getStyleClass().add("action-button"); - buyBsqButton.getStyleClass().add("tiny-button"); - buyBsqButton.setMinWidth(60); - buyBsqButton.setOnAction(e -> openBuyBsqOfferBook(navigation) - ); - - var info = new AutoTooltipLabel("BSQ is colored BTC that helps fund Haveno developers."); - var learnMore = new HyperlinkWithIcon("Learn More"); - learnMore.setOnAction(e -> new Popup().headLine(buyBsqText) - .information(Res.get("createOffer.buyBsq.popupMessage")) - .actionButtonText(buyBsqText) - .buttonAlignment(HPos.CENTER) - .onAction(() -> openBuyBsqOfferBook(navigation)).show()); - learnMore.setMinWidth(100); - - HBox buyBsqBox = new HBox(buyBsqButton, info, learnMore); - buyBsqBox.setAlignment(Pos.BOTTOM_LEFT); - buyBsqBox.setSpacing(10); - buyBsqBox.setPadding(new Insets(0, 0, 4, -20)); - - return new Tuple2<>(buyBsqButton, buyBsqBox); - } - - private static void openBuyBsqOfferBook(Navigation navigation) { - throw new Error("BSQ not supported"); - } - public static Class<? extends OfferBookView<?, ?>> getOfferBookViewClass(String currencyCode) { Class<? extends OfferBookView<?, ?>> offerBookViewClazz; - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) { - offerBookViewClazz = XmrOfferBookView.class; - } else if (currencyCode.equals(GUIUtil.TOP_CRYPTO.getCode())) { - offerBookViewClazz = TopCryptoOfferBookView.class; + if (CurrencyUtil.isFiatCurrency(currencyCode)) { + offerBookViewClazz = FiatOfferBookView.class; + } else if (CurrencyUtil.isCryptoCurrency(currencyCode)) { + offerBookViewClazz = CryptoOfferBookView.class; } else { offerBookViewClazz = OtherOfferBookView.class; } @@ -145,7 +108,7 @@ public class OfferViewUtil { } public static boolean isShownAsSellOffer(String currencyCode, OfferDirection direction) { - return CurrencyUtil.isTraditionalCurrency(currencyCode) == (direction == OfferDirection.SELL); + return direction == OfferDirection.SELL; } public static boolean isShownAsBuyOffer(Offer offer) { @@ -160,10 +123,18 @@ public class OfferViewUtil { return getMainCryptoCurrencies().findAny().get(); } + public static TradeCurrency getAnyOfOtherCurrencies() { + return getOtherCurrencies().findAny().get(); + } + @NotNull public static Stream<CryptoCurrency> getMainCryptoCurrencies() { - return CurrencyUtil.getMainCryptoCurrencies().stream().filter(cryptoCurrency -> - !Objects.equals(cryptoCurrency.getCode(), GUIUtil.TOP_CRYPTO.getCode())); + return CurrencyUtil.getMainCryptoCurrencies().stream(); + } + + @NotNull + public static Stream<TraditionalCurrency> getOtherCurrencies() { + return CurrencyUtil.getTraditionalNonFiatCurrencies().stream(); } public static void submitTransactionHex(XmrWalletService xmrWalletService, diff --git a/desktop/src/main/java/haveno/desktop/main/offer/SelectableView.java b/desktop/src/main/java/haveno/desktop/main/offer/SelectableView.java index 0978098af7..feca8f51f3 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/SelectableView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/SelectableView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/SellOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/SellOfferView.java index 144aee1cf8..fde0e57f02 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/SellOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/SellOfferView.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer; +import com.google.inject.Inject; + +import haveno.core.locale.Res; import haveno.core.offer.OfferDirection; import haveno.core.user.Preferences; import haveno.core.user.User; @@ -25,8 +28,6 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.ViewLoader; import haveno.network.p2p.P2PService; -import javax.inject.Inject; - @FxmlView public class SellOfferView extends OfferView { @@ -43,4 +44,9 @@ public class SellOfferView extends OfferView { p2PService, OfferDirection.SELL); } + + @Override + protected String getOfferLabel() { + return Res.get("offerbook.sellXmrFor"); + } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModel.java index 3e54df3355..c511cabe4e 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.createoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.offer.CreateOfferService; import haveno.core.offer.OfferUtil; @@ -33,8 +34,6 @@ import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.Navigation; import haveno.desktop.main.offer.MutableOfferDataModel; import haveno.network.p2p.P2PService; - -import javax.inject.Named; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferView.java index 6dace11d42..ba9f3d312f 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferView.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.createoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.TradeCurrency; import haveno.core.offer.OfferDirection; @@ -30,14 +31,10 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.offer.MutableOfferView; import haveno.desktop.main.offer.OfferView; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; -import haveno.desktop.util.GUIUtil; +import java.util.stream.Collectors; import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javax.inject.Named; -import java.util.Objects; -import java.util.stream.Collectors; - @FxmlView public class CreateOfferView extends MutableOfferView<CreateOfferViewModel> { @@ -54,22 +51,19 @@ public class CreateOfferView extends MutableOfferView<CreateOfferViewModel> { public void initWithData(OfferDirection direction, TradeCurrency tradeCurrency, OfferView.OfferActionHandler offerActionHandler) { - // Invert direction for non-Fiat trade currencies -> BUY BSQ is to SELL Bitcoin - OfferDirection offerDirection = CurrencyUtil.isFiatCurrency(tradeCurrency.getCode()) ? direction : - direction == OfferDirection.BUY ? OfferDirection.SELL : OfferDirection.BUY; - super.initWithData(offerDirection, tradeCurrency, offerActionHandler); + super.initWithData(direction, tradeCurrency, offerActionHandler); } @Override protected ObservableList<PaymentAccount> filterPaymentAccounts(ObservableList<PaymentAccount> paymentAccounts) { return FXCollections.observableArrayList( paymentAccounts.stream().filter(paymentAccount -> { - if (model.getTradeCurrency().equals(GUIUtil.TOP_CRYPTO)) { - return Objects.equals(paymentAccount.getSingleTradeCurrency(), GUIUtil.TOP_CRYPTO); - } else if (CurrencyUtil.isFiatCurrency(model.getTradeCurrency().getCode())) { + if (CurrencyUtil.isFiatCurrency(model.getTradeCurrency().getCode())) { return paymentAccount.isFiat(); + } else if (CurrencyUtil.isCryptoCurrency(model.getTradeCurrency().getCode())) { + return paymentAccount.isCryptoCurrency(); } else { - return !paymentAccount.isFiat() && !Objects.equals(paymentAccount.getSingleTradeCurrency(), GUIUtil.TOP_CRYPTO); + return !paymentAccount.isFiat() && !paymentAccount.isCryptoCurrency(); } }).collect(Collectors.toList())); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModel.java index a38f3d7710..7f9de4c88a 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.createoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.offer.OfferUtil; import haveno.core.payment.validation.FiatVolumeValidator; @@ -27,14 +28,12 @@ import haveno.core.provider.price.PriceFeedService; import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; -import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.AmountValidator4Decimals; +import haveno.core.util.validation.AmountValidator8Decimals; import haveno.desktop.Navigation; import haveno.desktop.common.model.ViewModel; import haveno.desktop.main.offer.MutableOfferViewModel; -import javax.inject.Named; - class CreateOfferViewModel extends MutableOfferViewModel<CreateOfferDataModel> implements ViewModel { @Inject diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookView.fxml b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookView.fxml similarity index 97% rename from desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookView.fxml rename to desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookView.fxml index 45a46ca7d0..658f138cf3 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookView.fxml +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookView.fxml @@ -19,7 +19,7 @@ <?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.GridPane?> -<GridPane fx:id="root" fx:controller="haveno.desktop.main.offer.offerbook.TopCryptoOfferBookView" +<GridPane fx:id="root" fx:controller="haveno.desktop.main.offer.offerbook.CryptoOfferBookView" hgap="5.0" vgap="5" xmlns:fx="http://javafx.com/fxml"> diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookView.java new file mode 100644 index 0000000000..8dfdc68671 --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookView.java @@ -0,0 +1,61 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.main.offer.offerbook; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import haveno.common.config.Config; +import haveno.core.account.sign.SignedWitnessService; +import haveno.core.account.witness.AccountAgeWitnessService; +import haveno.core.alert.PrivateNotificationManager; +import haveno.core.locale.Res; +import haveno.core.offer.OfferDirection; +import haveno.core.util.FormattingUtils; +import haveno.core.util.coin.CoinFormatter; +import haveno.desktop.Navigation; +import haveno.desktop.common.view.FxmlView; +import haveno.desktop.main.overlays.windows.OfferDetailsWindow; +import javafx.scene.layout.GridPane; + +@FxmlView +public class CryptoOfferBookView extends OfferBookView<GridPane, CryptoOfferBookViewModel> { + + @Inject + CryptoOfferBookView(CryptoOfferBookViewModel model, + Navigation navigation, + OfferDetailsWindow offerDetailsWindow, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, + PrivateNotificationManager privateNotificationManager, + @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys, + AccountAgeWitnessService accountAgeWitnessService, + SignedWitnessService signedWitnessService) { + super(model, navigation, offerDetailsWindow, formatter, privateNotificationManager, useDevPrivilegeKeys, accountAgeWitnessService, signedWitnessService); + } + + @Override + protected String getMarketTitle() { + return model.getDirection().equals(OfferDirection.BUY) ? + Res.get("offerbook.availableOffersToBuy", Res.getBaseCurrencyCode(), Res.get("shared.crypto")) : + Res.get("offerbook.availableOffersToSell", Res.getBaseCurrencyCode(), Res.get("shared.crypto")); + } + + @Override + String getTradeCurrencyCode() { + return Res.getBaseCurrencyCode(); + } +} diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java new file mode 100644 index 0000000000..e97c08558e --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/CryptoOfferBookViewModel.java @@ -0,0 +1,148 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.main.offer.offerbook; + +import com.google.inject.Inject; +import com.google.inject.name.Named; +import haveno.core.account.witness.AccountAgeWitnessService; +import haveno.core.api.CoreApi; +import haveno.core.locale.CryptoCurrency; +import haveno.core.locale.CurrencyUtil; +import haveno.core.locale.GlobalSettings; +import haveno.core.locale.TradeCurrency; +import haveno.core.offer.Offer; +import haveno.core.offer.OfferDirection; +import haveno.core.offer.OfferFilterService; +import haveno.core.offer.OpenOfferManager; +import haveno.core.payment.payload.PaymentMethod; +import haveno.core.provider.price.PriceFeedService; +import haveno.core.trade.ClosedTradableManager; +import haveno.core.user.Preferences; +import haveno.core.user.User; +import haveno.core.util.FormattingUtils; +import haveno.core.util.PriceUtil; +import haveno.core.util.coin.CoinFormatter; +import haveno.core.xmr.setup.WalletsSetup; +import haveno.desktop.Navigation; +import haveno.desktop.main.offer.OfferViewUtil; +import haveno.desktop.util.GUIUtil; +import haveno.network.p2p.P2PService; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +public class CryptoOfferBookViewModel extends OfferBookViewModel { + + @Inject + public CryptoOfferBookViewModel(User user, + OpenOfferManager openOfferManager, + OfferBook offerBook, + Preferences preferences, + WalletsSetup walletsSetup, + P2PService p2PService, + PriceFeedService priceFeedService, + ClosedTradableManager closedTradableManager, + AccountAgeWitnessService accountAgeWitnessService, + Navigation navigation, + PriceUtil priceUtil, + OfferFilterService offerFilterService, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, + CoreApi coreApi) { + super(user, openOfferManager, offerBook, preferences, walletsSetup, p2PService, priceFeedService, closedTradableManager, accountAgeWitnessService, navigation, priceUtil, offerFilterService, btcFormatter, coreApi); + } + + @Override + void saveSelectedCurrencyCodeInPreferences(OfferDirection direction, String code) { + if (direction == OfferDirection.BUY) { + preferences.setBuyScreenCryptoCurrencyCode(code); + } else { + preferences.setSellScreenCryptoCurrencyCode(code); + } + } + + @Override + protected ObservableList<PaymentMethod> filterPaymentMethods(ObservableList<PaymentMethod> list, + TradeCurrency selectedTradeCurrency) { + return FXCollections.observableArrayList(list.stream().filter(paymentMethod -> { + return paymentMethod.isBlockchain(); + }).collect(Collectors.toList())); + } + + @Override + void fillCurrencies(ObservableList<TradeCurrency> tradeCurrencies, + ObservableList<TradeCurrency> allCurrencies) { + + tradeCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, "")); + tradeCurrencies.addAll(preferences.getCryptoCurrenciesAsObservable().stream() + .collect(Collectors.toList())); + tradeCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, "")); + + allCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, "")); + allCurrencies.addAll(CurrencyUtil.getAllSortedCryptoCurrencies().stream() + .collect(Collectors.toList())); + allCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, "")); + } + + @Override + Predicate<OfferBookListItem> getCurrencyAndMethodPredicate(OfferDirection direction, + TradeCurrency selectedTradeCurrency) { + return offerBookListItem -> { + Offer offer = offerBookListItem.getOffer(); + boolean directionResult = offer.getDirection() != direction; // offer to buy xmr appears as offer to sell in peer's offer book and vice versa + boolean currencyResult = CurrencyUtil.isCryptoCurrency(offer.getCurrencyCode()) && + (showAllTradeCurrenciesProperty.get() || + offer.getCurrencyCode().equals(selectedTradeCurrency.getCode())); + boolean paymentMethodResult = showAllPaymentMethods || + offer.getPaymentMethod().equals(selectedPaymentMethod); + boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); + return directionResult && currencyResult && paymentMethodResult && notMyOfferOrShowMyOffersActivated; + }; + } + + @Override + TradeCurrency getDefaultTradeCurrency() { + TradeCurrency defaultTradeCurrency = GlobalSettings.getDefaultTradeCurrency(); + + if (CurrencyUtil.isCryptoCurrency(defaultTradeCurrency.getCode()) && + hasPaymentAccountForCurrency(defaultTradeCurrency)) { + return defaultTradeCurrency; + } + + ObservableList<TradeCurrency> tradeCurrencies = FXCollections.observableArrayList(getTradeCurrencies()); + if (!tradeCurrencies.isEmpty()) { + // drop show all entry and select first currency with payment account available + tradeCurrencies.remove(0); + List<TradeCurrency> sortedList = tradeCurrencies.stream().sorted((o1, o2) -> + Boolean.compare(!hasPaymentAccountForCurrency(o1), + !hasPaymentAccountForCurrency(o2))).collect(Collectors.toList()); + return sortedList.get(0); + } else { + return OfferViewUtil.getMainCryptoCurrencies().sorted((o1, o2) -> + Boolean.compare(!hasPaymentAccountForCurrency(o1), + !hasPaymentAccountForCurrency(o2))).collect(Collectors.toList()).get(0); + } + } + + @Override + String getCurrencyCodeFromPreferences(OfferDirection direction) { + return direction == OfferDirection.BUY ? preferences.getBuyScreenCryptoCurrencyCode() : + preferences.getSellScreenCryptoCurrencyCode(); + } +} \ No newline at end of file diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookView.fxml b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookView.fxml similarity index 97% rename from desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookView.fxml rename to desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookView.fxml index e5bad7e7b0..2f2b6602cf 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookView.fxml +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookView.fxml @@ -19,7 +19,7 @@ <?import javafx.scene.layout.ColumnConstraints?> <?import javafx.scene.layout.GridPane?> -<GridPane fx:id="root" fx:controller="haveno.desktop.main.offer.offerbook.XmrOfferBookView" +<GridPane fx:id="root" fx:controller="haveno.desktop.main.offer.offerbook.FiatOfferBookView" hgap="5.0" vgap="5" xmlns:fx="http://javafx.com/fxml"> diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookView.java similarity index 63% rename from desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookView.java rename to desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookView.java index 697431d5d9..9112ea9a80 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.account.sign.SignedWitnessService; import haveno.core.account.witness.AccountAgeWitnessService; @@ -30,21 +32,18 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import javafx.scene.layout.GridPane; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView -public class XmrOfferBookView extends OfferBookView<GridPane, XmrOfferBookViewModel> { +public class FiatOfferBookView extends OfferBookView<GridPane, FiatOfferBookViewModel> { @Inject - XmrOfferBookView(XmrOfferBookViewModel model, - Navigation navigation, - OfferDetailsWindow offerDetailsWindow, - @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, - PrivateNotificationManager privateNotificationManager, - @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys, - AccountAgeWitnessService accountAgeWitnessService, - SignedWitnessService signedWitnessService) { + FiatOfferBookView(FiatOfferBookViewModel model, + Navigation navigation, + OfferDetailsWindow offerDetailsWindow, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, + PrivateNotificationManager privateNotificationManager, + @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys, + AccountAgeWitnessService accountAgeWitnessService, + SignedWitnessService signedWitnessService) { super(model, navigation, offerDetailsWindow, formatter, privateNotificationManager, useDevPrivilegeKeys, accountAgeWitnessService, signedWitnessService); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java similarity index 80% rename from desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookViewModel.java rename to desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java index afa2a9d668..bea41743b6 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/XmrOfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/FiatOfferBookViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.api.CoreApi; import haveno.core.locale.CryptoCurrency; @@ -42,31 +43,29 @@ import haveno.core.xmr.setup.WalletsSetup; import haveno.desktop.Navigation; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import javax.inject.Named; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; -public class XmrOfferBookViewModel extends OfferBookViewModel { +public class FiatOfferBookViewModel extends OfferBookViewModel { @Inject - public XmrOfferBookViewModel(User user, - OpenOfferManager openOfferManager, - OfferBook offerBook, - Preferences preferences, - WalletsSetup walletsSetup, - P2PService p2PService, - PriceFeedService priceFeedService, - ClosedTradableManager closedTradableManager, - AccountAgeWitnessService accountAgeWitnessService, - Navigation navigation, - PriceUtil priceUtil, - OfferFilterService offerFilterService, - @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, - CoreApi coreApi) { + public FiatOfferBookViewModel(User user, + OpenOfferManager openOfferManager, + OfferBook offerBook, + Preferences preferences, + WalletsSetup walletsSetup, + P2PService p2PService, + PriceFeedService priceFeedService, + ClosedTradableManager closedTradableManager, + AccountAgeWitnessService accountAgeWitnessService, + Navigation navigation, + PriceUtil priceUtil, + OfferFilterService offerFilterService, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, + CoreApi coreApi) { super(user, openOfferManager, offerBook, preferences, walletsSetup, p2PService, priceFeedService, closedTradableManager, accountAgeWitnessService, navigation, priceUtil, offerFilterService, btcFormatter, coreApi); } @@ -142,9 +141,10 @@ public class XmrOfferBookViewModel extends OfferBookViewModel { !hasPaymentAccountForCurrency(o2))).collect(Collectors.toList()); return sortedList.get(0); } else { - return CurrencyUtil.getMainTraditionalCurrencies().stream().sorted((o1, o2) -> - Boolean.compare(!hasPaymentAccountForCurrency(o1), - !hasPaymentAccountForCurrency(o2))).collect(Collectors.toList()).get(0); + return CurrencyUtil.getMainTraditionalCurrencies().stream() + .filter(withFiatCurrency()) + .sorted((o1, o2) -> Boolean.compare(!hasPaymentAccountForCurrency(o1), !hasPaymentAccountForCurrency(o2))) + .collect(Collectors.toList()).get(0); } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java index a058939a51..2367f51c8d 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBook.java @@ -1,41 +1,39 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.filter.FilterManager; import haveno.core.offer.Offer; import haveno.core.offer.OfferBookService; +import static haveno.core.offer.OfferDirection.BUY; import haveno.core.offer.OfferRestrictions; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.utils.Utils; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; -import javax.inject.Singleton; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; - -import static haveno.core.offer.OfferDirection.BUY; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import lombok.extern.slf4j.Slf4j; /** * Holds and manages the unsorted and unfiltered offerbook list (except for banned offers) of both buy and sell offers. diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java index 282b7a0219..e340f9676c 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java index 3a8b8b701e..9b3571458f 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; +import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import haveno.common.UserThread; @@ -44,14 +45,13 @@ import haveno.desktop.common.view.ActivatableViewAndModel; import haveno.desktop.components.AccountStatusTooltipLabel; import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.AutoTooltipLabel; -import haveno.desktop.components.AutoTooltipSlideToggleButton; import haveno.desktop.components.AutoTooltipTableColumn; +import haveno.desktop.components.AutoTooltipTextField; import haveno.desktop.components.AutocompleteComboBox; import haveno.desktop.components.ColoredDecimalPlacesWithZerosText; import haveno.desktop.components.HyperlinkWithIcon; import haveno.desktop.components.InfoAutoTooltipLabel; import haveno.desktop.components.PeerInfoIconTrading; -import haveno.desktop.components.TitledGroupBg; import haveno.desktop.main.MainView; import haveno.desktop.main.account.AccountView; import haveno.desktop.main.account.content.cryptoaccounts.CryptoAccountsView; @@ -64,10 +64,8 @@ import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.portfolio.PortfolioView; import haveno.desktop.main.portfolio.editoffer.EditOfferView; -import haveno.desktop.util.CssTheme; import haveno.desktop.util.FormBuilder; import haveno.desktop.util.GUIUtil; -import haveno.desktop.util.Layout; import haveno.network.p2p.NodeAddress; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -85,6 +83,7 @@ import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; import javafx.scene.control.TableView; +import javafx.scene.control.ToggleButton; import javafx.scene.control.Tooltip; import javafx.scene.image.ImageView; import javafx.scene.layout.GridPane; @@ -96,7 +95,6 @@ import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; import javafx.util.Callback; import javafx.util.StringConverter; -import org.bitcoinj.core.Coin; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.monadic.MonadicBinding; @@ -107,7 +105,7 @@ import java.util.Comparator; import java.util.Map; import java.util.Optional; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelAutoToolTipTextField; abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewModel> extends ActivatableViewAndModel<R, M> { @@ -119,11 +117,12 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM private final AccountAgeWitnessService accountAgeWitnessService; private final SignedWitnessService signedWitnessService; - private TitledGroupBg titledGroupBg; protected AutocompleteComboBox<TradeCurrency> currencyComboBox; private AutocompleteComboBox<PaymentMethod> paymentMethodComboBox; private AutoTooltipButton createOfferButton; - private AutoTooltipSlideToggleButton matchingOffersToggle; + private AutoTooltipTextField filterInputField; + private ToggleButton matchingOffersToggleButton; + private ToggleButton noDepositOffersToggleButton; private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> amountColumn; private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> volumeColumn; private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> marketColumn; @@ -169,39 +168,39 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM public void initialize() { root.setPadding(new Insets(15, 15, 5, 15)); - titledGroupBg = addTitledGroupBg( - root, - gridRow, - 2, - "" - ); - titledGroupBg.getStyleClass().add("last"); - HBox offerToolsBox = new HBox(); offerToolsBox.setAlignment(Pos.BOTTOM_LEFT); offerToolsBox.setSpacing(10); - offerToolsBox.setPadding(new Insets(10, 0, 0, 0)); + offerToolsBox.setPadding(new Insets(0, 0, 0, 0)); Tuple3<VBox, Label, AutocompleteComboBox<TradeCurrency>> currencyBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox( Res.get("offerbook.filterByCurrency")); currencyComboBoxContainer = currencyBoxTuple.first; currencyComboBox = currencyBoxTuple.third; - currencyComboBox.setPrefWidth(270); + currencyComboBox.setPrefWidth(250); Tuple3<VBox, Label, AutocompleteComboBox<PaymentMethod>> paymentBoxTuple = FormBuilder.addTopLabelAutocompleteComboBox( Res.get("offerbook.filterByPaymentMethod")); paymentMethodComboBox = paymentBoxTuple.third; paymentMethodComboBox.setCellFactory(GUIUtil.getPaymentMethodCellFactory()); - paymentMethodComboBox.setPrefWidth(270); + paymentMethodComboBox.setPrefWidth(250); - matchingOffersToggle = new AutoTooltipSlideToggleButton(); - matchingOffersToggle.setText(Res.get("offerbook.matchingOffers")); - HBox.setMargin(matchingOffersToggle, new Insets(7, 0, -9, -15)); + matchingOffersToggleButton = AwesomeDude.createIconToggleButton(AwesomeIcon.USER, null, "1.3em", null); + matchingOffersToggleButton.getStyleClass().add("toggle-button-no-slider"); + matchingOffersToggleButton.setPrefHeight(27); + Tooltip matchingOffersTooltip = new Tooltip(Res.get("offerbook.matchingOffers")); + Tooltip.install(matchingOffersToggleButton, matchingOffersTooltip); + + noDepositOffersToggleButton = new ToggleButton(Res.get("offerbook.filterNoDeposit")); + noDepositOffersToggleButton.getStyleClass().add("toggle-button-no-slider"); + noDepositOffersToggleButton.setPrefHeight(27); + Tooltip noDepositOffersTooltip = new Tooltip(Res.get("offerbook.noDepositOffers")); + Tooltip.install(noDepositOffersToggleButton, noDepositOffersTooltip); createOfferButton = new AutoTooltipButton(""); createOfferButton.setMinHeight(40); createOfferButton.setGraphicTextGap(10); - + createOfferButton.setStyle("-fx-padding: 0 15 0 15;"); disabledCreateOfferButtonTooltip = new Label(""); disabledCreateOfferButtonTooltip.setMinSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); disabledCreateOfferButtonTooltip.setMaxSize(Region.USE_PREF_SIZE, Region.USE_PREF_SIZE); @@ -213,13 +212,18 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM var createOfferButtonStack = new StackPane(createOfferButton, disabledCreateOfferButtonTooltip); + Tuple3<VBox, Label, AutoTooltipTextField> autoToolTipTextField = addTopLabelAutoToolTipTextField(""); + VBox filterBox = autoToolTipTextField.first; + filterInputField = autoToolTipTextField.third; + filterInputField.setPromptText(Res.get("market.offerBook.filterPrompt")); + offerToolsBox.getChildren().addAll(currencyBoxTuple.first, paymentBoxTuple.first, - matchingOffersToggle, getSpacer(), createOfferButtonStack); + filterBox, matchingOffersToggleButton, noDepositOffersToggleButton, getSpacer(), createOfferButtonStack); GridPane.setHgrow(offerToolsBox, Priority.ALWAYS); GridPane.setRowIndex(offerToolsBox, gridRow); GridPane.setColumnSpan(offerToolsBox, 2); - GridPane.setMargin(offerToolsBox, new Insets(Layout.FIRST_ROW_DISTANCE, 0, 0, 0)); + GridPane.setMargin(offerToolsBox, new Insets(0, 0, 0, 0)); root.getChildren().add(offerToolsBox); tableView = new TableView<>(); @@ -291,8 +295,8 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM depositColumn.setComparator(Comparator.comparing(item -> { boolean isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL; BigInteger deposit = isSellOffer ? - item.getOffer().getBuyerSecurityDeposit() : - item.getOffer().getSellerSecurityDeposit(); + item.getOffer().getMaxBuyerSecurityDeposit() : + item.getOffer().getMaxSellerSecurityDeposit(); long amountValue = item.getOffer().getAmount().longValueExact(); if ((deposit == null || amountValue == 0)) { @@ -326,10 +330,6 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM @Override protected void activate() { - titledGroupBg.setText(getMarketTitle()); - titledGroupBg.setHelpUrl(model.getDirection() == OfferDirection.SELL - ? "https://bisq.wiki/Introduction#In_a_nutshell" - : "https://bisq.wiki/Taking_an_offer"); Map<String, Integer> offerCounts = OfferViewUtil.isShownAsBuyOffer(model.getDirection(), model.getSelectedTradeCurrency()) ? model.getSellOfferCounts() : model.getBuyOfferCounts(); currencyComboBox.setCellFactory(GUIUtil.getTradeCurrencyCellFactory(Res.get("shared.oneOffer"), @@ -356,11 +356,13 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM currencyComboBox.getEditor().setText(new CurrencyStringConverter(currencyComboBox).toString(currencyComboBox.getSelectionModel().getSelectedItem())); - matchingOffersToggle.setSelected(model.useOffersMatchingMyAccountsFilter); - matchingOffersToggle.disableProperty().bind(model.disableMatchToggle); - matchingOffersToggle.setOnAction(e -> model.onShowOffersMatchingMyAccounts(matchingOffersToggle.isSelected())); + matchingOffersToggleButton.setSelected(model.useOffersMatchingMyAccountsFilter); + matchingOffersToggleButton.disableProperty().bind(model.disableMatchToggle); + matchingOffersToggleButton.setOnAction(e -> model.onShowOffersMatchingMyAccounts(matchingOffersToggleButton.isSelected())); + + noDepositOffersToggleButton.setSelected(model.showPrivateOffers); + noDepositOffersToggleButton.setOnAction(e -> model.onShowPrivateOffers(noDepositOffersToggleButton.isSelected())); - volumeColumn.sortableProperty().bind(model.showAllTradeCurrenciesProperty.not()); model.getOfferList().comparatorProperty().bind(tableView.comparatorProperty()); amountColumn.sortTypeProperty().addListener((observable, oldValue, newValue) -> { @@ -428,6 +430,10 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM nrOfOffersLabel.setText(Res.get("offerbook.nrOffers", model.getOfferList().size())); model.priceFeedService.updateCounterProperty().addListener(priceFeedUpdateCounterListener); + + filterInputField.setOnKeyTyped(event -> { + model.onFilterKeyTyped(filterInputField.getText()); + }); } private void updatePaymentMethodComboBoxEditor() { @@ -459,8 +465,10 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM @Override protected void deactivate() { createOfferButton.setOnAction(null); - matchingOffersToggle.setOnAction(null); - matchingOffersToggle.disableProperty().unbind(); + matchingOffersToggleButton.setOnAction(null); + matchingOffersToggleButton.disableProperty().unbind(); + noDepositOffersToggleButton.setOnAction(null); + noDepositOffersToggleButton.disableProperty().unbind(); model.getOfferList().comparatorProperty().unbind(); volumeColumn.sortableProperty().unbind(); @@ -581,6 +589,10 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM iconView.setId(direction == OfferDirection.SELL ? "image-sell-white" : "image-buy-white"); createOfferButton.setId(direction == OfferDirection.SELL ? "sell-button-big" : "buy-button-big"); avatarColumn.setTitle(direction == OfferDirection.SELL ? Res.get("shared.buyerUpperCase") : Res.get("shared.sellerUpperCase")); + if (direction == OfferDirection.SELL) { + noDepositOffersToggleButton.setVisible(false); + noDepositOffersToggleButton.setManaged(false); + } } public void setOfferActionHandler(OfferView.OfferActionHandler offerActionHandler) { @@ -665,10 +677,10 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM Optional<PaymentAccount> account = model.getMostMaturePaymentAccountForOffer(offer); if (account.isPresent()) { long tradeLimit = model.accountAgeWitnessService.getMyTradeLimit(account.get(), - offer.getCurrencyCode(), offer.getMirroredDirection()); + offer.getCurrencyCode(), offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); new Popup() .warning(Res.get("popup.warning.tradeLimitDueAccountAgeRestriction.buyer", - formatter.formatCoinWithCode(Coin.valueOf(tradeLimit)), + HavenoUtils.formatXmr(tradeLimit, true), Res.get("offerbook.warning.newVersionAnnouncement"))) .show(); } else { @@ -763,8 +775,9 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM /////////////////////////////////////////////////////////////////////////////////////////// private AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> getAmountColumn() { - AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> column = new AutoTooltipTableColumn<>(Res.get("shared.BTCMinMax"), Res.get("shared.amountHelp")); + AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> column = new AutoTooltipTableColumn<>(Res.get("shared.XMRMinMax"), Res.get("shared.amountHelp")); column.setMinWidth(100); + column.setSortable(true); column.getStyleClass().add("number-column"); column.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue())); column.setCellFactory( @@ -908,6 +921,7 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM AutoTooltipTableColumn<OfferBookListItem, OfferBookListItem> column = new AutoTooltipTableColumn<>("") { { setMinWidth(125); + setSortable(true); } }; column.getStyleClass().add("number-column"); @@ -1015,14 +1029,15 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM super.updateItem(item, empty); if (item != null && !empty) { var isSellOffer = item.getOffer().getDirection() == OfferDirection.SELL; - var deposit = isSellOffer ? item.getOffer().getBuyerSecurityDeposit() : - item.getOffer().getSellerSecurityDeposit(); + var deposit = isSellOffer ? item.getOffer().getMaxBuyerSecurityDeposit() : + item.getOffer().getMaxSellerSecurityDeposit(); if (deposit == null) { setText(Res.get("shared.na")); setGraphic(null); } else { setText(""); - setGraphic(new ColoredDecimalPlacesWithZerosText(model.formatDepositString( + String rangePrefix = item.getOffer().isRange() ? "<= " : ""; + setGraphic(new ColoredDecimalPlacesWithZerosText(rangePrefix + model.formatDepositString( deposit, item.getOffer().getAmount().longValueExact()), GUIUtil.AMOUNT_DECIMALS_WITH_ZEROS)); } @@ -1118,20 +1133,19 @@ abstract public class OfferBookView<R extends GridPane, M extends OfferBookViewM if (myOffer) { iconView.setId("image-remove"); title = Res.get("shared.remove"); - button.setId(null); - button.setStyle(CssTheme.isDarkTheme() ? "-fx-text-fill: white" : "-fx-text-fill: #444444"); button.setOnAction(e -> onRemoveOpenOffer(offer)); iconView2.setId("image-edit"); button2.updateText(Res.get("shared.edit")); - button2.setId(null); - button2.setStyle(CssTheme.isDarkTheme() ? "-fx-text-fill: white" : "-fx-text-fill: #444444"); button2.setOnAction(e -> onEditOpenOffer(offer)); button2.setManaged(true); button2.setVisible(true); } else { boolean isSellOffer = OfferViewUtil.isShownAsSellOffer(offer); - iconView.setId(isSellOffer ? "image-buy-white" : "image-sell-white"); + boolean isPrivateOffer = offer.isPrivateOffer(); + iconView.setId(isPrivateOffer ? "image-lock2x" : isSellOffer ? "image-buy-white" : "image-sell-white"); + iconView.setFitHeight(16); + iconView.setFitWidth(16); button.setId(isSellOffer ? "buy-button" : "sell-button"); button.setStyle("-fx-text-fill: white"); title = Res.get("offerbook.takeOffer"); diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java index a65909ec48..55fb0946c8 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OfferBookViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; @@ -121,6 +121,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { PaymentMethod selectedPaymentMethod = getShowAllEntryForPaymentMethod(); boolean isTabSelected; + String filterText = ""; final BooleanProperty showAllTradeCurrenciesProperty = new SimpleBooleanProperty(true); final BooleanProperty disableMatchToggle = new SimpleBooleanProperty(); final IntegerProperty maxPlacesForAmount = new SimpleIntegerProperty(); @@ -129,6 +130,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { final IntegerProperty maxPlacesForMarketPriceMargin = new SimpleIntegerProperty(); boolean showAllPaymentMethods = true; boolean useOffersMatchingMyAccountsFilter; + boolean showPrivateOffers; /////////////////////////////////////////////////////////////////////////////////////////// @@ -212,6 +214,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { disableMatchToggle.set(user.getPaymentAccounts() == null || user.getPaymentAccounts().isEmpty()); } useOffersMatchingMyAccountsFilter = !disableMatchToggle.get() && isShowOffersMatchingMyAccounts(); + showPrivateOffers = preferences.isShowPrivateOffers(); fillCurrencies(); updateSelectedTradeCurrency(); @@ -269,6 +272,11 @@ abstract class OfferBookViewModel extends ActivatableViewModel { } } + void onFilterKeyTyped(String filterText) { + this.filterText = filterText; + filterOffers(); + } + abstract void saveSelectedCurrencyCodeInPreferences(OfferDirection direction, String code); protected void onSetPaymentMethod(PaymentMethod paymentMethod) { @@ -301,6 +309,12 @@ abstract class OfferBookViewModel extends ActivatableViewModel { filterOffers(); } + void onShowPrivateOffers(boolean isSelected) { + showPrivateOffers = isSelected; + preferences.setShowPrivateOffers(isSelected); + filterOffers(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Getters @@ -396,9 +410,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { } public Optional<Double> getMarketBasedPrice(Offer offer) { - OfferDirection displayDirection = offer.isTraditionalOffer() ? direction : - direction.equals(OfferDirection.BUY) ? OfferDirection.SELL : OfferDirection.BUY; - return priceUtil.getMarketBasedPrice(offer, displayDirection); + return priceUtil.getMarketBasedPrice(offer, direction); } String formatMarketPriceMarginPct(Offer offer) { @@ -553,6 +565,7 @@ abstract class OfferBookViewModel extends ActivatableViewModel { boolean canCreateOrTakeOffer() { return GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation) && + GUIUtil.isWalletSyncedWithinToleranceOrShowPopup(openOfferManager.getXmrWalletService()) && GUIUtil.isBootstrappedOrShowPopup(p2PService); } @@ -565,7 +578,27 @@ abstract class OfferBookViewModel extends ActivatableViewModel { Predicate<OfferBookListItem> predicate = useOffersMatchingMyAccountsFilter ? getCurrencyAndMethodPredicate(direction, selectedTradeCurrency).and(getOffersMatchingMyAccountsPredicate()) : getCurrencyAndMethodPredicate(direction, selectedTradeCurrency); - filteredItems.setPredicate(predicate); + + predicate = predicate.and(offerBookListItem -> offerBookListItem.getOffer().isPrivateOffer() == showPrivateOffers); + + if (!filterText.isEmpty()) { + + // filter node address + Predicate<OfferBookListItem> nextPredicate = offerBookListItem -> + offerBookListItem.getOffer().getOfferPayload().getOwnerNodeAddress().getFullAddress().toLowerCase().contains(filterText.toLowerCase()); + + // filter offer id + nextPredicate = nextPredicate.or(offerBookListItem -> + offerBookListItem.getOffer().getId().toLowerCase().contains(filterText.toLowerCase())); + + // filter payment method + nextPredicate = nextPredicate.or(offerBookListItem -> + Res.get(offerBookListItem.getOffer().getPaymentMethod().getId()).toLowerCase().contains(filterText.toLowerCase())); + + filteredItems.setPredicate(predicate.and(nextPredicate)); + } else { + filteredItems.setPredicate(predicate); + } } abstract Predicate<OfferBookListItem> getCurrencyAndMethodPredicate(OfferDirection direction, @@ -617,13 +650,9 @@ abstract class OfferBookViewModel extends ActivatableViewModel { return true; } - public String getMakerFeeAsString(Offer offer) { - return HavenoUtils.formatXmr(offer.getMakerFee(), true); - } - private static String getDirectionWithCodeDetailed(OfferDirection direction, String currencyCode) { if (CurrencyUtil.isTraditionalCurrency(currencyCode)) - return (direction == OfferDirection.BUY) ? Res.get("shared.buyingBTCWith", currencyCode) : Res.get("shared.sellingBTCFor", currencyCode); + return (direction == OfferDirection.BUY) ? Res.get("shared.buyingXMRWith", currencyCode) : Res.get("shared.sellingXMRFor", currencyCode); else return (direction == OfferDirection.SELL) ? Res.get("shared.buyingCurrency", currencyCode) : Res.get("shared.sellingCurrency", currencyCode); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookView.java index e6537cfd71..14d1f83564 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.core.account.sign.SignedWitnessService; import haveno.core.account.witness.AccountAgeWitnessService; @@ -30,33 +32,30 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import javafx.scene.layout.GridPane; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class OtherOfferBookView extends OfferBookView<GridPane, OtherOfferBookViewModel> { @Inject OtherOfferBookView(OtherOfferBookViewModel model, - Navigation navigation, - OfferDetailsWindow offerDetailsWindow, - @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, - PrivateNotificationManager privateNotificationManager, - @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys, - AccountAgeWitnessService accountAgeWitnessService, - SignedWitnessService signedWitnessService) { + Navigation navigation, + OfferDetailsWindow offerDetailsWindow, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, + PrivateNotificationManager privateNotificationManager, + @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys, + AccountAgeWitnessService accountAgeWitnessService, + SignedWitnessService signedWitnessService) { super(model, navigation, offerDetailsWindow, formatter, privateNotificationManager, useDevPrivilegeKeys, accountAgeWitnessService, signedWitnessService); } @Override protected String getMarketTitle() { return model.getDirection().equals(OfferDirection.BUY) ? - Res.get("offerbook.availableOffersToBuy", Res.get("shared.otherAssets"), Res.getBaseCurrencyCode()) : - Res.get("offerbook.availableOffersToSell", Res.get("shared.otherAssets"), Res.getBaseCurrencyCode()); + Res.get("offerbook.availableOffersToBuy", Res.getBaseCurrencyCode(), Res.get("shared.otherAssets")) : + Res.get("offerbook.availableOffersToSell", Res.getBaseCurrencyCode(), Res.get("shared.otherAssets")); } @Override String getTradeCurrencyCode() { - return model.showAllTradeCurrenciesProperty.get() ? "" : model.getSelectedTradeCurrency().getCode(); + return Res.getBaseCurrencyCode(); } } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java index c6fc412aa2..012af7a822 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/OtherOfferBookViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.api.CoreApi; import haveno.core.locale.CryptoCurrency; @@ -39,44 +40,41 @@ import haveno.core.util.PriceUtil; import haveno.core.util.coin.CoinFormatter; import haveno.core.xmr.setup.WalletsSetup; import haveno.desktop.Navigation; -import haveno.desktop.main.offer.OfferViewUtil; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import org.jetbrains.annotations.NotNull; - -import javax.inject.Named; import java.util.List; import java.util.function.Predicate; import java.util.stream.Collectors; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import org.jetbrains.annotations.NotNull; public class OtherOfferBookViewModel extends OfferBookViewModel { @Inject public OtherOfferBookViewModel(User user, - OpenOfferManager openOfferManager, - OfferBook offerBook, - Preferences preferences, - WalletsSetup walletsSetup, - P2PService p2PService, - PriceFeedService priceFeedService, - ClosedTradableManager closedTradableManager, - AccountAgeWitnessService accountAgeWitnessService, - Navigation navigation, - PriceUtil priceUtil, - OfferFilterService offerFilterService, - @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, - CoreApi coreApi) { + OpenOfferManager openOfferManager, + OfferBook offerBook, + Preferences preferences, + WalletsSetup walletsSetup, + P2PService p2PService, + PriceFeedService priceFeedService, + ClosedTradableManager closedTradableManager, + AccountAgeWitnessService accountAgeWitnessService, + Navigation navigation, + PriceUtil priceUtil, + OfferFilterService offerFilterService, + @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, + CoreApi coreApi) { super(user, openOfferManager, offerBook, preferences, walletsSetup, p2PService, priceFeedService, closedTradableManager, accountAgeWitnessService, navigation, priceUtil, offerFilterService, btcFormatter, coreApi); } @Override void saveSelectedCurrencyCodeInPreferences(OfferDirection direction, String code) { if (direction == OfferDirection.BUY) { - preferences.setBuyScreenCryptoCurrencyCode(code); + preferences.setBuyScreenOtherCurrencyCode(code); } else { - preferences.setSellScreenCryptoCurrencyCode(code); + preferences.setBuyScreenOtherCurrencyCode(code); } } @@ -84,7 +82,6 @@ public class OtherOfferBookViewModel extends OfferBookViewModel { protected ObservableList<PaymentMethod> filterPaymentMethods(ObservableList<PaymentMethod> list, TradeCurrency selectedTradeCurrency) { return FXCollections.observableArrayList(list.stream().filter(paymentMethod -> { - if (paymentMethod.isBlockchain()) return true; if (paymentMethod.getSupportedAssetCodes() == null) return true; for (String assetCode : paymentMethod.getSupportedAssetCodes()) { if (!CurrencyUtil.isFiatCurrency(assetCode)) return true; @@ -96,20 +93,13 @@ public class OtherOfferBookViewModel extends OfferBookViewModel { @Override void fillCurrencies(ObservableList<TradeCurrency> tradeCurrencies, ObservableList<TradeCurrency> allCurrencies) { - tradeCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, "")); - tradeCurrencies.addAll(preferences.getCryptoCurrenciesAsObservable().stream() - .filter(withoutTopCrypto()) - .collect(Collectors.toList())); tradeCurrencies.addAll(CurrencyUtil.getMainTraditionalCurrencies().stream() .filter(withoutFiatCurrency()) .collect(Collectors.toList())); tradeCurrencies.add(new CryptoCurrency(GUIUtil.EDIT_FLAG, "")); allCurrencies.add(new CryptoCurrency(GUIUtil.SHOW_ALL_FLAG, "")); - allCurrencies.addAll(CurrencyUtil.getAllSortedCryptoCurrencies().stream() - .filter(withoutTopCrypto()) - .collect(Collectors.toList())); allCurrencies.addAll(CurrencyUtil.getMainTraditionalCurrencies().stream() .filter(withoutFiatCurrency()) .collect(Collectors.toList())); @@ -121,12 +111,9 @@ public class OtherOfferBookViewModel extends OfferBookViewModel { TradeCurrency selectedTradeCurrency) { return offerBookListItem -> { Offer offer = offerBookListItem.getOffer(); - // BUY Crypto is actually SELL Monero - boolean directionResult = offer.getDirection() == direction; - boolean currencyResult = !CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && - ((showAllTradeCurrenciesProperty.get() && - !offer.getCurrencyCode().equals(GUIUtil.TOP_CRYPTO.getCode())) || - offer.getCurrencyCode().equals(selectedTradeCurrency.getCode())); + boolean directionResult = offer.getDirection() != direction; + boolean currencyResult = CurrencyUtil.isTraditionalCurrency(offer.getCurrencyCode()) && !CurrencyUtil.isFiatCurrency(offer.getCurrencyCode()) && + (showAllTradeCurrenciesProperty.get() || offer.getCurrencyCode().equals(selectedTradeCurrency.getCode())); boolean paymentMethodResult = showAllPaymentMethods || offer.getPaymentMethod().equals(selectedPaymentMethod); boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); @@ -138,8 +125,8 @@ public class OtherOfferBookViewModel extends OfferBookViewModel { TradeCurrency getDefaultTradeCurrency() { TradeCurrency defaultTradeCurrency = GlobalSettings.getDefaultTradeCurrency(); - if (!CurrencyUtil.isTraditionalCurrency(defaultTradeCurrency.getCode()) && - !defaultTradeCurrency.equals(GUIUtil.TOP_CRYPTO) && + if (CurrencyUtil.isTraditionalCurrency(defaultTradeCurrency.getCode()) && + !CurrencyUtil.isFiatCurrency(defaultTradeCurrency.getCode()) && hasPaymentAccountForCurrency(defaultTradeCurrency)) { return defaultTradeCurrency; } @@ -153,22 +140,19 @@ public class OtherOfferBookViewModel extends OfferBookViewModel { !hasPaymentAccountForCurrency(o2))).collect(Collectors.toList()); return sortedList.get(0); } else { - return OfferViewUtil.getMainCryptoCurrencies().sorted((o1, o2) -> - Boolean.compare(!hasPaymentAccountForCurrency(o1), - !hasPaymentAccountForCurrency(o2))).collect(Collectors.toList()).get(0); + return CurrencyUtil.getMainTraditionalCurrencies().stream() + .filter(withoutFiatCurrency()) + .sorted((o1, o2) -> Boolean.compare(!hasPaymentAccountForCurrency(o1), !hasPaymentAccountForCurrency(o2))) + .collect(Collectors.toList()).get(0); } } @Override String getCurrencyCodeFromPreferences(OfferDirection direction) { - return direction == OfferDirection.BUY ? preferences.getBuyScreenCryptoCurrencyCode() : - preferences.getSellScreenCryptoCurrencyCode(); - } + // validate if previous stored currencies are Traditional ones + String currencyCode = direction == OfferDirection.BUY ? preferences.getBuyScreenOtherCurrencyCode() : preferences.getSellScreenOtherCurrencyCode(); - @NotNull - private Predicate<CryptoCurrency> withoutTopCrypto() { - return cryptoCurrency -> - !cryptoCurrency.equals(GUIUtil.TOP_CRYPTO); + return CurrencyUtil.isTraditionalCurrency(currencyCode) ? currencyCode : null; } @NotNull diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookView.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookView.java deleted file mode 100644 index b04f04101d..0000000000 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookView.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.desktop.main.offer.offerbook; - -import haveno.common.config.Config; -import haveno.core.account.sign.SignedWitnessService; -import haveno.core.account.witness.AccountAgeWitnessService; -import haveno.core.alert.PrivateNotificationManager; -import haveno.core.locale.Res; -import haveno.core.offer.OfferDirection; -import haveno.core.util.FormattingUtils; -import haveno.core.util.coin.CoinFormatter; -import haveno.desktop.Navigation; -import haveno.desktop.common.view.FxmlView; -import haveno.desktop.main.overlays.windows.OfferDetailsWindow; -import javafx.scene.layout.GridPane; - -import javax.inject.Inject; -import javax.inject.Named; - -@FxmlView -public class TopCryptoOfferBookView extends OfferBookView<GridPane, TopCryptoOfferBookViewModel> { - - @Inject - TopCryptoOfferBookView(TopCryptoOfferBookViewModel model, - Navigation navigation, - OfferDetailsWindow offerDetailsWindow, - @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter formatter, - PrivateNotificationManager privateNotificationManager, - @Named(Config.USE_DEV_PRIVILEGE_KEYS) boolean useDevPrivilegeKeys, - AccountAgeWitnessService accountAgeWitnessService, - SignedWitnessService signedWitnessService) { - super(model, navigation, offerDetailsWindow, formatter, privateNotificationManager, useDevPrivilegeKeys, accountAgeWitnessService, signedWitnessService); - } - - @Override - protected String getMarketTitle() { - return model.getDirection().equals(OfferDirection.BUY) ? - Res.get("offerbook.availableOffersToBuy", TopCryptoOfferBookViewModel.TOP_CRYPTO.getCode(), Res.getBaseCurrencyCode()) : - Res.get("offerbook.availableOffersToSell", TopCryptoOfferBookViewModel.TOP_CRYPTO.getCode(), Res.getBaseCurrencyCode()); - } - - @Override - protected void activate() { - model.onSetTradeCurrency(TopCryptoOfferBookViewModel.TOP_CRYPTO); - - super.activate(); - - currencyComboBoxContainer.setVisible(false); - currencyComboBoxContainer.setManaged(false); - } - - @Override - String getTradeCurrencyCode() { - return TopCryptoOfferBookViewModel.TOP_CRYPTO.getCode(); - } -} diff --git a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookViewModel.java deleted file mode 100644 index 8ce52b69ee..0000000000 --- a/desktop/src/main/java/haveno/desktop/main/offer/offerbook/TopCryptoOfferBookViewModel.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.desktop.main.offer.offerbook; - -import com.google.inject.Inject; -import haveno.core.account.witness.AccountAgeWitnessService; -import haveno.core.api.CoreApi; -import haveno.core.locale.TradeCurrency; -import haveno.core.offer.Offer; -import haveno.core.offer.OfferDirection; -import haveno.core.offer.OfferFilterService; -import haveno.core.offer.OpenOfferManager; -import haveno.core.payment.payload.PaymentMethod; -import haveno.core.provider.price.PriceFeedService; -import haveno.core.trade.ClosedTradableManager; -import haveno.core.user.Preferences; -import haveno.core.user.User; -import haveno.core.util.FormattingUtils; -import haveno.core.util.PriceUtil; -import haveno.core.util.coin.CoinFormatter; -import haveno.core.xmr.setup.WalletsSetup; -import haveno.desktop.Navigation; -import haveno.desktop.util.GUIUtil; -import haveno.network.p2p.P2PService; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import javax.inject.Named; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -public class TopCryptoOfferBookViewModel extends OfferBookViewModel { - - public static TradeCurrency TOP_CRYPTO = GUIUtil.TOP_CRYPTO; - - @Inject - public TopCryptoOfferBookViewModel(User user, - OpenOfferManager openOfferManager, - OfferBook offerBook, - Preferences preferences, - WalletsSetup walletsSetup, - P2PService p2PService, - PriceFeedService priceFeedService, - ClosedTradableManager closedTradableManager, - AccountAgeWitnessService accountAgeWitnessService, - Navigation navigation, - PriceUtil priceUtil, - OfferFilterService offerFilterService, - @Named(FormattingUtils.BTC_FORMATTER_KEY) CoinFormatter btcFormatter, - CoreApi coreApi) { - super(user, openOfferManager, offerBook, preferences, walletsSetup, p2PService, priceFeedService, closedTradableManager, accountAgeWitnessService, navigation, priceUtil, offerFilterService, btcFormatter, coreApi); - } - - @Override - protected void activate() { - super.activate(); - TOP_CRYPTO = GUIUtil.TOP_CRYPTO; - } - - @Override - void saveSelectedCurrencyCodeInPreferences(OfferDirection direction, String code) { - // No need to store anything as it is just one Crypto offers anyway - } - - @Override - protected ObservableList<PaymentMethod> filterPaymentMethods(ObservableList<PaymentMethod> list, - TradeCurrency selectedTradeCurrency) { - return FXCollections.observableArrayList(list.stream().filter(PaymentMethod::isBlockchain).collect(Collectors.toList())); - } - - @Override - void fillCurrencies(ObservableList<TradeCurrency> tradeCurrencies, - ObservableList<TradeCurrency> allCurrencies) { - tradeCurrencies.add(TOP_CRYPTO); - allCurrencies.add(TOP_CRYPTO); - } - - @Override - Predicate<OfferBookListItem> getCurrencyAndMethodPredicate(OfferDirection direction, - TradeCurrency selectedTradeCurrency) { - return offerBookListItem -> { - Offer offer = offerBookListItem.getOffer(); - // BUY Crypto is actually SELL Bitcoin - boolean directionResult = offer.getDirection() == direction; - boolean currencyResult = offer.getCurrencyCode().equals(TOP_CRYPTO.getCode()); - boolean paymentMethodResult = showAllPaymentMethods || - offer.getPaymentMethod().equals(selectedPaymentMethod); - boolean notMyOfferOrShowMyOffersActivated = !isMyOffer(offerBookListItem.getOffer()) || preferences.isShowOwnOffersInOfferBook(); - return directionResult && currencyResult && paymentMethodResult && notMyOfferOrShowMyOffersActivated; - }; - } - - @Override - TradeCurrency getDefaultTradeCurrency() { - return TOP_CRYPTO; - } - - @Override - String getCurrencyCodeFromPreferences(OfferDirection direction) { - return TOP_CRYPTO.getCode(); - } -} diff --git a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferListItem.java b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferListItem.java index 7a1e267794..f27d618de0 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.signedoffer; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferView.java index dfbde8df65..f241797fc7 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOfferView.java @@ -1,54 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.signedoffer; -import javax.inject.Inject; - -import javafx.fxml.FXML; - -import javafx.scene.control.ContextMenu; -import javafx.scene.control.Label; -import javafx.scene.control.MenuItem; -import javafx.scene.control.TableCell; -import javafx.scene.control.TableColumn; -import javafx.scene.control.TableRow; -import javafx.scene.control.TableView; -import javafx.scene.control.Tooltip; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; -import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; - -import javafx.geometry.Insets; - -import javafx.beans.property.ReadOnlyObjectWrapper; - -import javafx.collections.transformation.FilteredList; -import javafx.collections.transformation.SortedList; - -import javafx.util.Callback; -import javafx.util.Duration; - -import java.util.Comparator; -import java.util.Date; - - - +import com.google.inject.Inject; import haveno.common.util.Utilities; import haveno.core.locale.Res; import haveno.core.offer.SignedOffer; @@ -65,6 +34,27 @@ import haveno.desktop.main.offer.OfferViewUtil; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.GUIUtil; +import java.util.Comparator; +import java.util.Date; +import javafx.beans.property.ReadOnlyObjectWrapper; +import javafx.collections.transformation.FilteredList; +import javafx.collections.transformation.SortedList; +import javafx.fxml.FXML; +import javafx.geometry.Insets; +import javafx.scene.control.ContextMenu; +import javafx.scene.control.Label; +import javafx.scene.control.MenuItem; +import javafx.scene.control.TableCell; +import javafx.scene.control.TableColumn; +import javafx.scene.control.TableRow; +import javafx.scene.control.TableView; +import javafx.scene.control.Tooltip; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Priority; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.util.Callback; +import javafx.util.Duration; @FxmlView public class SignedOfferView extends ActivatableViewAndModel<VBox, SignedOffersViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersDataModel.java index bdd66388f1..311cca3476 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.signedoffer; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersViewModel.java index 511f6ca4bb..770d7197e2 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/signedoffer/SignedOffersViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.signedoffer; diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java index ef3b335928..0f6c5db8fb 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferDataModel.java @@ -1,23 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.takeoffer; import com.google.inject.Inject; + +import haveno.common.ThreadUtils; +import haveno.common.UserThread; import haveno.common.handlers.ErrorMessageHandler; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.filter.FilterManager; @@ -129,7 +132,7 @@ class TakeOfferDataModel extends OfferDataModel { addListeners(); - updateAvailableBalance(); + updateBalances(); // TODO In case that we have funded but restarted, or canceled but took again the offer we would need to // store locally the result when we received the funding tx(s). @@ -147,7 +150,12 @@ class TakeOfferDataModel extends OfferDataModel { this.amount.get(), () -> { }, - errorMessage -> new Popup().warning(errorMessage).show()); + errorMessage -> { + log.warn(errorMessage); + if (offer.getState() != Offer.State.NOT_AVAILABLE && offer.getState() != Offer.State.INVALID) { // handled elsewhere in UI + new Popup().warning(errorMessage).show(); + } + }); } } @@ -177,9 +185,7 @@ class TakeOfferDataModel extends OfferDataModel { this.amount.set(offer.getAmount().min(BigInteger.valueOf(getMaxTradeLimit()))); - securityDeposit = offer.getDirection() == OfferDirection.SELL ? - getBuyerSecurityDeposit() : - getSellerSecurityDeposit(); + updateSecurityDeposit(); calculateVolume(); calculateTotalToPay(); @@ -187,7 +193,7 @@ class TakeOfferDataModel extends OfferDataModel { balanceListener = new XmrBalanceListener(addressEntry.getSubaddressIndex()) { @Override public void onBalanceChanged(BigInteger balance) { - updateAvailableBalance(); + updateBalances(); } }; @@ -218,7 +224,21 @@ class TakeOfferDataModel extends OfferDataModel { offerBook.removeOffer(checkNotNull(offer)); } - xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId()); + // reset address entries off thread + ThreadUtils.submitToPool(() -> xmrWalletService.resetAddressEntriesForOpenOffer(offer.getId())); + } + + protected void updateBalances() { + super.updateBalances(); + + // update remaining balance + UserThread.await(() -> { + missingCoin.set(offerUtil.getBalanceShortage(totalToPay.get(), balance.get())); + isXmrWalletFunded.set(offerUtil.isBalanceSufficient(totalToPay.get(), availableBalance.get())); + if (totalToPay.get() != null && isXmrWalletFunded.get() && !showWalletFundedNotification.get()) { + showWalletFundedNotification.set(true); + } + }); } @@ -226,8 +246,6 @@ class TakeOfferDataModel extends OfferDataModel { // UI actions /////////////////////////////////////////////////////////////////////////////////////////// - // errorMessageHandler is used only in the check availability phase. As soon we have a trade we write the error msg in the trade object as we want to - // have it persisted as well. void onTakeOffer(TradeResultHandler tradeResultHandler, ErrorMessageHandler errorMessageHandler) { checkNotNull(getTakerFee(), "takerFee must not be null"); @@ -235,21 +253,21 @@ class TakeOfferDataModel extends OfferDataModel { if (isBuyOffer()) fundsNeededForTrade = fundsNeededForTrade.add(amount.get()); + String errorMsg = null; if (filterManager.isCurrencyBanned(offer.getCurrencyCode())) { - new Popup().warning(Res.get("offerbook.warning.currencyBanned")).show(); + errorMsg = Res.get("offerbook.warning.currencyBanned"); } else if (filterManager.isPaymentMethodBanned(offer.getPaymentMethod())) { - new Popup().warning(Res.get("offerbook.warning.paymentMethodBanned")).show(); + errorMsg = Res.get("offerbook.warning.paymentMethodBanned"); } else if (filterManager.isOfferIdBanned(offer.getId())) { - new Popup().warning(Res.get("offerbook.warning.offerBlocked")).show(); + errorMsg = Res.get("offerbook.warning.offerBlocked"); } else if (filterManager.isNodeAddressBanned(offer.getMakerNodeAddress())) { - new Popup().warning(Res.get("offerbook.warning.nodeBlocked")).show(); + errorMsg = Res.get("offerbook.warning.nodeBlocked"); } else if (filterManager.requireUpdateToNewVersionForTrading()) { - new Popup().warning(Res.get("offerbook.warning.requireUpdateToNewVersion")).show(); + errorMsg = Res.get("offerbook.warning.requireUpdateToNewVersion"); } else if (tradeManager.wasOfferAlreadyUsedInTrade(offer.getId())) { - new Popup().warning(Res.get("offerbook.warning.offerWasAlreadyUsedInTrade")).show(); + errorMsg = Res.get("offerbook.warning.offerWasAlreadyUsedInTrade"); } else { tradeManager.onTakeOffer(amount.get(), - getTakerFee(), fundsNeededForTrade, offer, paymentAccount.getId(), @@ -262,6 +280,12 @@ class TakeOfferDataModel extends OfferDataModel { } ); } + + // handle error + if (errorMsg != null) { + new Popup().warning(errorMsg).show(); + errorMessageHandler.handleErrorMessage(errorMsg); + } } public void onPaymentAccountSelected(PaymentAccount paymentAccount) { @@ -277,11 +301,7 @@ class TakeOfferDataModel extends OfferDataModel { void fundFromSavingsWallet() { useSavingsWallet = true; - updateAvailableBalance(); - if (!isXmrWalletFunded.get()) { - this.useSavingsWallet = false; - updateAvailableBalance(); - } + updateBalances(); } @@ -321,7 +341,7 @@ class TakeOfferDataModel extends OfferDataModel { long getMaxTradeLimit() { if (paymentAccount != null) { return accountAgeWitnessService.getMyTradeLimit(paymentAccount, getCurrencyCode(), - offer.getMirroredDirection()); + offer.getMirroredDirection(), offer.hasBuyerAsTakerWithoutDeposit()); } else { return 0; } @@ -353,23 +373,24 @@ class TakeOfferDataModel extends OfferDataModel { void calculateVolume() { if (tradePrice != null && offer != null && amount.get() != null && - amount.get().compareTo(BigInteger.valueOf(0)) != 0) { + amount.get().compareTo(BigInteger.ZERO) != 0) { Volume volumeByAmount = tradePrice.getVolumeByAmount(amount.get()); volumeByAmount = VolumeUtil.getAdjustedVolume(volumeByAmount, offer.getPaymentMethod().getId()); volume.set(volumeByAmount); - updateAvailableBalance(); + updateBalances(); } } void applyAmount(BigInteger amount) { this.amount.set(amount.min(BigInteger.valueOf(getMaxTradeLimit()))); - calculateTotalToPay(); } void calculateTotalToPay() { + updateSecurityDeposit(); + // Taker pays 2 times the tx fee because the mining fee might be different when maker created the offer // and reserved his funds, so that would not work well with dynamic fees. // The mining fee for the takeOfferFee tx is deducted from the createOfferFee and not visible to the trader @@ -380,7 +401,7 @@ class TakeOfferDataModel extends OfferDataModel { totalToPay.set(feeAndSecDeposit.add(amount.get())); else totalToPay.set(feeAndSecDeposit); - updateAvailableBalance(); + updateBalances(); log.debug("totalToPay {}", totalToPay.get()); } } @@ -399,7 +420,7 @@ class TakeOfferDataModel extends OfferDataModel { @Nullable BigInteger getTakerFee() { - return HavenoUtils.getTakerFee(this.amount.get()); + return HavenoUtils.multiply(this.amount.get(), offer.getTakerFeePct()); } public void swapTradeToSavings() { @@ -459,12 +480,18 @@ class TakeOfferDataModel extends OfferDataModel { return securityDeposit; } - public BigInteger getBuyerSecurityDeposit() { - return offer.getBuyerSecurityDeposit(); + private void updateSecurityDeposit() { + securityDeposit = offer.getDirection() == OfferDirection.SELL ? + getBuyerSecurityDeposit() : + getSellerSecurityDeposit(); } - public BigInteger getSellerSecurityDeposit() { - return offer.getSellerSecurityDeposit(); + private BigInteger getBuyerSecurityDeposit() { + return offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(amount.get()); + } + + private BigInteger getSellerSecurityDeposit() { + return offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(amount.get()); } public boolean isRoundedForAtmCash() { diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java index ab4b9a0892..1d662aebc7 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.takeoffer; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.jfoenix.controls.JFXTextField; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import haveno.common.UserThread; @@ -54,6 +56,7 @@ import haveno.desktop.main.offer.ClosableView; import haveno.desktop.main.offer.InitializableViewWithTakeOfferData; import haveno.desktop.main.offer.OfferView; import haveno.desktop.main.offer.OfferViewUtil; +import static haveno.desktop.main.offer.OfferViewUtil.addPayInfoEntry; import haveno.desktop.main.offer.SelectableView; import haveno.desktop.main.overlays.notifications.Notification; import haveno.desktop.main.overlays.popups.Popup; @@ -62,9 +65,27 @@ import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.overlays.windows.QRCodeWindow; import haveno.desktop.main.portfolio.PortfolioView; import haveno.desktop.main.portfolio.pendingtrades.PendingTradesView; +import static haveno.desktop.util.FormBuilder.add2ButtonsWithBox; +import static haveno.desktop.util.FormBuilder.addAddressTextField; +import static haveno.desktop.util.FormBuilder.addBalanceTextField; +import static haveno.desktop.util.FormBuilder.addComboBoxTopLabelTextField; +import static haveno.desktop.util.FormBuilder.addFundsTextfield; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.getEditableValueBox; +import static haveno.desktop.util.FormBuilder.getIconForLabel; +import static haveno.desktop.util.FormBuilder.getNonEditableValueBox; +import static haveno.desktop.util.FormBuilder.getNonEditableValueBoxWithInfo; +import static haveno.desktop.util.FormBuilder.getSmallIconForLabel; +import static haveno.desktop.util.FormBuilder.getTopLabelWithVBox; import haveno.desktop.util.GUIUtil; import haveno.desktop.util.Layout; import haveno.desktop.util.Transitions; +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.net.URI; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; +import static javafx.beans.binding.Bindings.createStringBinding; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; import javafx.geometry.HPos; @@ -93,29 +114,6 @@ import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; -import javax.inject.Named; -import java.io.ByteArrayInputStream; -import java.math.BigInteger; -import java.net.URI; -import java.util.HashMap; -import java.util.concurrent.TimeUnit; - -import static haveno.desktop.main.offer.OfferViewUtil.addPayInfoEntry; -import static haveno.desktop.util.FormBuilder.add2ButtonsWithBox; -import static haveno.desktop.util.FormBuilder.addAddressTextField; -import static haveno.desktop.util.FormBuilder.addBalanceTextField; -import static haveno.desktop.util.FormBuilder.addComboBoxTopLabelTextField; -import static haveno.desktop.util.FormBuilder.addFundsTextfield; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.getEditableValueBox; -import static haveno.desktop.util.FormBuilder.getIconForLabel; -import static haveno.desktop.util.FormBuilder.getNonEditableValueBox; -import static haveno.desktop.util.FormBuilder.getNonEditableValueBoxWithInfo; -import static haveno.desktop.util.FormBuilder.getSmallIconForLabel; -import static haveno.desktop.util.FormBuilder.getTopLabelWithVBox; -import static javafx.beans.binding.Bindings.createStringBinding; - @FxmlView public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOfferViewModel> implements ClosableView, InitializableViewWithTakeOfferData, SelectableView { private final Navigation navigation; @@ -125,6 +123,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer private ScrollPane scrollPane; private GridPane gridPane; + private TitledGroupBg noFundingRequiredTitledGroupBg; + private Label noFundingRequiredLabel; private TitledGroupBg payFundsTitledGroupBg; private TitledGroupBg advancedOptionsGroup; private VBox priceAsPercentageInputBox, amountRangeBox; @@ -156,11 +156,13 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer showTransactionPublishedScreenSubscription, showWarningInvalidBtcDecimalPlacesSubscription, isWaitingForFundsSubscription, offerWarningSubscription, errorMessageSubscription, isOfferAvailableSubscription; + private ChangeListener<BigInteger> missingCoinListener; private int gridRow = 0; private final HashMap<String, Boolean> paymentAccountWarningDisplayed = new HashMap<>(); private boolean offerDetailsWindowDisplayed, zelleWarningDisplayed, fasterPaymentsWarningDisplayed, - takeOfferFromUnsignedAccountWarningDisplayed, payByMailWarningDisplayed, cashAtAtmWarningDisplayed; + takeOfferFromUnsignedAccountWarningDisplayed, payByMailWarningDisplayed, cashAtAtmWarningDisplayed, + australiaPayidWarningDisplayed, paypalWarningDisplayed, cashAppWarningDisplayed; private SimpleBooleanProperty errorPopupDisplayed; private ChangeListener<Boolean> amountFocusedListener, getShowWalletFundedNotificationListener; @@ -192,6 +194,8 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer addAmountPriceGroup(); addOptionsGroup(); + createListeners(); + addButtons(); addOfferAvailabilityLabel(); addFundingGroup(); @@ -269,6 +273,9 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer maybeShowAccountWarning(lastPaymentAccount, model.dataModel.isBuyOffer()); maybeShowPayByMailWarning(lastPaymentAccount, model.dataModel.getOffer()); maybeShowCashAtAtmWarning(lastPaymentAccount, model.dataModel.getOffer()); + maybeShowAustraliaPayidWarning(lastPaymentAccount, model.dataModel.getOffer()); + maybeShowPayPalWarning(lastPaymentAccount, model.dataModel.getOffer()); + maybeShowCashAppWarning(lastPaymentAccount, model.dataModel.getOffer()); if (!model.isRange()) { nextButton.setVisible(false); @@ -304,12 +311,12 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer takeOfferButton.setId("buy-button-big"); nextButton.setId("buy-button"); fundFromSavingsWalletButton.setId("buy-button"); - takeOfferButton.updateText(getTakeOfferLabel(offer, Res.get("shared.buy"))); + takeOfferButton.updateText(getTakeOfferLabel(offer, false)); } else { takeOfferButton.setId("sell-button-big"); nextButton.setId("sell-button"); fundFromSavingsWalletButton.setId("sell-button"); - takeOfferButton.updateText(getTakeOfferLabel(offer, Res.get("shared.sell"))); + takeOfferButton.updateText(getTakeOfferLabel(offer, true)); } priceAsPercentageDescription.setText(model.getPercentagePriceDescription()); @@ -360,7 +367,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer // Called from parent as the view does not get notified when the tab is closed public void onClose() { BigInteger availableBalance = model.dataModel.getAvailableBalance().get(); - if (availableBalance != null && availableBalance.compareTo(BigInteger.valueOf(0)) > 0 && !model.takeOfferCompleted.get() && !DevEnv.isDevMode()) { + if (availableBalance != null && availableBalance.compareTo(BigInteger.ZERO) > 0 && !model.takeOfferCompleted.get() && !DevEnv.isDevMode()) { model.dataModel.swapTradeToSavings(); } } @@ -447,7 +454,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer balanceTextField.setTargetAmount(model.dataModel.getTotalToPay().get()); - if (!DevEnv.isDevMode()) { + if (!DevEnv.isDevMode() && model.dataModel.hasTotalToPay()) { String tradeAmountText = model.isSeller() ? Res.get("takeOffer.takeOfferFundWalletInfo.tradeAmount", model.getTradeAmount()) : ""; String message = Res.get("takeOffer.takeOfferFundWalletInfo.msg", model.getTotalToPayInfo(), @@ -467,17 +474,22 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer // temporarily disabled due to high CPU usage (per issue #4649) //waitingForFundsBusyAnimation.play(); - payFundsTitledGroupBg.setVisible(true); - totalToPayTextField.setVisible(true); - addressTextField.setVisible(true); - qrCodeImageView.setVisible(true); - balanceTextField.setVisible(true); + if (model.getOffer().hasBuyerAsTakerWithoutDeposit()) { + noFundingRequiredTitledGroupBg.setVisible(true); + noFundingRequiredLabel.setVisible(true); + } else { + payFundsTitledGroupBg.setVisible(true); + totalToPayTextField.setVisible(true); + addressTextField.setVisible(true); + qrCodeImageView.setVisible(true); + balanceTextField.setVisible(true); + } totalToPayTextField.setFundsStructure(Res.get("takeOffer.fundsBox.fundsStructure", model.getSecurityDepositWithCode(), model.getTakerFeePercentage())); totalToPayTextField.setContentForInfoPopOver(createInfoPopover()); - if (model.dataModel.getIsXmrWalletFunded().get()) { + if (model.dataModel.getIsXmrWalletFunded().get() && model.dataModel.hasTotalToPay()) { if (walletFundedNotification == null) { walletFundedNotification = new Notification() .headLine(Res.get("notification.walletUpdate.headline")) @@ -487,6 +499,10 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer } } + updateQrCode(); + } + + private void updateQrCode() { final byte[] imageBytes = QRCode .from(getMoneroURI()) .withSize(300, 300) @@ -613,8 +629,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer errorMessageSubscription = EasyBind.subscribe(model.errorMessage, newValue -> { if (newValue != null) { - new Popup().error(Res.get("takeOffer.error.message", model.errorMessage.get()) + "\n\n" + - Res.get("popup.error.tryRestart")) + new Popup().warning(Res.get("takeOffer.error.message", model.errorMessage.get())) .onClose(() -> { errorPopupDisplayed.set(true); model.resetErrorMessage(); @@ -645,7 +660,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer showWarningInvalidBtcDecimalPlacesSubscription = EasyBind.subscribe(model.showWarningInvalidBtcDecimalPlaces, newValue -> { if (newValue) { - new Popup().warning(Res.get("takeOffer.amountPriceBox.warning.invalidBtcDecimalPlaces")).show(); + new Popup().warning(Res.get("takeOffer.amountPriceBox.warning.invalidXmrDecimalPlaces")).show(); model.showWarningInvalidBtcDecimalPlaces.set(false); } }); @@ -674,7 +689,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer } }); - balanceSubscription = EasyBind.subscribe(model.dataModel.getBalance(), balanceTextField::setBalance); + balanceSubscription = EasyBind.subscribe(model.dataModel.getAvailableBalance(), balanceTextField::setBalance); } private void removeSubscriptions() { @@ -688,14 +703,24 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer balanceSubscription.unsubscribe(); } + private void createListeners() { + missingCoinListener = (observable, oldValue, newValue) -> { + if (!newValue.toString().equals("")) { + updateQrCode(); + } + }; + } + private void addListeners() { amountTextField.focusedProperty().addListener(amountFocusedListener); model.dataModel.getShowWalletFundedNotification().addListener(getShowWalletFundedNotificationListener); + model.dataModel.getMissingCoin().addListener(missingCoinListener); } private void removeListeners() { amountTextField.focusedProperty().removeListener(amountFocusedListener); model.dataModel.getShowWalletFundedNotification().removeListener(getShowWalletFundedNotificationListener); + model.dataModel.getMissingCoin().removeListener(missingCoinListener); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -829,7 +854,24 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer } private void addFundingGroup() { - // don't increase gridRow as we removed button when this gets visible + + // no funding required title + noFundingRequiredTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 3, + Res.get("takeOffer.fundsBox.noFundingRequiredTitle"), Layout.COMPACT_GROUP_DISTANCE); + noFundingRequiredTitledGroupBg.getStyleClass().add("last"); + GridPane.setColumnSpan(noFundingRequiredTitledGroupBg, 2); + noFundingRequiredTitledGroupBg.setVisible(false); + + // no funding required description + noFundingRequiredLabel = new AutoTooltipLabel(Res.get("takeOffer.fundsBox.noFundingRequiredDescription")); + noFundingRequiredLabel.setVisible(false); + //GridPane.setRowSpan(noFundingRequiredLabel, 1); + GridPane.setRowIndex(noFundingRequiredLabel, gridRow); + noFundingRequiredLabel.setPadding(new Insets(Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE, 0, 0, 0)); + GridPane.setHalignment(noFundingRequiredLabel, HPos.LEFT); + gridPane.getChildren().add(noFundingRequiredLabel); + + // funding title payFundsTitledGroupBg = addTitledGroupBg(gridPane, gridRow, 3, Res.get("takeOffer.fundsBox.title"), Layout.COMPACT_GROUP_DISTANCE); payFundsTitledGroupBg.getStyleClass().add("last"); @@ -902,13 +944,15 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer takeOfferBox.getChildren().add(takeOfferButton); takeOfferBox.visibleProperty().addListener((observable, oldValue, newValue) -> { - if (newValue) { - fundingHBox.getChildren().remove(cancelButton2); - takeOfferBox.getChildren().add(cancelButton2); - } else if (!fundingHBox.getChildren().contains(cancelButton2)) { - takeOfferBox.getChildren().remove(cancelButton2); - fundingHBox.getChildren().add(cancelButton2); - } + UserThread.execute(() -> { + if (newValue) { + fundingHBox.getChildren().remove(cancelButton2); + takeOfferBox.getChildren().add(cancelButton2); + } else if (!fundingHBox.getChildren().contains(cancelButton2)) { + takeOfferBox.getChildren().remove(cancelButton2); + fundingHBox.getChildren().add(cancelButton2); + } + }); }); cancelButton2 = new AutoTooltipButton(Res.get("shared.cancel")); @@ -917,7 +961,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer cancelButton2.setOnAction(e -> { String key = "CreateOfferCancelAndFunded"; - if (model.dataModel.getIsXmrWalletFunded().get() && + if (model.dataModel.getIsXmrWalletFunded().get() && model.dataModel.hasTotalToPay() && model.dataModel.preferences.showAgain(key)) { new Popup().backgroundInfo(Res.get("takeOffer.alreadyFunded.askCancel")) .closeButtonText(Res.get("shared.no")) @@ -951,8 +995,7 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer return GUIUtil.getMoneroURI( model.dataModel.getAddressEntry().getAddressString(), model.dataModel.getMissingCoin().get(), - model.getPaymentLabel(), - model.dataModel.getXmrWalletService().getWallet()); + model.getPaymentLabel()); } private void addAmountPriceFields() { @@ -1141,6 +1184,57 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer } } + private void maybeShowAustraliaPayidWarning(PaymentAccount paymentAccount, Offer offer) { + if (paymentAccount.getPaymentMethod().getId().equals(PaymentMethod.AUSTRALIA_PAYID_ID) && + !australiaPayidWarningDisplayed && !offer.getExtraInfo().isEmpty()) { + australiaPayidWarningDisplayed = true; + UserThread.runAfter(() -> { + new GenericMessageWindow() + .preamble(Res.get("payment.tradingRestrictions")) + .instruction(offer.getExtraInfo()) + .actionButtonText(Res.get("shared.iConfirm")) + .closeButtonText(Res.get("shared.close")) + .width(Layout.INITIAL_WINDOW_WIDTH) + .onClose(() -> close(false)) + .show(); + }, 500, TimeUnit.MILLISECONDS); + } + } + + private void maybeShowPayPalWarning(PaymentAccount paymentAccount, Offer offer) { + if (paymentAccount.getPaymentMethod().getId().equals(PaymentMethod.PAYPAL_ID) && + !paypalWarningDisplayed && !offer.getExtraInfo().isEmpty()) { + paypalWarningDisplayed = true; + UserThread.runAfter(() -> { + new GenericMessageWindow() + .preamble(Res.get("payment.tradingRestrictions")) + .instruction(offer.getExtraInfo()) + .actionButtonText(Res.get("shared.iConfirm")) + .closeButtonText(Res.get("shared.close")) + .width(Layout.INITIAL_WINDOW_WIDTH) + .onClose(() -> close(false)) + .show(); + }, 500, TimeUnit.MILLISECONDS); + } + } + + private void maybeShowCashAppWarning(PaymentAccount paymentAccount, Offer offer) { + if (paymentAccount.getPaymentMethod().getId().equals(PaymentMethod.CASH_APP_ID) && + !cashAppWarningDisplayed && !offer.getExtraInfo().isEmpty()) { + cashAppWarningDisplayed = true; + UserThread.runAfter(() -> { + new GenericMessageWindow() + .preamble(Res.get("payment.tradingRestrictions")) + .instruction(offer.getExtraInfo()) + .actionButtonText(Res.get("shared.iConfirm")) + .closeButtonText(Res.get("shared.close")) + .width(Layout.INITIAL_WINDOW_WIDTH) + .onClose(() -> close(false)) + .show(); + }, 500, TimeUnit.MILLISECONDS); + } + } + private Tuple2<Label, VBox> getTradeInputBox(HBox amountValueBox, String promptText) { Label descriptionLabel = new AutoTooltipLabel(promptText); descriptionLabel.setId("input-description-label"); @@ -1179,11 +1273,11 @@ public class TakeOfferView extends ActivatableViewAndModel<AnchorPane, TakeOffer } @NotNull - private String getTakeOfferLabel(Offer offer, String direction) { + private String getTakeOfferLabel(Offer offer, boolean isBuyOffer) { return offer.isTraditionalOffer() ? - Res.get("takeOffer.takeOfferButton", direction) : + Res.get("takeOffer.takeOfferButton", isBuyOffer ? Res.get("shared.sell") : Res.get("shared.buy")) : Res.get("takeOffer.takeOfferButtonCrypto", - direction, + isBuyOffer ? Res.get("shared.buy") : Res.get("shared.sell"), offer.getCurrencyCode()); } diff --git a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java index 90607d8a74..c8f21ff0aa 100644 --- a/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/offer/takeoffer/TakeOfferViewModel.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.takeoffer; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.locale.Res; @@ -35,7 +38,6 @@ import haveno.core.util.VolumeUtil; import haveno.core.util.coin.CoinFormatter; import haveno.core.util.coin.CoinUtil; import haveno.core.util.validation.InputValidator; -import haveno.core.xmr.wallet.Restrictions; import haveno.desktop.Navigation; import haveno.desktop.common.model.ActivatableWithDataModel; import haveno.desktop.common.model.ViewModel; @@ -50,6 +52,8 @@ import haveno.network.p2p.P2PService; import haveno.network.p2p.network.CloseConnectionReason; import haveno.network.p2p.network.Connection; import haveno.network.p2p.network.ConnectionListener; +import java.math.BigInteger; +import static javafx.beans.binding.Bindings.createStringBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -62,14 +66,7 @@ import javafx.scene.control.ComboBox; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; import javafx.util.Callback; - import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import java.math.BigInteger; - -import static com.google.common.base.Preconditions.checkNotNull; -import static javafx.beans.binding.Bindings.createStringBinding; class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> implements ViewModel { final TakeOfferDataModel dataModel; @@ -267,7 +264,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im } private void applyTakerFee() { - tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionBTCOnly")); + tradeFeeDescription.set(Res.get("createOffer.tradeFee.descriptionXMROnly")); BigInteger takerFee = dataModel.getTakerFee(); if (takerFee == null) { return; @@ -292,7 +289,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im amountValidationResult.set(result); if (result.isValid) { showWarningInvalidBtcDecimalPlaces.set(!DisplayUtils.hasBtcValidDecimals(userInput, xmrFormatter)); - // only allow max 4 decimal places for btc values + // only allow max 4 decimal places for xmr values setAmountToModel(); // reformat input amount.set(HavenoUtils.formatXmr(dataModel.getAmount().get())); @@ -352,73 +349,79 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im /////////////////////////////////////////////////////////////////////////////////////////// private void applyOfferState(Offer.State state) { - offerWarning.set(null); + UserThread.execute(() -> { + offerWarning.set(null); - // We have 2 situations handled here: - // 1. when clicking take offer in the offerbook screen, we do the availability check - // 2. Before actually taking the offer in the take offer screen, we check again the availability as some time might have passed in the meantime - // So we use the takeOfferRequested flag to display different network_messages depending on the context. - switch (state) { - case UNKNOWN: - break; - case OFFER_FEE_RESERVED: - // irrelevant for taker - break; - case AVAILABLE: - isOfferAvailable.set(true); - updateButtonDisableState(); - break; - case NOT_AVAILABLE: - if (takeOfferRequested) - offerWarning.set(Res.get("takeOffer.failed.offerNotAvailable")); - else - offerWarning.set(Res.get("takeOffer.failed.offerTaken")); - takeOfferRequested = false; - break; - case REMOVED: - if (!takeOfferRequested) - offerWarning.set(Res.get("takeOffer.failed.offerRemoved")); - - takeOfferRequested = false; - break; - case MAKER_OFFLINE: - if (takeOfferRequested) - offerWarning.set(Res.get("takeOffer.failed.offererNotOnline")); - else - offerWarning.set(Res.get("takeOffer.failed.offererOffline")); - takeOfferRequested = false; - break; - default: - log.error("Unhandled offer state: " + state); - break; - } - - updateSpinnerInfo(); - - updateButtonDisableState(); + // We have 2 situations handled here: + // 1. when clicking take offer in the offerbook screen, we do the availability check + // 2. Before actually taking the offer in the take offer screen, we check again the availability as some time might have passed in the meantime + // So we use the takeOfferRequested flag to display different network_messages depending on the context. + switch (state) { + case UNKNOWN: + break; + case OFFER_FEE_RESERVED: + // irrelevant for taker + break; + case AVAILABLE: + isOfferAvailable.set(true); + updateButtonDisableState(); + break; + case NOT_AVAILABLE: + if (takeOfferRequested) + offerWarning.set(Res.get("takeOffer.failed.offerNotAvailable")); + else + offerWarning.set(Res.get("takeOffer.failed.offerTaken")); + takeOfferRequested = false; + break; + case INVALID: + offerWarning.set(Res.get("takeOffer.failed.offerInvalid")); + takeOfferRequested = false; + break; + case REMOVED: + // if (takeOfferRequested) // TODO: show any warning or removed is expected? + // offerWarning.set(Res.get("takeOffer.failed.offerRemoved")); + + takeOfferRequested = false; + break; + case MAKER_OFFLINE: + if (takeOfferRequested) + offerWarning.set(Res.get("takeOffer.failed.offererNotOnline")); + else + offerWarning.set(Res.get("takeOffer.failed.offererOffline")); + takeOfferRequested = false; + break; + default: + log.error("Unhandled offer state: " + state); + break; + } + + updateSpinnerInfo(); + + updateButtonDisableState(); + }); } private void applyTradeErrorMessage(@Nullable String errorMessage) { if (errorMessage != null) { String appendMsg = ""; if (trade != null) { - switch (trade.getState().getPhase()) { - case INIT: - appendMsg = Res.get("takeOffer.error.noFundsLost"); - break; - case DEPOSIT_REQUESTED: - appendMsg = Res.get("takeOffer.error.feePaid"); - break; - case DEPOSITS_PUBLISHED: - case PAYMENT_SENT: - case PAYMENT_RECEIVED: - appendMsg = Res.get("takeOffer.error.depositPublished"); - break; - case COMPLETED: - appendMsg = Res.get("takeOffer.error.payoutPublished"); - break; - default: - break; + if (trade.isPayoutPublished()) appendMsg = Res.get("takeOffer.error.payoutPublished"); + else { + switch (trade.getState().getPhase()) { + case INIT: + appendMsg = Res.get("takeOffer.error.noFundsLost"); + break; + case DEPOSIT_REQUESTED: + appendMsg = Res.get("takeOffer.error.feePaid"); + break; + case DEPOSITS_PUBLISHED: + case PAYMENT_SENT: + case PAYMENT_RECEIVED: + appendMsg = Res.get("takeOffer.error.depositPublished"); + break; + default: + break; + } } } this.errorMessage.set(errorMessage + appendMsg); @@ -490,6 +493,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im connectionListener = new ConnectionListener() { @Override public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) { + if (trade == null) return; // ignore if trade initializing if (connection.getPeersNodeAddressOptional().isPresent() && connection.getPeersNodeAddressOptional().get().equals(offer.getMakerNodeAddress())) { offerWarning.set(Res.get("takeOffer.warning.connectionToPeerLost")); @@ -656,9 +660,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, dataModel.getSecurityDeposit(), dataModel.getAmount().get(), - xmrFormatter, - Restrictions.getMinBuyerSecurityDeposit() - ); + xmrFormatter); } public String getSecurityDepositWithCode() { @@ -669,8 +671,7 @@ class TakeOfferViewModel extends ActivatableWithDataModel<TakeOfferDataModel> im return OfferViewModelUtil.getTradeFeeWithFiatEquivalentAndPercentage(offerUtil, dataModel.getTakerFee(), dataModel.getAmount().get(), - xmrFormatter, - HavenoUtils.getMinMakerFee()); + xmrFormatter); } public String getTakerFeePercentage() { diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java b/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java index 944b07b302..f937fb4add 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/Overlay.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays; @@ -33,13 +33,17 @@ import haveno.desktop.components.AutoTooltipCheckBox; import haveno.desktop.components.AutoTooltipLabel; import haveno.desktop.components.BusyAnimation; import haveno.desktop.main.MainView; +import haveno.desktop.util.CssTheme; import haveno.desktop.util.FormBuilder; import haveno.desktop.util.GUIUtil; +import haveno.desktop.util.Layout; import haveno.desktop.util.Transitions; import javafx.animation.Interpolator; import javafx.animation.KeyFrame; import javafx.animation.KeyValue; import javafx.animation.Timeline; +import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; @@ -48,12 +52,15 @@ import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.NodeOrientation; import javafx.geometry.Pos; +import javafx.scene.Node; import javafx.scene.PerspectiveCamera; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Hyperlink; import javafx.scene.control.Label; +import javafx.scene.control.TextArea; +import javafx.scene.control.Tooltip; import javafx.scene.control.ScrollPane; import javafx.scene.control.ScrollPane.ScrollBarPolicy; import javafx.scene.input.KeyCode; @@ -85,6 +92,8 @@ import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; +import static javafx.scene.input.MouseEvent.MOUSE_CLICKED; + @Slf4j public abstract class Overlay<T extends Overlay<T>> { @@ -158,7 +167,8 @@ public abstract class Overlay<T extends Overlay<T>> { protected boolean useAnimation = true; protected boolean showScrollPane = false; - protected Label headlineIcon, headLineLabel, messageLabel; + protected TextArea messageTextArea; + protected Label headlineIcon, copyIcon, headLineLabel; protected String headLine, message, closeButtonText, actionButtonText, secondaryActionButtonText, dontShowAgainId, dontShowAgainText, truncatedMessage; @@ -748,6 +758,23 @@ public abstract class Overlay<T extends Overlay<T>> { if (headLineLabel != null) { + if (copyIcon != null) { + copyIcon.getStyleClass().add("popup-icon-information"); + copyIcon.setManaged(true); + copyIcon.setVisible(true); + FormBuilder.getIconForLabel(AwesomeIcon.COPY, copyIcon, "1.1em"); + copyIcon.addEventHandler(MOUSE_CLICKED, mouseEvent -> { + if (message != null) { + String forClipboard = headLineLabel.getText() + System.lineSeparator() + message + + System.lineSeparator() + (messageHyperlinks == null ? "" : messageHyperlinks.toString()); + Utilities.copyToClipboard(forClipboard); + Tooltip tp = new Tooltip(Res.get("shared.copiedToClipboard")); + Node node = (Node) mouseEvent.getSource(); + UserThread.runAfter(() -> tp.hide(), 1); + tp.show(node, mouseEvent.getScreenX() + Layout.PADDING, mouseEvent.getScreenY() + Layout.PADDING); + } + }); + } switch (type) { case Information: @@ -802,7 +829,19 @@ public abstract class Overlay<T extends Overlay<T>> { if (headlineStyle != null) headLineLabel.setStyle(headlineStyle); - hBox.getChildren().addAll(headlineIcon, headLineLabel); + if (message != null) { + copyIcon = new Label(); + copyIcon.setManaged(false); + copyIcon.setVisible(false); + copyIcon.setPadding(new Insets(3)); + copyIcon.setTooltip(new Tooltip(Res.get("shared.copyToClipboard"))); + final Pane spacer = new Pane(); + HBox.setHgrow(spacer, Priority.ALWAYS); + spacer.setMinSize(Layout.PADDING, 1); + hBox.getChildren().addAll(headlineIcon, headLineLabel, spacer, copyIcon); + } else { + hBox.getChildren().addAll(headlineIcon, headLineLabel); + } GridPane.setHalignment(hBox, HPos.LEFT); GridPane.setRowIndex(hBox, rowIndex); @@ -813,20 +852,37 @@ public abstract class Overlay<T extends Overlay<T>> { protected void addMessage() { if (message != null) { - messageLabel = new AutoTooltipLabel(truncatedMessage); - messageLabel.setMouseTransparent(true); - messageLabel.setWrapText(true); + messageTextArea = new TextArea(truncatedMessage); + messageTextArea.setEditable(false); + messageTextArea.getStyleClass().add("text-area-no-border"); + messageTextArea.sceneProperty().addListener((o, oldScene, newScene) -> { + if (newScene != null) { + // avoid javafx css warning + CssTheme.loadSceneStyles(newScene, CssTheme.CSS_THEME_LIGHT, false); + messageTextArea.applyCss(); + var text = messageTextArea.lookup(".text"); + + messageTextArea.prefHeightProperty().bind(Bindings.createDoubleBinding(() -> { + return messageTextArea.getFont().getSize() + text.getBoundsInLocal().getHeight(); + }, text.boundsInLocalProperty())); + + text.boundsInLocalProperty().addListener((observableBoundsAfter, boundsBefore, boundsAfter) -> { + Platform.runLater(() -> messageTextArea.requestLayout()); + }); + } + }); + messageTextArea.setWrapText(true); Region messageRegion; if (showScrollPane) { - scrollPane = new ScrollPane(messageLabel); + scrollPane = new ScrollPane(messageTextArea); scrollPane.setHbarPolicy(ScrollBarPolicy.NEVER); scrollPane.setVbarPolicy(ScrollBarPolicy.AS_NEEDED); scrollPane.setFitToWidth(true); messageRegion = scrollPane; } else - messageRegion = messageLabel; + messageRegion = messageTextArea; GridPane.setHalignment(messageRegion, HPos.LEFT); GridPane.setHgrow(messageRegion, Priority.ALWAYS); @@ -858,7 +914,7 @@ public abstract class Overlay<T extends Overlay<T>> { } private void addReportErrorButtons() { - messageLabel.setText(Res.get("popup.reportError", truncatedMessage)); + messageTextArea.setText(Res.get("popup.reportError", truncatedMessage)); Button logButton = new AutoTooltipButton(Res.get("popup.reportError.log")); GridPane.setMargin(logButton, new Insets(20, 0, 0, 0)); @@ -1002,7 +1058,7 @@ public abstract class Overlay<T extends Overlay<T>> { // separate a popup message from optional hyperlinks. [bisq-network/bisq/pull/4637] // hyperlinks are distinguished by [HYPERLINK:] tag // referenced in order from within the message via [1], [2] etc. - // e.g. [HYPERLINK:https://bisq.wiki] + // e.g. [HYPERLINK:https://haveno.exchange/wiki] private void preProcessMessage(String message) { Pattern pattern = Pattern.compile("\\[HYPERLINK:(.*?)\\]"); Matcher matcher = pattern.matcher(message); diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/editor/PasswordPopup.java b/desktop/src/main/java/haveno/desktop/main/overlays/editor/PasswordPopup.java new file mode 100644 index 0000000000..bd169b3a4b --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/main/overlays/editor/PasswordPopup.java @@ -0,0 +1,245 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.main.overlays.editor; + +import haveno.common.util.Utilities; +import haveno.core.locale.GlobalSettings; +import haveno.desktop.components.InputTextField; +import haveno.desktop.main.overlays.Overlay; +import haveno.desktop.util.FormBuilder; +import javafx.animation.Interpolator; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.beans.value.ChangeListener; +import javafx.collections.ObservableList; +import javafx.event.EventHandler; +import javafx.geometry.HPos; +import javafx.geometry.Insets; +import javafx.scene.Camera; +import javafx.scene.PerspectiveCamera; +import javafx.scene.Scene; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.GridPane; +import javafx.scene.transform.Rotate; +import javafx.stage.Modality; +import javafx.util.Duration; +import lombok.extern.slf4j.Slf4j; + +import java.util.function.Consumer; + +import de.jensd.fx.fontawesome.AwesomeIcon; + +import static haveno.desktop.util.FormBuilder.addInputTextField; + +@Slf4j +public class PasswordPopup extends Overlay<PasswordPopup> { + private InputTextField inputTextField; + private static PasswordPopup INSTANCE; + private Consumer<String> actionHandler; + private ChangeListener<Boolean> focusListener; + private EventHandler<KeyEvent> keyEventEventHandler; + + public PasswordPopup() { + width = 600; + type = Type.Confirmation; + if (INSTANCE != null) + INSTANCE.hide(); + INSTANCE = this; + } + + public PasswordPopup onAction(Consumer<String> confirmHandler) { + this.actionHandler = confirmHandler; + return this; + } + + @Override + public void show() { + actionButtonText("CONFIRM"); + createGridPane(); + addHeadLine(); + addContent(); + addButtons(); + applyStyles(); + onShow(); + } + + @Override + protected void onShow() { + super.display(); + + if (stage != null) { + focusListener = (observable, oldValue, newValue) -> { + if (!newValue) + hide(); + }; + stage.focusedProperty().addListener(focusListener); + + Scene scene = stage.getScene(); + if (scene != null) + scene.addEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); + } + } + + @Override + public void hide() { + animateHide(); + } + + @Override + protected void onHidden() { + INSTANCE = null; + + if (stage != null) { + if (focusListener != null) + stage.focusedProperty().removeListener(focusListener); + + Scene scene = stage.getScene(); + if (scene != null) + scene.removeEventHandler(KeyEvent.KEY_RELEASED, keyEventEventHandler); + } + } + + private void addContent() { + gridPane.setPadding(new Insets(64)); + + inputTextField = addInputTextField(gridPane, ++rowIndex, null, -10d); + GridPane.setColumnSpan(inputTextField, 2); + inputTextField.requestFocus(); + + keyEventEventHandler = event -> { + if (Utilities.isAltOrCtrlPressed(KeyCode.R, event)) { + doClose(); + } + }; + } + + @Override + protected void addHeadLine() { + super.addHeadLine(); + GridPane.setHalignment(headLineLabel, HPos.CENTER); + } + + protected void setupKeyHandler(Scene scene) { + scene.setOnKeyPressed(e -> { + if (e.getCode() == KeyCode.ESCAPE) { + e.consume(); + doClose(); + } + if (e.getCode() == KeyCode.ENTER) { + e.consume(); + apply(); + } + }); + } + + @Override + protected void animateHide(Runnable onFinishedHandler) { + if (GlobalSettings.getUseAnimations()) { + double duration = getDuration(300); + Interpolator interpolator = Interpolator.SPLINE(0.25, 0.1, 0.25, 1); + + gridPane.setRotationAxis(Rotate.X_AXIS); + Camera camera = gridPane.getScene().getCamera(); + gridPane.getScene().setCamera(new PerspectiveCamera()); + + Timeline timeline = new Timeline(); + ObservableList<KeyFrame> keyFrames = timeline.getKeyFrames(); + keyFrames.add(new KeyFrame(Duration.millis(0), + new KeyValue(gridPane.rotateProperty(), 0, interpolator), + new KeyValue(gridPane.opacityProperty(), 1, interpolator) + )); + keyFrames.add(new KeyFrame(Duration.millis(duration), + new KeyValue(gridPane.rotateProperty(), -90, interpolator), + new KeyValue(gridPane.opacityProperty(), 0, interpolator) + )); + timeline.setOnFinished(event -> { + gridPane.setRotate(0); + gridPane.setRotationAxis(Rotate.Z_AXIS); + gridPane.getScene().setCamera(camera); + onFinishedHandler.run(); + }); + timeline.play(); + } else { + onFinishedHandler.run(); + } + } + + @Override + protected void animateDisplay() { + if (GlobalSettings.getUseAnimations()) { + double startY = -160; + double duration = getDuration(400); + Interpolator interpolator = Interpolator.SPLINE(0.25, 0.1, 0.25, 1); + Timeline timeline = new Timeline(); + ObservableList<KeyFrame> keyFrames = timeline.getKeyFrames(); + keyFrames.add(new KeyFrame(Duration.millis(0), + new KeyValue(gridPane.opacityProperty(), 0, interpolator), + new KeyValue(gridPane.translateYProperty(), startY, interpolator) + )); + + keyFrames.add(new KeyFrame(Duration.millis(duration), + new KeyValue(gridPane.opacityProperty(), 1, interpolator), + new KeyValue(gridPane.translateYProperty(), 0, interpolator) + )); + + timeline.play(); + } + } + + @Override + protected void createGridPane() { + super.createGridPane(); + gridPane.setPadding(new Insets(15, 15, 30, 30)); + } + + @Override + protected void addButtons() { + buttonDistance = 10; + super.addButtons(); + + actionButton.setOnAction(event -> apply()); + } + + private void apply() { + hide(); + if (actionHandler != null && inputTextField != null) + actionHandler.accept(inputTextField.getText()); + } + + @Override + protected void applyStyles() { + super.applyStyles(); + FormBuilder.getIconForLabel(AwesomeIcon.LOCK, headlineIcon, "1.5em"); + } + + @Override + protected void setModality() { + stage.initOwner(owner.getScene().getWindow()); + stage.initModality(Modality.NONE); + } + + @Override + protected void addEffectToBackground() { + } + + @Override + protected void removeEffectFromBackground() { + } +} diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/editor/PeerInfoWithTagEditor.java b/desktop/src/main/java/haveno/desktop/main/overlays/editor/PeerInfoWithTagEditor.java index 068845a22a..43a2c6d5ba 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/editor/PeerInfoWithTagEditor.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/editor/PeerInfoWithTagEditor.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.editor; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/notifications/Notification.java b/desktop/src/main/java/haveno/desktop/main/overlays/notifications/Notification.java index 261d24c6af..57a9550e3a 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/notifications/Notification.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/notifications/Notification.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.notifications; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationCenter.java b/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationCenter.java index 81c81dfc44..829a0640d5 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationCenter.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationCenter.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.notifications; import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.UserThread; import haveno.core.api.NotificationListener; import haveno.core.locale.Res; @@ -45,19 +46,17 @@ import haveno.desktop.main.support.dispute.client.mediation.MediationClientView; import haveno.desktop.main.support.dispute.client.refund.RefundClientView; import haveno.proto.grpc.NotificationMessage; import haveno.proto.grpc.NotificationMessage.NotificationType; -import javafx.collections.ListChangeListener; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; - -import javax.annotation.Nullable; -import javax.inject.Singleton; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Consumer; +import javafx.collections.ListChangeListener; +import javax.annotation.Nullable; +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.Subscription; @Slf4j @Singleton diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationManager.java b/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationManager.java index d788dce223..f8e332db24 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationManager.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/notifications/NotificationManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.notifications; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/popups/Popup.java b/desktop/src/main/java/haveno/desktop/main/overlays/popups/Popup.java index 416c3566f8..a620706754 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/popups/Popup.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/popups/Popup.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.popups; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/popups/PopupManager.java b/desktop/src/main/java/haveno/desktop/main/overlays/popups/PopupManager.java index 1889a0390c..ed354b4f9a 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/popups/PopupManager.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/popups/PopupManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.popups; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ClosedTradesSummaryWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ClosedTradesSummaryWindow.java index de49b4e1e0..cce9c01663 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ClosedTradesSummaryWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ClosedTradesSummaryWindow.java @@ -1,34 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.portfolio.closedtrades.ClosedTradesViewModel; -import haveno.desktop.util.Layout; -import javafx.geometry.Insets; - -import javax.inject.Inject; -import java.math.BigInteger; -import java.util.Map; - import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel; import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import haveno.desktop.util.Layout; +import java.math.BigInteger; +import java.util.Map; +import javafx.geometry.Insets; public class ClosedTradesSummaryWindow extends Overlay<ClosedTradesSummaryWindow> { private final ClosedTradesViewModel model; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java index 7f1f2574cf..4cefcbde26 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ContractWindow.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; import com.google.common.base.Joiner; +import com.google.inject.Inject; import haveno.common.UserThread; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.locale.CountryUtil; @@ -38,8 +39,17 @@ import haveno.desktop.components.HavenoTextArea; import haveno.desktop.main.MainView; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.util.DisplayUtils; +import static haveno.desktop.util.DisplayUtils.getAccountWitnessDescription; +import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelButton; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextField; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon; +import static haveno.desktop.util.FormBuilder.addLabelExplorerAddressTextField; +import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import haveno.desktop.util.Layout; import haveno.network.p2p.NodeAddress; +import java.util.List; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.Button; @@ -54,18 +64,6 @@ import javafx.stage.Window; import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.Utils; -import javax.inject.Inject; -import java.util.List; - -import static haveno.desktop.util.DisplayUtils.getAccountWitnessDescription; -import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelButton; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextField; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon; -import static haveno.desktop.util.FormBuilder.addLabelExplorerAddressTextField; -import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; - @Slf4j public class ContractWindow extends Overlay<ContractWindow> { private final ArbitrationManager arbitrationManager; @@ -143,7 +141,7 @@ public class ContractWindow extends Overlay<ContractWindow> { DisplayUtils.formatDateTime(offer.getDate()) + " / " + DisplayUtils.formatDateTime(dispute.getTradeDate())); String currencyCode = offer.getCurrencyCode(); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.offerType"), - DisplayUtils.getDirectionBothSides(offer.getDirection())); + DisplayUtils.getDirectionBothSides(offer.getDirection(), offer.isPrivateOffer())); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradePrice"), FormattingUtils.formatPrice(contract.getPrice())); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.tradeAmount"), @@ -154,15 +152,15 @@ public class ContractWindow extends Overlay<ContractWindow> { VolumeUtil.formatVolumeWithCode(contract.getTradeVolume())); String securityDeposit = Res.getWithColAndCap("shared.buyer") + " " + - HavenoUtils.formatXmr(offer.getBuyerSecurityDeposit(), true) + + HavenoUtils.formatXmr(offer.getOfferPayload().getBuyerSecurityDepositForTradeAmount(contract.getTradeAmount()), true) + " / " + Res.getWithColAndCap("shared.seller") + " " + - HavenoUtils.formatXmr(offer.getSellerSecurityDeposit(), true); + HavenoUtils.formatXmr(offer.getOfferPayload().getSellerSecurityDepositForTradeAmount(contract.getTradeAmount()), true); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); addConfirmationLabelTextField(gridPane, ++rowIndex, - Res.get("contractWindow.btcAddresses"), + Res.get("contractWindow.xmrAddresses"), contract.getBuyerPayoutAddressString() + " / " + contract.getSellerPayoutAddressString()); addConfirmationLabelTextField(gridPane, ++rowIndex, diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisplayAlertMessageWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisplayAlertMessageWindow.java index a989bc391c..03f4fa3564 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisplayAlertMessageWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisplayAlertMessageWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; @@ -26,7 +26,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow> { private static final Logger log = LoggerFactory.getLogger(DisplayAlertMessageWindow.class); @@ -41,6 +40,7 @@ public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow type = Type.Attention; } + @Override public void show() { width = 768; // need to set headLine, otherwise the fields will not be created in addHeadLine @@ -75,7 +75,8 @@ public class DisplayAlertMessageWindow extends Overlay<DisplayAlertMessageWindow private void addContent() { checkNotNull(alert, "alertMessage must not be null"); - addMultilineLabel(gridPane, ++rowIndex, alert.getMessage(), 10); + message(alert.getMessage()); + addMessage(); if (alert.isSoftwareUpdateNotification()) { String url = "https://haveno.exchange/downloads"; HyperlinkWithIcon hyperlinkWithIcon = FormBuilder.addLabelHyperlinkWithIcon(gridPane, ++rowIndex, diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisputeSummaryWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisputeSummaryWindow.java index 96efed5af6..ebf1c25309 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisputeSummaryWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/DisputeSummaryWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; @@ -99,6 +99,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { reasonWasOtherRadioButton, reasonWasBankRadioButton, reasonWasOptionTradeRadioButton, reasonWasSellerNotRespondingRadioButton, reasonWasWrongSenderAccountRadioButton, reasonWasPeerWasLateRadioButton, reasonWasTradeAlreadySettledRadioButton; + private CoreDisputesService.PayoutSuggestion payoutSuggestion; // Dispute object of other trade peer. The dispute field is the one from which we opened the close dispute window. private Optional<Dispute> peersDisputeOptional; @@ -211,11 +212,12 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { if (applyPeersDisputeResult) { // If the other peers dispute has been closed we apply the result to ourselves DisputeResult peersDisputeResult = peersDisputeOptional.get().getDisputeResultProperty().get(); - disputeResult.setBuyerPayoutAmount(peersDisputeResult.getBuyerPayoutAmount()); - disputeResult.setSellerPayoutAmount(peersDisputeResult.getSellerPayoutAmount()); + disputeResult.setBuyerPayoutAmountBeforeCost(peersDisputeResult.getBuyerPayoutAmountBeforeCost()); + disputeResult.setSellerPayoutAmountBeforeCost(peersDisputeResult.getSellerPayoutAmountBeforeCost()); disputeResult.setWinner(peersDisputeResult.getWinner()); disputeResult.setReason(peersDisputeResult.getReason()); disputeResult.setSummaryNotes(peersDisputeResult.summaryNotesProperty().get()); + disputeResult.setSubtractFeeFrom(peersDisputeResult.getSubtractFeeFrom()); buyerGetsTradeAmountRadioButton.setDisable(true); buyerGetsAllRadioButton.setDisable(true); @@ -285,11 +287,11 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.tradeFee"), tradeFee); String securityDeposit = Res.getWithColAndCap("shared.buyer") + " " + - HavenoUtils.formatXmr(trade.getBuyerSecurityDeposit(), true) + + HavenoUtils.formatXmr(trade.getBuyer().getSecurityDeposit(), true) + " / " + Res.getWithColAndCap("shared.seller") + " " + - HavenoUtils.formatXmr(trade.getSellerSecurityDeposit(), true); + HavenoUtils.formatXmr(trade.getSeller().getSecurityDeposit(), true); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); } @@ -353,8 +355,8 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { Contract contract = dispute.getContract(); BigInteger tradeAmount = contract.getTradeAmount(); BigInteger available = tradeAmount - .add(trade.getBuyerSecurityDeposit()) - .add(trade.getSellerSecurityDeposit()); + .add(trade.getBuyer().getSecurityDeposit()) + .add(trade.getSeller().getSecurityDeposit()); BigInteger totalAmount = buyerAmount.add(sellerAmount); boolean isRefundAgent = getDisputeManager(dispute) instanceof RefundManager; @@ -363,7 +365,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { // be made return totalAmount.compareTo(available) <= 0; } else { - if (totalAmount.compareTo(BigInteger.valueOf(0)) <= 0) { + if (totalAmount.compareTo(BigInteger.ZERO) <= 0) { return false; } return totalAmount.compareTo(available) == 0; @@ -379,8 +381,8 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { Contract contract = dispute.getContract(); BigInteger available = contract.getTradeAmount() - .add(trade.getBuyerSecurityDeposit()) - .add(trade.getSellerSecurityDeposit()); + .add(trade.getBuyer().getSecurityDeposit()) + .add(trade.getSeller().getSecurityDeposit()); BigInteger enteredAmount = HavenoUtils.parseXmr(inputTextField.getText()); if (enteredAmount.compareTo(available) > 0) { enteredAmount = available; @@ -401,11 +403,10 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { buyerPayoutAmountInputTextField.setText(formattedCounterPartAmount); } - disputeResult.setBuyerPayoutAmount(buyerAmount); - disputeResult.setSellerPayoutAmount(sellerAmount); - disputeResult.setWinner(buyerAmount.compareTo(sellerAmount) > 0 ? - DisputeResult.Winner.BUYER : - DisputeResult.Winner.SELLER); + disputeResult.setBuyerPayoutAmountBeforeCost(buyerAmount); + disputeResult.setSellerPayoutAmountBeforeCost(sellerAmount); + disputeResult.setWinner(buyerAmount.compareTo(sellerAmount) > 0 ? DisputeResult.Winner.BUYER : DisputeResult.Winner.SELLER); // TODO: UI should allow selection of receiver of exact custom amount, otherwise defaulting to bigger receiver. could extend API to specify who pays payout tx fee: buyer, seller, or both + disputeResult.setSubtractFeeFrom(buyerAmount.compareTo(sellerAmount) > 0 ? DisputeResult.SubtractFeeFrom.SELLER_ONLY : DisputeResult.SubtractFeeFrom.BUYER_ONLY); } private void addPayoutAmountTextFields() { @@ -581,21 +582,26 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { Button cancelButton = tuple.second; closeTicketButton.setOnAction(e -> { + closeTicketButton.disableProperty().unbind(); + closeTicketButton.setDisable(true); if (dispute.getSupportType() == SupportType.ARBITRATION && peersDisputeOptional.isPresent() && !peersDisputeOptional.get().isClosed() && !trade.isPayoutPublished()) { // create payout tx - MoneroTxWallet payoutTx = arbitrationManager.createDisputePayoutTx(trade, dispute.getContract(), disputeResult, false); - trade.getProcessModel().setUnsignedPayoutTx((MoneroTxWallet) payoutTx); + MoneroTxWallet payoutTx = arbitrationManager.createDisputePayoutTx(trade, dispute.getContract(), disputeResult, true); // show confirmation showPayoutTxConfirmation(contract, payoutTx, - () -> doClose(closeTicketButton)); + () -> doClose(closeTicketButton, cancelButton), + () -> { + closeTicketButton.setDisable(false); + cancelButton.setDisable(false); + }); } else { - doClose(closeTicketButton); + doClose(closeTicketButton, cancelButton); } }); @@ -606,30 +612,30 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { }); } - private void showPayoutTxConfirmation(Contract contract, MoneroTxWallet payoutTx, ResultHandler resultHandler) { + private void showPayoutTxConfirmation(Contract contract, MoneroTxWallet payoutTx, ResultHandler resultHandler, ResultHandler cancelHandler) { // get buyer and seller destinations (order not preserved) String buyerPayoutAddressString = contract.getBuyerPayoutAddressString(); String sellerPayoutAddressString = contract.getSellerPayoutAddressString(); List<MoneroDestination> destinations = payoutTx.getOutgoingTransfer().getDestinations(); boolean buyerFirst = destinations.get(0).getAddress().equals(buyerPayoutAddressString); - BigInteger buyerPayoutAmount = buyerFirst ? destinations.get(0).getAmount() : destinations.size() == 2 ? destinations.get(1).getAmount() : BigInteger.valueOf(0); - BigInteger sellerPayoutAmount = buyerFirst ? (destinations.size() == 2 ? destinations.get(1).getAmount() : BigInteger.valueOf(0)) : destinations.get(0).getAmount(); + BigInteger buyerPayoutAmount = buyerFirst ? destinations.get(0).getAmount() : destinations.size() == 2 ? destinations.get(1).getAmount() : BigInteger.ZERO; + BigInteger sellerPayoutAmount = buyerFirst ? (destinations.size() == 2 ? destinations.get(1).getAmount() : BigInteger.ZERO) : destinations.get(0).getAmount(); String buyerDetails = ""; - if (buyerPayoutAmount.compareTo(BigInteger.valueOf(0)) > 0) { + if (buyerPayoutAmount.compareTo(BigInteger.ZERO) > 0) { buyerDetails = Res.get("disputeSummaryWindow.close.txDetails.buyer", HavenoUtils.formatXmr(buyerPayoutAmount, true), buyerPayoutAddressString); } String sellerDetails = ""; - if (sellerPayoutAmount.compareTo(BigInteger.valueOf(0)) > 0) { + if (sellerPayoutAmount.compareTo(BigInteger.ZERO) > 0) { sellerDetails = Res.get("disputeSummaryWindow.close.txDetails.seller", HavenoUtils.formatXmr(sellerPayoutAmount, true), sellerPayoutAddressString); } BigInteger outputAmount = buyerPayoutAmount.add(sellerPayoutAmount).add(payoutTx.getFee()); - if (outputAmount.compareTo(BigInteger.valueOf(0)) > 0) { + if (outputAmount.compareTo(BigInteger.ZERO) > 0) { new Popup().width(900) .headLine(Res.get("disputeSummaryWindow.close.txDetails.headline")) .confirmation(Res.get("disputeSummaryWindow.close.txDetails", @@ -640,6 +646,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { .actionButtonText(Res.get("shared.yes")) .onAction(() -> resultHandler.handleResult()) .closeButtonText(Res.get("shared.cancel")) + .onClose(() -> cancelHandler.handleResult()) .show(); } else { // No payout will be made @@ -648,11 +655,14 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { .actionButtonText(Res.get("shared.yes")) .onAction(resultHandler::handleResult) .closeButtonText(Res.get("shared.cancel")) + .onClose(() -> cancelHandler.handleResult()) .show(); } } - private void doClose(Button closeTicketButton) { + private void doClose(Button closeTicketButton, Button cancelButton) { + cancelButton.setDisable(true); + DisputeManager<? extends DisputeList<Dispute>> disputeManager = getDisputeManager(dispute); if (disputeManager == null) { return; @@ -669,7 +679,7 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { closeTicketButton.disableProperty().unbind(); hide(); }, (errMessage, err) -> { - log.error(errMessage); + log.error("Error closing dispute ticket: " + errMessage + "\n", err); new Popup().error(err.toString()).show(); }); } @@ -691,54 +701,51 @@ public class DisputeSummaryWindow extends Overlay<DisputeSummaryWindow> { } private void applyPayoutAmountsToDisputeResult(Toggle selectedTradeAmountToggle) { - CoreDisputesService.DisputePayout payout; if (selectedTradeAmountToggle == buyerGetsTradeAmountRadioButton) { - payout = CoreDisputesService.DisputePayout.BUYER_GETS_TRADE_AMOUNT; + payoutSuggestion = CoreDisputesService.PayoutSuggestion.BUYER_GETS_TRADE_AMOUNT; disputeResult.setWinner(DisputeResult.Winner.BUYER); } else if (selectedTradeAmountToggle == buyerGetsAllRadioButton) { - payout = CoreDisputesService.DisputePayout.BUYER_GETS_ALL; + payoutSuggestion = CoreDisputesService.PayoutSuggestion.BUYER_GETS_ALL; disputeResult.setWinner(DisputeResult.Winner.BUYER); } else if (selectedTradeAmountToggle == sellerGetsTradeAmountRadioButton) { - payout = CoreDisputesService.DisputePayout.SELLER_GETS_TRADE_AMOUNT; + payoutSuggestion = CoreDisputesService.PayoutSuggestion.SELLER_GETS_TRADE_AMOUNT; disputeResult.setWinner(DisputeResult.Winner.SELLER); } else if (selectedTradeAmountToggle == sellerGetsAllRadioButton) { - payout = CoreDisputesService.DisputePayout.SELLER_GETS_ALL; + payoutSuggestion = CoreDisputesService.PayoutSuggestion.SELLER_GETS_ALL; disputeResult.setWinner(DisputeResult.Winner.SELLER); } else { // should not happen throw new IllegalStateException("Unknown radio button"); } - disputesService.applyPayoutAmountsToDisputeResult(payout, dispute, disputeResult, -1); - buyerPayoutAmountInputTextField.setText(HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmount())); - sellerPayoutAmountInputTextField.setText(HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmount())); + disputesService.applyPayoutAmountsToDisputeResult(payoutSuggestion, dispute, disputeResult, -1); + buyerPayoutAmountInputTextField.setText(HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmountBeforeCost())); + sellerPayoutAmountInputTextField.setText(HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmountBeforeCost())); } private void applyTradeAmountRadioButtonStates() { - Contract contract = dispute.getContract(); - BigInteger buyerSecurityDeposit = trade.getBuyerSecurityDeposit(); - BigInteger sellerSecurityDeposit = trade.getSellerSecurityDeposit(); - BigInteger tradeAmount = contract.getTradeAmount(); - BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmount(); - BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmount(); + BigInteger buyerPayoutAmount = disputeResult.getBuyerPayoutAmountBeforeCost(); + BigInteger sellerPayoutAmount = disputeResult.getSellerPayoutAmountBeforeCost(); buyerPayoutAmountInputTextField.setText(HavenoUtils.formatXmr(buyerPayoutAmount)); sellerPayoutAmountInputTextField.setText(HavenoUtils.formatXmr(sellerPayoutAmount)); - if (buyerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit)) && - sellerPayoutAmount.equals(sellerSecurityDeposit)) { - buyerGetsTradeAmountRadioButton.setSelected(true); - } else if (buyerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit)) && - sellerPayoutAmount.equals(BigInteger.valueOf(0))) { - buyerGetsAllRadioButton.setSelected(true); - } else if (sellerPayoutAmount.equals(tradeAmount.add(sellerSecurityDeposit)) - && buyerPayoutAmount.equals(buyerSecurityDeposit)) { - sellerGetsTradeAmountRadioButton.setSelected(true); - } else if (sellerPayoutAmount.equals(tradeAmount.add(buyerSecurityDeposit).add(sellerSecurityDeposit)) - && buyerPayoutAmount.equals(BigInteger.valueOf(0))) { - sellerGetsAllRadioButton.setSelected(true); - } else { - customRadioButton.setSelected(true); + switch (payoutSuggestion) { + case BUYER_GETS_TRADE_AMOUNT: + buyerGetsTradeAmountRadioButton.setSelected(true); + break; + case BUYER_GETS_ALL: + buyerGetsAllRadioButton.setSelected(true); + break; + case SELLER_GETS_TRADE_AMOUNT: + sellerGetsTradeAmountRadioButton.setSelected(true); + break; + case SELLER_GETS_ALL: + sellerGetsAllRadioButton.setSelected(true); + break; + case CUSTOM: + customRadioButton.setSelected(true); + break; } } } diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/EditCustomExplorerWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/EditCustomExplorerWindow.java index 1274ef0e30..c1fab70898 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/EditCustomExplorerWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/EditCustomExplorerWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/FilterWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/FilterWindow.java index e0a3a7ec53..f3a6338005 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/FilterWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/FilterWindow.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.config.Config; @@ -29,6 +30,14 @@ import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.InputTextField; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addLabelCheckBox; +import static haveno.desktop.util.FormBuilder.addTopLabelInputTextField; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.stream.Collectors; import javafx.collections.FXCollections; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -42,17 +51,6 @@ import javafx.scene.layout.HBox; import javafx.scene.layout.Region; import org.apache.commons.lang3.StringUtils; -import javax.inject.Named; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Collectors; - -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addLabelCheckBox; -import static haveno.desktop.util.FormBuilder.addTopLabelInputTextField; - public class FilterWindow extends Overlay<FilterWindow> { private final FilterManager filterManager; private final boolean useDevPrivilegeKeys; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/GenericMessageWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/GenericMessageWindow.java index 1351e29c1c..01d119a479 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/GenericMessageWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/GenericMessageWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java index 6d5f217718..7825c7a610 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/OfferDetailsWindow.java @@ -1,24 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; import com.google.common.base.Joiner; - +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.crypto.KeyRing; import haveno.common.util.Tuple2; @@ -28,6 +29,7 @@ import haveno.core.locale.Res; import haveno.core.monetary.Price; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; +import haveno.core.offer.OpenOffer; import haveno.core.payment.PaymentAccount; import haveno.core.payment.payload.PaymentMethod; import haveno.core.trade.HavenoUtils; @@ -41,9 +43,23 @@ import haveno.desktop.Navigation; import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.BusyAnimation; import haveno.desktop.main.overlays.Overlay; +import haveno.desktop.main.overlays.editor.PasswordPopup; +import haveno.desktop.main.overlays.popups.Popup; +import haveno.desktop.util.CssTheme; import haveno.desktop.util.DisplayUtils; +import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; +import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import haveno.desktop.util.GUIUtil; import haveno.desktop.util.Layout; +import java.math.BigInteger; +import java.util.List; +import java.util.Optional; +import javafx.application.Platform; +import javafx.beans.binding.Bindings; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.scene.control.Button; @@ -58,19 +74,6 @@ import org.fxmisc.easybind.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.inject.Inject; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.List; -import java.util.Optional; - -import static haveno.desktop.util.FormBuilder.addButtonAfterGroup; -import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; - public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { protected static final Logger log = LoggerFactory.getLogger(OfferDetailsWindow.class); @@ -174,7 +177,11 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { List<String> acceptedCountryCodes = offer.getAcceptedCountryCodes(); boolean showAcceptedCountryCodes = acceptedCountryCodes != null && !acceptedCountryCodes.isEmpty(); boolean isF2F = offer.getPaymentMethod().equals(PaymentMethod.F2F); - boolean showExtraInfo = offer.getPaymentMethod().equals(PaymentMethod.F2F) || offer.getPaymentMethod().equals(PaymentMethod.PAY_BY_MAIL); + boolean showExtraInfo = offer.getPaymentMethod().equals(PaymentMethod.F2F) || + offer.getPaymentMethod().equals(PaymentMethod.PAY_BY_MAIL) || + offer.getPaymentMethod().equals(PaymentMethod.AUSTRALIA_PAYID)|| + offer.getPaymentMethod().equals(PaymentMethod.PAYPAL_ID)|| + offer.getPaymentMethod().equals(PaymentMethod.CASH_APP_ID); if (!takeOfferHandlerOptional.isPresent()) rows++; if (showAcceptedBanks) @@ -191,7 +198,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { rows++; } - addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.Offer")); + addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get(offer.isPrivateOffer() ? "shared.Offer" : "shared.Offer")); String counterCurrencyDirectionInfo = ""; String xmrDirectionInfo = ""; @@ -213,18 +220,18 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { xmrDirectionInfo = direction == OfferDirection.BUY ? toReceive : toSpend; } else { addConfirmationLabelLabel(gridPane, rowIndex, offerTypeLabel, - DisplayUtils.getDirectionBothSides(direction), firstRowDistance); + DisplayUtils.getDirectionBothSides(direction, offer.isPrivateOffer()), firstRowDistance); } - String btcAmount = Res.get("shared.btcAmount"); + String amount = Res.get("shared.xmrAmount"); if (takeOfferHandlerOptional.isPresent()) { - addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + xmrDirectionInfo, + addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo, HavenoUtils.formatXmr(tradeAmount, true)); addConfirmationLabelLabel(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(currencyCode) + counterCurrencyDirectionInfo, VolumeUtil.formatVolumeWithCode(offer.getVolumeByAmount(tradeAmount))); } else { - addConfirmationLabelLabel(gridPane, ++rowIndex, btcAmount + xmrDirectionInfo, + addConfirmationLabelLabel(gridPane, ++rowIndex, amount + xmrDirectionInfo, HavenoUtils.formatXmr(offer.getAmount(), true)); - addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minBtcAmount"), + addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.minXmrAmount"), HavenoUtils.formatXmr(offer.getMinAmount(), true)); String volume = VolumeUtil.formatVolumeWithCode(offer.getVolume()); String minVolume = ""; @@ -260,7 +267,8 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { final String makerPaymentAccountId = offer.getMakerPaymentAccountId(); final PaymentAccount myPaymentAccount = user.getPaymentAccount(makerPaymentAccountId); String countryCode = offer.getCountryCode(); - if (offer.isMyOffer(keyRing) && makerPaymentAccountId != null && myPaymentAccount != null) { + boolean isMyOffer = offer.isMyOffer(keyRing); + if (isMyOffer && makerPaymentAccountId != null && myPaymentAccount != null) { addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.myTradingAccount"), myPaymentAccount.getAccountName()); } else { final String method = Res.get(paymentMethod.getId()); @@ -300,7 +308,7 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { tooltip = new Tooltip(CountryUtil.getNamesByCodesString(acceptedCountryCodes)); } } - Label acceptedCountries = addConfirmationLabelLabel(gridPane, ++rowIndex, + Label acceptedCountries = addConfirmationLabelLabel(gridPane, true, ++rowIndex, Res.get("shared.acceptedTakerCountries"), countries).second; if (tooltip != null) { acceptedCountries.setMouseTransparent(false); @@ -314,16 +322,42 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { if (showExtraInfo) { TextArea textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("payment.shared.extraInfo"), "", 0).second; textArea.setText(offer.getExtraInfo()); - textArea.setMinHeight(33); - textArea.setMaxHeight(textArea.getMinHeight()); + textArea.setMaxHeight(200); + textArea.sceneProperty().addListener((o, oldScene, newScene) -> { + if (newScene != null) { + // avoid javafx css warning + CssTheme.loadSceneStyles(newScene, CssTheme.CSS_THEME_LIGHT, false); + textArea.applyCss(); + var text = textArea.lookup(".text"); + + textArea.prefHeightProperty().bind(Bindings.createDoubleBinding(() -> { + return textArea.getFont().getSize() + text.getBoundsInLocal().getHeight(); + }, text.boundsInLocalProperty())); + + text.boundsInLocalProperty().addListener((observableBoundsAfter, boundsBefore, boundsAfter) -> { + Platform.runLater(() -> textArea.requestLayout()); + }); + } + }); textArea.setEditable(false); } + // get amount reserved for the offer + BigInteger reservedAmount = isMyOffer ? offer.getReservedAmount() : null; + + // get offer challenge + OpenOffer myOpenOffer = HavenoUtils.openOfferManager.getOpenOfferById(offer.getId()).orElse(null); + String offerChallenge = myOpenOffer == null ? null : myOpenOffer.getChallenge(); + rows = 3; if (countryCode != null) rows++; if (!isF2F) rows++; + if (reservedAmount != null) + rows++; + if (offerChallenge != null) + rows++; addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("shared.details"), Layout.GROUP_DISTANCE); addConfirmationLabelTextFieldWithCopyIcon(gridPane, rowIndex, Res.get("shared.offerId"), offer.getId(), @@ -334,17 +368,24 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { DisplayUtils.formatDateTime(offer.getDate())); String value = Res.getWithColAndCap("shared.buyer") + " " + - HavenoUtils.formatXmr(offer.getBuyerSecurityDeposit(), true) + + HavenoUtils.formatXmr(offer.getOfferPayload().getMaxBuyerSecurityDeposit(), true) + " / " + Res.getWithColAndCap("shared.seller") + " " + - HavenoUtils.formatXmr(offer.getSellerSecurityDeposit(), true); + HavenoUtils.formatXmr(offer.getOfferPayload().getMaxSellerSecurityDeposit(), true); addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), value); + if (reservedAmount != null) { + addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.reservedAmount"), HavenoUtils.formatXmr(reservedAmount, true)); + } + if (countryCode != null && !isF2F) addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("offerDetailsWindow.countryBank"), CountryUtil.getNameAndCode(countryCode)); + if (offerChallenge != null) + addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("offerDetailsWindow.challenge"), offerChallenge); + if (placeOfferHandlerOptional.isPresent()) { addTitledGroupBg(gridPane, ++rowIndex, 1, Res.get("offerDetailsWindow.commitment"), Layout.GROUP_DISTANCE); final Tuple2<Label, Label> labelLabelTuple2 = addConfirmationLabelLabel(gridPane, rowIndex, Res.get("offerDetailsWindow.agree"), Res.get("createOffer.tac"), @@ -388,13 +429,13 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { ++rowIndex, 1, isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); - AutoTooltipButton button = (AutoTooltipButton) placeOfferTuple.first; - button.setMinHeight(40); - button.setPadding(new Insets(0, 20, 0, 20)); - button.setGraphic(iconView); - button.setGraphicTextGap(10); - button.setId(isBuyerRole ? "buy-button-big" : "sell-button-big"); - button.updateText(isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); + AutoTooltipButton confirmButton = (AutoTooltipButton) placeOfferTuple.first; + confirmButton.setMinHeight(40); + confirmButton.setPadding(new Insets(0, 20, 0, 20)); + confirmButton.setGraphic(iconView); + confirmButton.setGraphicTextGap(10); + confirmButton.setId(isBuyerRole ? "buy-button-big" : "sell-button-big"); + confirmButton.updateText(isPlaceOffer ? placeOfferButtonText : takeOfferButtonText); busyAnimation = placeOfferTuple.second; Label spinnerInfoLabel = placeOfferTuple.third; @@ -408,35 +449,54 @@ public class OfferDetailsWindow extends Overlay<OfferDetailsWindow> { placeOfferTuple.fourth.getChildren().add(cancelButton); - button.setOnAction(e -> { + confirmButton.setOnAction(e -> { if (GUIUtil.canCreateOrTakeOfferOrShowPopup(user, navigation)) { - button.setDisable(true); - cancelButton.setDisable(true); - // temporarily disabled due to high CPU usage (per issue #4649) - // busyAnimation.play(); - if (isPlaceOffer) { - spinnerInfoLabel.setText(Res.get("createOffer.fundsBox.placeOfferSpinnerInfo")); - placeOfferHandlerOptional.ifPresent(Runnable::run); + if (!isPlaceOffer && offer.isPrivateOffer()) { + new PasswordPopup() + .headLine(Res.get("offerbook.takeOffer.enterChallenge")) + .onAction(password -> { + if (offer.getChallengeHash().equals(HavenoUtils.getChallengeHash(password))) { + offer.setChallenge(password); + confirmTakeOfferAux(confirmButton, cancelButton, spinnerInfoLabel, isPlaceOffer); + } else { + new Popup().warning(Res.get("password.wrongPw")).show(); + } + }) + .closeButtonText(Res.get("shared.cancel")) + .show(); } else { - - // subscribe to trade progress - spinnerInfoLabel.setText(Res.get("takeOffer.fundsBox.takeOfferSpinnerInfo") + " 0%"); - numTradesSubscription = EasyBind.subscribe(tradeManager.getNumPendingTrades(), newNum -> { - subscribeToProgress(spinnerInfoLabel); - }); - - takeOfferHandlerOptional.ifPresent(Runnable::run); + confirmTakeOfferAux(confirmButton, cancelButton, spinnerInfoLabel, isPlaceOffer); } } }); } + private void confirmTakeOfferAux(Button button, Button cancelButton, Label spinnerInfoLabel, boolean isPlaceOffer) { + button.setDisable(true); + cancelButton.setDisable(isPlaceOffer ? false : true); // TODO: enable cancel button for taking an offer until messages sent + // temporarily disabled due to high CPU usage (per issue #4649) + // busyAnimation.play(); + if (isPlaceOffer) { + spinnerInfoLabel.setText(Res.get("createOffer.fundsBox.placeOfferSpinnerInfo")); + placeOfferHandlerOptional.ifPresent(Runnable::run); + } else { + + // subscribe to trade progress + spinnerInfoLabel.setText(Res.get("takeOffer.fundsBox.takeOfferSpinnerInfo", "0%")); + numTradesSubscription = EasyBind.subscribe(tradeManager.getNumPendingTrades(), newNum -> { + subscribeToProgress(spinnerInfoLabel); + }); + + takeOfferHandlerOptional.ifPresent(Runnable::run); + } + } + private void subscribeToProgress(Label spinnerInfoLabel) { Trade trade = tradeManager.getTrade(offer.getId()); if (trade == null || initProgressSubscription != null) return; initProgressSubscription = EasyBind.subscribe(trade.initProgressProperty(), newProgress -> { String progress = (int) (newProgress.doubleValue() * 100.0) + "%"; - UserThread.execute(() -> spinnerInfoLabel.setText(Res.get("takeOffer.fundsBox.takeOfferSpinnerInfo") + " " + progress)); + UserThread.execute(() -> spinnerInfoLabel.setText(Res.get("takeOffer.fundsBox.takeOfferSpinnerInfo", progress))); }); } } diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java index 1786b00cee..223933e5c1 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/QRCodeWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SelectDepositTxWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SelectDepositTxWindow.java index 4a7cac56ce..a0ce3fb9b8 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SelectDepositTxWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SelectDepositTxWindow.java @@ -1,25 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.util.FormBuilder; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; import javafx.collections.FXCollections; import javafx.geometry.Insets; import javafx.scene.control.ComboBox; @@ -28,13 +33,6 @@ import javafx.scene.layout.GridPane; import javafx.util.StringConverter; import org.bitcoinj.core.Transaction; -import javax.inject.Inject; -import java.util.List; -import java.util.Optional; -import java.util.function.Consumer; - -import static haveno.desktop.util.FormBuilder.addMultilineLabel; - //TODO might be removed, but leave it for now until sure we will not use it anymore. public class SelectDepositTxWindow extends Overlay<SelectDepositTxWindow> { private ComboBox<Transaction> transactionsComboBox; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendAlertMessageWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendAlertMessageWindow.java index ca8ce6fcfc..a03e7e111f 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendAlertMessageWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendAlertMessageWindow.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.app.DevEnv; import haveno.common.config.Config; import haveno.common.util.Tuple2; @@ -29,6 +30,10 @@ import haveno.desktop.components.InputTextField; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.util.FormBuilder; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addLabelCheckBox; +import static haveno.desktop.util.FormBuilder.addRadioButton; +import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.scene.Scene; @@ -42,13 +47,6 @@ import javafx.scene.input.KeyCode; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; -import javax.inject.Named; - -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addLabelCheckBox; -import static haveno.desktop.util.FormBuilder.addRadioButton; -import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; - public class SendAlertMessageWindow extends Overlay<SendAlertMessageWindow> { private final AlertManager alertManager; private final boolean useDevPrivilegeKeys; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendLogFilesWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendLogFilesWindow.java new file mode 100644 index 0000000000..e5d20d5811 --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendLogFilesWindow.java @@ -0,0 +1,257 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.main.overlays.windows; + +import haveno.desktop.components.AutoTooltipButton; +import haveno.desktop.main.overlays.Overlay; +import haveno.desktop.main.portfolio.pendingtrades.steps.TradeWizardItem; +import haveno.desktop.main.portfolio.pendingtrades.steps.buyer.BuyerStep1View; +import haveno.desktop.main.portfolio.pendingtrades.steps.buyer.BuyerStep2View; +import haveno.desktop.main.portfolio.pendingtrades.steps.buyer.BuyerStep3View; +import haveno.desktop.util.Layout; + +import haveno.core.locale.Res; +import haveno.core.support.dispute.arbitration.ArbitrationManager; +import haveno.core.support.dispute.mediation.FileTransferSender; +import haveno.core.support.dispute.mediation.FileTransferSession; + +import haveno.common.UserThread; + +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ProgressBar; +import javafx.scene.control.Separator; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; + +import javafx.geometry.HPos; +import javafx.geometry.Insets; +import javafx.geometry.Orientation; +import javafx.geometry.Pos; + +import javafx.beans.property.DoubleProperty; +import javafx.beans.property.SimpleDoubleProperty; + +import java.io.IOException; + +import lombok.extern.slf4j.Slf4j; + +import static haveno.desktop.util.FormBuilder.addMultilineLabel; + +@Slf4j +public class SendLogFilesWindow extends Overlay<SendLogFilesWindow> implements FileTransferSession.FtpCallback { + + private final String tradeId; + private final int traderId; + private final ArbitrationManager arbitrationManager; + private Label statusLabel; + private Button sendButton, stopButton; + private final DoubleProperty ftpProgress = new SimpleDoubleProperty(-1); + TradeWizardItem step1, step2, step3; + private FileTransferSender fileTransferSender; + + public SendLogFilesWindow(String tradeId, int traderId, + ArbitrationManager arbitrationManager) { + this.tradeId = tradeId; + this.traderId = traderId; + this.arbitrationManager = arbitrationManager; + type = Type.Attention; + } + + public void show() { + headLine = Res.get("support.sendLogs.title"); + width = 668; + createGridPane(); + addHeadLine(); + addContent(); + addButtons(); + applyStyles(); + display(); + } + + @Override + protected void createGridPane() { + gridPane = new GridPane(); + gridPane.setHgap(5); + gridPane.setVgap(5); + gridPane.setPadding(new Insets(64, 64, 64, 64)); + gridPane.setPrefWidth(width); + } + + void addWizardsToGridPane(TradeWizardItem tradeWizardItem) { + GridPane.setRowIndex(tradeWizardItem, rowIndex++); + GridPane.setColumnIndex(tradeWizardItem, 0); + GridPane.setHalignment(tradeWizardItem, HPos.LEFT); + gridPane.getChildren().add(tradeWizardItem); + } + + void addLineSeparatorToGridPane() { + final Separator separator = new Separator(Orientation.VERTICAL); + separator.setMinHeight(22); + GridPane.setMargin(separator, new Insets(0, 0, 0, 13)); + GridPane.setHalignment(separator, HPos.LEFT); + GridPane.setRowIndex(separator, rowIndex++); + gridPane.getChildren().add(separator); + } + + void addRegionToGridPane() { + final Region region = new Region(); + region.setMinHeight(22); + GridPane.setMargin(region, new Insets(0, 0, 0, 13)); + GridPane.setRowIndex(region, rowIndex++); + gridPane.getChildren().add(region); + } + + private void addContent() { + this.hideCloseButton = true; + + addMultilineLabel(gridPane, ++rowIndex, Res.get("support.sendLogs.backgroundInfo"), 0); + addRegionToGridPane(); + + step1 = new TradeWizardItem(BuyerStep1View.class, Res.get("support.sendLogs.step1"), "1"); + step2 = new TradeWizardItem(BuyerStep2View.class, Res.get("support.sendLogs.step2"), "2"); + step3 = new TradeWizardItem(BuyerStep3View.class, Res.get("support.sendLogs.step3"), "3"); + + addRegionToGridPane(); + addRegionToGridPane(); + addWizardsToGridPane(step1); + addLineSeparatorToGridPane(); + addWizardsToGridPane(step2); + addLineSeparatorToGridPane(); + addWizardsToGridPane(step3); + addRegionToGridPane(); + + ProgressBar progressBar = new ProgressBar(); + progressBar.setMinHeight(19); + progressBar.setMaxHeight(19); + progressBar.setPrefWidth(9305); + progressBar.setVisible(false); + progressBar.progressProperty().bind(ftpProgress); + gridPane.add(progressBar, 0, ++rowIndex); + + statusLabel = addMultilineLabel(gridPane, ++rowIndex, "", -Layout.FLOATING_LABEL_DISTANCE); + statusLabel.getStyleClass().add("sub-info"); + addRegionToGridPane(); + + sendButton = new AutoTooltipButton(Res.get("support.sendLogs.send")); + stopButton = new AutoTooltipButton(Res.get("support.sendLogs.cancel")); + stopButton.setDisable(true); + closeButton = new AutoTooltipButton(Res.get("shared.close")); + sendButton.setOnAction(e -> { + try { + progressBar.setVisible(true); + if (fileTransferSender == null) { + setActiveStep(1); + statusLabel.setText(Res.get("support.sendLogs.init")); + fileTransferSender = arbitrationManager.initLogUpload(this, tradeId, traderId); + UserThread.runAfter(() -> { + fileTransferSender.createZipFileToSend(); + setActiveStep(2); + UserThread.runAfter(() -> { + setActiveStep(3); + try { + fileTransferSender.initSend(); + } catch (IOException ioe) { + log.error(ioe.toString()); + statusLabel.setText(ioe.toString()); + ioe.printStackTrace(); + } + }, 1); + }, 1); + sendButton.setDisable(true); + stopButton.setDisable(false); + } else { + // resend the latest block in the event of a timeout + statusLabel.setText(Res.get("support.sendLogs.retry")); + fileTransferSender.retrySend(); + sendButton.setDisable(true); + } + } catch (IOException ex) { + log.error(ex.toString()); + statusLabel.setText(ex.toString()); + ex.printStackTrace(); + } + }); + stopButton.setOnAction(e -> { + if (fileTransferSender != null) { + fileTransferSender.resetSession(); + statusLabel.setText(Res.get("support.sendLogs.stopped")); + stopButton.setDisable(true); + } + }); + closeButton.setOnAction(e -> { + hide(); + closeHandlerOptional.ifPresent(Runnable::run); + }); + HBox hBox = new HBox(); + hBox.setSpacing(10); + hBox.setAlignment(Pos.CENTER_RIGHT); + GridPane.setRowIndex(hBox, ++rowIndex); + GridPane.setColumnSpan(hBox, 2); + GridPane.setColumnIndex(hBox, 0); + hBox.getChildren().addAll(sendButton, stopButton, closeButton); + gridPane.getChildren().add(hBox); + GridPane.setMargin(hBox, new Insets(10, 0, 0, 0)); + } + + void setActiveStep(int step) { + if (step < 1) { + step1.setDisabled(); + step2.setDisabled(); + step3.setDisabled(); + } else if (step == 1) { + step1.setActive(); + } else if (step == 2) { + step1.setCompleted(); + step2.setActive(); + } else if (step == 3) { + step2.setCompleted(); + step3.setActive(); + } else { + step3.setCompleted(); + } + } + + @Override + public void onFtpProgress(double progressPct) { + UserThread.execute(() -> { + if (progressPct > 0.0) { + statusLabel.setText(String.format(Res.get("support.sendLogs.progress"), progressPct * 100)); + sendButton.setDisable(true); + } + ftpProgress.set(progressPct); + }); + } + @Override + public void onFtpComplete(FileTransferSession session) { + UserThread.execute(() -> { + setActiveStep(4); // all finished + statusLabel.setText(Res.get("support.sendLogs.finished")); + stopButton.setDisable(true); + }); + } + + @Override + public void onFtpTimeout(String statusMsg, FileTransferSession session) { + UserThread.execute(() -> { + statusLabel.setText(statusMsg + "\r\n" + Res.get("support.sendLogs.command")); + sendButton.setDisable(false); + }); + } +} diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendPrivateNotificationWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendPrivateNotificationWindow.java index 6990cf65e5..e8e70ff714 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendPrivateNotificationWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SendPrivateNotificationWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ShowWalletDataWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ShowWalletDataWindow.java index 754ed678ea..6b2545c2bd 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/ShowWalletDataWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/ShowWalletDataWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignPaymentAccountsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignPaymentAccountsWindow.java index 798414900e..fe8b8c9009 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignPaymentAccountsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignPaymentAccountsWindow.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.util.Tuple2; import haveno.common.util.Tuple3; @@ -34,6 +36,22 @@ import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.InputTextField; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.addComboBox; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addLabelCheckBox; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addTopLabelDatePicker; +import static haveno.desktop.util.FormBuilder.addTopLabelListView; +import static haveno.desktop.util.FormBuilder.removeRowsFromGridPane; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.geometry.HPos; @@ -54,26 +72,6 @@ import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.Utils; -import javax.inject.Inject; -import javax.inject.Named; -import java.time.Instant; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.stream.Collectors; - -import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.addComboBox; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addLabelCheckBox; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; -import static haveno.desktop.util.FormBuilder.addTopLabelDatePicker; -import static haveno.desktop.util.FormBuilder.addTopLabelListView; -import static haveno.desktop.util.FormBuilder.removeRowsFromGridPane; - @Slf4j public class SignPaymentAccountsWindow extends Overlay<SignPaymentAccountsWindow> { diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignSpecificWitnessWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignSpecificWitnessWindow.java index 880494b84f..f008dd7b9e 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignSpecificWitnessWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignSpecificWitnessWindow.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; import haveno.common.util.Tuple2; import haveno.common.util.Utilities; import haveno.core.account.witness.AccountAgeWitness; @@ -28,6 +29,12 @@ import haveno.desktop.components.HavenoTextArea; import haveno.desktop.components.InputTextField; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addTopLabelTextField; +import static haveno.desktop.util.FormBuilder.removeRowsFromGridPane; +import java.util.Date; import javafx.geometry.VPos; import javafx.scene.control.TextArea; import javafx.scene.layout.GridPane; @@ -36,15 +43,6 @@ import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.Utils; -import javax.inject.Inject; -import java.util.Date; - -import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; -import static haveno.desktop.util.FormBuilder.addTopLabelTextField; -import static haveno.desktop.util.FormBuilder.removeRowsFromGridPane; - @Slf4j public class SignSpecificWitnessWindow extends Overlay<SignSpecificWitnessWindow> { diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignUnsignedPubKeysWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignUnsignedPubKeysWindow.java index c840a718ec..6b618adf68 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignUnsignedPubKeysWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SignUnsignedPubKeysWindow.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; import haveno.common.crypto.Hash; import haveno.common.util.Tuple3; import haveno.common.util.Utilities; @@ -28,6 +29,12 @@ import haveno.desktop.components.AutoTooltipButton; import haveno.desktop.components.InputTextField; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addTopLabelListView; +import static haveno.desktop.util.FormBuilder.removeRowsFromGridPane; +import java.util.ArrayList; +import java.util.List; import javafx.collections.FXCollections; import javafx.geometry.VPos; import javafx.scene.control.Label; @@ -40,15 +47,6 @@ import javafx.util.Callback; import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.Utils; -import javax.inject.Inject; -import java.util.ArrayList; -import java.util.List; - -import static haveno.desktop.util.FormBuilder.add2ButtonsAfterGroup; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addTopLabelListView; -import static haveno.desktop.util.FormBuilder.removeRowsFromGridPane; - @Slf4j public class SignUnsignedPubKeysWindow extends Overlay<SignUnsignedPubKeysWindow> { diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SwiftPaymentDetails.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SwiftPaymentDetails.java index 178c3debb9..93810ad67c 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/SwiftPaymentDetails.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/SwiftPaymentDetails.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TacWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TacWindow.java index a25666d3d2..755e814076 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TacWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TacWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; @@ -41,7 +41,7 @@ public class TacWindow extends Overlay<TacWindow> { this.width = primaryScreenBoundsWidth * 0.8; log.warn("Very small screen: primaryScreenBounds=" + primaryScreenBounds.toString()); } else { - width = 1100; + width = 1250; } } @@ -70,15 +70,14 @@ public class TacWindow extends Overlay<TacWindow> { "accordance with the Haveno arbitration rules as at present in force. The arbitration is conducted online. " + "The language to be used in the arbitration proceedings shall be English if not otherwise stated.\n\n" + - "6. The user confirms that they have read and agreed to the rules regarding the dispute process:\n" + + "6. The user confirms that they have read and agreed to the rules regarding the trade and dispute processes:\n" + " - You must complete trades within the maximum duration specified for each payment method.\n" + " - Leave the \"reason for payment\" field empty. DO NOT put the trade ID or any other text like 'monero', 'XMR', or 'Haveno'.\n" + - " - If the bank of the fiat sender charges fees, the sender (" + Res.getBaseCurrencyCode() + " buyer) has to cover the fees.\n" + + " - If the bank of the fiat sender charges fees, the fiat sender (" + Res.getBaseCurrencyCode() + " buyer) has to cover the fees.\n" + + " - If either trader opens a dispute, the arbitrator can settle the dispute and pay out trade funds accordingly.\n" + " - In case of arbitration, you must cooperate with the arbitrator and respond to each message within 48 hours.\n" + - " - In case of arbitration, the decision of the arbitrator is final.\n" + - " - The arbitrator may charge a small fee (max. the traders security deposit) as compensation for their work.\n"; + " - The arbitrator may penalize offer makers and traders for breaching Haveno rules and the principle of acting in good faith within the network, up to the value of the security deposit.\n"; message(text); - showScrollPane(); actionButtonText(Res.get("tacWindow.agree")); closeButtonText(Res.get("tacWindow.disagree")); onClose(HavenoApp.getShutDownHandler()); @@ -90,11 +89,11 @@ public class TacWindow extends Overlay<TacWindow> { protected void addMessage() { super.addMessage(); String fontStyleClass = smallScreen ? "small-text" : "normal-text"; - messageLabel.getStyleClass().add(fontStyleClass); + messageTextArea.getStyleClass().add(fontStyleClass); // TODO: link to the wiki // HyperlinkWithIcon hyperlinkWithIcon = addHyperlinkWithIcon(gridPane, ++rowIndex, Res.get("tacWindow.arbitrationSystem"), - // "https://bisq.wiki/Dispute_resolution"); + // "https://haveno.exchange/wiki/Dispute_resolution"); // hyperlinkWithIcon.getStyleClass().add(fontStyleClass); // GridPane.setMargin(hyperlinkWithIcon, new Insets(-6, 0, -20, -4)); } diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TorNetworkSettingsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TorNetworkSettingsWindow.java index 1899041b3a..3d65d0e9c7 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TorNetworkSettingsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TorNetworkSettingsWindow.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.UserThread; import haveno.common.util.Tuple2; import haveno.common.util.Tuple4; @@ -30,9 +32,19 @@ import haveno.desktop.components.BusyAnimation; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; +import static haveno.desktop.util.FormBuilder.addComboBox; +import static haveno.desktop.util.FormBuilder.addLabel; +import static haveno.desktop.util.FormBuilder.addRadioButton; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; import haveno.desktop.util.Layout; import haveno.network.p2p.network.DefaultPluggableTransports; import haveno.network.p2p.network.NetworkNode; +import java.io.IOException; +import java.net.URI; +import java.util.Arrays; +import java.util.concurrent.TimeUnit; import javafx.collections.FXCollections; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -52,20 +64,6 @@ import javafx.scene.layout.Priority; import javafx.util.StringConverter; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.io.IOException; -import java.net.URI; -import java.util.Arrays; -import java.util.concurrent.TimeUnit; - -import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; -import static haveno.desktop.util.FormBuilder.addComboBox; -import static haveno.desktop.util.FormBuilder.addLabel; -import static haveno.desktop.util.FormBuilder.addRadioButton; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelTextArea; - @Slf4j @Singleton public class TorNetworkSettingsWindow extends Overlay<TorNetworkSettingsWindow> { diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java index 0decace925..0484305792 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeDetailsWindow.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.util.Tuple3; import haveno.common.util.Utilities; @@ -37,6 +39,12 @@ import haveno.desktop.components.HavenoTextArea; import haveno.desktop.main.MainView; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.util.DisplayUtils; +import static haveno.desktop.util.DisplayUtils.getAccountWitnessDescription; +import static haveno.desktop.util.FormBuilder.add2ButtonsWithBox; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextField; +import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; import haveno.desktop.util.Layout; import haveno.network.p2p.NodeAddress; import javafx.beans.property.IntegerProperty; @@ -59,16 +67,6 @@ import javafx.stage.Window; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.inject.Inject; -import javax.inject.Named; - -import static haveno.desktop.util.DisplayUtils.getAccountWitnessDescription; -import static haveno.desktop.util.FormBuilder.add2ButtonsWithBox; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextArea; -import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextField; -import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; - public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> { protected static final Logger log = LoggerFactory.getLogger(TradeDetailsWindow.class); @@ -155,7 +153,7 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> { xmrDirectionInfo = toSpend; } - addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.btcAmount") + xmrDirectionInfo, + addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.xmrAmount") + xmrDirectionInfo, HavenoUtils.formatXmr(trade.getAmount(), true)); addConfirmationLabelTextField(gridPane, ++rowIndex, VolumeUtil.formatVolumeLabel(offer.getCurrencyCode()) + counterCurrencyDirectionInfo, @@ -185,12 +183,12 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> { rows++; } - if (trade.getPayoutTxId() != null) - rows++; boolean showDisputedTx = arbitrationManager.findOwnDispute(trade.getId()).isPresent() && arbitrationManager.findOwnDispute(trade.getId()).get().getDisputePayoutTxId() != null; if (showDisputedTx) rows++; + else if (trade.getPayoutTxId() != null) + rows++; if (trade.hasFailed()) rows += 2; if (trade.getTradePeerNodeAddress() != null) @@ -203,11 +201,11 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> { DisplayUtils.formatDateTime(trade.getDate())); String securityDeposit = Res.getWithColAndCap("shared.buyer") + " " + - HavenoUtils.formatXmr(offer.getBuyerSecurityDeposit(), true) + + HavenoUtils.formatXmr(offer.getMaxBuyerSecurityDeposit(), true) + " / " + Res.getWithColAndCap("shared.seller") + " " + - HavenoUtils.formatXmr(offer.getSellerSecurityDeposit(), true); + HavenoUtils.formatXmr(offer.getMaxSellerSecurityDeposit(), true); addConfirmationLabelTextField(gridPane, ++rowIndex, Res.get("shared.securityDeposit"), securityDeposit); NodeAddress arbitratorNodeAddress = trade.getArbitratorNodeAddress(); @@ -246,16 +244,18 @@ public class TradeDetailsWindow extends Overlay<TradeDetailsWindow> { if (trade.getMaker().getDepositTxHash() != null) addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.makerDepositTransactionId"), trade.getMaker().getDepositTxHash()); - if (trade.getTaker().getDepositTxHash() != null) + if (trade.getTaker().getDepositTxHash() != null) addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.takerDepositTransactionId"), trade.getTaker().getDepositTxHash()); - if (trade.getPayoutTxId() != null && !trade.getPayoutTxId().isBlank()) - addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.payoutTxId"), - trade.getPayoutTxId()); - if (showDisputedTx) + + if (showDisputedTx) { addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("tradeDetailsWindow.disputedPayoutTxId"), arbitrationManager.findOwnDispute(trade.getId()).get().getDisputePayoutTxId()); + } else if (trade.getPayoutTxId() != null && !trade.getPayoutTxId().isBlank()) { + addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("shared.payoutTxId"), + trade.getPayoutTxId()); + } if (trade.hasFailed()) { textArea = addConfirmationLabelTextArea(gridPane, ++rowIndex, Res.get("shared.errorMessage"), "", 0).second; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeFeedbackWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeFeedbackWindow.java index 092f099078..76d414b380 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeFeedbackWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TradeFeedbackWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; @@ -62,7 +62,7 @@ public class TradeFeedbackWindow extends Overlay<TradeFeedbackWindow> { gridPane.getChildren().add(messageLabel2); HyperlinkWithIcon matrix = addHyperlinkWithIcon(gridPane, ++rowIndex, "https://matrix.to/#/#haveno:monero.social", - "https://matrix.to/#/#haveno:monero.social", 40); + "https://matrix.to/#/%23haveno:monero.social", 40); GridPane.setMargin(matrix, new Insets(-6, 0, 10, 0)); AutoTooltipLabel messageLabel3 = new AutoTooltipLabel(Res.get("tradeFeedbackWindow.msg.part3")); diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxDetailsWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxDetailsWindow.java new file mode 100644 index 0000000000..1af5d97fbf --- /dev/null +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxDetailsWindow.java @@ -0,0 +1,108 @@ +/* + * This file is part of Haveno. + * + * Haveno is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Haveno is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.desktop.main.overlays.windows; + +import haveno.core.locale.Res; +import haveno.core.trade.HavenoUtils; +import haveno.core.xmr.wallet.XmrWalletService; +import haveno.desktop.main.funds.transactions.TransactionsListItem; +import haveno.desktop.main.overlays.Overlay; +import javafx.scene.layout.GridPane; +import javafx.scene.layout.Region; +import monero.wallet.model.MoneroTxWallet; + +import static haveno.desktop.util.FormBuilder.addConfirmationLabelLabel; +import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithCopyIcon; +import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; + +import java.math.BigInteger; + +import com.google.inject.Inject; + +public class TxDetailsWindow extends Overlay<TxDetailsWindow> { + + private XmrWalletService xmrWalletService; + private TransactionsListItem item; + + @Inject + public TxDetailsWindow(XmrWalletService xmrWalletService) { + this.xmrWalletService = xmrWalletService; + } + + public void show(TransactionsListItem item) { + this.item = item; + rowIndex = -1; + width = 918; + createGridPane(); + gridPane.setHgap(15); + addHeadLine(); + addContent(); + addButtons(); + addDontShowAgainCheckBox(); + applyStyles(); + display(); + } + + protected void addContent() { + int rows = 10; + MoneroTxWallet tx = item.getTx(); + String memo = tx.getNote(); + if (memo != null && !"".equals(memo)) rows++; + String txKey = null; + boolean isOutgoing = tx.getOutgoingTransfer() != null; + if (isOutgoing) { + try { + txKey = xmrWalletService.getWallet().getTxKey(tx.getHash()); + } catch (Exception e) { + // TODO (monero-java): wallet.getTxKey() should return null if key does not exist instead of throwing exception + } + } + if (txKey != null && !"".equals(txKey)) rows++; + + // add title + addTitledGroupBg(gridPane, ++rowIndex, rows, Res.get("txDetailsWindow.headline")); + Region spacer = new Region(); + spacer.setMinHeight(15); + gridPane.add(spacer, 0, ++rowIndex); + + // add sent or received note + String resKey = isOutgoing ? "txDetailsWindow.xmr.noteSent" : "txDetailsWindow.xmr.noteReceived"; + GridPane.setColumnSpan(addMultilineLabel(gridPane, ++rowIndex, Res.get(resKey), 0), 2); + spacer = new Region(); + spacer.setMinHeight(15); + gridPane.add(spacer, 0, ++rowIndex); + + // add tx fields + addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.dateTime"), item.getDateString()); + BigInteger amount; + if (isOutgoing) { + addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("txDetailsWindow.sentTo"), item.getAddressString()); + amount = tx.getOutgoingAmount(); + } else { + addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("txDetailsWindow.receivedWith"), item.getAddressString()); + amount = tx.getIncomingAmount(); + } + addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.amount"), HavenoUtils.formatXmr(amount)); + addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("shared.txFee"), HavenoUtils.formatXmr(tx.getFee())); + if (memo != null && !"".equals(memo)) addConfirmationLabelLabel(gridPane, ++rowIndex, Res.get("funds.withdrawal.memoLabel"), memo); + if (txKey != null && !"".equals(txKey)) addConfirmationLabelTextFieldWithCopyIcon(gridPane, ++rowIndex, Res.get("txDetailsWindow.txKey"), txKey); + addLabelTxIdTextField(gridPane, ++rowIndex, Res.get("txDetailsWindow.txId"), tx.getHash()); + } +} diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxDetails.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxWithdrawWindow.java similarity index 84% rename from desktop/src/main/java/haveno/desktop/main/overlays/windows/TxDetails.java rename to desktop/src/main/java/haveno/desktop/main/overlays/windows/TxWithdrawWindow.java index 2100e22ea2..f3dfc654b8 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxDetails.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/TxWithdrawWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; @@ -28,12 +28,12 @@ import static haveno.desktop.util.FormBuilder.addConfirmationLabelTextFieldWithC import static haveno.desktop.util.FormBuilder.addLabelTxIdTextField; import static haveno.desktop.util.FormBuilder.addMultilineLabel; -public class TxDetails extends Overlay<TxDetails> { +public class TxWithdrawWindow extends Overlay<TxWithdrawWindow> { protected String txId, address, amount, fee, memo; protected TxIdTextField txIdTextField; - public TxDetails(String txId, String address, String amount, String fee, String memo) { + public TxWithdrawWindow(String txId, String address, String amount, String fee, String memo) { type = Type.Attention; this.txId = txId; this.address = address; @@ -59,7 +59,7 @@ public class TxDetails extends Overlay<TxDetails> { protected void addContent() { GridPane.setColumnSpan( - addMultilineLabel(gridPane, ++rowIndex, Res.get("txDetailsWindow.xmr.note"), 0), 2); + addMultilineLabel(gridPane, ++rowIndex, Res.get("txDetailsWindow.xmr.noteSent"), 0), 2); Region spacer = new Region(); spacer.setMinHeight(20); gridPane.add(spacer, 0, ++rowIndex); diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/UnlockDisputeAgentRegistrationWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/UnlockDisputeAgentRegistrationWindow.java index 6a84138ff2..b7313f1a35 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/UnlockDisputeAgentRegistrationWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/UnlockDisputeAgentRegistrationWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateAmazonGiftCardAccountWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateAmazonGiftCardAccountWindow.java index bfe18e2be7..fca183d05d 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateAmazonGiftCardAccountWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateAmazonGiftCardAccountWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateRevolutAccountWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateRevolutAccountWindow.java index 6c152a78b5..413d375f06 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateRevolutAccountWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/UpdateRevolutAccountWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; @@ -66,7 +66,7 @@ public class UpdateRevolutAccountWindow extends Overlay<UpdateRevolutAccountWind private void addContent() { addLabel(gridPane, ++rowIndex, Res.get("payment.account.revolut.addUserNameInfo", Res.get("payment.revolut.info"), revolutAccount.getAccountName())); - userNameInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("payment.account.userName"), Layout.COMPACT_FIRST_ROW_DISTANCE); + userNameInputTextField = addInputTextField(gridPane, ++rowIndex, Res.get("payment.account.username"), Layout.COMPACT_FIRST_ROW_DISTANCE); userNameInputTextField.setValidator(revolutValidator); userNameInputTextField.textProperty().addListener((observable, oldValue, newValue) -> actionButton.setDisable(!revolutValidator.validate(newValue).isValid)); @@ -81,7 +81,7 @@ public class UpdateRevolutAccountWindow extends Overlay<UpdateRevolutAccountWind actionButton.setOnAction(event -> { String userName = userNameInputTextField.getText(); if (revolutValidator.validate(userName).isValid) { - revolutAccount.setUserName(userName); + revolutAccount.setUsername(userName); user.requestPersistence(); closeHandlerOptional.ifPresent(Runnable::run); hide(); diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/VerifyDisputeResultSignatureWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/VerifyDisputeResultSignatureWindow.java index afbb6a3e59..fd60d07193 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/VerifyDisputeResultSignatureWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/VerifyDisputeResultSignatureWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/WalletPasswordWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/WalletPasswordWindow.java index 9a0d65ddf3..dbdc6696d2 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/WalletPasswordWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/WalletPasswordWindow.java @@ -1,23 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; +import static com.google.common.base.Preconditions.checkArgument; import com.google.common.base.Splitter; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.IncorrectPasswordException; import haveno.common.util.Tuple2; @@ -32,7 +35,18 @@ import haveno.desktop.components.PasswordTextField; import haveno.desktop.main.SharedPresentation; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.addPasswordTextField; +import static haveno.desktop.util.FormBuilder.addPrimaryActionButton; +import static haveno.desktop.util.FormBuilder.addTextArea; +import static haveno.desktop.util.FormBuilder.addTopLabelDatePicker; import haveno.desktop.util.Layout; +import java.io.File; +import java.io.IOException; +import java.time.Instant; +import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZoneOffset; +import static javafx.beans.binding.Bindings.createBooleanBinding; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.value.ChangeListener; @@ -54,22 +68,6 @@ import org.bitcoinj.crypto.MnemonicCode; import org.bitcoinj.crypto.MnemonicException; import org.bitcoinj.wallet.DeterministicSeed; -import javax.inject.Inject; -import javax.inject.Named; -import java.io.File; -import java.io.IOException; -import java.time.Instant; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZoneOffset; - -import static com.google.common.base.Preconditions.checkArgument; -import static haveno.desktop.util.FormBuilder.addPasswordTextField; -import static haveno.desktop.util.FormBuilder.addPrimaryActionButton; -import static haveno.desktop.util.FormBuilder.addTextArea; -import static haveno.desktop.util.FormBuilder.addTopLabelDatePicker; -import static javafx.beans.binding.Bindings.createBooleanBinding; - @Slf4j public class WalletPasswordWindow extends Overlay<WalletPasswordWindow> { private final CoreAccountService accountService; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/WebCamWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/WebCamWindow.java index 88a7abb2c0..fd3bf31acf 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/WebCamWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/WebCamWindow.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DisplayUpdateDownloadWindow.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DisplayUpdateDownloadWindow.java index ce63422887..12974cb6f3 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DisplayUpdateDownloadWindow.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DisplayUpdateDownloadWindow.java @@ -1,24 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows.downloadupdate; import com.google.common.base.Joiner; -import com.jfoenix.controls.JFXProgressBar; +import static com.google.common.base.Preconditions.checkNotNull; import haveno.common.config.Config; import haveno.common.util.Utilities; import haveno.core.alert.Alert; @@ -28,6 +28,18 @@ import haveno.desktop.components.AutoTooltipLabel; import haveno.desktop.components.BusyAnimation; import haveno.desktop.main.overlays.Overlay; import haveno.desktop.main.overlays.popups.Popup; +import static haveno.desktop.util.FormBuilder.addLabel; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.Scanner; import javafx.beans.value.ChangeListener; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -43,21 +55,6 @@ import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import lombok.extern.slf4j.Slf4j; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.PrintWriter; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Scanner; - -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.desktop.util.FormBuilder.addLabel; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; - @Slf4j public class DisplayUpdateDownloadWindow extends Overlay<DisplayUpdateDownloadWindow> { private final Alert alert; @@ -134,7 +131,7 @@ public class DisplayUpdateDownloadWindow extends Overlay<DisplayUpdateDownloadWi downloadingFileLabel.setOpacity(0.2); GridPane.setHalignment(downloadingFileLabel, HPos.LEFT); - progressBar = new JFXProgressBar(0L); + progressBar = new ProgressBar(0L); progressBar.setMaxHeight(4); progressBar.managedProperty().bind(progressBar.visibleProperty()); diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DownloadTask.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DownloadTask.java index a307b742f3..4d4550174a 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DownloadTask.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/DownloadTask.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows.downloadupdate; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstaller.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstaller.java index d24de49e7c..8bc4080fb6 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstaller.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstaller.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows.downloadupdate; diff --git a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTask.java b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTask.java index 89a36d7d42..96f69889e0 100644 --- a/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTask.java +++ b/desktop/src/main/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTask.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows.downloadupdate; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/PortfolioView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/PortfolioView.java index 982f3e787c..3b17109a29 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/PortfolioView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/PortfolioView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio; +import com.google.inject.Inject; +import haveno.common.UserThread; import haveno.core.locale.Res; import haveno.core.offer.OfferPayload; import haveno.core.offer.OpenOffer; @@ -34,15 +36,13 @@ import haveno.desktop.main.portfolio.editoffer.EditOfferView; import haveno.desktop.main.portfolio.failedtrades.FailedTradesView; import haveno.desktop.main.portfolio.openoffer.OpenOffersView; import haveno.desktop.main.portfolio.pendingtrades.PendingTradesView; +import java.util.List; import javafx.beans.value.ChangeListener; import javafx.collections.ListChangeListener; import javafx.fxml.FXML; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; - import javax.annotation.Nullable; -import javax.inject.Inject; -import java.util.List; @FxmlView public class PortfolioView extends ActivatableView<TabPane, Void> { @@ -140,8 +140,10 @@ public class PortfolioView extends ActivatableView<TabPane, Void> { @Override protected void activate() { failedTradesManager.getObservableList().addListener((ListChangeListener<Trade>) c -> { - if (failedTradesManager.getObservableList().size() > 0 && root.getTabs().size() == 3) - root.getTabs().add(failedTradesTab); + UserThread.execute(() -> { + if (failedTradesManager.getObservableList().size() > 0 && root.getTabs().size() == 3) + root.getTabs().add(failedTradesTab); + }); }); if (failedTradesManager.getObservableList().size() > 0 && root.getTabs().size() == 3) root.getTabs().add(failedTradesTab); @@ -192,13 +194,16 @@ public class PortfolioView extends ActivatableView<TabPane, Void> { } else if (view instanceof FailedTradesView) { currentTab = failedTradesTab; } else if (view instanceof EditOfferView) { + if (data instanceof OpenOffer) { + openOffer = (OpenOffer) data; + } if (openOffer != null) { if (editOfferView == null) { editOfferView = (EditOfferView) view; editOfferView.applyOpenOffer(openOffer); editOpenOfferTab = new Tab(Res.get("portfolio.tab.editOpenOffer").toUpperCase()); editOfferView.setCloseHandler(() -> { - root.getTabs().remove(editOpenOfferTab); + UserThread.execute(() -> root.getTabs().remove(editOpenOfferTab)); }); root.getTabs().add(editOpenOfferTab); } @@ -218,7 +223,7 @@ public class PortfolioView extends ActivatableView<TabPane, Void> { duplicateOfferView.initWithData((OfferPayload) data); duplicateOfferTab = new Tab(Res.get("portfolio.tab.duplicateOffer").toUpperCase()); duplicateOfferView.setCloseHandler(() -> { - root.getTabs().remove(duplicateOfferTab); + UserThread.execute(() -> root.getTabs().remove(duplicateOfferTab)); }); root.getTabs().add(duplicateOfferTab); } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradableListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradableListItem.java index d17ec3db6b..55331b721f 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradableListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradableListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.closedtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesDataModel.java index 98b8f479d0..910b649145 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.closedtrades; @@ -27,6 +27,8 @@ import haveno.core.trade.ClosedTradableFormatter; import haveno.core.trade.ClosedTradableManager; import haveno.core.trade.ClosedTradableUtil; import haveno.core.trade.Tradable; +import haveno.core.trade.Trade; +import haveno.core.trade.TradeManager; import haveno.core.user.Preferences; import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; @@ -49,18 +51,21 @@ class ClosedTradesDataModel extends ActivatableDataModel { final AccountAgeWitnessService accountAgeWitnessService; private final ObservableList<ClosedTradesListItem> list = FXCollections.observableArrayList(); private final ListChangeListener<Tradable> tradesListChangeListener; + private final TradeManager tradeManager; @Inject public ClosedTradesDataModel(ClosedTradableManager closedTradableManager, ClosedTradableFormatter closedTradableFormatter, Preferences preferences, PriceFeedService priceFeedService, - AccountAgeWitnessService accountAgeWitnessService) { + AccountAgeWitnessService accountAgeWitnessService, + TradeManager tradeManager) { this.closedTradableManager = closedTradableManager; this.closedTradableFormatter = closedTradableFormatter; this.preferences = preferences; this.priceFeedService = priceFeedService; this.accountAgeWitnessService = accountAgeWitnessService; + this.tradeManager = tradeManager; tradesListChangeListener = change -> applyList(); } @@ -124,4 +129,8 @@ class ClosedTradesDataModel extends ActivatableDataModel { // We sort by date, the earliest first list.sort((o1, o2) -> o2.getTradable().getDate().compareTo(o1.getTradable().getDate())); } + + public void onMoveTradeToPendingTrades(Trade trade) { + tradeManager.onMoveClosedTradeToPendingTrades(trade); + } } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java index 36725fa474..6c1e30b828 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.closedtrades; @@ -21,6 +21,7 @@ import haveno.core.locale.CurrencyUtil; import haveno.core.monetary.Price; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; +import haveno.core.trade.ArbitratorTrade; import haveno.core.trade.ClosedTradableFormatter; import haveno.core.trade.ClosedTradableManager; import haveno.core.trade.Tradable; @@ -100,7 +101,7 @@ public class ClosedTradesListItem implements FilterableListItem { public String getDirectionLabel() { Offer offer = tradable.getOffer(); - OfferDirection direction = closedTradableManager.wasMyOffer(offer) + OfferDirection direction = closedTradableManager.wasMyOffer(offer) || tradable instanceof ArbitratorTrade ? offer.getDirection() : offer.getMirroredDirection(); String currencyCode = tradable.getOffer().getCurrencyCode(); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml index d4b9e90cb6..230557d4db 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.fxml @@ -50,6 +50,7 @@ <TableColumn fx:id="stateColumn" minWidth="80"/> <TableColumn fx:id="duplicateColumn" minWidth="30" maxWidth="30" sortable="false"/> <TableColumn fx:id="avatarColumn" minWidth="40" maxWidth="40"/> + <TableColumn fx:id="removeTradeColumn" minWidth="40" maxWidth="40"/> </columns> </TableView> diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.java index a43d677605..3257d21059 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesView.java @@ -1,23 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.closedtrades; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.googlecode.jcsv.writer.CSVEntryConverter; +import com.jfoenix.controls.JFXButton; +import de.jensd.fx.fontawesome.AwesomeIcon; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; @@ -43,8 +47,11 @@ import haveno.desktop.main.overlays.windows.ClosedTradesSummaryWindow; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.portfolio.presentation.PortfolioUtil; +import haveno.desktop.util.FormBuilder; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.NodeAddress; +import java.util.Comparator; +import java.util.function.Function; import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -70,13 +77,6 @@ import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Callback; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.Comparator; -import java.util.function.Function; - -import static haveno.desktop.util.FormBuilder.getRegularIconButton; - @FxmlView public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTradesViewModel> { private final boolean useDevPrivilegeKeys; @@ -91,8 +91,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades VOLUME(Res.get("shared.amount")), VOLUME_CURRENCY(Res.get("shared.currency")), TX_FEE(Res.get("shared.txFee")), - TRADE_FEE_BTC(Res.get("shared.tradeFee") + " BTC"), - TRADE_FEE_BSQ(Res.get("shared.tradeFee") + " BSQ"), + TRADE_FEE(Res.get("shared.tradeFee")), BUYER_SEC(Res.get("shared.buyerSecurityDeposit")), SELLER_SEC(Res.get("shared.sellerSecurityDeposit")), OFFER_TYPE(Res.get("shared.offerType")), @@ -115,7 +114,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades @FXML TableColumn<ClosedTradesListItem, ClosedTradesListItem> priceColumn, deviationColumn, amountColumn, volumeColumn, tradeFeeColumn, buyerSecurityDepositColumn, sellerSecurityDepositColumn, - marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, + marketColumn, directionColumn, dateColumn, tradeIdColumn, stateColumn, removeTradeColumn, duplicateColumn, avatarColumn; @FXML FilterBox filterBox; @@ -158,7 +157,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades @Override public void initialize() { widthListener = (observable, oldValue, newValue) -> onWidthChange((double) newValue); - tradeFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_FEE_BTC.toString().replace(" BTC", ""))); + tradeFeeColumn.setGraphic(new AutoTooltipLabel(ColumnNames.TRADE_FEE.toString().replace(" BTC", ""))); buyerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(ColumnNames.BUYER_SEC.toString())); sellerSecurityDepositColumn.setGraphic(new AutoTooltipLabel(ColumnNames.SELLER_SEC.toString())); priceColumn.setGraphic(new AutoTooltipLabel(ColumnNames.PRICE.toString())); @@ -189,6 +188,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades setDateColumnCellFactory(); setMarketColumnCellFactory(); setStateColumnCellFactory(); + setRemoveTradeColumnCellFactory(); setDuplicateColumnCellFactory(); setAvatarColumnCellFactory(); @@ -210,10 +210,10 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades return "BTC" + tradeFee; }, Comparator.nullsFirst(Comparator.naturalOrder()))); buyerSecurityDepositColumn.setComparator(nullsFirstComparing(o -> - o.getTradable().getOffer() != null ? o.getTradable().getOffer().getBuyerSecurityDeposit() : null + o.getTradable().getOffer() != null ? o.getTradable().getOffer().getMaxBuyerSecurityDeposit() : null )); sellerSecurityDepositColumn.setComparator(nullsFirstComparing(o -> - o.getTradable().getOffer() != null ? o.getTradable().getOffer().getSellerSecurityDeposit() : null + o.getTradable().getOffer() != null ? o.getTradable().getOffer().getMaxSellerSecurityDeposit() : null )); stateColumn.setComparator(Comparator.comparing(ClosedTradesListItem::getState)); @@ -275,11 +275,9 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades columns[ColumnNames.VOLUME_CURRENCY.ordinal()] = item.getVolumeCurrencyAsString(); columns[ColumnNames.TX_FEE.ordinal()] = item.getTxFeeAsString(); if (model.dataModel.isCurrencyForTradeFeeBtc(item.getTradable())) { - columns[ColumnNames.TRADE_FEE_BTC.ordinal()] = item.getTradeFeeAsString(false); - columns[ColumnNames.TRADE_FEE_BSQ.ordinal()] = ""; + columns[ColumnNames.TRADE_FEE.ordinal()] = item.getTradeFeeAsString(false); } else { - columns[ColumnNames.TRADE_FEE_BTC.ordinal()] = ""; - columns[ColumnNames.TRADE_FEE_BSQ.ordinal()] = item.getTradeFeeAsString(false); + columns[ColumnNames.TRADE_FEE.ordinal()] = ""; } columns[ColumnNames.BUYER_SEC.ordinal()] = item.getBuyerSecurityDepositAsString(); columns[ColumnNames.SELLER_SEC.ordinal()] = item.getSellerSecurityDepositAsString(); @@ -445,7 +443,7 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades if (item != null && !empty && isMyOfferAsMaker(item.getTradable().getOffer().getOfferPayload())) { if (button == null) { - button = getRegularIconButton(MaterialDesignIcon.CONTENT_COPY); + button = FormBuilder.getRegularIconButton(MaterialDesignIcon.CONTENT_COPY); button.setTooltip(new Tooltip(Res.get("shared.duplicateOffer"))); setGraphic(button); } @@ -677,6 +675,54 @@ public class ClosedTradesView extends ActivatableViewAndModel<VBox, ClosedTrades }); } + private TableColumn<ClosedTradesListItem, ClosedTradesListItem> setRemoveTradeColumnCellFactory() { + removeTradeColumn.setCellValueFactory((trade) -> new ReadOnlyObjectWrapper<>(trade.getValue())); + removeTradeColumn.setCellFactory( + new Callback<>() { + @Override + public TableCell<ClosedTradesListItem, ClosedTradesListItem> call(TableColumn<ClosedTradesListItem, + ClosedTradesListItem> column) { + return new TableCell<>() { + + @Override + public void updateItem(ClosedTradesListItem newItem, boolean empty) { + if (newItem == null || !(newItem.getTradable() instanceof Trade)) { + setGraphic(null); + return; + } + + Trade trade = (Trade) newItem.getTradable(); + super.updateItem(newItem, empty); + if (!empty && newItem != null && !trade.isPayoutConfirmed()) { + Label icon = FormBuilder.getIcon(AwesomeIcon.UNDO); + JFXButton iconButton = new JFXButton("", icon); + iconButton.setStyle("-fx-cursor: hand;"); + iconButton.getStyleClass().add("hidden-icon-button"); + iconButton.setTooltip(new Tooltip(Res.get("portfolio.failed.revertToPending"))); + iconButton.setOnAction(e -> onRevertTrade(trade)); + setGraphic(iconButton); + } else { + setGraphic(null); + } + } + }; + } + }); + return removeTradeColumn; + } + + private void onRevertTrade(Trade trade) { + new Popup().attention(Res.get("portfolio.failed.revertToPending.popup")) + .onAction(() -> onMoveTradeToPendingTrades(trade)) + .actionButtonText(Res.get("shared.yes")) + .closeButtonText(Res.get("shared.no")) + .show(); + } + + private void onMoveTradeToPendingTrades(Trade trade) { + model.dataModel.onMoveTradeToPendingTrades(trade); + } + private void onDuplicateOffer(Offer offer) { try { OfferPayload offerPayload = offer.getOfferPayload(); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java index d522ca9b98..4819d83b90 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/closedtrades/ClosedTradesViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.closedtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java index 780667087f..e3fd44c0ba 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferDataModel.java @@ -1,24 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.duplicateoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.TradeCurrency; @@ -39,8 +40,6 @@ import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.Navigation; import haveno.desktop.main.offer.MutableOfferDataModel; import haveno.network.p2p.P2PService; - -import javax.inject.Named; import java.math.BigInteger; import java.util.Objects; import java.util.Optional; @@ -53,7 +52,7 @@ class DuplicateOfferDataModel extends MutableOfferDataModel { DuplicateOfferDataModel(CreateOfferService createOfferService, OpenOfferManager openOfferManager, OfferUtil offerUtil, - XmrWalletService btcWalletService, + XmrWalletService xmrWalletService, Preferences preferences, User user, P2PService p2PService, @@ -66,7 +65,7 @@ class DuplicateOfferDataModel extends MutableOfferDataModel { super(createOfferService, openOfferManager, offerUtil, - btcWalletService, + xmrWalletService, preferences, user, p2PService, @@ -86,20 +85,21 @@ class DuplicateOfferDataModel extends MutableOfferDataModel { setPrice(offer.getPrice()); setVolume(offer.getVolume()); setUseMarketBasedPrice(offer.isUseMarketBasedPrice()); + setBuyerAsTakerWithoutDeposit(offer.hasBuyerAsTakerWithoutDeposit()); - setBuyerSecurityDeposit(getBuyerSecurityAsPercent(offer)); + setSecurityDepositPct(getSecurityAsPercent(offer)); if (offer.isUseMarketBasedPrice()) { setMarketPriceMarginPct(offer.getMarketPriceMarginPct()); } } - private double getBuyerSecurityAsPercent(Offer offer) { - BigInteger offerBuyerSecurityDeposit = getBoundedBuyerSecurityDeposit(offer.getBuyerSecurityDeposit()); - double offerBuyerSecurityDepositAsPercent = CoinUtil.getAsPercentPerBtc(offerBuyerSecurityDeposit, + private double getSecurityAsPercent(Offer offer) { + BigInteger offerSellerSecurityDeposit = getBoundedSecurityDeposit(offer.getMaxSellerSecurityDeposit()); + double offerSellerSecurityDepositAsPercent = CoinUtil.getAsPercentPerXmr(offerSellerSecurityDeposit, offer.getAmount()); - return Math.min(offerBuyerSecurityDepositAsPercent, - Restrictions.getMaxBuyerSecurityDepositAsPercent()); + return Math.min(offerSellerSecurityDepositAsPercent, + Restrictions.getMaxSecurityDepositAsPercent()); } @Override diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java index b2c6a10f07..33285e7c32 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferView.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.duplicateoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.locale.CurrencyUtil; import haveno.core.offer.OfferPayload; import haveno.core.payment.PaymentAccount; @@ -31,8 +32,6 @@ import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import javafx.collections.ObservableList; import javafx.geometry.Insets; -import javax.inject.Named; - @FxmlView public class DuplicateOfferView extends MutableOfferView<DuplicateOfferViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java index 6eafc192a7..08c5e18f9e 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/duplicateoffer/DuplicateOfferViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.duplicateoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.offer.Offer; import haveno.core.offer.OfferPayload; @@ -29,14 +30,12 @@ import haveno.core.provider.price.PriceFeedService; import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; import haveno.core.util.coin.CoinFormatter; -import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.AmountValidator4Decimals; +import haveno.core.util.validation.AmountValidator8Decimals; import haveno.desktop.Navigation; import haveno.desktop.main.offer.MutableOfferViewModel; import lombok.extern.slf4j.Slf4j; -import javax.inject.Named; - @Slf4j class DuplicateOfferViewModel extends MutableOfferViewModel<DuplicateOfferDataModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java index 6e15745255..d7ab366b75 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferDataModel.java @@ -1,24 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.editoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.account.witness.AccountAgeWitnessService; @@ -45,8 +46,6 @@ import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.Navigation; import haveno.desktop.main.offer.MutableOfferDataModel; import haveno.network.p2p.P2PService; - -import javax.inject.Named; import java.util.Optional; import java.util.Set; @@ -96,7 +95,7 @@ class EditOfferDataModel extends MutableOfferDataModel { price.set(null); volume.set(null); minVolume.set(null); - buyerSecurityDepositPct.set(0); + securityDepositPct.set(0); paymentAccounts.clear(); paymentAccount = null; marketPriceMargin = 0; @@ -122,16 +121,18 @@ class EditOfferDataModel extends MutableOfferDataModel { else paymentAccount.setSelectedTradeCurrency(selectedTradeCurrency); } + + // TODO: update for XMR to use percent as double? // If the security deposit got bounded because it was below the coin amount limit, it can be bigger // by percentage than the restriction. We can't determine the percentage originally entered at offer // creation, so just use the default value as it doesn't matter anyway. - double buyerSecurityDepositPercent = CoinUtil.getAsPercentPerBtc(offer.getBuyerSecurityDeposit(), offer.getAmount()); - if (buyerSecurityDepositPercent > Restrictions.getMaxBuyerSecurityDepositAsPercent() - && offer.getBuyerSecurityDeposit().equals(Restrictions.getMinBuyerSecurityDeposit())) - buyerSecurityDepositPct.set(Restrictions.getDefaultBuyerSecurityDepositAsPercent()); + double securityDepositPercent = CoinUtil.getAsPercentPerXmr(offer.getMaxSellerSecurityDeposit(), offer.getAmount()); + if (securityDepositPercent > Restrictions.getMaxSecurityDepositAsPercent() + && offer.getMaxSellerSecurityDeposit().equals(Restrictions.getMinSecurityDeposit())) + securityDepositPct.set(Restrictions.getDefaultSecurityDepositAsPercent()); else - buyerSecurityDepositPct.set(buyerSecurityDepositPercent); + securityDepositPct.set(securityDepositPercent); allowAmountUpdate = false; } @@ -188,6 +189,11 @@ class EditOfferDataModel extends MutableOfferDataModel { newOfferPayload.isUseMarketBasedPrice(), offerPayload.getAmount(), offerPayload.getMinAmount(), + offerPayload.getMakerFeePct(), + offerPayload.getTakerFeePct(), + offerPayload.getPenaltyFeePct(), + offerPayload.getBuyerSecurityDepositPct(), + offerPayload.getSellerSecurityDepositPct(), newOfferPayload.getBaseCurrencyCode(), newOfferPayload.getCounterCurrencyCode(), newOfferPayload.getPaymentMethodId(), @@ -198,9 +204,6 @@ class EditOfferDataModel extends MutableOfferDataModel { newOfferPayload.getAcceptedBankIds(), offerPayload.getVersionNr(), offerPayload.getBlockHeightAtOfferCreation(), - offerPayload.getMakerFee(), - offerPayload.getBuyerSecurityDeposit(), - offerPayload.getSellerSecurityDeposit(), offerPayload.getMaxTradeLimit(), offerPayload.getMaxTradePeriod(), offerPayload.isUseAutoClose(), @@ -208,7 +211,7 @@ class EditOfferDataModel extends MutableOfferDataModel { offerPayload.getLowerClosePrice(), offerPayload.getUpperClosePrice(), offerPayload.isPrivateOffer(), - offerPayload.getHashOfChallenge(), + offerPayload.getChallengeHash(), offerPayload.getExtraDataMap(), offerPayload.getProtocolVersion(), offerPayload.getArbitratorSigner(), diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java index 549661b0b7..60aa3c4dec 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferView.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.editoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.util.Tuple4; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -34,6 +35,7 @@ import haveno.desktop.components.BusyAnimation; import haveno.desktop.main.offer.MutableOfferView; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; +import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; import javafx.collections.ObservableList; import javafx.geometry.HPos; import javafx.geometry.Insets; @@ -44,10 +46,6 @@ import javafx.scene.image.ImageView; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; -import javax.inject.Named; - -import static haveno.desktop.util.FormBuilder.addButtonBusyAnimationLabelAfterGroup; - @FxmlView public class EditOfferView extends MutableOfferView<EditOfferViewModel> { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferViewModel.java index ceb5027ff9..34b78be683 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/editoffer/EditOfferViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.editoffer; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.account.witness.AccountAgeWitnessService; @@ -31,13 +32,11 @@ import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; import haveno.core.util.PriceUtil; import haveno.core.util.coin.CoinFormatter; -import haveno.core.util.validation.AmountValidator8Decimals; import haveno.core.util.validation.AmountValidator4Decimals; +import haveno.core.util.validation.AmountValidator8Decimals; import haveno.desktop.Navigation; import haveno.desktop.main.offer.MutableOfferViewModel; -import javax.inject.Named; - class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> { @Inject @@ -103,7 +102,6 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> { } public void onInvalidateMarketPriceMarginPct() { - marketPriceMargin.set("0.00%"); marketPriceMargin.set(FormattingUtils.formatToPercent(dataModel.getMarketPriceMarginPct())); } @@ -113,7 +111,7 @@ class EditOfferViewModel extends MutableOfferViewModel<EditOfferDataModel> { } public boolean isSecurityDepositValid() { - return securityDepositValidator.validate(buyerSecurityDeposit.get()).isValid; + return securityDepositValidator.validate(securityDeposit.get()).isValid; } @Override diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java index 481bad488e..dbbfa956ba 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesDataModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.failedtrades; @@ -75,8 +75,7 @@ class FailedTradesDataModel extends ActivatableDataModel { } public void onMoveTradeToPendingTrades(Trade trade) { - failedTradesManager.removeTrade(trade); - tradeManager.addFailedTradeToPendingTrades(trade); + tradeManager.onMoveFailedTradeToPendingTrades(trade); } public void unfailTrade(Trade trade) { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesListItem.java index b2ada1cfe2..0b7b7c3a0a 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.failedtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesView.java index 908b924583..b95aad8806 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.failedtrades; +import com.google.inject.Inject; import com.googlecode.jcsv.writer.CSVEntryConverter; import com.jfoenix.controls.JFXButton; import de.jensd.fx.fontawesome.AwesomeIcon; @@ -38,6 +39,8 @@ import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.util.FormBuilder; import haveno.desktop.util.GUIUtil; +import java.math.BigInteger; +import java.util.Comparator; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; import javafx.collections.ObservableList; @@ -65,10 +68,6 @@ import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Callback; -import javax.inject.Inject; -import java.math.BigInteger; -import java.util.Comparator; - @FxmlView public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTradesViewModel> { @@ -358,7 +357,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades private String checkTxs() { Trade trade = sortedList.get(tableView.getSelectionModel().getFocusedIndex()).getTrade(); log.info("Initiated unfail of trade {}", trade.getId()); - if (trade.getMakerDepositTx() == null || trade.getTakerDepositTx() == null) { + if (trade.getMakerDepositTx() == null || (trade.getTakerDepositTx() == null && !trade.hasBuyerAsTakerWithoutDeposit())) { log.info("Check unfail found no deposit tx(s) for trade {}", trade.getId()); return Res.get("portfolio.failed.depositTxNull"); } @@ -557,7 +556,7 @@ public class FailedTradesView extends ActivatableViewAndModel<VBox, FailedTrades @Override public void updateItem(FailedTradesListItem newItem, boolean empty) { super.updateItem(newItem, empty); - if (!empty && newItem != null) { + if (!empty && newItem != null && newItem.getTrade().isDepositsPublished()) { Label icon = FormBuilder.getIcon(AwesomeIcon.UNDO); JFXButton iconButton = new JFXButton("", icon); iconButton.setStyle("-fx-cursor: hand;"); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java index cdf8ac053c..eef2ffa444 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/failedtrades/FailedTradesViewModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.failedtrades; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; import haveno.core.trade.HavenoUtils; @@ -29,8 +30,6 @@ import haveno.desktop.common.model.ViewModel; import haveno.desktop.util.DisplayUtils; import javafx.collections.ObservableList; -import javax.inject.Named; - class FailedTradesViewModel extends ActivatableWithDataModel<FailedTradesDataModel> implements ViewModel { private final CoinFormatter formatter; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOfferListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOfferListItem.java index 93721abd5e..67869a9ff9 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOfferListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOfferListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.openoffer; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersDataModel.java index 3161bad539..c1f255d96d 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersDataModel.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.openoffer; import com.google.inject.Inject; +import haveno.common.UserThread; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.offer.Offer; @@ -46,9 +47,8 @@ class OpenOffersDataModel extends ActivatableDataModel { public OpenOffersDataModel(OpenOfferManager openOfferManager, PriceFeedService priceFeedService) { this.openOfferManager = openOfferManager; this.priceFeedService = priceFeedService; - - tradesListChangeListener = change -> applyList(); - currenciesUpdateFlagPropertyListener = (observable, oldValue, newValue) -> applyList(); + tradesListChangeListener = change -> UserThread.execute(() -> applyList()); + currenciesUpdateFlagPropertyListener = (observable, oldValue, newValue) -> UserThread.execute(() -> applyList()); } @Override @@ -85,10 +85,10 @@ class OpenOffersDataModel extends ActivatableDataModel { return openOfferManager.isMyOffer(offer) ? offer.getDirection() : offer.getMirroredDirection(); } - private void applyList() { + private synchronized void applyList() { list.clear(); - list.addAll(openOfferManager.getObservableList().stream().map(OpenOfferListItem::new).collect(Collectors.toList())); + list.addAll(openOfferManager.getOpenOffers().stream().map(OpenOfferListItem::new).collect(Collectors.toList())); // we sort by date, earliest first list.sort((o1, o2) -> o2.getOffer().getDate().compareTo(o1.getOffer().getDate())); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersView.java index e4f68c0d9b..c1f5566398 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.openoffer; +import com.google.inject.Inject; import com.googlecode.jcsv.writer.CSVEntryConverter; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import haveno.core.locale.Res; @@ -40,7 +41,13 @@ import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.OfferDetailsWindow; import haveno.desktop.main.portfolio.PortfolioView; import haveno.desktop.main.portfolio.duplicateoffer.DuplicateOfferView; +import static haveno.desktop.util.FormBuilder.getRegularIconButton; import haveno.desktop.util.GUIUtil; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -68,20 +75,8 @@ import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Callback; - -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.Subscription; import org.jetbrains.annotations.NotNull; -import javax.inject.Inject; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static haveno.desktop.util.FormBuilder.getRegularIconButton; - @FxmlView public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersViewModel> { @@ -116,7 +111,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView private PortfolioView.OpenOfferActionHandler openOfferActionHandler; private ChangeListener<Number> widthListener; - private Map<String, Subscription> offerStateSubscriptions = new HashMap<String, Subscription>(); + private Map<String, ChangeListener<OpenOffer.State>> offerStateChangeListeners = new HashMap<String, ChangeListener<OpenOffer.State>>(); @Inject public OpenOffersView(OpenOffersViewModel model, Navigation navigation, OfferDetailsWindow offerDetailsWindow) { @@ -132,7 +127,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView priceColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.price"))); deviationColumn.setGraphic(new AutoTooltipTableColumn<>(Res.get("shared.deviation"), Res.get("portfolio.closedTrades.deviation.help")).getGraphic()); - amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.BTCMinMax"))); + amountColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.XMRMinMax"))); volumeColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.amountMinMax"))); marketColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.market"))); directionColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.offerType"))); @@ -301,7 +296,7 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView private void updateSelectToggleButtonState() { List<OpenOfferListItem> availableItems = sortedList.stream() - .filter(openOfferListItem -> !openOfferListItem.getOpenOffer().isScheduled()) + .filter(openOfferListItem -> !openOfferListItem.getOpenOffer().isPending()) .collect(Collectors.toList()); if (availableItems.size() == 0) { selectToggleButton.setDisable(true); @@ -705,12 +700,17 @@ public class OpenOffersView extends ActivatableViewAndModel<VBox, OpenOffersView super.updateItem(item, empty); if (item != null && !empty) { OpenOffer openOffer = item.getOpenOffer(); - if (!offerStateSubscriptions.containsKey(openOffer.getId())) { - offerStateSubscriptions.put(openOffer.getId(), EasyBind.subscribe(openOffer.stateProperty(), state -> { - refresh(); - })); + + // refresh on state change + if (offerStateChangeListeners.containsKey(openOffer.getId())) { + openOffer.stateProperty().removeListener(offerStateChangeListeners.get(openOffer.getId())); + offerStateChangeListeners.remove(openOffer.getId()); } - if (openOffer.getState() == OpenOffer.State.SCHEDULED) { + ChangeListener<OpenOffer.State> listener = (observable, oldValue, newValue) -> { if (oldValue != newValue) refresh(); }; + offerStateChangeListeners.put(openOffer.getId(), listener); + openOffer.stateProperty().addListener(listener); + + if (openOffer.getState() == OpenOffer.State.PENDING) { setGraphic(new AutoTooltipLabel(Res.get("shared.pending"))); return; } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java index 57992bf310..68ae7385a1 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/openoffer/OpenOffersViewModel.java @@ -1,23 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.openoffer; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.handlers.ErrorMessageHandler; import haveno.common.handlers.ResultHandler; import haveno.core.locale.CurrencyUtil; @@ -25,7 +27,6 @@ import haveno.core.locale.Res; import haveno.core.monetary.Price; import haveno.core.offer.Offer; import haveno.core.offer.OpenOffer; -import haveno.core.trade.HavenoUtils; import haveno.core.util.FormattingUtils; import haveno.core.util.PriceUtil; import haveno.core.util.VolumeUtil; @@ -37,10 +38,6 @@ import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; import javafx.collections.ObservableList; -import javax.inject.Named; - -import static com.google.common.base.Preconditions.checkNotNull; - class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> implements ViewModel { private final P2PService p2PService; private final PriceUtil priceUtil; @@ -124,7 +121,7 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> if ((item == null)) return ""; - return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCurrencyCode()); + return DisplayUtils.getDirectionWithCode(dataModel.getDirection(item.getOffer()), item.getOffer().getCurrencyCode(), item.getOffer().isPrivateOffer()); } String getMarketLabel(OpenOfferListItem item) { @@ -157,11 +154,6 @@ class OpenOffersViewModel extends ActivatableWithDataModel<OpenOffersDataModel> return GUIUtil.isBootstrappedOrShowPopup(p2PService); } - public String getMakerFeeAsString(OpenOffer openOffer) { - Offer offer = openOffer.getOffer(); - return HavenoUtils.formatXmr(offer.getMakerFee(), true); - } - String getTriggerPrice(OpenOfferListItem item) { if ((item == null)) { return ""; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/BuyerSubView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/BuyerSubView.java index 60a05f1462..0488c9c325 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/BuyerSubView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/BuyerSubView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java index ea2d60267d..e4fc8b1bdc 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesDataModel.java @@ -1,23 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.crypto.PubKeyRing; import haveno.common.crypto.PubKeyRingProvider; @@ -26,7 +29,7 @@ import haveno.common.handlers.FaultHandler; import haveno.common.handlers.ResultHandler; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.api.CoreDisputesService; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.locale.Res; import haveno.core.offer.Offer; import haveno.core.offer.OfferDirection; @@ -34,7 +37,6 @@ import haveno.core.offer.OfferUtil; import haveno.core.payment.payload.PaymentAccountPayload; import haveno.core.support.SupportType; import haveno.core.support.dispute.Dispute; -import haveno.core.support.dispute.DisputeAlreadyOpenException; import haveno.core.support.dispute.DisputeList; import haveno.core.support.dispute.DisputeManager; import haveno.core.support.dispute.arbitration.ArbitrationManager; @@ -61,6 +63,12 @@ import haveno.desktop.main.support.dispute.client.arbitration.ArbitrationClientV import haveno.desktop.main.support.dispute.client.mediation.MediationClientView; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; +import java.math.BigInteger; +import java.util.Date; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; @@ -69,19 +77,11 @@ import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; +import javax.annotation.Nullable; import lombok.Getter; import org.bitcoinj.core.Coin; import org.bouncycastle.crypto.params.KeyParameter; -import javax.annotation.Nullable; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.Date; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - public class PendingTradesDataModel extends ActivatableDataModel { @Getter public final TradeManager tradeManager; @@ -89,7 +89,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { public final ArbitrationManager arbitrationManager; public final MediationManager mediationManager; private final P2PService p2PService; - private final CoreMoneroConnectionsService connectionService; + private final XmrConnectionService xmrConnectionService; @Getter private final AccountAgeWitnessService accountAgeWitnessService; public final Navigation navigation; @@ -116,6 +116,11 @@ public class PendingTradesDataModel extends ActivatableDataModel { private final PubKeyRingProvider pubKeyRingProvider; private final CoreDisputesService disputesService; + private final Set<Trade> hiddenTrades = new HashSet<Trade>(); + private final ChangeListener<Trade.State> hiddenStateChangeListener = (observable, oldValue, newValue) -> { + onListChanged(); + }; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor, initialization /////////////////////////////////////////////////////////////////////////////////////////// @@ -129,7 +134,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { TraderChatManager traderChatManager, Preferences preferences, P2PService p2PService, - CoreMoneroConnectionsService connectionService, + XmrConnectionService xmrConnectionService, AccountAgeWitnessService accountAgeWitnessService, Navigation navigation, WalletPasswordWindow walletPasswordWindow, @@ -145,7 +150,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { this.traderChatManager = traderChatManager; this.preferences = preferences; this.p2PService = p2PService; - this.connectionService = connectionService; + this.xmrConnectionService = xmrConnectionService; this.accountAgeWitnessService = accountAgeWitnessService; this.navigation = navigation; this.walletPasswordWindow = walletPasswordWindow; @@ -170,6 +175,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { @Override protected void deactivate() { + for (Trade trade : hiddenTrades) trade.stateProperty().removeListener(hiddenStateChangeListener); tradeManager.getObservableList().removeListener(tradesListChangeListener); notificationCenter.setSelectedTradeId(null); activated = false; @@ -273,17 +279,17 @@ public class PendingTradesDataModel extends ActivatableDataModel { Offer offer = trade.getOffer(); if (isMaker()) { if (offer != null) { - return offer.getMakerFee(); + return trade.getMakerFee(); } else { log.error("offer is null"); - return BigInteger.valueOf(0); + return BigInteger.ZERO; } } else { return trade.getTakerFee(); } } else { log.error("Trade is null at getTotalFees"); - return BigInteger.valueOf(0); + return BigInteger.ZERO; } } @@ -308,10 +314,30 @@ public class PendingTradesDataModel extends ActivatableDataModel { /////////////////////////////////////////////////////////////////////////////////////////// private void onListChanged() { - list.clear(); - list.addAll(tradeManager.getObservableList().stream() - .map(trade -> new PendingTradesListItem(trade, btcFormatter)) - .collect(Collectors.toList())); + synchronized (tradeManager.getObservableList()) { + + // add or remove listener for hidden trades + for (Trade trade : tradeManager.getObservableList()) { + if (isTradeShown(trade)) { + if (hiddenTrades.contains(trade)) { + trade.stateProperty().removeListener(hiddenStateChangeListener); + hiddenTrades.remove(trade); + } + } else { + if (!hiddenTrades.contains(trade)) { + trade.stateProperty().addListener(hiddenStateChangeListener); + hiddenTrades.add(trade); + } + } + } + + // add shown trades to list + list.clear(); + list.addAll(tradeManager.getObservableList().stream() + .filter(trade -> isTradeShown(trade)) + .map(trade -> new PendingTradesListItem(trade, btcFormatter)) + .collect(Collectors.toList())); + } // we sort by date, earliest first list.sort((o1, o2) -> o2.getTrade().getDate().compareTo(o1.getTrade().getDate())); @@ -319,6 +345,10 @@ public class PendingTradesDataModel extends ActivatableDataModel { selectBestItem(); } + private boolean isTradeShown(Trade trade) { + return trade.isDepositsPublished(); + } + private void selectBestItem() { if (list.size() == 1) doSelectItem(list.get(0)); @@ -350,14 +380,11 @@ public class PendingTradesDataModel extends ActivatableDataModel { tradeStateChangeListener = (observable, oldValue, newValue) -> { String makerDepositTxHash = selectedTrade.getMaker().getDepositTxHash(); String takerDepositTxHash = selectedTrade.getTaker().getDepositTxHash(); - if (makerDepositTxHash != null && takerDepositTxHash != null) { // TODO (woodser): this treats separate deposit ids as one unit, being both available or unavailable - makerTxId.set(makerDepositTxHash); - takerTxId.set(takerDepositTxHash); + makerTxId.set(nullToEmptyString(makerDepositTxHash)); + takerTxId.set(nullToEmptyString(takerDepositTxHash)); + if (makerDepositTxHash != null || takerDepositTxHash != null) { notificationCenter.setSelectedTradeId(tradeId); selectedTrade.stateProperty().removeListener(tradeStateChangeListener); - } else { - makerTxId.set(""); - takerTxId.set(""); } }; selectedTrade.stateProperty().addListener(tradeStateChangeListener); @@ -371,13 +398,8 @@ public class PendingTradesDataModel extends ActivatableDataModel { isMaker = tradeManager.isMyOffer(offer); String makerDepositTxHash = selectedTrade.getMaker().getDepositTxHash(); String takerDepositTxHash = selectedTrade.getTaker().getDepositTxHash(); - if (makerDepositTxHash != null && takerDepositTxHash != null) { - makerTxId.set(makerDepositTxHash); - takerTxId.set(takerDepositTxHash); - } else { - makerTxId.set(""); - takerTxId.set(""); - } + makerTxId.set(nullToEmptyString(makerDepositTxHash)); + takerTxId.set(nullToEmptyString(takerDepositTxHash)); notificationCenter.setSelectedTradeId(tradeId); } else { selectedTrade = null; @@ -389,6 +411,10 @@ public class PendingTradesDataModel extends ActivatableDataModel { }); } + private String nullToEmptyString(String str) { + return str == null ? "" : str; + } + private void tryOpenDispute(boolean isSupportTicket) { Trade trade = getTrade(); if (trade == null) { @@ -416,7 +442,7 @@ public class PendingTradesDataModel extends ActivatableDataModel { } depositTxId = trade.getMaker().getDepositTxHash(); } else { - if (trade.getTaker().getDepositTxHash() == null) { + if (trade.getTaker().getDepositTxHash() == null && !trade.hasBuyerAsTakerWithoutDeposit()) { log.error("Deposit tx must not be null"); new Popup().instruction(Res.get("portfolio.pending.error.depositTxNull")).show(); return; @@ -515,36 +541,49 @@ public class PendingTradesDataModel extends ActivatableDataModel { dispute.setExtraData("counterCurrencyExtraData", trade.getCounterCurrencyExtraData()); trade.setDisputeState(Trade.DisputeState.MEDIATION_REQUESTED); - sendDisputeOpenedMessage(dispute, false, disputeManager, trade.getSelf().getUpdatedMultisigHex()); + sendDisputeOpenedMessage(dispute, disputeManager); tradeManager.requestPersistence(); } else if (useArbitration) { - // Only if we have completed mediation we allow arbitration disputeManager = arbitrationManager; Dispute dispute = disputesService.createDisputeForTrade(trade, offer, pubKeyRingProvider.get(), isMaker, isSupportTicket); - sendDisputeOpenedMessage(dispute, false, disputeManager, trade.getSelf().getUpdatedMultisigHex()); + + // export latest multisig hex + try { + trade.exportMultisigHex(); + } catch (Exception e) { + log.error("Failed to export multisig hex", e); + } + + // send dispute opened message + sendDisputeOpenedMessage(dispute, disputeManager); tradeManager.requestPersistence(); } else { log.warn("Invalid dispute state {}", disputeState.name()); } } - private void sendDisputeOpenedMessage(Dispute dispute, boolean reOpen, DisputeManager<? extends DisputeList<Dispute>> disputeManager, String senderMultisigHex) { - disputeManager.sendDisputeOpenedMessage(dispute, reOpen, senderMultisigHex, - () -> navigation.navigateTo(MainView.class, SupportView.class, ArbitrationClientView.class), (errorMessage, throwable) -> { - if ((throwable instanceof DisputeAlreadyOpenException)) { - errorMessage += "\n\n" + Res.get("portfolio.pending.openAgainDispute.msg"); - new Popup().warning(errorMessage) - .actionButtonText(Res.get("portfolio.pending.openAgainDispute.button")) - .onAction(() -> sendDisputeOpenedMessage(dispute, true, disputeManager, senderMultisigHex)) - .closeButtonText(Res.get("shared.cancel")).show(); - } else { - new Popup().warning(errorMessage).show(); - } - }); + private void sendDisputeOpenedMessage(Dispute dispute, DisputeManager<? extends DisputeList<Dispute>> disputeManager) { + Optional<Dispute> optionalDispute = disputeManager.findDispute(dispute); + boolean disputeClosed = optionalDispute.isPresent() && optionalDispute.get().isClosed(); + if (disputeClosed) { + String msg = "We got a dispute already open for that trade and trading peer.\n" + "TradeId = " + dispute.getTradeId(); + new Popup().warning(msg + "\n\n" + Res.get("portfolio.pending.openAgainDispute.msg")) + .actionButtonText(Res.get("portfolio.pending.openAgainDispute.button")) + .onAction(() -> doSendDisputeOpenedMessage(dispute, disputeManager)) + .closeButtonText(Res.get("shared.cancel")).show(); + } else { + doSendDisputeOpenedMessage(dispute, disputeManager); + } + } + + private void doSendDisputeOpenedMessage(Dispute dispute, DisputeManager<? extends DisputeList<Dispute>> disputeManager) { + disputeManager.sendDisputeOpenedMessage(dispute, + () -> navigation.navigateTo(MainView.class, SupportView.class, ArbitrationClientView.class), + (errorMessage, throwable) -> new Popup().warning(errorMessage).show()); } public boolean isReadyForTxBroadcast() { - return GUIUtil.isBootstrappedOrShowPopup(p2PService) && GUIUtil.isReadyForTxBroadcastOrShowPopup(connectionService); + return GUIUtil.isBootstrappedOrShowPopup(p2PService) && GUIUtil.isReadyForTxBroadcastOrShowPopup(xmrWalletService); } public boolean isBootstrappedOrShowPopup() { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java index 66292c3033..8e47d0e07e 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.fxml b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.fxml index 29dec24a74..c0240455f2 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.fxml +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.fxml @@ -19,13 +19,15 @@ <?import haveno.desktop.components.list.FilterBox?> <?import javafx.geometry.Insets?> +<?import javafx.scene.control.ScrollPane?> <?import javafx.scene.control.TableColumn?> <?import javafx.scene.control.TableView?> +<?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.VBox?> <VBox fx:id="root" fx:controller="haveno.desktop.main.portfolio.pendingtrades.PendingTradesView" spacing="20" xmlns:fx="http://javafx.com/fxml"> <padding> - <Insets bottom="15.0" left="15.0" right="15.0" top="15.0"/> + <Insets bottom="0.0" left="15.0" right="15.0" top="15.0"/> </padding> <FilterBox fx:id="filterBox" /> <TableView fx:id="tableView" VBox.vgrow="SOMETIMES"> @@ -43,4 +45,8 @@ <TableColumn fx:id="moveTradeToFailedColumn" minWidth="80" maxWidth="80"/> </columns> </TableView> + <ScrollPane fx:id="scrollView" fitToWidth="true" hbarPolicy="NEVER" + AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" + AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/> + </VBox> diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.java index b309de20a3..8c31e3d8e6 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; +import com.google.inject.Inject; +import com.google.inject.name.Named; import com.jfoenix.controls.JFXBadge; import com.jfoenix.controls.JFXButton; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; @@ -54,7 +56,9 @@ import haveno.desktop.util.CssTheme; import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.FormBuilder; import haveno.network.p2p.NodeAddress; -import javafx.application.Platform; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Map; import javafx.beans.binding.Bindings; import javafx.beans.property.ReadOnlyObjectWrapper; import javafx.beans.value.ChangeListener; @@ -71,6 +75,7 @@ import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.ContextMenu; import javafx.scene.control.MenuItem; +import javafx.scene.control.ScrollPane; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableRow; @@ -80,7 +85,6 @@ import javafx.scene.input.KeyCode; import javafx.scene.input.KeyEvent; import javafx.scene.layout.AnchorPane; import javafx.scene.layout.HBox; -import javafx.scene.layout.Priority; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; @@ -92,12 +96,6 @@ import javafx.util.Callback; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import javax.inject.Inject; -import javax.inject.Named; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; - @FxmlView public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTradesViewModel> { public interface ChatCallback { @@ -119,6 +117,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad @FXML TableColumn<PendingTradesListItem, PendingTradesListItem> priceColumn, volumeColumn, amountColumn, avatarColumn, marketColumn, roleColumn, paymentMethodColumn, tradeIdColumn, dateColumn, chatColumn, moveTradeToFailedColumn; + @FXML + ScrollPane scrollView; private FilteredList<PendingTradesListItem> filteredList; private SortedList<PendingTradesListItem> sortedList; private TradeSubView selectedSubView; @@ -277,6 +277,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad sortedList = new SortedList<>(filteredList); sortedList.comparatorProperty().bind(tableView.comparatorProperty()); tableView.setItems(sortedList); + tableView.setPrefHeight(100); + tableView.setMaxHeight(200); filterBox.initialize(filteredList, tableView); // here because filteredList is instantiated here filterBox.activate(); @@ -297,13 +299,13 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad selectedSubView = model.dataModel.tradeManager.isBuyer(model.dataModel.getOffer()) ? new BuyerSubView(model) : new SellerSubView(model); - selectedSubView.setMinHeight(460); - VBox.setVgrow(selectedSubView, Priority.ALWAYS); + //selectedSubView.setMinHeight(460); + //VBox.setVgrow(selectedSubView, Priority.SOMETIMES); if (root.getChildren().size() == 2) - root.getChildren().add(selectedSubView); + root.getChildren().add(scrollView); else if (root.getChildren().size() == 3) - root.getChildren().set(2, selectedSubView); - + root.getChildren().set(2, scrollView); + scrollView.setContent(selectedSubView); // create and register a callback so we can be notified when the subview // wants to open the chat window ChatCallback chatCallback = this::openChat; @@ -323,8 +325,10 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad selectedTableItemSubscription = EasyBind.subscribe(tableView.getSelectionModel().selectedItemProperty(), selectedItem -> { - if (selectedItem != null && !selectedItem.equals(model.dataModel.selectedItemProperty.get())) + if (selectedItem != null && !selectedItem.equals(model.dataModel.selectedItemProperty.get())) { + if (selectedSubView != null) selectedSubView.deactivate(); model.dataModel.onSelectItem(selectedItem); + } }); updateTableSelection(); @@ -399,8 +403,8 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad return Res.get("portfolio.pending.failedTrade.missingDepositTx"); } - if (trade.getTakerDepositTx() == null) { - return Res.get("portfolio.pending.failedTrade.missingDepositTx"); // TODO (woodser): use .missingTakerDepositTx, .missingMakerDepositTx + if (trade.getTakerDepositTx() == null && !trade.hasBuyerAsTakerWithoutDeposit()) { + return Res.get("portfolio.pending.failedTrade.missingDepositTx"); // TODO (woodser): use .missingTakerDepositTx, .missingMakerDepositTx, update translation to 2-of-3 multisig } if (trade.hasErrorMessage()) { @@ -418,11 +422,13 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad private void updateNewChatMessagesByTradeMap() { model.dataModel.list.forEach(t -> { Trade trade = t.getTrade(); - newChatMessagesByTradeMap.put(trade.getId(), - trade.getChatMessages().stream() - .filter(m -> !m.isWasDisplayed()) - .filter(m -> !m.isSystemMessage()) - .count()); + synchronized (trade.getChatMessages()) { + newChatMessagesByTradeMap.put(trade.getId(), + trade.getChatMessages().stream() + .filter(m -> !m.isWasDisplayed()) + .filter(m -> !m.isSystemMessage()) + .count()); + } }); } @@ -439,7 +445,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad model.dataModel.getTradeManager().requestPersistence(); tradeIdOfOpenChat = trade.getId(); - ChatView chatView = new ChatView(traderChatManager, formatter, Res.get("offerbook.trader")); + ChatView chatView = new ChatView(traderChatManager, Res.get("offerbook.trader")); chatView.setAllowAttachments(false); chatView.setDisplayHeader(false); chatView.initialize(); @@ -931,11 +937,7 @@ public class PendingTradesView extends ActivatableViewAndModel<VBox, PendingTrad super.updateItem(newItem, empty); if (!empty && newItem != null) { trade = newItem.getTrade(); - listener = (observable, oldValue, newValue) -> Platform.runLater(new Runnable() { - @Override public void run() { - update(); - } - }); + listener = (observable, oldValue, newValue) -> UserThread.execute(() -> update()); trade.stateProperty().addListener(listener); update(); } else { diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java index 793e531d83..41881c58be 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/PendingTradesViewModel.java @@ -1,24 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.ClockWatcher; +import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.core.account.witness.AccountAgeWitnessService; import haveno.core.network.MessageState; @@ -36,31 +39,26 @@ import haveno.core.util.FormattingUtils; import haveno.core.util.VolumeUtil; import haveno.core.util.coin.CoinFormatter; import haveno.core.util.validation.BtcAddressValidator; -import haveno.core.xmr.wallet.Restrictions; import haveno.desktop.Navigation; import haveno.desktop.common.model.ActivatableWithDataModel; import haveno.desktop.common.model.ViewModel; +import static haveno.desktop.main.portfolio.pendingtrades.PendingTradesViewModel.SellerState.UNDEFINED; import haveno.desktop.util.DisplayUtils; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; +import java.math.BigInteger; +import java.util.Date; +import java.util.stream.Collectors; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleObjectProperty; +import javax.annotation.Nullable; import lombok.Getter; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import javax.annotation.Nullable; -import javax.inject.Named; -import java.math.BigInteger; -import java.util.Date; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.desktop.main.portfolio.pendingtrades.PendingTradesViewModel.SellerState.UNDEFINED; - public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTradesDataModel> implements ViewModel { @Getter @@ -104,6 +102,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad @Getter private final ObjectProperty<MessageState> messageStateProperty = new SimpleObjectProperty<>(MessageState.UNDEFINED); private Subscription tradeStateSubscription; + private Subscription paymentAccountDecryptedSubscription; private Subscription payoutStateSubscription; private Subscription messageStateSubscription; @Getter @@ -148,12 +147,17 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad tradeStateSubscription.unsubscribe(); tradeStateSubscription = null; } - + + if (paymentAccountDecryptedSubscription != null) { + paymentAccountDecryptedSubscription.unsubscribe(); + paymentAccountDecryptedSubscription = null; + } + if (payoutStateSubscription != null) { payoutStateSubscription.unsubscribe(); payoutStateSubscription = null; } - + if (messageStateSubscription != null) { messageStateSubscription.unsubscribe(); messageStateSubscription = null; @@ -169,42 +173,46 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad sellerState.set(SellerState.UNDEFINED); buyerState.set(BuyerState.UNDEFINED); } - + + if (paymentAccountDecryptedSubscription != null) { + paymentAccountDecryptedSubscription.unsubscribe(); + } + if (payoutStateSubscription != null) { payoutStateSubscription.unsubscribe(); sellerState.set(SellerState.UNDEFINED); buyerState.set(BuyerState.UNDEFINED); } - + if (messageStateSubscription != null) { messageStateSubscription.unsubscribe(); messageStateProperty.set(MessageState.UNDEFINED); } - + if (selectedItem != null) { this.trade = selectedItem.getTrade(); tradeStateSubscription = EasyBind.subscribe(trade.stateProperty(), state -> { onTradeStateChanged(state); }); + paymentAccountDecryptedSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentAccountDecryptedProperty(), decrypted -> { + refresh(); + }); payoutStateSubscription = EasyBind.subscribe(trade.payoutStateProperty(), state -> { onPayoutStateChanged(state); }); messageStateSubscription = EasyBind.subscribe(trade.getProcessModel().getPaymentSentMessageStateProperty(), this::onMessageStateChanged); } - } } - public void setMessageStateProperty(MessageState messageState) { - // ARRIVED is set internally after ACKNOWLEDGED, otherwise warn if subsequent states received - if ((messageStateProperty.get() == MessageState.ACKNOWLEDGED && messageState != MessageState.ARRIVED) || messageStateProperty.get() == MessageState.ARRIVED) { - log.warn("We have already an ACKNOWLEDGED/ARRIVED message received. " + - "We would not expect any other message after that. Received messageState={}", messageState); - return; - } - - if (trade != null) - trade.getProcessModel().setPaymentSentMessageState(messageState); + private void refresh() { + UserThread.execute(() -> { + sellerState.set(UNDEFINED); + buyerState.set(BuyerState.UNDEFINED); + onTradeStateChanged(trade.getState()); + if (trade.isPayoutPublished()) onPayoutStateChanged(trade.getPayoutState()); // TODO: payout state takes precedence in case PaymentReceivedMessage not processed + else onTradeStateChanged(trade.getState()); + }); } private void onMessageStateChanged(MessageState messageState) { @@ -223,9 +231,9 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad return sellerState; } - public String getPayoutAmount() { + public String getPayoutAmountBeforeCost() { return dataModel.getTrade() != null - ? HavenoUtils.formatXmr(dataModel.getTrade().getPayoutAmount(), true) + ? HavenoUtils.formatXmr(dataModel.getTrade().getPayoutAmountBeforeCost(), true) : ""; } @@ -287,12 +295,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad BigInteger tradeFeeInXmr = dataModel.getTradeFee(); - BigInteger minTradeFee = dataModel.isMaker() ? - HavenoUtils.getMinMakerFee() : - HavenoUtils.getMinTakerFee(); - - String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInXmr, trade.getAmount(), - minTradeFee); + String percentage = GUIUtil.getPercentageOfTradeAmount(tradeFeeInXmr, trade.getAmount()); return HavenoUtils.formatXmr(tradeFeeInXmr, true) + percentage; } else { return ""; @@ -304,16 +307,10 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad Trade trade = dataModel.getTrade(); if (offer != null && trade != null && trade.getAmount() != null) { BigInteger securityDeposit = dataModel.isBuyer() ? - offer.getBuyerSecurityDeposit() - : offer.getSellerSecurityDeposit(); + offer.getMaxBuyerSecurityDeposit() + : offer.getMaxSellerSecurityDeposit(); - BigInteger minSecurityDeposit = dataModel.isBuyer() ? - Restrictions.getMinBuyerSecurityDeposit() : - Restrictions.getMinSellerSecurityDeposit(); - - String percentage = GUIUtil.getPercentageOfTradeAmount(securityDeposit, - trade.getAmount(), - minSecurityDeposit); + String percentage = GUIUtil.getPercentageOfTradeAmount(securityDeposit, trade.getAmount()); return HavenoUtils.formatXmr(securityDeposit, true) + percentage; } else { return ""; @@ -363,6 +360,12 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad return; } + if (trade.isCompleted()) { + sellerState.set(UNDEFINED); + buyerState.set(BuyerState.UNDEFINED); + return; + } + switch (tradeState) { // initialization @@ -395,7 +398,7 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad break; // buyer step 3 - case BUYER_CONFIRMED_IN_UI_PAYMENT_SENT: // UI action + case BUYER_CONFIRMED_PAYMENT_SENT: // UI action case BUYER_SENT_PAYMENT_SENT_MSG: // PAYMENT_SENT_MSG sent case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG: // PAYMENT_SENT_MSG arrived // We don't switch the UI before we got the feedback of the msg delivery @@ -418,18 +421,13 @@ public class PendingTradesViewModel extends ActivatableWithDataModel<PendingTrad break; // seller step 3 - case SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT: + case SELLER_CONFIRMED_PAYMENT_RECEIPT: case SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG: case SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG: case SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG: sellerState.set(trade.isPayoutPublished() ? SellerState.STEP4 : SellerState.STEP3); break; - case TRADE_COMPLETED: - sellerState.set(UNDEFINED); - buyerState.set(BuyerState.UNDEFINED); - break; - default: sellerState.set(UNDEFINED); buyerState.set(BuyerState.UNDEFINED); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/SellerSubView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/SellerSubView.java index 492ca154b2..5072fd243a 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/SellerSubView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/SellerSubView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeStepInfo.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeStepInfo.java index cb3aa43398..e61153cfbe 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeStepInfo.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeStepInfo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeSubView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeSubView.java index 9a3273407f..cef43e795c 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeSubView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/TradeSubView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades; @@ -61,7 +61,7 @@ public abstract class TradeSubView extends HBox { public TradeSubView(PendingTradesViewModel model) { this.model = model; - + HBox.setHgrow(this, Priority.ALWAYS); setSpacing(Layout.PADDING_WINDOW); buildViews(); } @@ -153,8 +153,7 @@ public abstract class TradeSubView extends HBox { tradeStepView.setChatCallback(chatCallback); tradeStepView.activate(); } catch (Exception e) { - log.error("Creating viewClass {} caused an error {}", viewClass, e.getMessage()); - e.printStackTrace(); + log.error("Creating viewClass {} caused an error {}\n", viewClass, e.getMessage(), e); } } diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java index c692259eb8..263e4d0ef0 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeStepView.java @@ -1,23 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps; -import com.jfoenix.controls.JFXProgressBar; +import static com.google.common.base.Preconditions.checkNotNull; import de.jensd.fx.fontawesome.AwesomeDude; import de.jensd.fx.fontawesome.AwesomeIcon; import haveno.common.ClockWatcher; @@ -39,12 +39,20 @@ import haveno.core.user.Preferences; import haveno.desktop.components.InfoTextField; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.components.TxIdTextField; +import static haveno.desktop.components.paymentmethods.PaymentMethodForm.addOpenTradeDuration; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; import haveno.desktop.main.portfolio.pendingtrades.TradeStepInfo; import haveno.desktop.main.portfolio.pendingtrades.TradeSubView; +import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; +import static haveno.desktop.util.FormBuilder.addMultilineLabel; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelTxIdTextField; import haveno.desktop.util.Layout; import haveno.network.p2p.BootstrapListener; +import java.time.Duration; +import java.time.Instant; +import java.util.Optional; import javafx.application.Platform; import javafx.beans.property.BooleanProperty; import javafx.beans.value.ChangeListener; @@ -64,19 +72,6 @@ import org.fxmisc.easybind.Subscription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.time.Duration; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; - -import static com.google.common.base.Preconditions.checkNotNull; -import static haveno.desktop.components.paymentmethods.PaymentMethodForm.addOpenTradeDuration; -import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; -import static haveno.desktop.util.FormBuilder.addMultilineLabel; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelTxIdTextField; - public abstract class TradeStepView extends AnchorPane { protected final Logger log = LoggerFactory.getLogger(this.getClass()); @@ -113,8 +108,6 @@ public abstract class TradeStepView extends AnchorPane { trade = model.dataModel.getTrade(); checkNotNull(trade, "Trade must not be null at TradeStepView"); - startCachingTxs(); - ScrollPane scrollPane = new ScrollPane(); scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.AS_NEEDED); @@ -170,13 +163,6 @@ public abstract class TradeStepView extends AnchorPane { // }; } - private void startCachingTxs() { - List<String> txIds = new ArrayList<String>(); - if (!model.dataModel.makerTxId.isEmpty().get()) txIds.add(model.dataModel.makerTxId.get()); - if (!model.dataModel.takerTxId.isEmpty().get()) txIds.add(model.dataModel.takerTxId.get()); - new Thread(() -> trade.getXmrWalletService().getTxsWithCache(txIds)).start(); - } - public void activate() { if (selfTxIdTextField != null) { if (selfTxIdSubscription != null) @@ -184,8 +170,7 @@ public abstract class TradeStepView extends AnchorPane { selfTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.makerTxId : model.dataModel.takerTxId, id -> { if (!id.isEmpty()) { - startCachingTxs(); - selfTxIdTextField.setup(id); + selfTxIdTextField.setup(id, trade); } else { selfTxIdTextField.cleanup(); } @@ -197,8 +182,7 @@ public abstract class TradeStepView extends AnchorPane { peerTxIdSubscription = EasyBind.subscribe(model.dataModel.isMaker() ? model.dataModel.takerTxId : model.dataModel.makerTxId, id -> { if (!id.isEmpty()) { - startCachingTxs(); - peerTxIdTextField.setup(id); + peerTxIdTextField.setup(id, trade); } else { peerTxIdTextField.cleanup(); } @@ -206,15 +190,13 @@ public abstract class TradeStepView extends AnchorPane { } trade.errorMessageProperty().addListener(errorMessageListener); - if (!isMediationClosedState()) { - tradeStepInfo.setOnAction(e -> { - if (this.isTradePeriodOver()) { - openSupportTicket(); - } else { - openChat(); - } - }); - } + tradeStepInfo.setOnAction(e -> { + if (!isArbitrationOpenedState() && this.isTradePeriodOver()) { + openSupportTicket(); + } else { + openChat(); + } + }); // We get mailbox messages processed after we have bootstrapped. This will influence the states we // handle in our disputeStateSubscription and mediationResultStateSubscriptions. To avoid that we show @@ -224,7 +206,7 @@ public abstract class TradeStepView extends AnchorPane { } else { bootstrapListener = new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { registerSubscriptions(); } }; @@ -344,32 +326,38 @@ public abstract class TradeStepView extends AnchorPane { GridPane.setColumnSpan(tradeInfoTitledGroupBg, 2); // self's deposit tx id - final Tuple3<Label, TxIdTextField, VBox> labelSelfTxIdTextFieldVBoxTuple3 = - addTopLabelTxIdTextField(gridPane, gridRow, Res.get("shared.yourDepositTransactionId"), - Layout.COMPACT_FIRST_ROW_DISTANCE); + boolean showSelfTxId = model.dataModel.isMaker() || !trade.hasBuyerAsTakerWithoutDeposit(); + if (showSelfTxId) { + final Tuple3<Label, TxIdTextField, VBox> labelSelfTxIdTextFieldVBoxTuple3 = + addTopLabelTxIdTextField(gridPane, gridRow, Res.get("shared.yourDepositTransactionId"), + Layout.COMPACT_FIRST_ROW_DISTANCE); - GridPane.setColumnSpan(labelSelfTxIdTextFieldVBoxTuple3.third, 2); - selfTxIdTextField = labelSelfTxIdTextFieldVBoxTuple3.second; + GridPane.setColumnSpan(labelSelfTxIdTextFieldVBoxTuple3.third, 2); + selfTxIdTextField = labelSelfTxIdTextFieldVBoxTuple3.second; - String selfTxId = model.dataModel.isMaker() ? model.dataModel.makerTxId.get() : model.dataModel.takerTxId.get(); - if (!selfTxId.isEmpty()) - selfTxIdTextField.setup(selfTxId); - else - selfTxIdTextField.cleanup(); + String selfTxId = model.dataModel.isMaker() ? model.dataModel.makerTxId.get() : model.dataModel.takerTxId.get(); + if (!selfTxId.isEmpty()) + selfTxIdTextField.setup(selfTxId, trade); + else + selfTxIdTextField.cleanup(); + } // peer's deposit tx id - final Tuple3<Label, TxIdTextField, VBox> labelPeerTxIdTextFieldVBoxTuple3 = - addTopLabelTxIdTextField(gridPane, ++gridRow, Res.get("shared.peerDepositTransactionId"), - -Layout.GROUP_DISTANCE_WITHOUT_SEPARATOR); + boolean showPeerTxId = !model.dataModel.isMaker() || !trade.hasBuyerAsTakerWithoutDeposit(); + if (showPeerTxId) { + final Tuple3<Label, TxIdTextField, VBox> labelPeerTxIdTextFieldVBoxTuple3 = + addTopLabelTxIdTextField(gridPane, showSelfTxId ? ++gridRow : gridRow, Res.get("shared.peerDepositTransactionId"), + showSelfTxId ? -Layout.GROUP_DISTANCE_WITHOUT_SEPARATOR : Layout.COMPACT_FIRST_ROW_DISTANCE); - GridPane.setColumnSpan(labelPeerTxIdTextFieldVBoxTuple3.third, 2); - peerTxIdTextField = labelPeerTxIdTextFieldVBoxTuple3.second; + GridPane.setColumnSpan(labelPeerTxIdTextFieldVBoxTuple3.third, 2); + peerTxIdTextField = labelPeerTxIdTextFieldVBoxTuple3.second; - String peerTxId = model.dataModel.isMaker() ? model.dataModel.takerTxId.get() : model.dataModel.makerTxId.get(); - if (!peerTxId.isEmpty()) - peerTxIdTextField.setup(peerTxId); - else - peerTxIdTextField.cleanup(); + String peerTxId = model.dataModel.isMaker() ? model.dataModel.takerTxId.get() : model.dataModel.makerTxId.get(); + if (!peerTxId.isEmpty()) + peerTxIdTextField.setup(peerTxId, trade); + else + peerTxIdTextField.cleanup(); + } if (model.dataModel.getTrade() != null) { checkNotNull(model.dataModel.getTrade().getOffer(), "Offer must not be null in TradeStepView"); @@ -384,7 +372,7 @@ public abstract class TradeStepView extends AnchorPane { timeLeftTextField = labelTextFieldVBoxTuple3.second; timeLeftTextField.setMinWidth(400); - timeLeftProgressBar = new JFXProgressBar(0); + timeLeftProgressBar = new ProgressBar(0); timeLeftProgressBar.setOpacity(0.7); timeLeftProgressBar.setMinHeight(9); timeLeftProgressBar.setMaxHeight(9); @@ -424,12 +412,7 @@ public abstract class TradeStepView extends AnchorPane { log.warn("deactivating TradeStepView because model's trade is null"); // schedule deactivation to avoid concurrent modification of clock listeners - Platform.runLater(new Runnable() { - @Override - public void run() { - deactivate(); - } - }); + Platform.runLater(() -> deactivate()); return; } @@ -593,7 +576,7 @@ public abstract class TradeStepView extends AnchorPane { } private void updateMediationResultState(boolean blockOpeningOfResultAcceptedPopup) { - if (isInArbitration()) { + if (isInMediation()) { if (isRefundRequestStartedByPeer()) { tradeStepInfo.setState(TradeStepInfo.State.IN_REFUND_REQUEST_PEER_REQUESTED); } else if (isRefundRequestSelfStarted()) { @@ -618,7 +601,7 @@ public abstract class TradeStepView extends AnchorPane { } } - private boolean isInArbitration() { + private boolean isInMediation() { return isRefundRequestStartedByPeer() || isRefundRequestSelfStarted(); } @@ -634,6 +617,10 @@ public abstract class TradeStepView extends AnchorPane { return trade.getDisputeState() == Trade.DisputeState.MEDIATION_CLOSED; } + private boolean isArbitrationOpenedState() { + return trade.getDisputeState().isOpen(); + } + private boolean isTradePeriodOver() { return Trade.TradePeriodState.TRADE_PERIOD_OVER == trade.tradePeriodStateProperty().get(); } @@ -667,7 +654,7 @@ public abstract class TradeStepView extends AnchorPane { model.dataModel.onMoveInvalidTradeToFailedTrades(trade); new Popup().warning(Res.get("portfolio.pending.mediationResult.error.depositTxNull")).show(); // TODO (woodser): separate error messages for maker/taker return; - } else if (trade instanceof TakerTrade && trade.getTakerDepositTx() == null) { + } else if (trade instanceof TakerTrade && trade.getTakerDepositTx() == null && !trade.hasBuyerAsTakerWithoutDeposit()) { log.error("trade.getTakerDepositTx() was null at openMediationResultPopup. " + "We add the trade to failed trades. TradeId={}", trade.getId()); //model.dataModel.addTradeToFailedTrades(); @@ -679,8 +666,8 @@ public abstract class TradeStepView extends AnchorPane { DisputeResult disputeResult = optionalDispute.get().getDisputeResultProperty().get(); Contract contract = checkNotNull(trade.getContract(), "contract must not be null"); boolean isMyRoleBuyer = contract.isMyRoleBuyer(model.dataModel.getPubKeyRingProvider().get()); - String buyerPayoutAmount = HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmount(), true); - String sellerPayoutAmount = HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmount(), true); + String buyerPayoutAmount = HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmountBeforeCost(), true); + String sellerPayoutAmount = HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmountBeforeCost(), true); String myPayoutAmount = isMyRoleBuyer ? buyerPayoutAmount : sellerPayoutAmount; String peersPayoutAmount = isMyRoleBuyer ? sellerPayoutAmount : buyerPayoutAmount; @@ -762,7 +749,7 @@ public abstract class TradeStepView extends AnchorPane { } private void updateTradePeriodState(Trade.TradePeriodState tradePeriodState) { - if (trade.getDisputeState() == Trade.DisputeState.NO_DISPUTE) { + if (!trade.getDisputeState().isOpen()) { switch (tradePeriodState) { case FIRST_HALF: // just for dev testing. not possible to go back in time ;-) diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeWizardItem.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeWizardItem.java index 819b83dfaf..335228978c 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeWizardItem.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/TradeWizardItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java index 3702bc3584..804a6dd741 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep1View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.buyer; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java index 37aaca27f6..e36cba49d4 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep2View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.buyer; @@ -22,7 +22,6 @@ import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.util.Tuple4; import haveno.core.locale.Res; -import haveno.core.network.MessageState; import haveno.core.offer.Offer; import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccountUtil; @@ -52,8 +51,10 @@ import haveno.desktop.components.paymentmethods.AssetsForm; import haveno.desktop.components.paymentmethods.AustraliaPayidForm; import haveno.desktop.components.paymentmethods.BizumForm; import haveno.desktop.components.paymentmethods.CapitualForm; +import haveno.desktop.components.paymentmethods.CashAppForm; import haveno.desktop.components.paymentmethods.CashAtAtmForm; import haveno.desktop.components.paymentmethods.PayByMailForm; +import haveno.desktop.components.paymentmethods.PayPalForm; import haveno.desktop.components.paymentmethods.CashDepositForm; import haveno.desktop.components.paymentmethods.CelPayForm; import haveno.desktop.components.paymentmethods.ChaseQuickPayForm; @@ -94,6 +95,7 @@ import haveno.desktop.components.paymentmethods.TransferwiseUsdForm; import haveno.desktop.components.paymentmethods.USPostalMoneyOrderForm; import haveno.desktop.components.paymentmethods.UpholdForm; import haveno.desktop.components.paymentmethods.UpiForm; +import haveno.desktop.components.paymentmethods.VenmoForm; import haveno.desktop.components.paymentmethods.VerseForm; import haveno.desktop.components.paymentmethods.WeChatPayForm; import haveno.desktop.components.paymentmethods.WesternUnionForm; @@ -101,8 +103,10 @@ import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.portfolio.pendingtrades.PendingTradesViewModel; import haveno.desktop.main.portfolio.pendingtrades.steps.TradeStepView; import haveno.desktop.util.Layout; +import javafx.geometry.Insets; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.control.TextArea; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; import javafx.scene.layout.Priority; @@ -147,45 +151,43 @@ public class BuyerStep2View extends TradeStepView { timeoutTimer.stop(); if (trade.isDepositsUnlocked() && !trade.isPaymentSent()) { + busyAnimation.stop(); + statusLabel.setText(""); showPopup(); } else if (state.ordinal() <= Trade.State.SELLER_RECEIVED_PAYMENT_SENT_MSG.ordinal()) { switch (state) { - case BUYER_CONFIRMED_IN_UI_PAYMENT_SENT: + case BUYER_CONFIRMED_PAYMENT_SENT: busyAnimation.play(); statusLabel.setText(Res.get("shared.preparingConfirmation")); break; case BUYER_SENT_PAYMENT_SENT_MSG: - case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG: busyAnimation.play(); statusLabel.setText(Res.get("shared.sendingConfirmation")); - model.setMessageStateProperty(MessageState.SENT); timeoutTimer = UserThread.runAfter(() -> { busyAnimation.stop(); statusLabel.setText(Res.get("shared.sendingConfirmationAgain")); - }, 10); + }, 30); break; case BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG: busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageStoredInMailbox")); - model.setMessageStateProperty(MessageState.STORED_IN_MAILBOX); break; + case BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG: case SELLER_RECEIVED_PAYMENT_SENT_MSG: busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageArrived")); - model.setMessageStateProperty(MessageState.ARRIVED); break; case BUYER_SEND_FAILED_PAYMENT_SENT_MSG: // We get a popup and the trade closed, so we dont need to show anything here busyAnimation.stop(); statusLabel.setText(""); - model.setMessageStateProperty(MessageState.FAILED); break; default: log.warn("Unexpected case: State={}, tradeId={} ", state.name(), trade.getId()); busyAnimation.stop(); statusLabel.setText(Res.get("shared.sendingConfirmationAgain")); break; - } + } } }); } @@ -222,8 +224,9 @@ public class BuyerStep2View extends TradeStepView { addTradeInfoBlock(); + PaymentAccountPayload paymentAccountPayload = model.dataModel.getSellersPaymentAccountPayload(); - String paymentMethodId = paymentAccountPayload != null ? paymentAccountPayload.getPaymentMethodId() : "<missing payment account payload>"; + String paymentMethodId = paymentAccountPayload != null ? paymentAccountPayload.getPaymentMethodId() : "<pending>"; TitledGroupBg accountTitledGroupBg = addTitledGroupBg(gridPane, ++gridRow, 4, Res.get("portfolio.pending.step2_buyer.startPaymentUsing", Res.get(paymentMethodId)), Layout.COMPACT_GROUP_DISTANCE); @@ -233,6 +236,14 @@ public class BuyerStep2View extends TradeStepView { Layout.COMPACT_FIRST_ROW_AND_GROUP_DISTANCE).second; field.setCopyWithoutCurrencyPostFix(true); + //preland: this fixes a textarea layout glitch + TextArea uiHack = new TextArea(); + uiHack.setMaxHeight(1); + GridPane.setRowIndex(uiHack, 1); + GridPane.setMargin(uiHack, new Insets(0, 0, 0, 0)); + uiHack.setVisible(false); + gridPane.getChildren().add(uiHack); + switch (paymentMethodId) { case PaymentMethod.UPHOLD_ID: gridRow = UpholdForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); @@ -397,6 +408,15 @@ public class BuyerStep2View extends TradeStepView { case PaymentMethod.DOMESTIC_WIRE_TRANSFER_ID: gridRow = DomesticWireTransferForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); break; + case PaymentMethod.CASH_APP_ID: + gridRow = CashAppForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; + case PaymentMethod.PAYPAL_ID: + gridRow = PayPalForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; + case PaymentMethod.VENMO_ID: + gridRow = VenmoForm.addFormForBuyer(gridPane, gridRow, paymentAccountPayload); + break; default: log.error("Not supported PaymentMethod: " + paymentMethodId); } @@ -436,7 +456,8 @@ public class BuyerStep2View extends TradeStepView { private boolean confirmPaymentSentPermitted() { if (!trade.confirmPermitted()) return false; - return trade.isDepositsUnlocked() && trade.getState().ordinal() < Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal(); + if (trade.getState() == Trade.State.BUYER_SEND_FAILED_PAYMENT_SENT_MSG) return true; + return trade.isDepositsUnlocked() && trade.getState().ordinal() < Trade.State.BUYER_CONFIRMED_PAYMENT_SENT.ordinal(); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -573,13 +594,13 @@ public class BuyerStep2View extends TradeStepView { private void confirmPaymentSent() { busyAnimation.play(); - statusLabel.setText(Res.get("shared.sendingConfirmation")); + statusLabel.setText(Res.get("shared.preparingConfirmation")); confirmButton.setDisable(true); model.dataModel.onPaymentSent(() -> { }, errorMessage -> { busyAnimation.stop(); - new Popup().warning(Res.get("popup.warning.sendMsgFailed")).show(); + new Popup().warning(Res.get("popup.warning.sendMsgFailed") + "\n\n" + errorMessage).show(); confirmButton.setDisable(!confirmPaymentSentPermitted()); UserThread.execute(() -> statusLabel.setText("Error confirming payment sent.")); }); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java index 0c80a5995c..57fda229f3 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep3View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.buyer; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java index 8ed71ec4be..34bfc75223 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/buyer/BuyerStep4View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.buyer; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java index 60772233a4..f641ddf3f4 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep1View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.seller; @@ -48,7 +48,7 @@ public class SellerStep1View extends TradeStepView { @Override protected String getInfoText() { - return Res.get("portfolio.pending.step1.info", Res.get("shared.TheBTCBuyer")); + return Res.get("portfolio.pending.step1.info", Res.get("shared.TheXMRBuyer")); } /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java index 8b78a3d21a..06ceba45a2 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep2View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.seller; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java index b28307f090..c5cfcbcdb5 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep3View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.seller; @@ -109,40 +109,40 @@ public class SellerStep3View extends TradeStepView { timeoutTimer.stop(); if (trade.isPaymentSent() && !trade.isPaymentReceived()) { + busyAnimation.stop(); + statusLabel.setText(""); showPopup(); } else if (trade.isPaymentReceived()) { - switch (state) { - case SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT: + if (trade.isCompleted()) { + if (!trade.isPayoutPublished()) log.warn("Payout is expected to be published for {} {} state {}", trade.getClass().getSimpleName(), trade.getId(), trade.getState()); + busyAnimation.stop(); + statusLabel.setText(""); + } else switch (state) { + case SELLER_CONFIRMED_PAYMENT_RECEIPT: busyAnimation.play(); statusLabel.setText(Res.get("shared.preparingConfirmation")); break; case SELLER_SENT_PAYMENT_RECEIVED_MSG: busyAnimation.play(); statusLabel.setText(Res.get("shared.sendingConfirmation")); - timeoutTimer = UserThread.runAfter(() -> { busyAnimation.stop(); statusLabel.setText(Res.get("shared.sendingConfirmationAgain")); - }, 10); - break; - case SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG: - busyAnimation.stop(); - statusLabel.setText(Res.get("shared.messageArrived")); + }, 30); break; case SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG: busyAnimation.stop(); statusLabel.setText(Res.get("shared.messageStoredInMailbox")); break; + case SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG: + busyAnimation.stop(); + statusLabel.setText(Res.get("shared.messageArrived")); + break; case SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG: // We get a popup and the trade closed, so we dont need to show anything here busyAnimation.stop(); statusLabel.setText(""); break; - case TRADE_COMPLETED: - if (!trade.isPayoutPublished()) log.warn("Payout is expected to be published for {} {} state {}", trade.getClass().getSimpleName(), trade.getId(), trade.getState()); - busyAnimation.stop(); - statusLabel.setText(""); - break; default: log.warn("Unexpected case: State={}, tradeId={} " + state.name(), trade.getId()); busyAnimation.stop(); @@ -203,10 +203,8 @@ public class SellerStep3View extends TradeStepView { .orElse(""); if (myPaymentAccountPayload instanceof AssetAccountPayload) { - if (myPaymentDetails.isEmpty()) { - // Not expected - myPaymentDetails = ((AssetAccountPayload) myPaymentAccountPayload).getAddress(); - } + // for crypto always display the receiving address + myPaymentDetails = ((AssetAccountPayload) myPaymentAccountPayload).getAddress(); peersPaymentDetails = peersPaymentAccountPayload != null ? ((AssetAccountPayload) peersPaymentAccountPayload).getAddress() : "NA"; myTitle = Res.get("portfolio.pending.step3_seller.yourAddress", currencyName); @@ -291,7 +289,8 @@ public class SellerStep3View extends TradeStepView { private boolean confirmPaymentReceivedPermitted() { if (!trade.confirmPermitted()) return false; - return trade.getState().ordinal() >= Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal() && trade.getState().ordinal() < Trade.State.SELLER_SENT_PAYMENT_RECEIVED_MSG.ordinal(); + if (trade.getState() == Trade.State.SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG) return true; + return trade.getState().ordinal() >= Trade.State.BUYER_SENT_PAYMENT_SENT_MSG.ordinal() && trade.getState().ordinal() < Trade.State.SELLER_CONFIRMED_PAYMENT_RECEIPT.ordinal(); } /////////////////////////////////////////////////////////////////////////////////////////// @@ -443,13 +442,13 @@ public class SellerStep3View extends TradeStepView { private void confirmPaymentReceived() { log.info("User pressed the [Confirm payment receipt] button for Trade {}", trade.getShortId()); busyAnimation.play(); - statusLabel.setText(Res.get("shared.sendingConfirmation")); + statusLabel.setText(Res.get("shared.preparingConfirmation")); confirmButton.setDisable(true); model.dataModel.onPaymentReceived(() -> { }, errorMessage -> { busyAnimation.stop(); - new Popup().warning(Res.get("popup.warning.sendMsgFailed")).show(); + new Popup().warning(Res.get("popup.warning.sendMsgFailed") + "\n\n" + errorMessage).show(); confirmButton.setDisable(!confirmPaymentReceivedPermitted()); UserThread.execute(() -> statusLabel.setText("Error confirming payment received.")); }); diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep4View.java b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep4View.java index c57eec9aee..82927e1d50 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep4View.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/pendingtrades/steps/seller/SellerStep4View.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.pendingtrades.steps.seller; diff --git a/desktop/src/main/java/haveno/desktop/main/portfolio/presentation/PortfolioUtil.java b/desktop/src/main/java/haveno/desktop/main/portfolio/presentation/PortfolioUtil.java index e01c55dbd8..90e5438676 100644 --- a/desktop/src/main/java/haveno/desktop/main/portfolio/presentation/PortfolioUtil.java +++ b/desktop/src/main/java/haveno/desktop/main/portfolio/presentation/PortfolioUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.portfolio.presentation; diff --git a/desktop/src/main/java/haveno/desktop/main/presentation/AccountPresentation.java b/desktop/src/main/java/haveno/desktop/main/presentation/AccountPresentation.java index c54dbff962..61b785439b 100644 --- a/desktop/src/main/java/haveno/desktop/main/presentation/AccountPresentation.java +++ b/desktop/src/main/java/haveno/desktop/main/presentation/AccountPresentation.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.presentation; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.app.DevEnv; import haveno.core.locale.Res; import haveno.core.user.DontShowAgainLookup; @@ -26,9 +28,6 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.collections.MapChangeListener; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public class AccountPresentation { diff --git a/desktop/src/main/java/haveno/desktop/main/presentation/MarketPricePresentation.java b/desktop/src/main/java/haveno/desktop/main/presentation/MarketPricePresentation.java index 35be328950..3529369285 100644 --- a/desktop/src/main/java/haveno/desktop/main/presentation/MarketPricePresentation.java +++ b/desktop/src/main/java/haveno/desktop/main/presentation/MarketPricePresentation.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.presentation; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.UserThread; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -28,6 +30,10 @@ import haveno.core.util.FormattingUtils; import haveno.core.xmr.wallet.XmrWalletService; import haveno.desktop.components.TxIdTextField; import haveno.desktop.main.shared.PriceFeedComboBoxItem; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javafx.beans.property.BooleanProperty; import javafx.beans.property.IntegerProperty; import javafx.beans.property.ObjectProperty; @@ -44,13 +50,6 @@ import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.monadic.MonadicBinding; -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.List; -import java.util.Optional; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - @Singleton public class MarketPricePresentation { private final Preferences preferences; @@ -111,9 +110,19 @@ public class MarketPricePresentation { } private void fillPriceFeedComboBoxItems() { - List<PriceFeedComboBoxItem> currencyItems = preferences.getTradeCurrenciesAsObservable() + + // collect unique currency code bases + List<String> uniqueCurrencyCodeBases = preferences.getTradeCurrenciesAsObservable() .stream() - .map(tradeCurrency -> new PriceFeedComboBoxItem(tradeCurrency.getCode())) + .map(TradeCurrency::getCode) + .map(CurrencyUtil::getCurrencyCodeBase) + .distinct() + .collect(Collectors.toList()); + + // create price feed items + List<PriceFeedComboBoxItem> currencyItems = uniqueCurrencyCodeBases + .stream() + .map(currencyCodeBase -> new PriceFeedComboBoxItem(currencyCodeBase)) .collect(Collectors.toList()); priceFeedComboBoxItems.setAll(currencyItems); } @@ -124,34 +133,40 @@ public class MarketPricePresentation { marketPriceBinding = EasyBind.combine( marketPriceCurrencyCode, marketPrice, - (currencyCode, price) -> CurrencyUtil.getCurrencyPair(currencyCode) + ": " + price); + (currencyCode, price) -> { + MarketPrice currentPrice = priceFeedService.getMarketPrice(currencyCode); + String currentPriceStr = currentPrice == null ? Res.get("shared.na") : FormattingUtils.formatMarketPrice(currentPrice.getPrice(), currencyCode); + return CurrencyUtil.getCurrencyPair(currencyCode) + ": " + currentPriceStr; + }); marketPriceBinding.subscribe((observable, oldValue, newValue) -> { - if (newValue != null && !newValue.equals(oldValue)) { - setMarketPriceInItems(); + UserThread.execute(() -> { + if (newValue != null && !newValue.equals(oldValue)) { + setMarketPriceInItems(); - String code = priceFeedService.currencyCodeProperty().get(); - Optional<PriceFeedComboBoxItem> itemOptional = findPriceFeedComboBoxItem(code); - if (itemOptional.isPresent()) { - itemOptional.get().setDisplayString(newValue); - selectedPriceFeedComboBoxItemProperty.set(itemOptional.get()); - } else { - if (CurrencyUtil.isCryptoCurrency(code)) { - CurrencyUtil.getCryptoCurrency(code).ifPresent(cryptoCurrency -> { - preferences.addCryptoCurrency(cryptoCurrency); - fillPriceFeedComboBoxItems(); - }); + String code = priceFeedService.currencyCodeProperty().get(); + Optional<PriceFeedComboBoxItem> itemOptional = findPriceFeedComboBoxItem(code); + if (itemOptional.isPresent()) { + itemOptional.get().setDisplayString(newValue); + selectedPriceFeedComboBoxItemProperty.set(itemOptional.get()); } else { - CurrencyUtil.getTraditionalCurrency(code).ifPresent(traditionalCurrency -> { - preferences.addTraditionalCurrency(traditionalCurrency); - fillPriceFeedComboBoxItems(); - }); + if (CurrencyUtil.isCryptoCurrency(code)) { + CurrencyUtil.getCryptoCurrency(code).ifPresent(cryptoCurrency -> { + preferences.addCryptoCurrency(cryptoCurrency); + fillPriceFeedComboBoxItems(); + }); + } else { + CurrencyUtil.getTraditionalCurrency(code).ifPresent(traditionalCurrency -> { + preferences.addTraditionalCurrency(traditionalCurrency); + fillPriceFeedComboBoxItems(); + }); + } } - } - if (selectedPriceFeedComboBoxItemProperty.get() != null) - selectedPriceFeedComboBoxItemProperty.get().setDisplayString(newValue); - } + if (selectedPriceFeedComboBoxItemProperty.get() != null) + selectedPriceFeedComboBoxItemProperty.get().setDisplayString(newValue); + } + }); }); marketPriceCurrencyCode.bind(priceFeedService.currencyCodeProperty()); @@ -166,7 +181,7 @@ public class MarketPricePresentation { private Optional<PriceFeedComboBoxItem> findPriceFeedComboBoxItem(String currencyCode) { return priceFeedComboBoxItems.stream() - .filter(item -> item.currencyCode.equals(currencyCode)) + .filter(item -> CurrencyUtil.getCurrencyCodeBase(item.currencyCode).equals(CurrencyUtil.getCurrencyCodeBase(currencyCode))) .findAny(); } diff --git a/desktop/src/main/java/haveno/desktop/main/presentation/SettingsPresentation.java b/desktop/src/main/java/haveno/desktop/main/presentation/SettingsPresentation.java index 8f25f91845..df2ca2665d 100644 --- a/desktop/src/main/java/haveno/desktop/main/presentation/SettingsPresentation.java +++ b/desktop/src/main/java/haveno/desktop/main/presentation/SettingsPresentation.java @@ -1,30 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.presentation; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.core.user.Preferences; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.collections.MapChangeListener; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public class SettingsPresentation { diff --git a/desktop/src/main/java/haveno/desktop/main/settings/SettingsView.java b/desktop/src/main/java/haveno/desktop/main/settings/SettingsView.java index 4a2f0a836d..ee147ad376 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/SettingsView.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/SettingsView.java @@ -1,22 +1,23 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings; +import com.google.inject.Inject; import haveno.core.locale.Res; import haveno.core.user.Preferences; import haveno.desktop.Navigation; @@ -36,8 +37,6 @@ import javafx.scene.control.ScrollPane; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; -import javax.inject.Inject; - @FxmlView public class SettingsView extends ActivatableView<TabPane, Void> { @FXML diff --git a/desktop/src/main/java/haveno/desktop/main/settings/about/AboutView.java b/desktop/src/main/java/haveno/desktop/main/settings/about/AboutView.java index 722638c0b4..e543837f5d 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/about/AboutView.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/about/AboutView.java @@ -1,38 +1,36 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.about; +import com.google.inject.Inject; import haveno.common.app.Version; import haveno.core.locale.Res; import haveno.desktop.common.view.ActivatableView; import haveno.desktop.common.view.FxmlView; import haveno.desktop.components.HyperlinkWithIcon; -import haveno.desktop.util.Layout; -import javafx.geometry.HPos; -import javafx.scene.control.Label; -import javafx.scene.layout.GridPane; - -import javax.inject.Inject; - import static haveno.desktop.util.FormBuilder.addCompactTopLabelTextField; import static haveno.desktop.util.FormBuilder.addHyperlinkWithIcon; import static haveno.desktop.util.FormBuilder.addLabel; import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import haveno.desktop.util.Layout; +import javafx.geometry.HPos; +import javafx.scene.control.Label; +import javafx.scene.layout.GridPane; @FxmlView public class AboutView extends ActivatableView<GridPane, Void> { @@ -112,7 +110,7 @@ public class AboutView extends ActivatableView<GridPane, Void> { addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.shortcuts.walletDetails"), Res.get("setting.about.shortcuts.ctrlOrAltOrCmd", "j")); - addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.shortcuts.openEmergencyBtcWalletTool"), + addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.shortcuts.openEmergencyXmrWalletTool"), Res.get("setting.about.shortcuts.ctrlOrAltOrCmd", "e")); addCompactTopLabelTextField(root, ++gridRow, Res.get("setting.about.shortcuts.showTorLogs"), diff --git a/desktop/src/main/java/haveno/desktop/main/settings/network/MoneroNetworkListItem.java b/desktop/src/main/java/haveno/desktop/main/settings/network/MoneroNetworkListItem.java index 8f74f474d0..fea0ef6f34 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/network/MoneroNetworkListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/network/MoneroNetworkListItem.java @@ -1,44 +1,39 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.network; -import monero.daemon.model.MoneroPeer; +import haveno.core.locale.Res; +import monero.common.MoneroRpcConnection; public class MoneroNetworkListItem { - private final MoneroPeer peer; - - public MoneroNetworkListItem(MoneroPeer peer) { - this.peer = peer; + private final MoneroRpcConnection connection; + private final boolean connected; + + public MoneroNetworkListItem(MoneroRpcConnection connection, boolean connected) { + this.connection = connection; + this.connected = connected; } - public String getOnionAddress() { - return peer.getHost() + ":" + peer.getPort(); + public String getAddress() { + return connection.getUri(); } - public String getVersion() { - return ""; - } - - public String getSubVersion() { - return ""; - } - - public String getHeight() { - return String.valueOf(peer.getHeight()); + public String getConnected() { + return connected ? Res.get("settings.net.connected") : ""; } } diff --git a/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.fxml b/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.fxml index 3e9d25428e..1f3e8840d7 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.fxml +++ b/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.fxml @@ -45,27 +45,17 @@ <TitledGroupBg fx:id="btcHeader" GridPane.rowSpan="5"/> <VBox GridPane.rowIndex="0" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES"> - <AutoTooltipLabel fx:id="moneroPeersLabel" styleClass="small-text"/> - <TableView fx:id="moneroPeersTableView"> + <AutoTooltipLabel fx:id="moneroConnectionsLabel" styleClass="small-text"/> + <TableView fx:id="moneroConnectionsTableView"> <columns> - <TableColumn fx:id="moneroPeerAddressColumn" minWidth="220"> + <TableColumn fx:id="moneroConnectionAddressColumn" minWidth="220"> <cellValueFactory> - <PropertyValueFactory property="onionAddress"/> + <PropertyValueFactory property="address"/> </cellValueFactory> </TableColumn> - <TableColumn fx:id="moneroPeerVersionColumn" minWidth="80" maxWidth="90"> + <TableColumn fx:id="moneroConnectionConnectedColumn" minWidth="80" maxWidth="90"> <cellValueFactory> - <PropertyValueFactory property="version"/> - </cellValueFactory> - </TableColumn> - <TableColumn fx:id="moneroPeerSubVersionColumn" minWidth="180" maxWidth="180"> - <cellValueFactory> - <PropertyValueFactory property="subVersion"/> - </cellValueFactory> - </TableColumn> - <TableColumn fx:id="moneroPeerHeightColumn" minWidth="80" maxWidth="80"> - <cellValueFactory> - <PropertyValueFactory property="height"/> + <PropertyValueFactory property="connected"/> </cellValueFactory> </TableColumn> </columns> diff --git a/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.java b/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.java index 9d46dfca32..546a55505f 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/network/NetworkSettingsView.java @@ -1,29 +1,31 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.network; +import com.google.inject.Inject; import haveno.common.ClockWatcher; import haveno.common.UserThread; -import haveno.core.api.CoreMoneroConnectionsService; -import haveno.core.api.LocalMoneroNode; +import haveno.core.api.XmrConnectionService; +import haveno.core.api.XmrLocalNode; import haveno.core.filter.Filter; import haveno.core.filter.FilterManager; import haveno.core.locale.Res; +import haveno.core.trade.HavenoUtils; import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; import haveno.core.util.validation.RegexValidator; @@ -42,6 +44,9 @@ import haveno.desktop.main.overlays.windows.TorNetworkSettingsWindow; import haveno.desktop.util.GUIUtil; import haveno.network.p2p.P2PService; import haveno.network.p2p.network.Statistic; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import static javafx.beans.binding.Bindings.createStringBinding; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -57,17 +62,9 @@ import javafx.scene.control.TextField; import javafx.scene.control.Toggle; import javafx.scene.control.ToggleGroup; import javafx.scene.layout.GridPane; -import monero.daemon.model.MoneroPeer; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import javax.inject.Inject; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static javafx.beans.binding.Bindings.createStringBinding; - @FxmlView public class NetworkSettingsView extends ActivatableView<GridPane, Void> { @@ -80,7 +77,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { @FXML TextField onionAddress, sentDataTextField, receivedDataTextField, chainHeightTextField; @FXML - Label p2PPeersLabel, moneroPeersLabel; + Label p2PPeersLabel, moneroConnectionsLabel; @FXML RadioButton useTorForXmrAfterSyncRadio, useTorForXmrOffRadio, useTorForXmrOnRadio; @FXML @@ -88,13 +85,12 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { @FXML TableView<P2pNetworkListItem> p2pPeersTableView; @FXML - TableView<MoneroNetworkListItem> moneroPeersTableView; + TableView<MoneroNetworkListItem> moneroConnectionsTableView; @FXML TableColumn<P2pNetworkListItem, String> onionAddressColumn, connectionTypeColumn, creationDateColumn, roundTripTimeColumn, sentBytesColumn, receivedBytesColumn, peerTypeColumn; @FXML - TableColumn<MoneroNetworkListItem, String> moneroPeerAddressColumn, moneroPeerVersionColumn, - moneroPeerSubVersionColumn, moneroPeerHeightColumn; + TableColumn<MoneroNetworkListItem, String> moneroConnectionAddressColumn, moneroConnectionConnectedColumn; @FXML Label rescanOutputsLabel; @FXML @@ -103,12 +99,12 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { private final Preferences preferences; private final XmrNodes xmrNodes; private final FilterManager filterManager; - private final LocalMoneroNode localMoneroNode; + private final XmrLocalNode xmrLocalNode; private final TorNetworkSettingsWindow torNetworkSettingsWindow; private final ClockWatcher clockWatcher; private final WalletsSetup walletsSetup; private final P2PService p2PService; - private final CoreMoneroConnectionsService connectionManager; + private final XmrConnectionService connectionService; private final ObservableList<P2pNetworkListItem> p2pNetworkListItems = FXCollections.observableArrayList(); private final SortedList<P2pNetworkListItem> p2pSortedList = new SortedList<>(p2pNetworkListItems); @@ -117,7 +113,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { private final SortedList<MoneroNetworkListItem> moneroSortedList = new SortedList<>(moneroNetworkListItems); private Subscription numP2PPeersSubscription; - private Subscription moneroPeersSubscription; + private Subscription moneroConnectionsSubscription; private Subscription moneroBlockHeightSubscription; private Subscription nodeAddressSubscription; private ChangeListener<Boolean> xmrNodesInputTextFieldFocusListener; @@ -132,42 +128,40 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { @Inject public NetworkSettingsView(WalletsSetup walletsSetup, P2PService p2PService, - CoreMoneroConnectionsService connectionManager, + XmrConnectionService connectionService, Preferences preferences, XmrNodes xmrNodes, FilterManager filterManager, - LocalMoneroNode localMoneroNode, + XmrLocalNode xmrLocalNode, TorNetworkSettingsWindow torNetworkSettingsWindow, ClockWatcher clockWatcher) { super(); this.walletsSetup = walletsSetup; this.p2PService = p2PService; - this.connectionManager = connectionManager; + this.connectionService = connectionService; this.preferences = preferences; this.xmrNodes = xmrNodes; this.filterManager = filterManager; - this.localMoneroNode = localMoneroNode; + this.xmrLocalNode = xmrLocalNode; this.torNetworkSettingsWindow = torNetworkSettingsWindow; this.clockWatcher = clockWatcher; } @Override public void initialize() { - btcHeader.setText(Res.get("settings.net.btcHeader")); + btcHeader.setText(Res.get("settings.net.xmrHeader")); p2pHeader.setText(Res.get("settings.net.p2pHeader")); onionAddress.setPromptText(Res.get("settings.net.onionAddressLabel")); xmrNodesLabel.setText(Res.get("settings.net.xmrNodesLabel")); - moneroPeersLabel.setText(Res.get("settings.net.moneroPeersLabel")); + moneroConnectionsLabel.setText(Res.get("settings.net.moneroPeersLabel")); useTorForXmrLabel.setText(Res.get("settings.net.useTorForXmrJLabel")); useTorForXmrAfterSyncRadio.setText(Res.get("settings.net.useTorForXmrAfterSyncRadio")); useTorForXmrOffRadio.setText(Res.get("settings.net.useTorForXmrOffRadio")); useTorForXmrOnRadio.setText(Res.get("settings.net.useTorForXmrOnRadio")); moneroNodesLabel.setText(Res.get("settings.net.moneroNodesLabel")); - moneroPeerAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn"))); - moneroPeerAddressColumn.getStyleClass().add("first-column"); - moneroPeerVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.versionColumn"))); - moneroPeerSubVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.subVersionColumn"))); - moneroPeerHeightColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.heightColumn"))); + moneroConnectionAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("shared.address"))); + moneroConnectionAddressColumn.getStyleClass().add("first-column"); + moneroConnectionConnectedColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.connection"))); localhostXmrNodeInfoLabel.setText(Res.get("settings.net.localhostXmrNodeInfo")); useProvidedNodesRadio.setText(Res.get("settings.net.useProvidedNodesRadio")); useCustomNodesRadio.setText(Res.get("settings.net.useCustomNodesRadio")); @@ -193,19 +187,19 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { rescanOutputsLabel.setVisible(false); rescanOutputsButton.setVisible(false); - GridPane.setMargin(moneroPeersLabel, new Insets(4, 0, 0, 0)); - GridPane.setValignment(moneroPeersLabel, VPos.TOP); + GridPane.setMargin(moneroConnectionsLabel, new Insets(4, 0, 0, 0)); + GridPane.setValignment(moneroConnectionsLabel, VPos.TOP); GridPane.setMargin(p2PPeersLabel, new Insets(4, 0, 0, 0)); GridPane.setValignment(p2PPeersLabel, VPos.TOP); - moneroPeersTableView.setMinHeight(180); - moneroPeersTableView.setPrefHeight(180); - moneroPeersTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); - moneroPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData"))); - moneroPeersTableView.getSortOrder().add(moneroPeerAddressColumn); - moneroPeerAddressColumn.setSortType(TableColumn.SortType.ASCENDING); - + moneroConnectionAddressColumn.setSortType(TableColumn.SortType.ASCENDING); + moneroConnectionConnectedColumn.setSortType(TableColumn.SortType.DESCENDING); + moneroConnectionsTableView.setMinHeight(180); + moneroConnectionsTableView.setPrefHeight(180); + moneroConnectionsTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); + moneroConnectionsTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData"))); + moneroConnectionsTableView.getSortOrder().add(moneroConnectionConnectedColumn); p2pPeersTableView.setMinHeight(180); p2pPeersTableView.setPrefHeight(180); @@ -213,7 +207,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { p2pPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData"))); p2pPeersTableView.getSortOrder().add(creationDateColumn); creationDateColumn.setSortType(TableColumn.SortType.ASCENDING); - + // use tor for xmr radio buttons useTorForXmrToggleGroup = new ToggleGroup(); @@ -236,7 +230,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { onUseTorForXmrToggleSelected(true); } }; - + // monero nodes radio buttons moneroPeersToggleGroup = new ToggleGroup(); @@ -268,7 +262,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { } }; - xmrNodesInputTextField.setPromptText(Res.get("settings.net.ips")); + xmrNodesInputTextField.setPromptText(Res.get("settings.net.ips", "" + HavenoUtils.getDefaultMoneroPort())); RegexValidator regexValidator = RegexValidatorFactory.addressRegexValidator(); xmrNodesInputTextField.setValidator(regexValidator); xmrNodesInputTextField.setErrorMessage(Res.get("validation.invalidAddressList")); @@ -283,6 +277,12 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { }; filterPropertyListener = (observable, oldValue, newValue) -> applyPreventPublicXmrNetwork(); + // disable radio buttons if no nodes available + if (xmrNodes.getProvidedXmrNodes().isEmpty()) { + useProvidedNodesRadio.setDisable(true); + } + usePublicNodesRadio.setDisable(isPublicNodesDisabled()); + //TODO sorting needs other NetworkStatisticListItem as columns type /* creationDateColumn.setComparator((o1, o2) -> o1.statistic.getCreationDate().compareTo(o2.statistic.getCreationDate())); @@ -304,11 +304,11 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { rescanOutputsButton.setOnAction(event -> GUIUtil.rescanOutputs(preferences)); - moneroPeersSubscription = EasyBind.subscribe(connectionManager.peerConnectionsProperty(), - this::updateMoneroPeersTable); + moneroConnectionsSubscription = EasyBind.subscribe(connectionService.connectionsProperty(), + connections -> updateMoneroConnectionsTable()); - moneroBlockHeightSubscription = EasyBind.subscribe(connectionManager.chainHeightProperty(), - this::updateChainHeightTextField); + moneroBlockHeightSubscription = EasyBind.subscribe(connectionService.chainHeightProperty(), + height -> updateMoneroConnectionsTable()); nodeAddressSubscription = EasyBind.subscribe(p2PService.getNetworkNode().nodeAddressProperty(), nodeAddress -> onionAddress.setText(nodeAddress == null ? @@ -328,8 +328,8 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { Statistic.numTotalReceivedMessagesPerSecProperty().get()), Statistic.numTotalReceivedMessagesPerSecProperty())); - moneroSortedList.comparatorProperty().bind(moneroPeersTableView.comparatorProperty()); - moneroPeersTableView.setItems(moneroSortedList); + moneroSortedList.comparatorProperty().bind(moneroConnectionsTableView.comparatorProperty()); + moneroConnectionsTableView.setItems(moneroSortedList); p2pSortedList.comparatorProperty().bind(p2pPeersTableView.comparatorProperty()); p2pPeersTableView.setItems(p2pSortedList); @@ -350,8 +350,8 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { if (nodeAddressSubscription != null) nodeAddressSubscription.unsubscribe(); - if (moneroPeersSubscription != null) - moneroPeersSubscription.unsubscribe(); + if (moneroConnectionsSubscription != null) + moneroConnectionsSubscription.unsubscribe(); if (moneroBlockHeightSubscription != null) moneroBlockHeightSubscription.unsubscribe(); @@ -374,7 +374,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { return filterManager.getFilter() != null && filterManager.getFilter().isPreventPublicXmrNetwork(); } - + private void selectUseTorForXmrToggle() { switch (selectedUseTorForXmr) { case OFF: @@ -412,7 +412,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { .useShutDownButton() .show(); } - + private void onUseTorForXmrToggleSelected(boolean calledFromUser) { Preferences.UseTorForXmr currentUseTorForXmr = Preferences.UseTorForXmr.values()[preferences.getUseTorForXmrOrdinal()]; if (currentUseTorForXmr != selectedUseTorForXmr) { @@ -434,14 +434,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { } private void onMoneroPeersToggleSelected(boolean calledFromUser) { - boolean localMoneroNodeShouldBeUsed = localMoneroNode.shouldBeUsed(); - useTorForXmrLabel.setDisable(localMoneroNodeShouldBeUsed); - moneroNodesLabel.setDisable(localMoneroNodeShouldBeUsed); - xmrNodesLabel.setDisable(localMoneroNodeShouldBeUsed); - xmrNodesInputTextField.setDisable(localMoneroNodeShouldBeUsed); - useProvidedNodesRadio.setDisable(localMoneroNodeShouldBeUsed); - useCustomNodesRadio.setDisable(localMoneroNodeShouldBeUsed); - usePublicNodesRadio.setDisable(localMoneroNodeShouldBeUsed || isPreventPublicXmrNetwork()); + usePublicNodesRadio.setDisable(isPublicNodesDisabled()); XmrNodes.MoneroNodesOption currentMoneroNodesOption = XmrNodes.MoneroNodesOption.values()[preferences.getMoneroNodesOptionOrdinal()]; @@ -501,7 +494,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { private void applyPreventPublicXmrNetwork() { final boolean preventPublicXmrNetwork = isPreventPublicXmrNetwork(); - usePublicNodesRadio.setDisable(localMoneroNode.shouldBeUsed() || preventPublicXmrNetwork); + usePublicNodesRadio.setDisable(isPublicNodesDisabled()); if (preventPublicXmrNetwork && selectedMoneroNodesOption == XmrNodes.MoneroNodesOption.PUBLIC) { selectedMoneroNodesOption = XmrNodes.MoneroNodesOption.PROVIDED; preferences.setMoneroNodesOptionOrdinal(selectedMoneroNodesOption.ordinal()); @@ -510,7 +503,12 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { } } + private boolean isPublicNodesDisabled() { + return xmrNodes.getPublicXmrNodes().isEmpty() || isPreventPublicXmrNetwork(); + } + private void updateP2PTable() { + if (connectionService.isShutDownStarted()) return; // ignore if shutting down p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup); p2pNetworkListItems.clear(); p2pNetworkListItems.setAll(p2PService.getNetworkNode().getAllConnections().stream() @@ -518,13 +516,15 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> { .collect(Collectors.toList())); } - private void updateMoneroPeersTable(List<MoneroPeer> peers) { - moneroNetworkListItems.clear(); - if (peers != null) { - moneroNetworkListItems.setAll(peers.stream() - .map(MoneroNetworkListItem::new) + private void updateMoneroConnectionsTable() { + UserThread.execute(() -> { + if (connectionService.isShutDownStarted()) return; // ignore if shutting down + moneroNetworkListItems.clear(); + moneroNetworkListItems.setAll(connectionService.getConnections().stream() + .map(connection -> new MoneroNetworkListItem(connection, Boolean.TRUE.equals(connection.isConnected()) && connection == connectionService.getConnection())) .collect(Collectors.toList())); - } + updateChainHeightTextField(connectionService.chainHeightProperty().get()); + }); } private void updateChainHeightTextField(Number chainHeight) { diff --git a/desktop/src/main/java/haveno/desktop/main/settings/network/P2pNetworkListItem.java b/desktop/src/main/java/haveno/desktop/main/settings/network/P2pNetworkListItem.java index dc652c1fde..0a1de7ca4d 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/network/P2pNetworkListItem.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/network/P2pNetworkListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.network; diff --git a/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesView.java b/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesView.java index 62d5db1c9c..da71490b9a 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesView.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesView.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.preferences; +import static com.google.common.base.Preconditions.checkArgument; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.config.Config; @@ -29,10 +32,10 @@ import haveno.core.locale.Country; import haveno.core.locale.CountryUtil; import haveno.core.locale.CryptoCurrency; import haveno.core.locale.CurrencyUtil; -import haveno.core.locale.TraditionalCurrency; import haveno.core.locale.LanguageUtil; import haveno.core.locale.Res; import haveno.core.locale.TradeCurrency; +import haveno.core.locale.TraditionalCurrency; import haveno.core.payment.PaymentAccount; import haveno.core.payment.payload.PaymentMethod; import haveno.core.payment.validation.XmrValidator; @@ -54,9 +57,24 @@ import haveno.desktop.components.PasswordTextField; import haveno.desktop.components.TitledGroupBg; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.EditCustomExplorerWindow; +import static haveno.desktop.util.FormBuilder.addButton; +import static haveno.desktop.util.FormBuilder.addComboBox; +import static haveno.desktop.util.FormBuilder.addInputTextField; +import static haveno.desktop.util.FormBuilder.addSlideToggleButton; +import static haveno.desktop.util.FormBuilder.addTextFieldWithEditButton; +import static haveno.desktop.util.FormBuilder.addTitledGroupBg; +import static haveno.desktop.util.FormBuilder.addTopLabelListView; import haveno.desktop.util.GUIUtil; import haveno.desktop.util.ImageUtil; import haveno.desktop.util.Layout; +import java.io.File; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import javafx.beans.value.ChangeListener; import javafx.collections.FXCollections; import javafx.collections.ObservableList; @@ -81,26 +99,6 @@ import javafx.util.Callback; import javafx.util.StringConverter; import org.apache.commons.lang3.StringUtils; -import javax.inject.Inject; -import javax.inject.Named; -import java.io.File; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; -import static haveno.desktop.util.FormBuilder.addButton; -import static haveno.desktop.util.FormBuilder.addComboBox; -import static haveno.desktop.util.FormBuilder.addInputTextField; -import static haveno.desktop.util.FormBuilder.addSlideToggleButton; -import static haveno.desktop.util.FormBuilder.addTextFieldWithEditButton; -import static haveno.desktop.util.FormBuilder.addTitledGroupBg; -import static haveno.desktop.util.FormBuilder.addTopLabelListView; - @FxmlView public class PreferencesView extends ActivatableViewAndModel<GridPane, PreferencesViewModel> { private final User user; @@ -110,7 +108,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc private ComboBox<TradeCurrency> preferredTradeCurrencyComboBox; private ToggleButton showOwnOffersInOfferBook, useAnimations, useDarkMode, sortMarketCurrenciesNumerically, - avoidStandbyMode, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle, + avoidStandbyMode, useSoundForNotifications, useCustomFee, autoConfirmXmrToggle, hideNonAccountPaymentMethodsToggle, denyApiTakerToggle, notifyOnPreReleaseToggle; private int gridRow = 0; private int displayCurrenciesGridRowIndex = 0; @@ -189,7 +187,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc @Override protected void activate() { // We want to have it updated in case an asset got removed - allCryptoCurrencies = FXCollections.observableArrayList(CurrencyUtil.getActiveSortedCryptoCurrencies( filterManager)); + allCryptoCurrencies = FXCollections.observableArrayList(CurrencyUtil.getActiveSortedCryptoCurrencies(filterManager)); allCryptoCurrencies.removeAll(cryptoCurrencies); activateGeneralOptions(); @@ -211,7 +209,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc /////////////////////////////////////////////////////////////////////////////////////////// private void initializeGeneralOptions() { - int titledGroupBgRowSpan = displayStandbyModeFeature ? 7 : 6; + int titledGroupBgRowSpan = displayStandbyModeFeature ? 8 : 7; TitledGroupBg titledGroupBg = addTitledGroupBg(root, gridRow, titledGroupBgRowSpan, Res.get("setting.preferences.general")); GridPane.setColumnSpan(titledGroupBg, 1); @@ -287,6 +285,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc avoidStandbyMode = addSlideToggleButton(root, ++gridRow, Res.get("setting.preferences.avoidStandbyMode")); } + + useSoundForNotifications = addSlideToggleButton(root, ++gridRow, + Res.get("setting.preferences.useSoundForNotifications"), Layout.GROUP_DISTANCE * -1); // TODO: why must negative value be used to place toggle consistently? } private void initializeSeparator() { @@ -520,6 +521,7 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc GridPane.setHgrow(resetDontShowAgainButton, Priority.ALWAYS); GridPane.setColumnIndex(resetDontShowAgainButton, 0); } + private void initializeAutoConfirmOptions() { GridPane autoConfirmGridPane = new GridPane(); GridPane.setHgrow(autoConfirmGridPane, Priority.ALWAYS); @@ -792,6 +794,9 @@ public class PreferencesView extends ActivatableViewAndModel<GridPane, Preferenc } else { preferences.setUseStandbyMode(false); } + + useSoundForNotifications.setSelected(preferences.isUseSoundForNotifications()); + useSoundForNotifications.setOnAction(e -> preferences.setUseSoundForNotifications(useSoundForNotifications.isSelected())); } private void activateAutoConfirmPreferences() { diff --git a/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesViewModel.java b/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesViewModel.java index c681ad0c37..dd6c8ad3a4 100644 --- a/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesViewModel.java +++ b/desktop/src/main/java/haveno/desktop/main/settings/preferences/PreferencesViewModel.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.preferences; diff --git a/desktop/src/main/java/haveno/desktop/main/shared/ChatView.java b/desktop/src/main/java/haveno/desktop/main/shared/ChatView.java index fcb0d3d745..236f8471e9 100644 --- a/desktop/src/main/java/haveno/desktop/main/shared/ChatView.java +++ b/desktop/src/main/java/haveno/desktop/main/shared/ChatView.java @@ -1,51 +1,52 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.shared; -import com.google.common.io.ByteStreams; -import de.jensd.fx.fontawesome.AwesomeDude; -import de.jensd.fx.fontawesome.AwesomeIcon; -import haveno.common.Timer; -import haveno.common.UserThread; -import haveno.common.util.Utilities; +import haveno.desktop.components.AutoTooltipButton; +import haveno.desktop.components.AutoTooltipLabel; +import haveno.desktop.components.HavenoTextArea; +import haveno.desktop.components.BusyAnimation; +import haveno.desktop.components.TableGroupHeadline; +import haveno.desktop.main.overlays.notifications.Notification; +import haveno.desktop.main.overlays.popups.Popup; +import haveno.desktop.util.DisplayUtils; +import haveno.desktop.util.GUIUtil; + import haveno.core.locale.Res; import haveno.core.support.SupportManager; import haveno.core.support.SupportSession; import haveno.core.support.dispute.Attachment; import haveno.core.support.messages.ChatMessage; -import haveno.core.util.coin.CoinFormatter; -import haveno.desktop.components.AutoTooltipButton; -import haveno.desktop.components.AutoTooltipLabel; -import haveno.desktop.components.BusyAnimation; -import haveno.desktop.components.HavenoTextArea; -import haveno.desktop.components.TableGroupHeadline; -import haveno.desktop.components.TextFieldWithIcon; -import haveno.desktop.main.overlays.popups.Popup; -import haveno.desktop.util.DisplayUtils; -import haveno.desktop.util.GUIUtil; + import haveno.network.p2p.network.Connection; -import javafx.beans.property.ReadOnlyDoubleProperty; -import javafx.beans.value.ChangeListener; -import javafx.collections.ListChangeListener; -import javafx.collections.ObservableList; -import javafx.collections.transformation.SortedList; -import javafx.event.EventHandler; -import javafx.geometry.Insets; + +import haveno.common.Timer; +import haveno.common.UserThread; +import haveno.common.util.Utilities; + +import com.google.common.io.ByteStreams; + +import de.jensd.fx.fontawesome.AwesomeDude; +import de.jensd.fx.fontawesome.AwesomeIcon; + +import javafx.stage.FileChooser; + +import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.ListCell; @@ -61,22 +62,32 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.Priority; import javafx.scene.layout.VBox; import javafx.scene.text.TextAlignment; -import javafx.stage.FileChooser; -import javafx.util.Callback; -import lombok.Getter; -import lombok.Setter; + +import javafx.geometry.Insets; + +import org.apache.commons.lang3.exception.ExceptionUtils; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; +import javafx.beans.property.ReadOnlyDoubleProperty; +import javafx.beans.value.ChangeListener; + +import javafx.event.EventHandler; + +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.collections.transformation.SortedList; + +import javafx.util.Callback; + +import java.net.MalformedURLException; +import java.net.URL; + import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; + import java.util.ArrayList; import java.util.Comparator; import java.util.Date; @@ -84,8 +95,14 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.TimeUnit; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; + +import javax.annotation.Nullable; + +@Slf4j public class ChatView extends AnchorPane { - public static final Logger log = LoggerFactory.getLogger(TextFieldWithIcon.class); // UI private TextArea inputTextArea; @@ -98,7 +115,7 @@ public class ChatView extends AnchorPane { // Options @Getter - Button extraButton; + Node extraButton; @Getter private ReadOnlyDoubleProperty widthProperty; @Setter @@ -112,18 +129,16 @@ public class ChatView extends AnchorPane { private ListChangeListener<ChatMessage> disputeDirectMessageListListener; private Subscription inputTextAreaTextSubscription; private final List<Attachment> tempAttachments = new ArrayList<>(); - private ChangeListener<Boolean> storedInMailboxPropertyListener, arrivedPropertyListener; + private ChangeListener<Boolean> storedInMailboxPropertyListener, acknowledgedPropertyListener; private ChangeListener<String> sendMessageErrorPropertyListener; - protected final CoinFormatter formatter; private EventHandler<KeyEvent> keyEventEventHandler; private SupportManager supportManager; private Optional<SupportSession> optionalSupportSession = Optional.empty(); private String counterpartyName; - public ChatView(SupportManager supportManager, CoinFormatter formatter, String counterpartyName) { + public ChatView(SupportManager supportManager, String counterpartyName) { this.supportManager = supportManager; - this.formatter = formatter; this.counterpartyName = counterpartyName; allowAttachments = true; displayHeader = true; @@ -157,7 +172,7 @@ public class ChatView extends AnchorPane { } public void display(SupportSession supportSession, - @Nullable Button extraButton, + @Nullable Node extraButton, ReadOnlyDoubleProperty widthProperty) { optionalSupportSession = Optional.of(supportSession); removeListenersOnSessionChange(); @@ -201,6 +216,10 @@ public class ChatView extends AnchorPane { Button uploadButton = new AutoTooltipButton(Res.get("support.addAttachments")); uploadButton.setOnAction(e -> onRequestUpload()); + Button clipboardButton = new AutoTooltipButton(Res.get("shared.copyToClipboard")); + clipboardButton.setOnAction(e -> copyChatMessagesToClipboard(clipboardButton)); + uploadButton.setStyle("-fx-pref-width: 125; -fx-padding: 3 3 3 3;"); + clipboardButton.setStyle("-fx-pref-width: 125; -fx-padding: 3 3 3 3;"); sendMsgInfoLabel = new AutoTooltipLabel(); sendMsgInfoLabel.setVisible(false); @@ -216,12 +235,11 @@ public class ChatView extends AnchorPane { HBox buttonBox = new HBox(); buttonBox.setSpacing(10); if (allowAttachments) - buttonBox.getChildren().addAll(sendButton, uploadButton, sendMsgBusyAnimation, sendMsgInfoLabel); + buttonBox.getChildren().addAll(sendButton, uploadButton, clipboardButton, sendMsgBusyAnimation, sendMsgInfoLabel); else buttonBox.getChildren().addAll(sendButton, sendMsgBusyAnimation, sendMsgInfoLabel); if (extraButton != null) { - extraButton.setDefaultButton(true); Pane spacer = new Pane(); HBox.setHgrow(spacer, Priority.ALWAYS); buttonBox.getChildren().addAll(spacer, extraButton); @@ -282,216 +300,216 @@ public class ChatView extends AnchorPane { @Override protected void updateItem(ChatMessage message, boolean empty) { - super.updateItem(message, empty); - if (message != null && !empty) { - copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(messageLabel.getText())); - messageLabel.setOnMouseClicked(event -> { - if (2 > event.getClickCount()) { - return; - } - GUIUtil.showSelectableTextModal(headerLabel.getText(), messageLabel.getText()); - }); - - if (!messageAnchorPane.prefWidthProperty().isBound()) - messageAnchorPane.prefWidthProperty() - .bind(messageListView.widthProperty().subtract(padding + GUIUtil.getScrollbarWidth(messageListView))); - - AnchorPane.clearConstraints(bg); - AnchorPane.clearConstraints(headerLabel); - AnchorPane.clearConstraints(arrow); - AnchorPane.clearConstraints(messageLabel); - AnchorPane.clearConstraints(copyIcon); - AnchorPane.clearConstraints(statusHBox); - AnchorPane.clearConstraints(attachmentsBox); - - AnchorPane.setTopAnchor(bg, 15d); - AnchorPane.setBottomAnchor(bg, bottomBorder); - AnchorPane.setTopAnchor(headerLabel, 0d); - AnchorPane.setBottomAnchor(arrow, bottomBorder + 5d); - AnchorPane.setTopAnchor(messageLabel, 25d); - AnchorPane.setTopAnchor(copyIcon, 25d); - AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10); - - boolean senderIsTrader = message.isSenderIsTrader(); - boolean isMyMsg = supportSession.isClient() == senderIsTrader; - - arrow.setVisible(!message.isSystemMessage()); - arrow.setManaged(!message.isSystemMessage()); - statusHBox.setVisible(false); - - headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text", - "highlight-static"); - messageLabel.getStyleClass().removeAll("my-message", "message"); - copyIcon.getStyleClass().removeAll("my-message", "message"); - - if (message.isSystemMessage()) { - headerLabel.getStyleClass().addAll("message-header", "success-text"); - bg.setId("message-bubble-green"); - messageLabel.getStyleClass().add("my-message"); - copyIcon.getStyleClass().add("my-message"); - message.addChangeListener(() -> updateMsgState(message)); - updateMsgState(message); - } else if (isMyMsg) { - headerLabel.getStyleClass().add("my-message-header"); - bg.setId("message-bubble-blue"); - messageLabel.getStyleClass().add("my-message"); - copyIcon.getStyleClass().add("my-message"); - if (supportSession.isClient()) - arrow.setId("bubble_arrow_blue_left"); - else - arrow.setId("bubble_arrow_blue_right"); - - if (sendMsgBusyAnimationListener != null) - sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener); - - sendMsgBusyAnimationListener = (observable, oldValue, newValue) -> { - if (!newValue) - updateMsgState(message); - }; - - sendMsgBusyAnimation.isRunningProperty().addListener(sendMsgBusyAnimationListener); - message.addChangeListener(() -> updateMsgState(message)); - updateMsgState(message); - } else { - headerLabel.getStyleClass().add("message-header"); - bg.setId("message-bubble-grey"); - messageLabel.getStyleClass().add("message"); - copyIcon.getStyleClass().add("message"); - if (supportSession.isClient()) - arrow.setId("bubble_arrow_grey_right"); - else - arrow.setId("bubble_arrow_grey_left"); - } - - if (message.isSystemMessage()) { - AnchorPane.setLeftAnchor(headerLabel, padding); - AnchorPane.setRightAnchor(headerLabel, padding); - AnchorPane.setLeftAnchor(bg, border); - AnchorPane.setRightAnchor(bg, border); - AnchorPane.setLeftAnchor(messageLabel, padding); - AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight); - AnchorPane.setRightAnchor(copyIcon, padding); - AnchorPane.setLeftAnchor(attachmentsBox, padding); - AnchorPane.setRightAnchor(attachmentsBox, padding); - AnchorPane.setLeftAnchor(statusHBox, padding); - } else if (senderIsTrader) { - AnchorPane.setLeftAnchor(headerLabel, padding + arrowWidth); - AnchorPane.setLeftAnchor(bg, border + arrowWidth); - AnchorPane.setRightAnchor(bg, border); - AnchorPane.setLeftAnchor(arrow, border); - AnchorPane.setLeftAnchor(messageLabel, padding + arrowWidth); - AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight); - AnchorPane.setRightAnchor(copyIcon, padding); - AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth); - AnchorPane.setRightAnchor(attachmentsBox, padding); - AnchorPane.setRightAnchor(statusHBox, padding); - } else { - AnchorPane.setRightAnchor(headerLabel, padding + arrowWidth); - AnchorPane.setRightAnchor(bg, border + arrowWidth); - AnchorPane.setLeftAnchor(bg, border); - AnchorPane.setRightAnchor(arrow, border); - AnchorPane.setLeftAnchor(messageLabel, padding); - AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight + arrowWidth); - AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth); - AnchorPane.setLeftAnchor(attachmentsBox, padding); - AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth); - AnchorPane.setLeftAnchor(statusHBox, padding); - } - AnchorPane.setBottomAnchor(statusHBox, 7d); - String metaData = DisplayUtils.formatDateTime(new Date(message.getDate())); - if (!message.isSystemMessage()) - metaData = (isMyMsg ? "Sent " : "Received ") + metaData - + (isMyMsg ? "" : " from " + counterpartyName); - headerLabel.setText(metaData); - messageLabel.setText(message.getMessage()); - attachmentsBox.getChildren().clear(); - if (allowAttachments && - message.getAttachments() != null && - message.getAttachments().size() > 0) { - AnchorPane.setBottomAnchor(messageLabel, bottomBorder + attachmentsBoxHeight + 10); - attachmentsBox.getChildren().add(new AutoTooltipLabel(Res.get("support.attachments") + " ") {{ - setPadding(new Insets(0, 0, 3, 0)); - if (isMyMsg) - getStyleClass().add("my-message"); - else - getStyleClass().add("message"); - }}); - message.getAttachments().forEach(attachment -> { - Label icon = new Label(); - setPadding(new Insets(0, 0, 3, 0)); - if (isMyMsg) - icon.getStyleClass().add("attachment-icon"); - else - icon.getStyleClass().add("attachment-icon-black"); - - AwesomeDude.setIcon(icon, AwesomeIcon.FILE_TEXT); - icon.setPadding(new Insets(-2, 0, 0, 0)); - icon.setTooltip(new Tooltip(attachment.getFileName())); - icon.setOnMouseClicked(event -> onOpenAttachment(attachment)); - attachmentsBox.getChildren().add(icon); + UserThread.execute(() -> { + super.updateItem(message, empty); + if (message != null && !empty) { + copyIcon.setOnMouseClicked(e -> Utilities.copyToClipboard(messageLabel.getText())); + messageLabel.setOnMouseClicked(event -> { + if (2 > event.getClickCount()) { + return; + } + GUIUtil.showSelectableTextModal(headerLabel.getText(), messageLabel.getText()); }); + + if (!messageAnchorPane.prefWidthProperty().isBound()) + messageAnchorPane.prefWidthProperty() + .bind(messageListView.widthProperty().subtract(padding + GUIUtil.getScrollbarWidth(messageListView))); + + AnchorPane.clearConstraints(bg); + AnchorPane.clearConstraints(headerLabel); + AnchorPane.clearConstraints(arrow); + AnchorPane.clearConstraints(messageLabel); + AnchorPane.clearConstraints(copyIcon); + AnchorPane.clearConstraints(statusHBox); + AnchorPane.clearConstraints(attachmentsBox); + + AnchorPane.setTopAnchor(bg, 15d); + AnchorPane.setBottomAnchor(bg, bottomBorder); + AnchorPane.setTopAnchor(headerLabel, 0d); + AnchorPane.setBottomAnchor(arrow, bottomBorder + 5d); + AnchorPane.setTopAnchor(messageLabel, 25d); + AnchorPane.setTopAnchor(copyIcon, 25d); + AnchorPane.setBottomAnchor(attachmentsBox, bottomBorder + 10); + + boolean senderIsTrader = message.isSenderIsTrader(); + boolean isMyMsg = supportSession.isClient() == senderIsTrader; + + arrow.setVisible(!message.isSystemMessage()); + arrow.setManaged(!message.isSystemMessage()); + statusHBox.setVisible(false); + + headerLabel.getStyleClass().removeAll("message-header", "my-message-header", "success-text", + "highlight-static"); + messageLabel.getStyleClass().removeAll("my-message", "message"); + copyIcon.getStyleClass().removeAll("my-message", "message"); + + if (message.isSystemMessage()) { + headerLabel.getStyleClass().addAll("message-header", "success-text"); + bg.setId("message-bubble-green"); + messageLabel.getStyleClass().add("my-message"); + copyIcon.getStyleClass().add("my-message"); + message.addWeakMessageStateListener(() -> UserThread.execute(() -> updateMsgState(message))); + updateMsgState(message); + } else if (isMyMsg) { + headerLabel.getStyleClass().add("my-message-header"); + bg.setId("message-bubble-blue"); + messageLabel.getStyleClass().add("my-message"); + copyIcon.getStyleClass().add("my-message"); + if (supportSession.isClient()) + arrow.setId("bubble_arrow_blue_left"); + else + arrow.setId("bubble_arrow_blue_right"); + + if (sendMsgBusyAnimationListener != null) + sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener); + + sendMsgBusyAnimationListener = (observable, oldValue, newValue) -> { + if (!newValue) + UserThread.execute(() -> updateMsgState(message)); + }; + + sendMsgBusyAnimation.isRunningProperty().addListener(sendMsgBusyAnimationListener); + message.addWeakMessageStateListener(() -> UserThread.execute(() -> updateMsgState(message))); + updateMsgState(message); + } else { + headerLabel.getStyleClass().add("message-header"); + bg.setId("message-bubble-grey"); + messageLabel.getStyleClass().add("message"); + copyIcon.getStyleClass().add("message"); + if (supportSession.isClient()) + arrow.setId("bubble_arrow_grey_right"); + else + arrow.setId("bubble_arrow_grey_left"); + } + + if (message.isSystemMessage()) { + AnchorPane.setLeftAnchor(headerLabel, padding); + AnchorPane.setRightAnchor(headerLabel, padding); + AnchorPane.setLeftAnchor(bg, border); + AnchorPane.setRightAnchor(bg, border); + AnchorPane.setLeftAnchor(messageLabel, padding); + AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight); + AnchorPane.setRightAnchor(copyIcon, padding); + AnchorPane.setLeftAnchor(attachmentsBox, padding); + AnchorPane.setRightAnchor(attachmentsBox, padding); + AnchorPane.setLeftAnchor(statusHBox, padding); + } else if (senderIsTrader) { + AnchorPane.setLeftAnchor(headerLabel, padding + arrowWidth); + AnchorPane.setLeftAnchor(bg, border + arrowWidth); + AnchorPane.setRightAnchor(bg, border); + AnchorPane.setLeftAnchor(arrow, border); + AnchorPane.setLeftAnchor(messageLabel, padding + arrowWidth); + AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight); + AnchorPane.setRightAnchor(copyIcon, padding); + AnchorPane.setLeftAnchor(attachmentsBox, padding + arrowWidth); + AnchorPane.setRightAnchor(attachmentsBox, padding); + AnchorPane.setRightAnchor(statusHBox, padding); + } else { + AnchorPane.setRightAnchor(headerLabel, padding + arrowWidth); + AnchorPane.setRightAnchor(bg, border + arrowWidth); + AnchorPane.setLeftAnchor(bg, border); + AnchorPane.setRightAnchor(arrow, border); + AnchorPane.setLeftAnchor(messageLabel, padding); + AnchorPane.setRightAnchor(messageLabel, msgLabelPaddingRight + arrowWidth); + AnchorPane.setRightAnchor(copyIcon, padding + arrowWidth); + AnchorPane.setLeftAnchor(attachmentsBox, padding); + AnchorPane.setRightAnchor(attachmentsBox, padding + arrowWidth); + AnchorPane.setLeftAnchor(statusHBox, padding); + } + AnchorPane.setBottomAnchor(statusHBox, 7d); + String metaData = DisplayUtils.formatDateTime(new Date(message.getDate())); + if (!message.isSystemMessage()) + metaData = (isMyMsg ? "Sent " : "Received ") + metaData + + (isMyMsg ? "" : " from " + counterpartyName); + headerLabel.setText(metaData); + messageLabel.setText(message.getMessage()); + attachmentsBox.getChildren().clear(); + if (allowAttachments && + message.getAttachments() != null && + message.getAttachments().size() > 0) { + AnchorPane.setBottomAnchor(messageLabel, bottomBorder + attachmentsBoxHeight + 10); + attachmentsBox.getChildren().add(new AutoTooltipLabel(Res.get("support.attachments") + " ") {{ + setPadding(new Insets(0, 0, 3, 0)); + if (isMyMsg) + getStyleClass().add("my-message"); + else + getStyleClass().add("message"); + }}); + message.getAttachments().forEach(attachment -> { + Label icon = new Label(); + setPadding(new Insets(0, 0, 3, 0)); + if (isMyMsg) + icon.getStyleClass().add("attachment-icon"); + else + icon.getStyleClass().add("attachment-icon-black"); + + AwesomeDude.setIcon(icon, AwesomeIcon.FILE_TEXT); + icon.setPadding(new Insets(-2, 0, 0, 0)); + icon.setTooltip(new Tooltip(attachment.getFileName())); + icon.setOnMouseClicked(event -> onOpenAttachment(attachment)); + attachmentsBox.getChildren().add(icon); + }); + } else { + AnchorPane.setBottomAnchor(messageLabel, bottomBorder + 10); + } + + // Need to set it here otherwise style is not correct + AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY, "16.0"); + copyIcon.getStyleClass().addAll("icon", "copy-icon-disputes"); + + // TODO There are still some cell rendering issues on updates + setGraphic(messageAnchorPane); } else { - AnchorPane.setBottomAnchor(messageLabel, bottomBorder + 10); + if (sendMsgBusyAnimation != null && sendMsgBusyAnimationListener != null) + sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener); + + messageAnchorPane.prefWidthProperty().unbind(); + + copyIcon.setOnMouseClicked(null); + messageLabel.setOnMouseClicked(null); + setGraphic(null); } - - // Need to set it here otherwise style is not correct - AwesomeDude.setIcon(copyIcon, AwesomeIcon.COPY, "16.0"); - copyIcon.getStyleClass().addAll("icon", "copy-icon-disputes"); - - // TODO There are still some cell rendering issues on updates - setGraphic(messageAnchorPane); - } else { - if (sendMsgBusyAnimation != null && sendMsgBusyAnimationListener != null) - sendMsgBusyAnimation.isRunningProperty().removeListener(sendMsgBusyAnimationListener); - - messageAnchorPane.prefWidthProperty().unbind(); - - copyIcon.setOnMouseClicked(null); - messageLabel.setOnMouseClicked(null); - setGraphic(null); - } + }); } private void updateMsgState(ChatMessage message) { - UserThread.execute(() -> { - boolean visible; - AwesomeIcon icon = null; - String text = null; - statusIcon.getStyleClass().add("status-icon"); - statusInfoLabel.getStyleClass().add("status-icon"); - statusHBox.setOpacity(1); - log.debug("updateMsgState msg-{}, ack={}, arrived={}", message.getMessage(), - message.acknowledgedProperty().get(), message.arrivedProperty().get()); - if (message.acknowledgedProperty().get()) { - visible = true; - icon = AwesomeIcon.OK_SIGN; - text = Res.get("support.acknowledged"); - } else if (message.ackErrorProperty().get() != null) { - visible = true; - icon = AwesomeIcon.EXCLAMATION_SIGN; - text = Res.get("support.error", message.ackErrorProperty().get()); - statusIcon.getStyleClass().add("error-text"); - statusInfoLabel.getStyleClass().add("error-text"); - } else if (message.arrivedProperty().get()) { - visible = true; - icon = AwesomeIcon.OK; - text = Res.get("support.arrived"); - } else if (message.storedInMailboxProperty().get()) { - visible = true; - icon = AwesomeIcon.ENVELOPE; - text = Res.get("support.savedInMailbox"); - } else { - visible = false; - log.debug("updateMsgState called but no msg state available. message={}", message); - } + boolean visible; + AwesomeIcon icon = null; + String text = null; + statusIcon.getStyleClass().add("status-icon"); + statusInfoLabel.getStyleClass().add("status-icon"); + statusHBox.setOpacity(1); + log.debug("updateMsgState msg-{}, ack={}, arrived={}", message.getMessage(), + message.acknowledgedProperty().get(), message.arrivedProperty().get()); + if (message.acknowledgedProperty().get()) { + visible = true; + icon = AwesomeIcon.OK_SIGN; + text = Res.get("support.acknowledged"); + } else if (message.storedInMailboxProperty().get()) { + visible = true; + icon = AwesomeIcon.ENVELOPE; + text = Res.get("support.savedInMailbox"); + } else if (message.ackErrorProperty().get() != null) { + visible = true; + icon = AwesomeIcon.EXCLAMATION_SIGN; + text = Res.get("support.error", message.ackErrorProperty().get()); + statusIcon.getStyleClass().add("error-text"); + statusInfoLabel.getStyleClass().add("error-text"); + } else if (message.arrivedProperty().get()) { + visible = true; + icon = AwesomeIcon.MAIL_REPLY; + text = Res.get("support.transient"); + } else { + visible = false; + log.debug("updateMsgState called but no msg state available. message={}", message); + } - statusHBox.setVisible(visible); - if (visible) { - AwesomeDude.setIcon(statusIcon, icon, "14"); - statusIcon.setTooltip(new Tooltip(text)); - statusInfoLabel.setText(text); - } - }); + statusHBox.setVisible(visible); + if (visible) { + AwesomeDude.setIcon(statusIcon, icon, "14"); + statusIcon.setTooltip(new Tooltip(text)); + statusInfoLabel.setText(text); + } } }; } @@ -529,7 +547,7 @@ public class ChatView extends AnchorPane { int maxMsgSize = Connection.getPermittedMessageSize(); int maxSizeInKB = maxMsgSize / 1024; fileChooser.setTitle(Res.get("support.openFile", maxSizeInKB)); - /* if (Utilities.isUnix()) + /* if (Utilities.isUnix()) fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));*/ File result = fileChooser.showOpenDialog(getScene().getWindow()); if (result != null) { @@ -548,12 +566,10 @@ public class ChatView extends AnchorPane { inputTextArea.setText(inputTextArea.getText() + "\n[" + Res.get("support.attachment") + " " + result.getName() + "]"); } } catch (java.io.IOException e) { - e.printStackTrace(); - log.error(e.getMessage()); + log.error(ExceptionUtils.getStackTrace(e)); } } catch (MalformedURLException e2) { - e2.printStackTrace(); - log.error(e2.getMessage()); + log.error(ExceptionUtils.getStackTrace(e2)); } } } else { @@ -561,28 +577,64 @@ public class ChatView extends AnchorPane { } } + public void onAttachText(String textAttachment, String name) { + if (!allowAttachments) + return; + try { + byte[] filesAsBytes = textAttachment.getBytes("UTF8"); + int size = filesAsBytes.length; + int maxMsgSize = Connection.getPermittedMessageSize(); + int maxSizeInKB = maxMsgSize / 1024; + if (size > maxMsgSize) { + new Popup().warning(Res.get("support.attachmentTooLarge", (size / 1024), maxSizeInKB)).show(); + } else { + tempAttachments.add(new Attachment(name, filesAsBytes)); + inputTextArea.setText(inputTextArea.getText() + "\n[" + Res.get("support.attachment") + " " + name + "]"); + } + } catch (Exception e) { + log.error(ExceptionUtils.getStackTrace(e)); + } + } + + private void copyChatMessagesToClipboard(Button sourceBtn) { + optionalSupportSession.ifPresent(session -> { + StringBuilder stringBuilder = new StringBuilder(); + chatMessages.forEach(i -> { + String metaData = DisplayUtils.formatDateTime(new Date(i.getDate())); + metaData = metaData + (i.isSystemMessage() ? " (System message)" : + (i.isSenderIsTrader() ? " (from Trader)" : " (from Agent)")); + stringBuilder.append(metaData).append("\n").append(i.getMessage()).append("\n\n"); + }); + Utilities.copyToClipboard(stringBuilder.toString()); + new Notification() + .notification(Res.get("shared.copiedToClipboard")) + .hideCloseButton() + .autoClose() + .show(); + }); + } + private void onOpenAttachment(Attachment attachment) { if (!allowAttachments) return; FileChooser fileChooser = new FileChooser(); fileChooser.setTitle(Res.get("support.save")); fileChooser.setInitialFileName(attachment.getFileName()); - /* if (Utilities.isUnix()) + /* if (Utilities.isUnix()) fileChooser.setInitialDirectory(new File(System.getProperty("user.home")));*/ File file = fileChooser.showSaveDialog(getScene().getWindow()); if (file != null) { try (FileOutputStream fileOutputStream = new FileOutputStream(file.getAbsolutePath())) { fileOutputStream.write(attachment.getBytes()); } catch (IOException e) { - e.printStackTrace(); - System.out.println(e.getMessage()); + log.error("Error opening attachment: {}\n", e.getMessage(), e); } } } private void onSendMessage(String inputText) { if (chatMessage != null) { - chatMessage.arrivedProperty().removeListener(arrivedPropertyListener); + chatMessage.acknowledgedProperty().removeListener(acknowledgedPropertyListener); chatMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener); chatMessage.sendMessageErrorProperty().removeListener(sendMessageErrorPropertyListener); } @@ -594,6 +646,8 @@ public class ChatView extends AnchorPane { inputTextArea.setDisable(true); inputTextArea.clear(); + chatMessage.startAckTimer(); + Timer timer = UserThread.runAfter(() -> { sendMsgInfoLabel.setVisible(true); sendMsgInfoLabel.setManaged(true); @@ -602,8 +656,9 @@ public class ChatView extends AnchorPane { sendMsgBusyAnimation.play(); }, 500, TimeUnit.MILLISECONDS); - arrivedPropertyListener = (observable, oldValue, newValue) -> { + acknowledgedPropertyListener = (observable, oldValue, newValue) -> { if (newValue) { + sendMsgInfoLabel.setVisible(false); hideSendMsgInfo(timer); } }; @@ -624,7 +679,7 @@ public class ChatView extends AnchorPane { } }; if (chatMessage != null) { - chatMessage.arrivedProperty().addListener(arrivedPropertyListener); + chatMessage.acknowledgedProperty().addListener(acknowledgedPropertyListener); chatMessage.storedInMailboxProperty().addListener(storedInMailboxPropertyListener); chatMessage.sendMessageErrorProperty().addListener(sendMessageErrorPropertyListener); } @@ -662,8 +717,12 @@ public class ChatView extends AnchorPane { } public void scrollToBottom() { - if (messageListView != null) - UserThread.execute(() -> messageListView.scrollTo(Integer.MAX_VALUE)); + UserThread.execute(() -> { + if (messageListView != null && !messageListView.getItems().isEmpty()) { + int lastIndex = messageListView.getItems().size(); + messageListView.scrollTo(lastIndex); + } + }); } public void setInputBoxVisible(boolean visible) { @@ -693,15 +752,12 @@ public class ChatView extends AnchorPane { } private void removeListenersOnSessionChange() { - if (chatMessages != null) { - if (disputeDirectMessageListListener != null) chatMessages.removeListener(disputeDirectMessageListListener); - chatMessages.forEach(msg -> msg.removeChangeListener()); - } + if (chatMessages != null && disputeDirectMessageListListener != null) + chatMessages.removeListener(disputeDirectMessageListListener); if (chatMessage != null) { - chatMessage.removeChangeListener(); - if (arrivedPropertyListener != null) - chatMessage.arrivedProperty().removeListener(arrivedPropertyListener); + if (acknowledgedPropertyListener != null) + chatMessage.arrivedProperty().removeListener(acknowledgedPropertyListener); if (storedInMailboxPropertyListener != null) chatMessage.storedInMailboxProperty().removeListener(storedInMailboxPropertyListener); } @@ -718,4 +774,4 @@ public class ChatView extends AnchorPane { inputTextAreaTextSubscription.unsubscribe(); } -} +} \ No newline at end of file diff --git a/desktop/src/main/java/haveno/desktop/main/shared/PriceFeedComboBoxItem.java b/desktop/src/main/java/haveno/desktop/main/shared/PriceFeedComboBoxItem.java index 64f5cb49c2..17ad7ecae1 100644 --- a/desktop/src/main/java/haveno/desktop/main/shared/PriceFeedComboBoxItem.java +++ b/desktop/src/main/java/haveno/desktop/main/shared/PriceFeedComboBoxItem.java @@ -1,23 +1,22 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.shared; -import haveno.common.UserThread; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import lombok.Getter; @@ -38,6 +37,6 @@ public class PriceFeedComboBoxItem { } public void setDisplayString(String displayString) { - UserThread.execute(() -> this.displayStringProperty.set(displayString)); + this.displayStringProperty.set(displayString); } } diff --git a/desktop/src/main/java/haveno/desktop/main/support/SupportView.java b/desktop/src/main/java/haveno/desktop/main/support/SupportView.java index 0ff81ea2a3..42503f315f 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/SupportView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/SupportView.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,9 @@ package haveno.desktop.main.support; +import com.google.inject.Inject; + +import haveno.common.UserThread; import haveno.common.app.DevEnv; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; @@ -37,8 +57,8 @@ import haveno.desktop.common.view.FxmlView; import haveno.desktop.common.view.View; import haveno.desktop.common.view.ViewLoader; import haveno.desktop.main.MainView; -import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.offer.signedoffer.SignedOfferView; +import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.support.dispute.agent.arbitration.ArbitratorView; import haveno.desktop.main.support.dispute.agent.mediation.MediatorView; import haveno.desktop.main.support.dispute.agent.refund.RefundAgentView; @@ -50,9 +70,7 @@ import javafx.beans.value.ChangeListener; import javafx.collections.MapChangeListener; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; - import javax.annotation.Nullable; -import javax.inject.Inject; @FxmlView public class SupportView extends ActivatableView<TabPane, Void> { @@ -127,7 +145,7 @@ public class SupportView extends ActivatableView<TabPane, Void> { navigationListener = (viewPath, data) -> { if (viewPath.size() == 3 && viewPath.indexOf(SupportView.class) == 1) - loadView(viewPath.tip()); + UserThread.execute(() -> loadView(viewPath.tip())); }; tabChangeListener = (ov, oldValue, newValue) -> { diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeChatPopup.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeChatPopup.java index c0a9efecbb..50662ce750 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeChatPopup.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeChatPopup.java @@ -1,67 +1,79 @@ /* - * This file is part of Haveno. + * This file is part of haveno. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with haveno. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute; -import haveno.common.UserThread; +import haveno.desktop.components.AutoTooltipButton; +import haveno.desktop.main.MainView; +import haveno.desktop.main.shared.ChatView; +import haveno.desktop.util.CssTheme; +import haveno.desktop.util.DisplayUtils; + import haveno.core.locale.Res; import haveno.core.support.dispute.Dispute; import haveno.core.support.dispute.DisputeList; import haveno.core.support.dispute.DisputeManager; import haveno.core.support.dispute.DisputeSession; +import haveno.core.support.messages.ChatMessage; import haveno.core.user.Preferences; import haveno.core.util.coin.CoinFormatter; -import haveno.desktop.components.AutoTooltipButton; -import haveno.desktop.main.MainView; -import haveno.desktop.main.shared.ChatView; -import haveno.desktop.util.CssTheme; -import javafx.beans.value.ChangeListener; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.input.KeyCode; -import javafx.scene.input.KeyEvent; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.StackPane; + +import haveno.common.UserThread; + import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.StageStyle; import javafx.stage.Window; + +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.MenuButton; +import javafx.scene.control.MenuItem; +import javafx.scene.input.KeyCode; +import javafx.scene.input.KeyEvent; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.StackPane; + +import javafx.beans.value.ChangeListener; + +import java.util.Date; +import java.util.List; + import lombok.Getter; public class DisputeChatPopup { public interface ChatCallback { void onCloseDisputeFromChatWindow(Dispute dispute); + void onSendLogsFromChatWindow(Dispute dispute); } private Stage chatPopupStage; protected final DisputeManager<? extends DisputeList<Dispute>> disputeManager; protected final CoinFormatter formatter; protected final Preferences preferences; - private ChatCallback chatCallback; + private final ChatCallback chatCallback; private double chatPopupStageXPosition = -1; private double chatPopupStageYPosition = -1; - private ChangeListener<Number> xPositionListener; - private ChangeListener<Number> yPositionListener; @Getter private Dispute selectedDispute; DisputeChatPopup(DisputeManager<? extends DisputeList<Dispute>> disputeManager, - CoinFormatter formatter, - Preferences preferences, - ChatCallback chatCallback) { + CoinFormatter formatter, + Preferences preferences, + ChatCallback chatCallback) { this.disputeManager = disputeManager; this.formatter = formatter; this.preferences = preferences; @@ -84,7 +96,7 @@ public class DisputeChatPopup { selectedDispute.getChatMessages().forEach(m -> m.setWasDisplayed(true)); disputeManager.requestPersistence(); - ChatView chatView = new ChatView(disputeManager, formatter, counterpartyName); + ChatView chatView = new ChatView(disputeManager, counterpartyName); chatView.setAllowAttachments(true); chatView.setDisplayHeader(false); chatView.initialize(); @@ -96,12 +108,27 @@ public class DisputeChatPopup { AnchorPane.setTopAnchor(chatView, -20d); AnchorPane.setBottomAnchor(chatView, 10d); pane.getStyleClass().add("dispute-chat-border"); - Button closeDisputeButton = null; - if (!selectedDispute.isClosed() && !disputeManager.isTrader(selectedDispute)) { - closeDisputeButton = new AutoTooltipButton(Res.get("support.closeTicket")); - closeDisputeButton.setOnAction(e -> chatCallback.onCloseDisputeFromChatWindow(selectedDispute)); + if (selectedDispute.isClosed()) { + chatView.display(concreteDisputeSession, null, pane.widthProperty()); + } else { + if (disputeManager.isAgent(selectedDispute)) { + Button closeDisputeButton = new AutoTooltipButton(Res.get("support.closeTicket")); + closeDisputeButton.setDefaultButton(true); + closeDisputeButton.setOnAction(e -> chatCallback.onCloseDisputeFromChatWindow(selectedDispute)); + chatView.display(concreteDisputeSession, closeDisputeButton, pane.widthProperty()); + } else { + MenuButton menuButton = new MenuButton(Res.get("support.moreButton")); + MenuItem menuItem1 = new MenuItem(Res.get("support.uploadTraderChat")); + MenuItem menuItem2 = new MenuItem(Res.get("support.sendLogFiles")); + menuItem1.setOnAction(e -> doTextAttachment(chatView)); + setChatUploadEnabledState(menuItem1); + menuItem2.setOnAction(e -> chatCallback.onSendLogsFromChatWindow(selectedDispute)); + menuButton.getItems().addAll(menuItem1, menuItem2); + menuButton.getStyleClass().add("jfx-button"); + menuButton.setStyle("-fx-padding: 0 10 0 10;"); + chatView.display(concreteDisputeSession, menuButton, pane.widthProperty()); + } } - chatView.display(concreteDisputeSession, closeDisputeButton, pane.widthProperty()); chatView.activate(); chatView.scrollToBottom(); chatPopupStage = new Stage(); @@ -132,9 +159,9 @@ public class DisputeChatPopup { chatPopupStage.setOpacity(0); chatPopupStage.show(); - xPositionListener = (observable, oldValue, newValue) -> chatPopupStageXPosition = (double) newValue; + ChangeListener<Number> xPositionListener = (observable, oldValue, newValue) -> chatPopupStageXPosition = (double) newValue; chatPopupStage.xProperty().addListener(xPositionListener); - yPositionListener = (observable, oldValue, newValue) -> chatPopupStageYPosition = (double) newValue; + ChangeListener<Number> yPositionListener = (observable, oldValue, newValue) -> chatPopupStageYPosition = (double) newValue; chatPopupStage.yProperty().addListener(yPositionListener); if (chatPopupStageXPosition == -1) { @@ -151,4 +178,31 @@ public class DisputeChatPopup { // and after a short moment in the correct position UserThread.execute(() -> chatPopupStage.setOpacity(1)); } + + private void doTextAttachment(ChatView chatView) { + disputeManager.findTrade(selectedDispute).ifPresent(t -> { + List<ChatMessage> chatMessages = t.getChatMessages(); + if (chatMessages.size() > 0) { + StringBuilder stringBuilder = new StringBuilder(); + chatMessages.forEach(i -> { + boolean isMyMsg = i.isSenderIsTrader(); + String metaData = DisplayUtils.formatDateTime(new Date(i.getDate())); + if (!i.isSystemMessage()) + metaData = (isMyMsg ? "Sent " : "Received ") + metaData + + (isMyMsg ? "" : " from Trader"); + stringBuilder.append(metaData).append("\n").append(i.getMessage()).append("\n\n"); + }); + String fileName = selectedDispute.getShortTradeId() + "_" + selectedDispute.getRoleStringForLogFile() + "_TraderChat.txt"; + chatView.onAttachText(stringBuilder.toString(), fileName); + } + }); + } + + private void setChatUploadEnabledState(MenuItem menuItem) { + disputeManager.findTrade(selectedDispute).ifPresentOrElse(t -> { + menuItem.setDisable(t.getChatMessages().size() == 0); + }, () -> { + menuItem.setDisable(true); + }); + } } diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeView.java index 698bff0ac2..7e3cad8de3 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/DisputeView.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -34,13 +51,13 @@ import haveno.core.support.dispute.DisputeManager; import haveno.core.support.dispute.DisputeResult; import haveno.core.support.dispute.DisputeSession; import haveno.core.support.dispute.agent.DisputeAgentLookupMap; +import haveno.core.support.dispute.arbitration.ArbitrationManager; import haveno.core.support.dispute.arbitration.arbitrator.ArbitratorManager; import haveno.core.support.dispute.mediation.MediationManager; import haveno.core.support.messages.ChatMessage; import haveno.core.trade.Contract; import haveno.core.trade.HavenoUtils; import haveno.core.trade.Trade; -import haveno.core.trade.Trade.DisputeState; import haveno.core.trade.TradeManager; import haveno.core.user.Preferences; import haveno.core.util.FormattingUtils; @@ -51,9 +68,12 @@ import haveno.desktop.components.AutoTooltipLabel; import haveno.desktop.components.AutoTooltipTableColumn; import haveno.desktop.components.HyperlinkWithIcon; import haveno.desktop.components.InputTextField; +import haveno.desktop.components.PeerInfoIconDispute; +import haveno.desktop.components.PeerInfoIconMap; import haveno.desktop.main.overlays.popups.Popup; import haveno.desktop.main.overlays.windows.ContractWindow; import haveno.desktop.main.overlays.windows.DisputeSummaryWindow; +import haveno.desktop.main.overlays.windows.SendLogFilesWindow; import haveno.desktop.main.overlays.windows.SendPrivateNotificationWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.overlays.windows.VerifyDisputeResultSignatureWindow; @@ -85,7 +105,6 @@ import javafx.scene.text.Text; import javafx.util.Callback; import javafx.util.Duration; import lombok.Getter; -import org.bitcoinj.core.Coin; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; @@ -104,7 +123,7 @@ import java.util.concurrent.atomic.AtomicReference; import static haveno.desktop.util.FormBuilder.getIconForLabel; import static haveno.desktop.util.FormBuilder.getRegularIconButton; -public abstract class DisputeView extends ActivatableView<VBox, Void> { +public abstract class DisputeView extends ActivatableView<VBox, Void> implements DisputeChatPopup.ChatCallback { public enum FilterResult { NO_MATCH("No Match"), NO_FILTER("No filter text"), @@ -166,6 +185,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { private Map<String, Button> chatButtonByDispute = new HashMap<>(); private Map<String, JFXBadge> chatBadgeByDispute = new HashMap<>(); private Map<String, JFXBadge> newBadgeByDispute = new HashMap<>(); + @SuppressWarnings("MismatchedQueryAndUpdateOfCollection") + private final PeerInfoIconMap avatarMap = new PeerInfoIconMap(); protected DisputeChatPopup chatPopup; @@ -197,8 +218,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { this.accountAgeWitnessService = accountAgeWitnessService; this.arbitratorManager = arbitratorManager; this.useDevPrivilegeKeys = useDevPrivilegeKeys; - DisputeChatPopup.ChatCallback chatCallback = this::handleOnProcessDispute; - chatPopup = new DisputeChatPopup(disputeManager, formatter, preferences, chatCallback); + chatPopup = new DisputeChatPopup(disputeManager, formatter, preferences, this); } @Override @@ -208,6 +228,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { HBox.setHgrow(label, Priority.NEVER); filterTextField = new InputTextField(); + filterTextField.setPromptText(Res.get("support.filter.prompt")); Tooltip tooltip = new Tooltip(); tooltip.setShowDelay(Duration.millis(100)); tooltip.setShowDuration(Duration.seconds(10)); @@ -367,7 +388,9 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { ObservableList<ChatMessage> chatMessages = dispute.getChatMessages(); // If last message is not a result message we re-open as we might have received a new message from the // trader/mediator/arbitrator who has reopened the case - if (!chatMessages.isEmpty() && !chatMessages.get(chatMessages.size() - 1).isResultMessage(dispute)) { + if (!chatMessages.isEmpty() && + !chatMessages.get(chatMessages.size() - 1).isResultMessage(dispute) && + dispute.unreadMessageCount(senderFlag()) > 0) { onSelectDispute(dispute); reOpenDispute(); } @@ -413,7 +436,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { // For open filter we do not want to continue further as json data would cause a match if (filter.equalsIgnoreCase("open")) { - return !dispute.isClosed() ? FilterResult.OPEN_DISPUTES : FilterResult.NO_MATCH; + return !dispute.isClosed() || dispute.unreadMessageCount(senderFlag()) > 0 ? + FilterResult.OPEN_DISPUTES : FilterResult.NO_MATCH; } if (dispute.getTradeId().toLowerCase().contains(filter)) { @@ -640,10 +664,9 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { String sellersRole = contract.isBuyerMakerAndSellerTaker() ? "Seller as taker" : "Seller as maker"; String opener = firstDispute.isDisputeOpenerIsBuyer() ? buyersRole : sellersRole; DisputeResult disputeResult = firstDispute.getDisputeResultProperty().get(); - String winner = disputeResult != null && - disputeResult.getWinner() == DisputeResult.Winner.BUYER ? "Buyer" : "Seller"; - String buyerPayoutAmount = disputeResult != null ? HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmount(), true) : ""; - String sellerPayoutAmount = disputeResult != null ? HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmount(), true) : ""; + String winner = disputeResult != null && disputeResult.getWinner() == DisputeResult.Winner.BUYER ? "Buyer" : "Seller"; + String buyerPayoutAmount = disputeResult != null ? HavenoUtils.formatXmr(disputeResult.getBuyerPayoutAmountBeforeCost(), true) : ""; + String sellerPayoutAmount = disputeResult != null ? HavenoUtils.formatXmr(disputeResult.getSellerPayoutAmountBeforeCost(), true) : ""; int index = disputeIndex.incrementAndGet(); String tradeDateString = dateFormatter.format(firstDispute.getTradeDate()); @@ -691,8 +714,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { String paymentMethod = Res.get(contract.getPaymentMethodId()); String currency = CurrencyUtil.getNameAndCode(contract.getOfferPayload().getCurrencyCode()); String tradeAmount = HavenoUtils.formatXmr(contract.getTradeAmount(), true); - String buyerDeposit = Coin.valueOf(contract.getOfferPayload().getBuyerSecurityDeposit()).toFriendlyString(); - String sellerDeposit = Coin.valueOf(contract.getOfferPayload().getSellerSecurityDeposit()).toFriendlyString(); + String buyerDeposit = HavenoUtils.formatXmr(contract.getOfferPayload().getBuyerSecurityDepositForTradeAmount(contract.getTradeAmount()), true); + String sellerDeposit = HavenoUtils.formatXmr(contract.getOfferPayload().getSellerSecurityDepositForTradeAmount(contract.getTradeAmount()), true); stringBuilder.append("Payment method: ") .append(paymentMethod) .append("\n") @@ -702,7 +725,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { .append("Trade amount: ") .append(tradeAmount) .append("\n") - .append("Buyer/seller security deposit: ") + .append("Buyer/seller security deposit %: ") .append(buyerDeposit) .append("/") .append(sellerDeposit) @@ -904,6 +927,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { buyerOnionAddressColumn.setComparator(Comparator.comparing(this::getBuyerOnionAddressColumnLabel)); sellerOnionAddressColumn.setComparator(Comparator.comparing(this::getSellerOnionAddressColumnLabel)); marketColumn.setComparator((o1, o2) -> CurrencyUtil.getCurrencyPair(o1.getContract().getOfferPayload().getCurrencyCode()).compareTo(o2.getContract().getOfferPayload().getCurrencyCode())); + stateColumn.setComparator(Comparator.comparing(this::getDisputeStateText)); dateColumn.setSortType(TableColumn.SortType.DESCENDING); tableView.getSortOrder().add(dateColumn); @@ -1069,7 +1093,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { private TableColumn<Dispute, Dispute> getDateColumn() { TableColumn<Dispute, Dispute> column = new AutoTooltipTableColumn<>(Res.get("shared.date")) { { - setMinWidth(180); + setMinWidth(100); + setPrefWidth(150); } }; column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue())); @@ -1095,7 +1120,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { private TableColumn<Dispute, Dispute> getTradeIdColumn() { TableColumn<Dispute, Dispute> column = new AutoTooltipTableColumn<>(Res.get("shared.tradeId")) { { - setMinWidth(110); + setMinWidth(50); + setPrefWidth(100); } }; column.setCellValueFactory((dispute) -> new ReadOnlyObjectWrapper<>(dispute.getValue())); @@ -1117,10 +1143,14 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { field.setMouseTransparent(false); field.setTooltip(new Tooltip(Res.get("tooltip.openPopupForDetails"))); field.setOnAction(event -> tradeDetailsWindow.show(tradeOptional.get())); + setGraphic(field); + setText(""); } else { setText(item.getShortTradeId()); + setGraphic(null); + if (field != null) + field.setOnAction(null); } - setGraphic(field); } else { setGraphic(null); setText(""); @@ -1149,10 +1179,14 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { @Override public void updateItem(final Dispute item, boolean empty) { super.updateItem(item, empty); - if (item != null && !empty) + if (item != null && !empty) { setText(getBuyerOnionAddressColumnLabel(item)); - else + PeerInfoIconDispute peerInfoIconDispute = createAvatar(tableRowProperty().get().getIndex(), item, true); + setGraphic(peerInfoIconDispute); + } else { setText(""); + setGraphic(null); + } } }; } @@ -1175,10 +1209,14 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { @Override public void updateItem(final Dispute item, boolean empty) { super.updateItem(item, empty); - if (item != null && !empty) + if (item != null && !empty) { setText(getSellerOnionAddressColumnLabel(item)); - else + PeerInfoIconDispute peerInfoIconDispute = createAvatar(tableRowProperty().get().getIndex(), item, false); + setGraphic(peerInfoIconDispute); + } else { setText(""); + setGraphic(null); + } } }; } @@ -1196,7 +1234,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { long accountAge = accountAgeWitnessService.getAccountAge(item.getBuyerPaymentAccountPayload(), contract.getBuyerPubKeyRing()); String age = DisplayUtils.formatAccountAge(accountAge); String postFix = CurrencyUtil.isTraditionalCurrency(item.getContract().getOfferPayload().getCurrencyCode()) ? " / " + age : ""; - return buyerNodeAddress.getHostNameWithoutPostFix() + " (" + nrOfDisputes + postFix + ")"; + return buyerNodeAddress.getAddressForDisplay() + " (" + nrOfDisputes + postFix + ")"; } else return Res.get("shared.na"); } else { @@ -1213,7 +1251,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { long accountAge = accountAgeWitnessService.getAccountAge(item.getSellerPaymentAccountPayload(), contract.getSellerPubKeyRing()); String age = DisplayUtils.formatAccountAge(accountAge); String postFix = CurrencyUtil.isTraditionalCurrency(item.getContract().getOfferPayload().getCurrencyCode()) ? " / " + age : ""; - return sellerNodeAddress.getHostNameWithoutPostFix() + " (" + nrOfDisputes + postFix + ")"; + return sellerNodeAddress.getAddressForDisplay() + " (" + nrOfDisputes + postFix + ")"; } else return Res.get("shared.na"); } else { @@ -1296,8 +1334,8 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { return; } - String keyBaseUserName = DisputeAgentLookupMap.getMatrixUserName(agentNodeAddress.getFullAddress()); - setText(keyBaseUserName); + String MatrixUserName = DisputeAgentLookupMap.getMatrixUserName(agentNodeAddress.getFullAddress()); + setText(MatrixUserName); } else { setText(""); } @@ -1355,7 +1393,7 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { // subscribe to trade's dispute state Trade trade = tradeManager.getTrade(item.getTradeId()); if (trade == null) log.warn("Dispute's trade is null for trade {}", item.getTradeId()); - else subscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> setText(getDisputeStateText(disputeState))); + else subscription = EasyBind.subscribe(trade.disputeStateProperty(), disputeState -> setText(getDisputeStateText(item))); } else { if (closedProperty != null) { closedProperty.removeListener(listener); @@ -1375,28 +1413,18 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { return column; } - private String getDisputeStateText(DisputeState disputeState) { - switch (disputeState) { - case DISPUTE_REQUESTED: - return Res.get("support.requested"); - case DISPUTE_CLOSED: - return Res.get("support.closed"); - default: - return Res.get("support.open"); - } - } - private String getDisputeStateText(Dispute dispute) { Trade trade = tradeManager.getTrade(dispute.getTradeId()); if (trade == null) { - log.warn("Dispute's trade is null for trade {}", dispute.getTradeId()); + log.warn("Dispute's trade is null for trade {}, defaulting to dispute state text 'closed'", dispute.getTradeId()); return Res.get("support.closed"); } + if (dispute.isClosed()) return Res.get("support.closed"); switch (trade.getDisputeState()) { + case NO_DISPUTE: + return Res.get("shared.pending"); case DISPUTE_REQUESTED: return Res.get("support.requested"); - case DISPUTE_CLOSED: - return Res.get("support.closed"); default: return Res.get("support.open"); } @@ -1442,4 +1470,36 @@ public abstract class DisputeView extends ActivatableView<VBox, Void> { return (disputeManager instanceof MediationManager) ? Res.get("shared.mediator") : Res.get("shared.refundAgent"); } } + + private PeerInfoIconDispute createAvatar(Integer tableRowId, Dispute dispute, boolean isBuyer) { + NodeAddress nodeAddress = isBuyer ? dispute.getContract().getBuyerNodeAddress() : dispute.getContract().getSellerNodeAddress(); + String key = tableRowId + nodeAddress.getAddressForDisplay() + (isBuyer ? "BUYER" : "SELLER"); + Long accountAge = isBuyer ? + accountAgeWitnessService.getAccountAge(dispute.getBuyerPaymentAccountPayload(), dispute.getContract().getBuyerPubKeyRing()) : + accountAgeWitnessService.getAccountAge(dispute.getSellerPaymentAccountPayload(), dispute.getContract().getSellerPubKeyRing()); + PeerInfoIconDispute peerInfoIcon = new PeerInfoIconDispute( + nodeAddress, + disputeManager.getNrOfDisputes(isBuyer, dispute.getContract()), + accountAge, + preferences); + avatarMap.put(key, peerInfoIcon); // TODO + return peerInfoIcon; + } + + @Override + public void onCloseDisputeFromChatWindow(Dispute dispute) { + if (dispute.getDisputeState() == Dispute.State.NEW || dispute.getDisputeState().isOpen()) { + handleOnProcessDispute(dispute); + } else { + closeDisputeFromButton(); + } + } + + @Override + public void onSendLogsFromChatWindow(Dispute dispute) { + if (!(disputeManager instanceof ArbitrationManager)) + return; + ArbitrationManager arbitrationManager = (ArbitrationManager) disputeManager; + new SendLogFilesWindow(dispute.getTradeId(), dispute.getTraderId(), arbitrationManager).show(); + } } diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/DisputeAgentView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/DisputeAgentView.java index e5a01e7c86..10c657dce7 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/DisputeAgentView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/DisputeAgentView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.agent; diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/arbitration/ArbitratorView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/arbitration/ArbitratorView.java index 821892e108..c5d122cffa 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/arbitration/ArbitratorView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/arbitration/ArbitratorView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.agent.arbitration; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; @@ -37,9 +39,6 @@ import haveno.desktop.main.overlays.windows.DisputeSummaryWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.support.dispute.agent.DisputeAgentView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class ArbitratorView extends DisputeAgentView { diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/mediation/MediatorView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/mediation/MediatorView.java index dca55b0871..e8e3f9d6ac 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/mediation/MediatorView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/mediation/MediatorView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.agent.mediation; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; @@ -37,9 +39,6 @@ import haveno.desktop.main.overlays.windows.DisputeSummaryWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.support.dispute.agent.DisputeAgentView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class MediatorView extends DisputeAgentView { diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/refund/RefundAgentView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/refund/RefundAgentView.java index 8b225c7fe6..c7e1705d58 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/refund/RefundAgentView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/agent/refund/RefundAgentView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.agent.refund; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; @@ -39,9 +41,6 @@ import haveno.desktop.main.overlays.windows.DisputeSummaryWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.support.dispute.agent.DisputeAgentView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class RefundAgentView extends DisputeAgentView { diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/DisputeClientView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/DisputeClientView.java index 202bf11701..90c945466e 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/DisputeClientView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/DisputeClientView.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.client; diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/arbitration/ArbitrationClientView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/arbitration/ArbitrationClientView.java index b9eda655cd..182bd815ae 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/arbitration/ArbitrationClientView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/arbitration/ArbitrationClientView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.client.arbitration; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; @@ -37,9 +39,6 @@ import haveno.desktop.main.overlays.windows.DisputeSummaryWindow; import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.support.dispute.client.DisputeClientView; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class ArbitrationClientView extends DisputeClientView { @Inject diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/mediation/MediationClientView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/mediation/MediationClientView.java index 73865352ef..63eed5ff64 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/mediation/MediationClientView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/mediation/MediationClientView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.client.mediation; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; @@ -41,9 +43,6 @@ import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.support.dispute.client.DisputeClientView; import haveno.network.p2p.NodeAddress; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class MediationClientView extends DisputeClientView { @Inject diff --git a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/refund/RefundClientView.java b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/refund/RefundClientView.java index 2dfa06ad82..52d77038e3 100644 --- a/desktop/src/main/java/haveno/desktop/main/support/dispute/client/refund/RefundClientView.java +++ b/desktop/src/main/java/haveno/desktop/main/support/dispute/client/refund/RefundClientView.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.support.dispute.client.refund; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.config.Config; import haveno.common.crypto.KeyRing; import haveno.core.account.witness.AccountAgeWitnessService; @@ -39,9 +41,6 @@ import haveno.desktop.main.overlays.windows.TradeDetailsWindow; import haveno.desktop.main.support.dispute.client.DisputeClientView; import haveno.network.p2p.NodeAddress; -import javax.inject.Inject; -import javax.inject.Named; - @FxmlView public class RefundClientView extends DisputeClientView { @Inject diff --git a/desktop/src/main/java/haveno/desktop/setup/DesktopPersistedDataHost.java b/desktop/src/main/java/haveno/desktop/setup/DesktopPersistedDataHost.java index 646ec366fb..6ce1cf4a87 100644 --- a/desktop/src/main/java/haveno/desktop/setup/DesktopPersistedDataHost.java +++ b/desktop/src/main/java/haveno/desktop/setup/DesktopPersistedDataHost.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.setup; diff --git a/desktop/src/main/java/haveno/desktop/theme-dark.css b/desktop/src/main/java/haveno/desktop/theme-dark.css index fed0297599..37903692ce 100644 --- a/desktop/src/main/java/haveno/desktop/theme-dark.css +++ b/desktop/src/main/java/haveno/desktop/theme-dark.css @@ -131,7 +131,7 @@ -bs-red-soft: derive(-bs-rd-error-red, 60%); -bs-progress-bar-track: #272728; -bs-chart-tick: rgba(255, 255, 255, 0.7); - -bs-chart-lines: rgba(0, 0, 0, 0.3); + -bs-chart-lines: -bs-color-gray-2; -bs-white: white; -bs-prompt-text: -bs-color-gray-6; -bs-decimals: #db6300; @@ -241,6 +241,10 @@ -fx-border-width: 0 0 10 0; } +#address-text-field.jfx-text-field:readonly { + -fx-background-color: derive(-bs-background-color, 15%); +} + .wallet-seed-words { -fx-text-fill: -bs-color-gray-6; } @@ -553,3 +557,12 @@ -fx-text-fill: -bs-text-color; -fx-fill: -bs-text-color; } + +.toggle-button-no-slider { + -fx-focus-color: transparent; + -fx-faint-focus-color: transparent; +} + +.toggle-button-no-slider:selected { + -fx-background-color: -bs-color-gray-ddd; +} diff --git a/desktop/src/main/java/haveno/desktop/theme-light.css b/desktop/src/main/java/haveno/desktop/theme-light.css index 8f057a5054..7605eb1819 100644 --- a/desktop/src/main/java/haveno/desktop/theme-light.css +++ b/desktop/src/main/java/haveno/desktop/theme-light.css @@ -41,7 +41,7 @@ -bs-rd-green: #0b65da; -bs-rd-green-dark: #3EA34A; -bs-rd-nav-selected: #0b65da; - -bs-rd-nav-deselected: rgba(255, 255, 255, 0.59); + -bs-rd-nav-deselected: rgba(255, 255, 255, 0.75); -bs-rd-nav-background: #0c59bd; -bs-rd-nav-primary-background: #0b65da; -bs-rd-nav-primary-border: #0B65DA; @@ -125,3 +125,8 @@ .progress-bar > .secondary-bar { -fx-background-color: -bs-color-gray-3; } + +.toggle-button-no-slider { + -fx-focus-color: transparent; + -fx-faint-focus-color: transparent; +} diff --git a/desktop/src/main/java/haveno/desktop/util/AxisInlierUtils.java b/desktop/src/main/java/haveno/desktop/util/AxisInlierUtils.java index ea9c46f219..03956c6d80 100644 --- a/desktop/src/main/java/haveno/desktop/util/AxisInlierUtils.java +++ b/desktop/src/main/java/haveno/desktop/util/AxisInlierUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/Colors.java b/desktop/src/main/java/haveno/desktop/util/Colors.java index c5ce12f802..366987c273 100644 --- a/desktop/src/main/java/haveno/desktop/util/Colors.java +++ b/desktop/src/main/java/haveno/desktop/util/Colors.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/CssTheme.java b/desktop/src/main/java/haveno/desktop/util/CssTheme.java index 380f96ab3b..1e1c547607 100644 --- a/desktop/src/main/java/haveno/desktop/util/CssTheme.java +++ b/desktop/src/main/java/haveno/desktop/util/CssTheme.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/CurrencyList.java b/desktop/src/main/java/haveno/desktop/util/CurrencyList.java index e196394bea..3e68ccf876 100644 --- a/desktop/src/main/java/haveno/desktop/util/CurrencyList.java +++ b/desktop/src/main/java/haveno/desktop/util/CurrencyList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/CurrencyListItem.java b/desktop/src/main/java/haveno/desktop/util/CurrencyListItem.java index b40b7668db..5a85a80d08 100644 --- a/desktop/src/main/java/haveno/desktop/util/CurrencyListItem.java +++ b/desktop/src/main/java/haveno/desktop/util/CurrencyListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/CurrencyPredicates.java b/desktop/src/main/java/haveno/desktop/util/CurrencyPredicates.java index d97889ef64..a201bd6f36 100644 --- a/desktop/src/main/java/haveno/desktop/util/CurrencyPredicates.java +++ b/desktop/src/main/java/haveno/desktop/util/CurrencyPredicates.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java b/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java index 2a38895421..250c8ad339 100644 --- a/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java +++ b/desktop/src/main/java/haveno/desktop/util/DisplayUtils.java @@ -117,17 +117,21 @@ public class DisplayUtils { /////////////////////////////////////////////////////////////////////////////////////////// public static String getDirectionWithCode(OfferDirection direction, String currencyCode) { - if (CurrencyUtil.isTraditionalCurrency(currencyCode)) - return (direction == OfferDirection.BUY) ? Res.get("shared.buyCurrency", Res.getBaseCurrencyCode()) : Res.get("shared.sellCurrency", Res.getBaseCurrencyCode()); - else - return (direction == OfferDirection.SELL) ? Res.get("shared.buyCurrency", currencyCode) : Res.get("shared.sellCurrency", currencyCode); + return getDirectionWithCode(direction, currencyCode, false); } - public static String getDirectionBothSides(OfferDirection direction) { + public static String getDirectionWithCode(OfferDirection direction, String currencyCode, boolean isPrivate) { + if (CurrencyUtil.isTraditionalCurrency(currencyCode)) + return (direction == OfferDirection.BUY) ? Res.get(isPrivate ? "shared.buyCurrencyLocked" : "shared.buyCurrency", Res.getBaseCurrencyCode()) : Res.get(isPrivate ? "shared.sellCurrencyLocked" : "shared.sellCurrency", Res.getBaseCurrencyCode()); + else + return (direction == OfferDirection.SELL) ? Res.get(isPrivate ? "shared.buyCurrencyLocked" : "shared.buyCurrency", currencyCode) : Res.get(isPrivate ? "shared.sellCurrencyLocked" : "shared.sellCurrency", currencyCode); + } + + public static String getDirectionBothSides(OfferDirection direction, boolean isLocked) { String currencyCode = Res.getBaseCurrencyCode(); return direction == OfferDirection.BUY ? - Res.get("formatter.makerTaker", currencyCode, Res.get("shared.buyer"), currencyCode, Res.get("shared.seller")) : - Res.get("formatter.makerTaker", currencyCode, Res.get("shared.seller"), currencyCode, Res.get("shared.buyer")); + Res.get(isLocked ? "formatter.makerTakerLocked" : "formatter.makerTaker", currencyCode, Res.get("shared.buyer"), currencyCode, Res.get("shared.seller")) : + Res.get(isLocked ? "formatter.makerTakerLocked" : "formatter.makerTaker", currencyCode, Res.get("shared.seller"), currencyCode, Res.get("shared.buyer")); } public static String getDirectionForBuyer(boolean isMyOffer, String currencyCode) { diff --git a/desktop/src/main/java/haveno/desktop/util/FormBuilder.java b/desktop/src/main/java/haveno/desktop/util/FormBuilder.java index e1767bfed4..7df49216a2 100644 --- a/desktop/src/main/java/haveno/desktop/util/FormBuilder.java +++ b/desktop/src/main/java/haveno/desktop/util/FormBuilder.java @@ -1,24 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; import com.jfoenix.controls.JFXComboBox; -import com.jfoenix.controls.JFXDatePicker; +//import com.jfoenix.controls.JFXDatePicker; import com.jfoenix.controls.JFXTextArea; import com.jfoenix.controls.JFXToggleButton; import de.jensd.fx.fontawesome.AwesomeDude; @@ -36,6 +36,7 @@ import haveno.desktop.components.AutoTooltipCheckBox; import haveno.desktop.components.AutoTooltipLabel; import haveno.desktop.components.AutoTooltipRadioButton; import haveno.desktop.components.AutoTooltipSlideToggleButton; +import haveno.desktop.components.AutoTooltipTextField; import haveno.desktop.components.AutocompleteComboBox; import haveno.desktop.components.BalanceTextField; import haveno.desktop.components.BusyAnimation; @@ -57,6 +58,7 @@ import haveno.desktop.components.TxIdTextField; import javafx.geometry.HPos; import javafx.geometry.Insets; import javafx.geometry.Pos; +import javafx.geometry.VPos; import javafx.scene.Node; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; @@ -379,15 +381,30 @@ public class FormBuilder { /////////////////////////////////////////////////////////////////////////////////////////// // Confirmation Fields /////////////////////////////////////////////////////////////////////////////////////////// - + public static Tuple2<Label, Label> addConfirmationLabelLabel(GridPane gridPane, + int rowIndex, + String title1, + String title2, + double top) { + return addConfirmationLabelLabel(gridPane, false, rowIndex, title1, title2, top); + } public static Tuple2<Label, Label> addConfirmationLabelLabel(GridPane gridPane, int rowIndex, String title1, String title2) { - return addConfirmationLabelLabel(gridPane, rowIndex, title1, title2, 0); + return addConfirmationLabelLabel(gridPane, false, rowIndex, title1, title2, 0); } public static Tuple2<Label, Label> addConfirmationLabelLabel(GridPane gridPane, + boolean isWrapped, + int rowIndex, + String title1, + String title2) { + return addConfirmationLabelLabel(gridPane, isWrapped, rowIndex, title1, title2, 0); + } + + public static Tuple2<Label, Label> addConfirmationLabelLabel(GridPane gridPane, + boolean isWrapped, int rowIndex, String title1, String title2, @@ -396,10 +413,14 @@ public class FormBuilder { label1.getStyleClass().add("confirmation-label"); Label label2 = addLabel(gridPane, rowIndex, title2); label2.getStyleClass().add("confirmation-value"); + label2.setWrapText(isWrapped); GridPane.setColumnIndex(label2, 1); GridPane.setMargin(label1, new Insets(top, 0, 0, 0)); GridPane.setHalignment(label1, HPos.LEFT); + GridPane.setValignment(label1, VPos.TOP); GridPane.setMargin(label2, new Insets(top, 0, 0, 0)); + GridPane.setHalignment(label2, HPos.LEFT); + GridPane.setValignment(label2, VPos.TOP); return new Tuple2<>(label1, label2); } @@ -451,12 +472,21 @@ public class FormBuilder { String title1, String title2, double top) { + return addConfirmationLabelTextArea(gridPane, false, rowIndex, title1, title2, top); + } + + public static Tuple2<Label, TextArea> addConfirmationLabelTextArea(GridPane gridPane, + boolean isWrapped, + int rowIndex, + String title1, + String title2, + double top) { Label label = addLabel(gridPane, rowIndex, title1); label.getStyleClass().add("confirmation-label"); TextArea textArea = addTextArea(gridPane, rowIndex, title2); ((JFXTextArea) textArea).setLabelFloat(false); - + textArea.setWrapText(isWrapped); GridPane.setColumnIndex(textArea, 1); GridPane.setMargin(label, new Insets(top, 0, 0, 0)); GridPane.setHalignment(label, HPos.LEFT); @@ -466,6 +496,7 @@ public class FormBuilder { } + /////////////////////////////////////////////////////////////////////////////////////////// // Label + TextFieldWithIcon /////////////////////////////////////////////////////////////////////////////////////////// @@ -645,7 +676,7 @@ public class FormBuilder { TextArea textArea = new HavenoTextArea(); textArea.setPromptText(prompt); textArea.setWrapText(true); - + textArea.setPrefHeight(100); final Tuple2<Label, VBox> topLabelWithVBox = addTopLabelWithVBox(gridPane, rowIndex, title, textArea, top); GridPane.setColumnIndex(topLabelWithVBox.second, colIndex); @@ -669,7 +700,13 @@ public class FormBuilder { int columnIndex, String title, double top) { - DatePicker datePicker = new JFXDatePicker(); + //DatePicker datePicker = new JFXDatePicker(); + // + //Temporary solution to fix issue 527; a more + //permanant solution would require this issue to be solved: + //(https://github.com/sshahine/JFoenix/issues/1245) + DatePicker datePicker = new DatePicker(); + Tuple2<Label, VBox> topLabelWithVBox = addTopLabelWithVBox(gridPane, rowIndex, columnIndex, title, datePicker, top); return new Tuple2<>(topLabelWithVBox.first, datePicker); } @@ -684,11 +721,14 @@ public class FormBuilder { String title1, String title2, double top) { - DatePicker datePicker1 = new JFXDatePicker(); + + //DatePicker datePicker1 = new JFXDatePicker(); + DatePicker datePicker1 = new DatePicker(); Tuple2<Label, VBox> topLabelWithVBox1 = getTopLabelWithVBox(title1, datePicker1); VBox vBox1 = topLabelWithVBox1.second; - DatePicker datePicker2 = new JFXDatePicker(); + //DatePicker datePicker2 = new JFXDatePicker(); + DatePicker datePicker2 = new DatePicker(); Tuple2<Label, VBox> topLabelWithVBox2 = getTopLabelWithVBox(title2, datePicker2); VBox vBox2 = topLabelWithVBox2.second; @@ -1120,35 +1160,28 @@ public class FormBuilder { } /////////////////////////////////////////////////////////////////////////////////////////// - // Label + TextField + RadioButton + RadioButton + // Label + TextField + HyperlinkWithIcon /////////////////////////////////////////////////////////////////////////////////////////// - public static Tuple4<Label, TextField, RadioButton, RadioButton> addTopLabelTextFieldRadioButtonRadioButton(GridPane gridPane, - int rowIndex, - ToggleGroup toggleGroup, - String title, - String textFieldTitle, - String radioButtonTitle1, - String radioButtonTitle2, - double top) { + public static Tuple3<Label, TextField, HyperlinkWithIcon> addTopLabelTextFieldHyperLink(GridPane gridPane, + int rowIndex, + String title, + String textFieldTitle, + String maxButtonTitle, + double top) { TextField textField = new HavenoTextField(); textField.setPromptText(textFieldTitle); - RadioButton radioButton1 = new AutoTooltipRadioButton(radioButtonTitle1); - radioButton1.setToggleGroup(toggleGroup); - radioButton1.setPadding(new Insets(6, 0, 0, 0)); - - RadioButton radioButton2 = new AutoTooltipRadioButton(radioButtonTitle2); - radioButton2.setToggleGroup(toggleGroup); - radioButton2.setPadding(new Insets(6, 0, 0, 0)); + HyperlinkWithIcon maxLink = new ExternalHyperlink(maxButtonTitle); HBox hBox = new HBox(); hBox.setSpacing(10); - hBox.getChildren().addAll(textField, radioButton1, radioButton2); + hBox.getChildren().addAll(textField, maxLink); + hBox.setAlignment(Pos.CENTER_LEFT); final Tuple2<Label, VBox> labelVBoxTuple2 = addTopLabelWithVBox(gridPane, rowIndex, title, hBox, top); - return new Tuple4<>(labelVBoxTuple2.first, textField, radioButton1, radioButton2); + return new Tuple3<>(labelVBoxTuple2.first, textField, maxLink); } @@ -1254,6 +1287,20 @@ public class FormBuilder { return new Tuple3<>(vBox, label, comboBox); } + public static Tuple3<VBox, Label, AutoTooltipTextField> addTopLabelAutoToolTipTextField(String title) { + return addTopLabelAutoToolTipTextField(title, 0); + } + + public static Tuple3<VBox, Label, AutoTooltipTextField> addTopLabelAutoToolTipTextField(String title, int top) { + Label label = getTopLabel(title); + VBox vBox = getTopLabelVBox(top); + + final AutoTooltipTextField textField = new AutoTooltipTextField(); + vBox.getChildren().addAll(label, textField); + + return new Tuple3<>(vBox, label, textField); + } + @NotNull private static VBox getTopLabelVBox(int top) { VBox vBox = new VBox(); @@ -1358,6 +1405,24 @@ public class FormBuilder { return comboBox; } + public static <T> AutocompleteComboBox<T> addAutocompleteComboBox(GridPane gridPane, int rowIndex, String title, double top) { + var comboBox = new AutocompleteComboBox<T>(); + comboBox.setLabelFloat(true); + comboBox.setPromptText(title); + comboBox.setMaxWidth(Double.MAX_VALUE); + + // Default ComboBox does not show promptText after clear selection. + // https://stackoverflow.com/questions/50569330/how-to-reset-combobox-and-display-prompttext?noredirect=1&lq=1 + comboBox.setButtonCell(getComboBoxButtonCell(title, comboBox)); + + GridPane.setRowIndex(comboBox, rowIndex); + GridPane.setColumnIndex(comboBox, 0); + GridPane.setMargin(comboBox, new Insets(top + Layout.FLOATING_LABEL_DISTANCE, 0, 0, 0)); + gridPane.getChildren().add(comboBox); + + return comboBox; + } + /////////////////////////////////////////////////////////////////////////////////////////// // Label + AutocompleteComboBox /////////////////////////////////////////////////////////////////////////////////////////// diff --git a/desktop/src/main/java/haveno/desktop/util/GUIProfiler.java b/desktop/src/main/java/haveno/desktop/util/GUIProfiler.java index f7d0cb1e81..4a8813f3b1 100644 --- a/desktop/src/main/java/haveno/desktop/util/GUIProfiler.java +++ b/desktop/src/main/java/haveno/desktop/util/GUIProfiler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/GUIUtil.java b/desktop/src/main/java/haveno/desktop/util/GUIUtil.java index 4ba30e62f4..a5a0b86dfe 100644 --- a/desktop/src/main/java/haveno/desktop/util/GUIUtil.java +++ b/desktop/src/main/java/haveno/desktop/util/GUIUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; @@ -28,7 +28,6 @@ import com.googlecode.jcsv.writer.internal.CSVWriterBuilder; import de.jensd.fx.glyphs.materialdesignicons.MaterialDesignIcon; import haveno.common.UserThread; import haveno.common.config.Config; -import haveno.common.crypto.KeyRing; import haveno.common.file.CorruptedStorageFileHandler; import haveno.common.persistence.PersistenceManager; import haveno.common.proto.persistable.PersistableEnvelope; @@ -38,7 +37,7 @@ import haveno.common.util.Tuple3; import haveno.common.util.Utilities; import haveno.core.account.witness.AccountAgeWitness; import haveno.core.account.witness.AccountAgeWitnessService; -import haveno.core.api.CoreMoneroConnectionsService; +import haveno.core.api.XmrConnectionService; import haveno.core.locale.Country; import haveno.core.locale.CountryUtil; import haveno.core.locale.CurrencyUtil; @@ -48,6 +47,7 @@ import haveno.core.payment.PaymentAccount; import haveno.core.payment.PaymentAccountList; import haveno.core.payment.payload.PaymentMethod; import haveno.core.trade.HavenoUtils; +import haveno.core.trade.Trade; import haveno.core.user.DontShowAgainLookup; import haveno.core.user.Preferences; import haveno.core.user.User; @@ -92,8 +92,8 @@ import javafx.stage.StageStyle; import javafx.util.Callback; import javafx.util.StringConverter; import lombok.extern.slf4j.Slf4j; +import monero.common.MoneroUtils; import monero.daemon.model.MoneroTx; -import monero.wallet.MoneroWallet; import monero.wallet.model.MoneroTxConfig; import org.apache.commons.lang3.StringUtils; import org.bitcoinj.core.Coin; @@ -134,8 +134,6 @@ public class GUIUtil { private static Preferences preferences; - public static TradeCurrency TOP_CRYPTO = CurrencyUtil.getTradeCurrency("BTC").get(); - public static void setPreferences(Preferences preferences) { GUIUtil.preferences = preferences; } @@ -167,12 +165,11 @@ public class GUIUtil { Preferences preferences, Stage stage, PersistenceProtoResolver persistenceProtoResolver, - CorruptedStorageFileHandler corruptedStorageFileHandler, - KeyRing keyRing) { + CorruptedStorageFileHandler corruptedStorageFileHandler) { if (!accounts.isEmpty()) { String directory = getDirectoryFromChooser(preferences, stage); if (!directory.isEmpty()) { - PersistenceManager<PersistableEnvelope> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, keyRing); + PersistenceManager<PersistableEnvelope> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, null); PaymentAccountList paymentAccounts = new PaymentAccountList(accounts); persistenceManager.initialize(paymentAccounts, fileName, PersistenceManager.Source.PRIVATE_LOW_PRIO); persistenceManager.persistNow(() -> { @@ -192,8 +189,7 @@ public class GUIUtil { Preferences preferences, Stage stage, PersistenceProtoResolver persistenceProtoResolver, - CorruptedStorageFileHandler corruptedStorageFileHandler, - KeyRing keyRing) { + CorruptedStorageFileHandler corruptedStorageFileHandler) { FileChooser fileChooser = new FileChooser(); File initDir = new File(preferences.getDirectoryChooserPath()); if (initDir.isDirectory()) { @@ -206,7 +202,7 @@ public class GUIUtil { if (Paths.get(path).getFileName().toString().equals(fileName)) { String directory = Paths.get(path).getParent().toString(); preferences.setDirectoryChooserPath(directory); - PersistenceManager<PaymentAccountList> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, keyRing); + PersistenceManager<PaymentAccountList> persistenceManager = new PersistenceManager<>(new File(directory), persistenceProtoResolver, corruptedStorageFileHandler, null); persistenceManager.readPersisted(fileName, persisted -> { StringBuilder msg = new StringBuilder(); HashSet<PaymentAccount> paymentAccounts = new HashSet<>(); @@ -528,18 +524,32 @@ public class GUIUtil { public static void updateConfidence(MoneroTx tx, Tooltip tooltip, TxConfidenceIndicator txConfidenceIndicator) { - if (tx != null && (tx.getNumConfirmations() == null || !tx.isRelayed())) { - tooltip.setText(Res.get("confidence.unknown")); - txConfidenceIndicator.setProgress(0); - } else if (tx != null && tx.isFailed()) { - tooltip.setText(Res.get("confidence.invalid")); - txConfidenceIndicator.setProgress(0); - } else if (tx != null && tx.isConfirmed()) { - tooltip.setText(Res.get("confidence.confirmed", tx.getNumConfirmations())); - txConfidenceIndicator.setProgress((double) tx.getNumConfirmations() / (double) XmrWalletService.NUM_BLOCKS_UNLOCK); + updateConfidence(tx, null, tooltip, txConfidenceIndicator); + } + + public static void updateConfidence(MoneroTx tx, + Trade trade, + Tooltip tooltip, + TxConfidenceIndicator txConfidenceIndicator) { + if (tx == null || tx.getNumConfirmations() == null || !tx.isRelayed()) { + if (trade != null && trade.isDepositsUnlocked()) { + tooltip.setText(Res.get("confidence.confirmed", ">=10")); + txConfidenceIndicator.setProgress(1.0); + } else { + tooltip.setText(Res.get("confidence.unknown")); + txConfidenceIndicator.setProgress(-1); + } } else { - tooltip.setText(Res.get("confidence.seen", 0)); // TODO: replace with numBroadcastPeers - txConfidenceIndicator.setProgress(-1.0); + if (tx.isFailed()) { + tooltip.setText(Res.get("confidence.invalid")); + txConfidenceIndicator.setProgress(0); + } else if (tx.isConfirmed()) { + tooltip.setText(Res.get("confidence.confirmed", tx.getNumConfirmations())); + txConfidenceIndicator.setProgress((double) tx.getNumConfirmations() / (double) XmrWalletService.NUM_BLOCKS_UNLOCK); + } else { + tooltip.setText(Res.get("confidence.confirmed", 0)); + txConfidenceIndicator.setProgress(-1); + } } txConfidenceIndicator.setPrefSize(24, 24); @@ -623,14 +633,10 @@ public class GUIUtil { } } - public static String getPercentageOfTradeAmount(BigInteger fee, BigInteger tradeAmount, BigInteger minFee) { + public static String getPercentageOfTradeAmount(BigInteger fee, BigInteger tradeAmount) { String result = " (" + getPercentage(fee, tradeAmount) + " " + Res.get("guiUtil.ofTradeAmount") + ")"; - if (fee.compareTo(minFee) <= 0) { - result = " " + Res.get("guiUtil.requiredMinimum"); - } - return result; } @@ -674,8 +680,8 @@ public class GUIUtil { .show(); } - public static String getMoneroURI(String address, BigInteger amount, String label, MoneroWallet wallet) { - return wallet.getPaymentUri(new MoneroTxConfig() + public static String getMoneroURI(String address, BigInteger amount, String label) { + return MoneroUtils.getPaymentUri(new MoneroTxConfig() .setAddress(address) .setAmount(amount) .setNote(label)); @@ -689,19 +695,24 @@ public class GUIUtil { return false; } - public static boolean isReadyForTxBroadcastOrShowPopup(CoreMoneroConnectionsService connectionService) { - if (!connectionService.hasSufficientPeersForBroadcast()) { - new Popup().information(Res.get("popup.warning.notSufficientConnectionsToBtcNetwork", connectionService.getMinBroadcastConnections())).show(); + public static boolean isReadyForTxBroadcastOrShowPopup(XmrWalletService xmrWalletService) { + XmrConnectionService xmrConnectionService = xmrWalletService.getXmrConnectionService(); + if (!xmrConnectionService.hasSufficientPeersForBroadcast()) { + new Popup().information(Res.get("popup.warning.notSufficientConnectionsToXmrNetwork", xmrConnectionService.getMinBroadcastConnections())).show(); return false; } - if (!connectionService.isDownloadComplete()) { + if (!xmrConnectionService.isDownloadComplete()) { new Popup().information(Res.get("popup.warning.downloadNotComplete")).show(); return false; } + if (!isWalletSyncedWithinToleranceOrShowPopup(xmrWalletService)) { + return false; + } + try { - connectionService.verifyConnection(); + xmrConnectionService.verifyConnection(); } catch (Exception e) { new Popup().information(e.getMessage()).show(); return false; @@ -710,12 +721,11 @@ public class GUIUtil { return true; } - public static boolean isChainHeightSyncedWithinToleranceOrShowPopup(CoreMoneroConnectionsService connectionService) { - if (!connectionService.isSyncedWithinTolerance()) { - new Popup().information(Res.get("popup.warning.chainNotSynced")).show(); + public static boolean isWalletSyncedWithinToleranceOrShowPopup(XmrWalletService xmrWalletService) { + if (!xmrWalletService.isSyncedWithinTolerance()) { + new Popup().information(Res.get("popup.warning.walletNotSynced")).show(); return false; } - return true; } @@ -742,7 +752,7 @@ public class GUIUtil { } public static void showWantToBurnBTCPopup(Coin miningFee, Coin amount, CoinFormatter btcFormatter) { - new Popup().warning(Res.get("popup.warning.burnBTC", btcFormatter.formatCoinWithCode(miningFee), + new Popup().warning(Res.get("popup.warning.burnXMR", btcFormatter.formatCoinWithCode(miningFee), btcFormatter.formatCoinWithCode(amount))).show(); } @@ -1021,12 +1031,4 @@ public class GUIUtil { columnConstraints2.setHgrow(Priority.ALWAYS); gridPane.getColumnConstraints().addAll(columnConstraints1, columnConstraints2); } - - public static void updateTopCrypto(Preferences preferences) { - TradeCurrency tradeCurrency = preferences.getPreferredTradeCurrency(); - if (CurrencyUtil.isTraditionalCurrency(tradeCurrency.getCode())) { - return; - } - TOP_CRYPTO = tradeCurrency; - } } diff --git a/desktop/src/main/java/haveno/desktop/util/ImageUtil.java b/desktop/src/main/java/haveno/desktop/util/ImageUtil.java index 52b99537f3..77b556204a 100644 --- a/desktop/src/main/java/haveno/desktop/util/ImageUtil.java +++ b/desktop/src/main/java/haveno/desktop/util/ImageUtil.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/Layout.java b/desktop/src/main/java/haveno/desktop/util/Layout.java index 44ff50cd6e..975bb40df6 100644 --- a/desktop/src/main/java/haveno/desktop/util/Layout.java +++ b/desktop/src/main/java/haveno/desktop/util/Layout.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/MovingAverageUtils.java b/desktop/src/main/java/haveno/desktop/util/MovingAverageUtils.java index 753be4509b..96ae9a42f6 100644 --- a/desktop/src/main/java/haveno/desktop/util/MovingAverageUtils.java +++ b/desktop/src/main/java/haveno/desktop/util/MovingAverageUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/main/java/haveno/desktop/util/Transitions.java b/desktop/src/main/java/haveno/desktop/util/Transitions.java index c0ce04c2ca..300524ccce 100644 --- a/desktop/src/main/java/haveno/desktop/util/Transitions.java +++ b/desktop/src/main/java/haveno/desktop/util/Transitions.java @@ -1,22 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.UserThread; import haveno.core.user.Preferences; import javafx.animation.FadeTransition; @@ -32,9 +34,6 @@ import javafx.scene.effect.GaussianBlur; import javafx.scene.layout.Pane; import javafx.util.Duration; -import javax.inject.Inject; -import javax.inject.Singleton; - @Singleton public class Transitions { diff --git a/desktop/src/main/java/haveno/desktop/util/filtering/FilterableListItem.java b/desktop/src/main/java/haveno/desktop/util/filtering/FilterableListItem.java index 188972a785..c22df51bfd 100644 --- a/desktop/src/main/java/haveno/desktop/util/filtering/FilterableListItem.java +++ b/desktop/src/main/java/haveno/desktop/util/filtering/FilterableListItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.filtering; diff --git a/desktop/src/main/java/haveno/desktop/util/filtering/FilteringUtils.java b/desktop/src/main/java/haveno/desktop/util/filtering/FilteringUtils.java index 6aa79ef997..177280b442 100644 --- a/desktop/src/main/java/haveno/desktop/util/filtering/FilteringUtils.java +++ b/desktop/src/main/java/haveno/desktop/util/filtering/FilteringUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.filtering; diff --git a/desktop/src/main/java/haveno/desktop/util/validation/PasswordValidator.java b/desktop/src/main/java/haveno/desktop/util/validation/PasswordValidator.java index f91b4a1ab4..40069b1c95 100644 --- a/desktop/src/main/java/haveno/desktop/util/validation/PasswordValidator.java +++ b/desktop/src/main/java/haveno/desktop/util/validation/PasswordValidator.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/main/resources/images/lock.png b/desktop/src/main/resources/images/lock.png deleted file mode 100644 index 3a4bba5d91..0000000000 Binary files a/desktop/src/main/resources/images/lock.png and /dev/null differ diff --git a/desktop/src/main/resources/images/lock@2x.png b/desktop/src/main/resources/images/lock@2x.png new file mode 100644 index 0000000000..371f6aeb5d Binary files /dev/null and b/desktop/src/main/resources/images/lock@2x.png differ diff --git a/desktop/src/main/resources/logback.xml b/desktop/src/main/resources/logback.xml index 668bfe0931..9cd449702c 100644 --- a/desktop/src/main/resources/logback.xml +++ b/desktop/src/main/resources/logback.xml @@ -1,15 +1,19 @@ <?xml version="1.0" encoding="UTF-8"?> <configuration> + + <conversionRule conversionWord="hl2" converterClass="haveno.common.app.LogHighlighter" /> + <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender"> <encoder> - <pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{30}: %msg %xEx%n)</pattern> + <pattern>%hl2(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}: %msg %xEx%n)</pattern> </encoder> </appender> + <!-- <logger name="org.bitcoinj" level="WARN"/>--> + <logger name="org.apache" level="WARN" /> + <logger name="org.berndpruenster.netlayer.tor.Tor" level="WARN"/> <root level="TRACE"> <appender-ref ref="CONSOLE_APPENDER"/> </root> - <logger name="org.apache" level="WARN" /> - </configuration> diff --git a/desktop/src/test/java/haveno/desktop/AwesomeFontDemo.java b/desktop/src/test/java/haveno/desktop/AwesomeFontDemo.java index 250593e794..31f12162ab 100644 --- a/desktop/src/test/java/haveno/desktop/AwesomeFontDemo.java +++ b/desktop/src/test/java/haveno/desktop/AwesomeFontDemo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; diff --git a/desktop/src/test/java/haveno/desktop/BindingTest.java b/desktop/src/test/java/haveno/desktop/BindingTest.java index 46e5977f29..8f333dfc81 100644 --- a/desktop/src/test/java/haveno/desktop/BindingTest.java +++ b/desktop/src/test/java/haveno/desktop/BindingTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; diff --git a/desktop/src/test/java/haveno/desktop/MarketsPrintTool.java b/desktop/src/test/java/haveno/desktop/MarketsPrintTool.java index 02a080b51a..f6298235af 100644 --- a/desktop/src/test/java/haveno/desktop/MarketsPrintTool.java +++ b/desktop/src/test/java/haveno/desktop/MarketsPrintTool.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; diff --git a/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemo.java b/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemo.java index 5f83ed6846..38c670d73c 100644 --- a/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemo.java +++ b/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemo.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; diff --git a/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemoLauncher.java b/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemoLauncher.java index 763f0e3b22..f6901f9350 100644 --- a/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemoLauncher.java +++ b/desktop/src/test/java/haveno/desktop/MaterialDesignIconDemoLauncher.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop; diff --git a/desktop/src/test/java/haveno/desktop/common/fxml/FxmlViewLoaderTests.java b/desktop/src/test/java/haveno/desktop/common/fxml/FxmlViewLoaderTests.java index 4e56e68631..b2672a1be0 100644 --- a/desktop/src/test/java/haveno/desktop/common/fxml/FxmlViewLoaderTests.java +++ b/desktop/src/test/java/haveno/desktop/common/fxml/FxmlViewLoaderTests.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.fxml; diff --git a/desktop/src/test/java/haveno/desktop/common/support/CachingViewLoaderTests.java b/desktop/src/test/java/haveno/desktop/common/support/CachingViewLoaderTests.java index 85b793e3bf..539aa4ca26 100644 --- a/desktop/src/test/java/haveno/desktop/common/support/CachingViewLoaderTests.java +++ b/desktop/src/test/java/haveno/desktop/common/support/CachingViewLoaderTests.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.common.support; diff --git a/desktop/src/test/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosTextTest.java b/desktop/src/test/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosTextTest.java index 44f9559810..234ddfccd5 100644 --- a/desktop/src/test/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosTextTest.java +++ b/desktop/src/test/java/haveno/desktop/components/ColoredDecimalPlacesWithZerosTextTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.components; diff --git a/desktop/src/test/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsTest.java b/desktop/src/test/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsTest.java index 773800e2e0..4f43d6e091 100644 --- a/desktop/src/test/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsTest.java +++ b/desktop/src/test/java/haveno/desktop/main/funds/transactions/DisplayedTransactionsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; @@ -40,7 +40,7 @@ public class DisplayedTransactionsTest { List<MoneroTxWallet> transactions = Lists.newArrayList(mock(MoneroTxWallet.class), mock(MoneroTxWallet.class)); XmrWalletService walletService = mock(XmrWalletService.class); - when(walletService.getTransactions(false)).thenReturn(transactions); + when(walletService.getTxs(false)).thenReturn(transactions); TransactionListItemFactory transactionListItemFactory = mock(TransactionListItemFactory.class, RETURNS_DEEP_STUBS); @@ -60,7 +60,7 @@ public class DisplayedTransactionsTest { @Test public void testUpdateWhenRepositoryIsEmpty() { XmrWalletService walletService = mock(XmrWalletService.class); - when(walletService.getTransactions(false)) + when(walletService.getTxs(false)) .thenReturn(Collections.singletonList(mock(MoneroTxWallet.class))); TradableRepository tradableRepository = mock(TradableRepository.class); diff --git a/desktop/src/test/java/haveno/desktop/main/funds/transactions/ObservableListDecoratorTest.java b/desktop/src/test/java/haveno/desktop/main/funds/transactions/ObservableListDecoratorTest.java index e9966cb6bd..976351724a 100644 --- a/desktop/src/test/java/haveno/desktop/main/funds/transactions/ObservableListDecoratorTest.java +++ b/desktop/src/test/java/haveno/desktop/main/funds/transactions/ObservableListDecoratorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactoryTest.java b/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactoryTest.java index 423e30bd55..0e131b4962 100644 --- a/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactoryTest.java +++ b/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradableFactoryTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradeTest.java b/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradeTest.java index d9186525b0..214ad2e60e 100644 --- a/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradeTest.java +++ b/desktop/src/test/java/haveno/desktop/main/funds/transactions/TransactionAwareTradeTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.funds.transactions; diff --git a/desktop/src/test/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModelTest.java index 3d3411d168..0aa4b545a7 100644 --- a/desktop/src/test/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/market/offerbook/OfferBookChartViewModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.offerbook; diff --git a/desktop/src/test/java/haveno/desktop/main/market/spread/SpreadViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/market/spread/SpreadViewModelTest.java index 1b66e60940..549384739b 100644 --- a/desktop/src/test/java/haveno/desktop/main/market/spread/SpreadViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/market/spread/SpreadViewModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.spread; diff --git a/desktop/src/test/java/haveno/desktop/main/market/trades/TradesChartsViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/market/trades/TradesChartsViewModelTest.java index 191f33c825..19c2359245 100644 --- a/desktop/src/test/java/haveno/desktop/main/market/trades/TradesChartsViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/market/trades/TradesChartsViewModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.market.trades; @@ -67,6 +67,11 @@ public class TradesChartsViewModelTest { false, 0, 0, + 0, + 0, + 0, + 0, + 0, "XMR", "EUR", null, @@ -79,9 +84,6 @@ public class TradesChartsViewModelTest { 0, 0, 0, - 0, - 0, - 0, false, false, 0, diff --git a/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModelTest.java b/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModelTest.java index 98c933ed4a..33d43b7bc5 100644 --- a/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferDataModelTest.java @@ -53,7 +53,7 @@ public class CreateOfferDataModelTest { when(xmrWalletService.getOrCreateAddressEntry(anyString(), any())).thenReturn(addressEntry); when(preferences.isUsePercentageBasedPrice()).thenReturn(true); - when(preferences.getBuyerSecurityDepositAsPercent(null)).thenReturn(0.01); + when(preferences.getSecurityDepositAsPercent(null)).thenReturn(0.01); when(createOfferService.getRandomOfferId()).thenReturn(UUID.randomUUID().toString()); when(tradeStats.getObservableTradeStatisticsSet()).thenReturn(FXCollections.observableSet()); diff --git a/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java index 9cda92f188..a8c6ede578 100644 --- a/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/offer/createoffer/CreateOfferViewModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.createoffer; @@ -55,6 +55,7 @@ import static haveno.desktop.maker.PreferenceMakers.empty; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -67,8 +68,8 @@ public class CreateOfferViewModelTest { @BeforeEach public void setUp() { - final CryptoCurrency btc = new CryptoCurrency("XMR", "monero"); - GlobalSettings.setDefaultTradeCurrency(btc); + final CryptoCurrency xmr = new CryptoCurrency("XMR", "monero"); + GlobalSettings.setDefaultTradeCurrency(xmr); Res.setup(); final XmrValidator btcValidator = new XmrValidator(); @@ -99,7 +100,7 @@ public class CreateOfferViewModelTest { when(paymentAccount.getPaymentMethod()).thenReturn(PaymentMethod.ZELLE); when(user.getPaymentAccountsAsObservable()).thenReturn(FXCollections.observableSet()); when(securityDepositValidator.validate(any())).thenReturn(new InputValidator.ValidationResult(false)); - when(accountAgeWitnessService.getMyTradeLimit(any(), any(), any())).thenReturn(100000000L); + when(accountAgeWitnessService.getMyTradeLimit(any(), any(), any(), anyBoolean())).thenReturn(100000000L); when(preferences.getUserCountry()).thenReturn(new Country("ES", "Spain", null)); when(createOfferService.getRandomOfferId()).thenReturn(UUID.randomUUID().toString()); when(tradeStats.getObservableTradeStatisticsSet()).thenReturn(FXCollections.observableSet()); diff --git a/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookListItemMaker.java b/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookListItemMaker.java index 0c59a1d78e..eea8787a2f 100644 --- a/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookListItemMaker.java +++ b/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookListItemMaker.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; diff --git a/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookViewModelTest.java index 9f4d208583..3b648533c0 100644 --- a/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/offer/offerbook/OfferBookViewModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.offer.offerbook; @@ -241,7 +241,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(null, null, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(null, null, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); assertEquals(0, model.maxPlacesForAmount.intValue()); } @@ -255,7 +255,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); model.activate(); @@ -273,7 +273,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); model.activate(); @@ -292,7 +292,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(null, null, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(null, null, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); assertEquals(0, model.maxPlacesForVolume.intValue()); } @@ -306,7 +306,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); model.activate(); @@ -324,7 +324,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); model.activate(); @@ -342,7 +342,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(null, null, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(null, null, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); assertEquals(0, model.maxPlacesForPrice.intValue()); } @@ -356,7 +356,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); model.activate(); @@ -374,7 +374,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); - final OfferBookViewModel model = new XmrOfferBookViewModel(null, null, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(null, null, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); assertEquals(0, model.maxPlacesForMarketPriceMargin.intValue()); } @@ -409,7 +409,7 @@ public class OfferBookViewModelTest { item4.getOffer().setPriceFeedService(priceFeedService); offerBookListItems.addAll(item1, item2); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, priceFeedService, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, priceFeedService, null, null, null, getPriceUtil(), null, coinFormatter, null); model.activate(); @@ -430,7 +430,7 @@ public class OfferBookViewModelTest { when(offerBook.getOfferBookListItems()).thenReturn(offerBookListItems); when(priceFeedService.getMarketPrice(anyString())).thenReturn(new MarketPrice("USD", 12684.0450, Instant.now().getEpochSecond(), true)); - final OfferBookViewModel model = new XmrOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, + final OfferBookViewModel model = new FiatOfferBookViewModel(user, openOfferManager, offerBook, empty, null, null, null, null, null, null, getPriceUtil(), null, coinFormatter, null); final OfferBookListItem item = make(xmrBuyItem.but( @@ -605,6 +605,11 @@ public class OfferBookViewModelTest { false, 0, 0, + 0, + 0, + 0, + 0, + 0, "BTC", tradeCurrencyCode, paymentMethodId, @@ -617,9 +622,6 @@ public class OfferBookViewModelTest { 0, 0, 0, - 0, - 0, - 0, false, false, 0, diff --git a/desktop/src/test/java/haveno/desktop/main/overlays/OverlayTest.java b/desktop/src/test/java/haveno/desktop/main/overlays/OverlayTest.java index fa86f85b36..096c02df8b 100644 --- a/desktop/src/test/java/haveno/desktop/main/overlays/OverlayTest.java +++ b/desktop/src/test/java/haveno/desktop/main/overlays/OverlayTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays; diff --git a/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstallerTest.java b/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstallerTest.java index 114241e41a..c715685ed6 100644 --- a/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstallerTest.java +++ b/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/HavenoInstallerTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows.downloadupdate; diff --git a/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTaskTest.java b/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTaskTest.java index d586d675b7..4d8ecaa9cb 100644 --- a/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTaskTest.java +++ b/desktop/src/test/java/haveno/desktop/main/overlays/windows/downloadupdate/VerifyTaskTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.overlays.windows.downloadupdate; diff --git a/desktop/src/test/java/haveno/desktop/main/settings/preferences/PreferencesViewModelTest.java b/desktop/src/test/java/haveno/desktop/main/settings/preferences/PreferencesViewModelTest.java index 1224905d8c..752cfabb19 100644 --- a/desktop/src/test/java/haveno/desktop/main/settings/preferences/PreferencesViewModelTest.java +++ b/desktop/src/test/java/haveno/desktop/main/settings/preferences/PreferencesViewModelTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.main.settings.preferences; diff --git a/desktop/src/test/java/haveno/desktop/maker/CurrencyListItemMakers.java b/desktop/src/test/java/haveno/desktop/maker/CurrencyListItemMakers.java index 98fbddee40..5ec853c55d 100644 --- a/desktop/src/test/java/haveno/desktop/maker/CurrencyListItemMakers.java +++ b/desktop/src/test/java/haveno/desktop/maker/CurrencyListItemMakers.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.maker; diff --git a/desktop/src/test/java/haveno/desktop/maker/OfferMaker.java b/desktop/src/test/java/haveno/desktop/maker/OfferMaker.java index 6c8233c7d9..ae6f73ac52 100644 --- a/desktop/src/test/java/haveno/desktop/maker/OfferMaker.java +++ b/desktop/src/test/java/haveno/desktop/maker/OfferMaker.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.maker; @@ -60,9 +60,11 @@ public class OfferMaker { public static final Property<Offer, PubKeyRing> pubKeyRing = newProperty(); public static final Property<Offer, Long> blockHeight = newProperty(); public static final Property<Offer, Long> txFee = newProperty(); - public static final Property<Offer, Long> makerFee = newProperty(); - public static final Property<Offer, Long> buyerSecurityDeposit = newProperty(); - public static final Property<Offer, Long> sellerSecurityDeposit = newProperty(); + public static final Property<Offer, Double> makerFeePct = newProperty(); + public static final Property<Offer, Double> takerFeePct = newProperty(); + public static final Property<Offer, Double> penaltyFeePct = newProperty(); + public static final Property<Offer, Double> buyerSecurityDepositPct = newProperty(); + public static final Property<Offer, Double> sellerSecurityDepositPct = newProperty(); public static final Property<Offer, Long> tradeLimit = newProperty(); public static final Property<Offer, Long> maxTradePeriod = newProperty(); public static final Property<Offer, Long> lowerClosePrice = newProperty(); @@ -80,6 +82,11 @@ public class OfferMaker { lookup.valueOf(useMarketBasedPrice, false), lookup.valueOf(amount, 100000L), lookup.valueOf(minAmount, 100000L), + lookup.valueOf(makerFeePct, .0015), + lookup.valueOf(takerFeePct, .0075), + lookup.valueOf(penaltyFeePct, 0.03), + lookup.valueOf(buyerSecurityDepositPct, .15), + lookup.valueOf(sellerSecurityDepositPct, .15), lookup.valueOf(baseCurrencyCode, "XMR"), lookup.valueOf(counterCurrencyCode, "USD"), lookup.valueOf(paymentMethodId, "SEPA"), @@ -92,9 +99,6 @@ public class OfferMaker { null, "2", lookup.valueOf(blockHeight, 700000L), - lookup.valueOf(makerFee, 1000L), - lookup.valueOf(buyerSecurityDeposit, 10000L), - lookup.valueOf(sellerSecurityDeposit, 10000L), lookup.valueOf(tradeLimit, 0L), lookup.valueOf(maxTradePeriod, 0L), false, diff --git a/desktop/src/test/java/haveno/desktop/maker/PreferenceMakers.java b/desktop/src/test/java/haveno/desktop/maker/PreferenceMakers.java index bfbb4be305..bdc8962621 100644 --- a/desktop/src/test/java/haveno/desktop/maker/PreferenceMakers.java +++ b/desktop/src/test/java/haveno/desktop/maker/PreferenceMakers.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.maker; @@ -22,7 +22,7 @@ import com.natpryce.makeiteasy.Property; import com.natpryce.makeiteasy.SameValueDonor; import haveno.common.config.Config; import haveno.common.persistence.PersistenceManager; -import haveno.core.api.LocalMoneroNode; +import haveno.core.api.XmrLocalNode; import haveno.core.user.Preferences; import static com.natpryce.makeiteasy.MakeItEasy.a; @@ -32,14 +32,15 @@ public class PreferenceMakers { public static final Property<Preferences, PersistenceManager> storage = new Property<>(); public static final Property<Preferences, Config> config = new Property<>(); - public static final Property<Preferences, LocalMoneroNode> localMoneroNode = new Property<>(); + public static final Property<Preferences, XmrLocalNode> xmrLocalNode = new Property<>(); public static final Property<Preferences, String> useTorFlagFromOptions = new Property<>(); public static final Property<Preferences, String> referralID = new Property<>(); public static final Instantiator<Preferences> Preferences = lookup -> new Preferences( lookup.valueOf(storage, new SameValueDonor<PersistenceManager>(null)), lookup.valueOf(config, new SameValueDonor<Config>(null)), - lookup.valueOf(useTorFlagFromOptions, new SameValueDonor<String>(null)) + lookup.valueOf(useTorFlagFromOptions, new SameValueDonor<String>(null)), + null ); public static final Preferences empty = make(a(Preferences)); diff --git a/desktop/src/test/java/haveno/desktop/maker/PriceMaker.java b/desktop/src/test/java/haveno/desktop/maker/PriceMaker.java index d33fb0bcc5..d5d618abfb 100644 --- a/desktop/src/test/java/haveno/desktop/maker/PriceMaker.java +++ b/desktop/src/test/java/haveno/desktop/maker/PriceMaker.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.maker; diff --git a/desktop/src/test/java/haveno/desktop/maker/TradeCurrencyMakers.java b/desktop/src/test/java/haveno/desktop/maker/TradeCurrencyMakers.java index 215d5943a1..cbf6b58dc6 100644 --- a/desktop/src/test/java/haveno/desktop/maker/TradeCurrencyMakers.java +++ b/desktop/src/test/java/haveno/desktop/maker/TradeCurrencyMakers.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.maker; diff --git a/desktop/src/test/java/haveno/desktop/maker/VolumeMaker.java b/desktop/src/test/java/haveno/desktop/maker/VolumeMaker.java index 47470f7537..45cd740493 100644 --- a/desktop/src/test/java/haveno/desktop/maker/VolumeMaker.java +++ b/desktop/src/test/java/haveno/desktop/maker/VolumeMaker.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.maker; diff --git a/desktop/src/test/java/haveno/desktop/util/CurrencyListTest.java b/desktop/src/test/java/haveno/desktop/util/CurrencyListTest.java index 4a89373eda..c44f9814bb 100644 --- a/desktop/src/test/java/haveno/desktop/util/CurrencyListTest.java +++ b/desktop/src/test/java/haveno/desktop/util/CurrencyListTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java b/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java index e568d20aff..dc7d68c873 100644 --- a/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java +++ b/desktop/src/test/java/haveno/desktop/util/GUIUtilTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; @@ -103,30 +103,19 @@ public class GUIUtilTest { } @Test - public void percentageOfTradeAmount_higherFeeAsMin() { + public void percentageOfTradeAmount1() { BigInteger fee = BigInteger.valueOf(200000000L); - BigInteger min = BigInteger.valueOf(100000000L); - assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0), min)); + assertEquals(" (0.02% of trade amount)", GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0))); } @Test - public void percentageOfTradeAmount_minFee() { - - BigInteger fee = BigInteger.valueOf(100000000L); - BigInteger min = BigInteger.valueOf(100000000L); - - assertEquals(" (required minimum)", - GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0), min)); - } - - @Test - public void percentageOfTradeAmount_minFeeZERO() { + public void percentageOfTradeAmount2() { BigInteger fee = BigInteger.valueOf(100000000L); assertEquals(" (0.01% of trade amount)", - GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0), BigInteger.valueOf(0))); + GUIUtil.getPercentageOfTradeAmount(fee, HavenoUtils.xmrToAtomicUnits(1.0))); } } diff --git a/desktop/src/test/java/haveno/desktop/util/ImmutableCoinFormatterTest.java b/desktop/src/test/java/haveno/desktop/util/ImmutableCoinFormatterTest.java index 4733ce5c12..1cb16e5fb3 100644 --- a/desktop/src/test/java/haveno/desktop/util/ImmutableCoinFormatterTest.java +++ b/desktop/src/test/java/haveno/desktop/util/ImmutableCoinFormatterTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/test/java/haveno/desktop/util/MovingAverageUtilsTest.java b/desktop/src/test/java/haveno/desktop/util/MovingAverageUtilsTest.java index de6d8d1fd1..b6830dff7c 100644 --- a/desktop/src/test/java/haveno/desktop/util/MovingAverageUtilsTest.java +++ b/desktop/src/test/java/haveno/desktop/util/MovingAverageUtilsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util; diff --git a/desktop/src/test/java/haveno/desktop/util/validation/FiatVolumeValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/FiatVolumeValidatorTest.java index bf31c7dfb8..cdd35f9646 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/FiatVolumeValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/FiatVolumeValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferAnswerValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferAnswerValidatorTest.java index a397aae867..8c0b88c89e 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferAnswerValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferAnswerValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferQuestionValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferQuestionValidatorTest.java index 5fc3aa4f69..dd9258e436 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferQuestionValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferQuestionValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; @@ -53,7 +53,7 @@ public class InteracETransferQuestionValidatorTest { assertFalse(validator.validate(null).isValid); // null assertFalse(validator.validate("").isValid); // empty - assertFalse(validator.validate("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ").isValid); // too long + assertFalse(validator.validate("abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ").isValid); // too long assertFalse(validator.validate("abc !@#").isValid); // invalid characters } diff --git a/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferValidatorTest.java index cb8c3696b3..1967e2c565 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/InteracETransferValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/test/java/haveno/desktop/util/validation/LengthValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/LengthValidatorTest.java index 8664bb767a..61a2eabd1c 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/LengthValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/LengthValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/test/java/haveno/desktop/util/validation/RegexValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/RegexValidatorTest.java index 7fb94a1015..b2dddcbc58 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/RegexValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/RegexValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/test/java/haveno/desktop/util/validation/XmrValidatorTest.java b/desktop/src/test/java/haveno/desktop/util/validation/XmrValidatorTest.java index 42792befeb..d4258328bd 100644 --- a/desktop/src/test/java/haveno/desktop/util/validation/XmrValidatorTest.java +++ b/desktop/src/test/java/haveno/desktop/util/validation/XmrValidatorTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.desktop.util.validation; diff --git a/desktop/src/test/java/org/bitcoinj/core/CoinMaker.java b/desktop/src/test/java/org/bitcoinj/core/CoinMaker.java index 87da551b08..5708af890c 100644 --- a/desktop/src/test/java/org/bitcoinj/core/CoinMaker.java +++ b/desktop/src/test/java/org/bitcoinj/core/CoinMaker.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package org.bitcoinj.core; diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 54bebbbf12..caa76ac1a9 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing to Haveno -Thanks for wishing to help! Here there are some guidelines and information about the development process. We suggest you to join the [matrix](https://app.element.io/#/room/#haveno-dev:haveno.network) room `#haveno-dev` (relayed on [IRC/Libera](irc://irc.libera.chat/#haveno-dev)) and have a chat with the devs, so that we can help get you started. +Thanks for wishing to help! Here there are some guidelines and information about the development process. We suggest you to join the [matrix](https://app.element.io/#/room/#haveno-development:monero.social) room `#haveno-development` (relayed on [IRC/Libera](irc://irc.libera.chat/#haveno-development)) and have a chat with the devs, so that we can help get you started. Issues are tracked on GitHub. We use [a label system](https://github.com/haveno-dex/haveno/issues/50) and GitHub's [project boards](https://github.com/haveno-dex/haveno/projects) to simplify development. Make sure to take a look at those and to follow the priorities suggested. diff --git a/docs/create-mainnet.md b/docs/create-mainnet.md new file mode 100644 index 0000000000..38c211d4cd --- /dev/null +++ b/docs/create-mainnet.md @@ -0,0 +1,158 @@ +# Create Haveno network quick start guide + +These instructions describe how to quickly start a public Haveno network running on Monero's main network from your local machine, which is useful for demonstration and testing. + +For a more robust and decentralized deployment to VPS for reliable uptime, see the [deployment guide](./deployment-guide.md). + +## Clone and build Haveno + +``` +git clone https://github.com/haveno-dex/haveno.git +cd haveno +git checkout master +make clean && make +``` + +## Start a Monero node + +In a new terminal window, run `make monerod` to start and sync a Monero node on mainnet. + +Seed nodes and arbitrators require a local, unrestricted Monero node for performance and functionality. + +## Start and register seed nodes + +In a new terminal window, run: `make seednode`. + +The seed node's onion address will print to the screen (denoted by `Hidden service`). Record the seed node's URL to xmr_mainnet.seednodes with port 1002. For example, `4op7nzb65z4xg2taqmt2uhih7uwi3ya25yx5bvskbkjisnq7rwepzvad.onion:1002`. + +In a new terminal window, run: `make seednode2`. + +The seed node's onion address will print to the screen (denoted by `Hidden service`). Record the seed node's URL to xmr_mainnet.seednodes with port 1003. For example, `abwyc7ccjq4oyiej5z3dpwupzql34nnedaft5jc5l2dbocko7naosrjqd.onion:1003`. + +Stop both seed nodes. + +## Register public key(s) for various roles + +Run `./gradlew generateKeypairs`. A list of public/private keypairs will print to the screen which can be used for different roles like arbitration, sending private notifications, etc. + +For demonstration, we can use the first generated public/private keypair for all roles, but you can customize as desired. + +Hardcode the public key(s) in these files: + +- [AlertManager.java](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/core/src/main/java/haveno/core/alert/AlertManager.java#L111) +- [ArbitratorManager.java](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java#L81) +- [FilterManager.java](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/core/src/main/java/haveno/core/filter/FilterManager.java#L117) +- [PrivateNotificationManager.java](https://github.com/haveno-dex/haveno/blob/mainnet_placeholders/core/src/main/java/haveno/core/alert/PrivateNotificationManager.java#L110) + +## Change the default folder name for Haveno application data + +To avoid user data corruption when using multiple Haveno networks, change the default folder name for Haveno's application data on your network: + +- Change `DEFAULT_APP_NAME` in [HavenoExecutable.java](https://github.com/haveno-dex/haveno/blob/64acf86fbea069b0ae9f9bce086f8ecce1e91b87/core/src/main/java/haveno/core/app/HavenoExecutable.java#L85). +- Change `appName` throughout the [Makefile](https://github.com/haveno-dex/haveno/blob/64acf86fbea069b0ae9f9bce086f8ecce1e91b87/Makefile#L479) accordingly. + +For example, change "Haveno" to "HavenoX", which will use this application folder: + +- Linux: ~/.local/share/HavenoX/ +- macOS: ~/Library/Application Support/HavenoX/ +- Windows: ~\AppData\Roaming\HavenoX\ + +## Change the P2P network version + +To avoid interference with other networks, change `P2P_NETWORK_VERSION` in [Version.java](https://github.com/haveno-dex/haveno/blob/a7e90395d24ec3d33262dd5d09c5faec61651a51/common/src/main/java/haveno/common/app/Version.java#L83). + +For example, change it to `"B"`. + +## Start the seed nodes + +Rebuild for the previous changes to the source code to take effect: `make skip-tests`. + +In a new terminal window, run: `make seednode`. + +In a new terminal window, run: `make seednode2`. + +> **Notes** +> * Avoid all seed nodes going offline at the same time. If all seed nodes go offline at the same time, the network will be reset, including registered arbitrators, the network filter object, and trade history. In that case, arbitrators need to restart or re-register, and the network filter object needs to be re-applied. This should be done immediately or clients will cancel their offers due to the signing arbitrators being unregistered and no replacements being available to re-sign. +> * At least 2 seed nodes should be run because the seed nodes restart once per day. + +## Start and register the arbitrator + +In a new terminal window, run: `make arbitrator-desktop-mainnet`. + +Ignore the error about not receiving a filter object. + +Go to the `Account` tab and then press `ctrl + r`. A prompt will open asking to enter the key to register the arbitrator. Enter your private key. + +## Set a network filter on mainnet + +On mainnet, the p2p network is expected to have a filter object for offers, onions, currencies, payment methods, etc. + +To set the network's filter object: + +1. Enter `ctrl + f` in the arbitrator or other Haveno instance to open the Filter window. +2. Enter a developer private key from the previous steps and click "Add Filter" to register. + +## Other configuration + +### Set the network's release date + +Set the network's approximate release date by setting `RELEASE_DATE` in HavenoUtils.java. + +This will prevent posting sell offers which no buyers can take before any buyer accounts are signed and aged, while the network bootstraps. + +After a period (default 60 days), the limit is lifted and sellers can post offers exceeding unsigned buy limits, but they will receive an informational warning for an additional period (default 6 months after release). + +The defaults can be adjusted with the related constants in HavenoUtils.java. + +### Optionally configure trade fees + +Trade fees can be configured in HavenoUtils.java. The maker and taker fee percents can be adjusted. + +Set `ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS` to `true` for the arbitrator to assign the trade fee address, which defaults to their own wallet. + +Otherwise set `ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS` to `false` and set the XMR address in `getGlobalTradeFeeAddress()` to collect all trade fees to a single address (e.g. a multisig wallet shared among network administrators). + +### Optionally start a price node + +The price node is separated from Haveno and is run as a standalone service. To deploy a pricenode on both TOR and clearnet, see the instructions on the repository: https://github.com/haveno-dex/haveno-pricenode. + +After the price node is built and deployed, add the price node to `DEFAULT_NODES` in [ProvidersRepository.java](https://github.com/haveno-dex/haveno/blob/3cdd88b56915c7f8afd4f1a39e6c1197c2665d63/core/src/main/java/haveno/core/provider/ProvidersRepository.java#L50). + +## Review all local changes + +For comparison, placeholders to run on mainnet are marked [here on this branch](https://github.com/haveno-dex/haveno/tree/mainnet_placeholders). + +## Start users for testing + +Optionally set `--ignoreLocalXmrNode` to `true` in Makefile for the user applications to use public nodes and ignore the locally running Monero node, in order test real network conditions. + +Start user1: `make user1-desktop-mainnet`. + +Start user2: `make user2-desktop-mainnet`. + +Test trades among the users and arbitrator over Monero's mainnet. + +## Share your git repository for others to test + +To share your network for others to use, commit your local changes and share your *git repository's URL*. + +It is not sufficient to share only your seed node addresses, because their application must be built with the same public keys and other configuration to work properly. + +After sharing your git repository, others can build and start their application with: + +``` +git clone <your repo url> +cd haveno +make skip-tests +make user1-desktop-mainnet +``` + +However a [more robust VPS setup](./deployment-guide.md) should be used for actual trades. + +## Build the installers for distribution + +To build the installers for distribution, first change `XMR_STAGENET` to `XMR_MAINNET` in [package.gradle](https://github.com/haveno-dex/haveno/blob/1bf83ecb8baa06b6bfcc30720f165f20b8f77025/desktop/package/package.gradle#L278). + +Then [follow instructions](https://github.com/haveno-dex/haveno/blob/master/desktop/package/README.md) to build the installers for distribution. + +Alternatively, the installers are built automatically by GitHub. \ No newline at end of file diff --git a/docs/deployment-guide.md b/docs/deployment-guide.md index eb9b1aa3b2..2f7590d0ec 100644 --- a/docs/deployment-guide.md +++ b/docs/deployment-guide.md @@ -2,95 +2,197 @@ This guide describes how to deploy a Haveno network: -- Build Haveno +- Manage services on a VPS +- Fork and build Haveno - Start a Monero node - Build and start price nodes -- Create and register seed nodes -- Register keypairs with administrative privileges -- Create and register arbitrators -- Set a network filter +- Add seed nodes +- Add arbitrators +- Configure trade fees and other configuration - Build Haveno installers for distribution -- Manage services on a VPS (WIP) -- Send alerts to update the application +- Send alerts to update the application and other maintenance -## Build Haveno +## Manage services on a VPS + +Haveno's services should be run on a VPS for reliable uptime. + +The seed node, price node, and Monero node can be run as system services. Scripts are available for reference in [scripts/deployment](scripts/deployment) to customize and run system services. + +Arbitrators can be started in a Screen session and then detached to run in the background. + +Some good hints about how to secure a VPS are in [Monero's meta repository](https://github.com/monero-project/meta/blob/master/SERVER_SETUP_HARDENING.md). + +## Install dependencies + +On Linux and macOS, install Java JDK 21: ``` -git clone https://github.com/haveno-dex/haveno.git +curl -s "https://get.sdkman.io" | bash +sdk install java 21.0.2.fx-librca +``` + +Alternatively, on Ubuntu 22.04: + +`sudo apt-get install openjdk-21-jdk` + +On Windows, install MSYS2 and Java JDK 21: + +1. Install [MSYS2](https://www.msys2.org/). +2. Start MSYS2 MINGW64 or MSYS MINGW32 depending on your system. Use MSYS2 for all commands throughout this document. +4. Update pacman: `pacman -Syy` +5. Install dependencies. During installation, use default=all by leaving the input blank and pressing enter. + + 64-bit: `pacman -S mingw-w64-x86_64-toolchain make mingw-w64-x86_64-cmake git` + + 32-bit: `pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake git` +6. `curl -s "https://get.sdkman.io" | bash` +7. `sdk install java 21.0.2.fx-librca` + +## Fork and build Haveno + +Fork Haveno to a public repository. Then build Haveno: + +``` +git clone <your fork url> cd haveno git checkout <latest tag> make clean && make ``` -See [installing.md](installing.md) for more detail. - ## Start a Monero node -Seed nodes and arbitrators should use a local, trusted Monero node. +Seed nodes and arbitrators must use a local, unrestricted Monero node for performance and functionality. -Arbitrators require a trusted node in order to submit and flush transactions from the pool. +To run a private Monero node as a system service, customize and deploy private-stagenet.service and private-stagenet.conf. -Start a Monero node by running `make monerod` for mainnet or `make monerod-stagenet` for stagenet. +Optionally customize and deploy monero-stagenet.service and monero-stagenet.conf to run a public Monero node as a system service for Haveno clients to use. + +You can also start the Monero node in your current terminal session by running `make monerod` for mainnet or `make monerod-stagenet` for stagenet. ## Build and start price nodes -The price node is separated from Haveno and is to be run as a standalone service. To deploy a pricenode on both Tor and clearnet, see the instructions on the repository: https://github.com/haveno-dex/haveno-pricenode +The price node is separated from Haveno and is run as a standalone service. To deploy a pricenode on both TOR and clearnet, see the instructions on the repository: https://github.com/haveno-dex/haveno-pricenode. -After a price node is deployed, add the price node to `DEFAULT_NODES` in ProvidersRepository.java. +After the price node is built and deployed, add the price node to `DEFAULT_NODES` in [ProvidersRepository.java](https://github.com/haveno-dex/haveno/blob/3cdd88b56915c7f8afd4f1a39e6c1197c2665d63/core/src/main/java/haveno/core/provider/ProvidersRepository.java#L50). -## Create and register seed nodes +Customize and deploy haveno-pricenode.env and haveno-pricenode.service to run as a system service. -From the root of the repository, run `make seednode` to run a seednode on Monero's mainnet or `make seednode-stagenet` to run a seednode on Monero's stagenet. +## Add seed nodes -The node will print its onion address to the console. +### Seed nodes without Proof of Work (PoW) -If you are building a network from scratch: for each seednode, record the onion address in `core/src/main/resources/xmr_<network>.seednodes` and remove unused seed nodes from `xmr_<network>.seednodes`. Be careful to record full addresses correctly. +> [!note] +> Using PoW is suggested. See next section for PoW setup. -Rebuild the seed nodes any time the list of registered seed nodes changes. +For each seed node: + +1. [Build the Haveno repository](#fork-and-build-haveno). +2. [Start a local Monero node](#start-a-local-monero-node). +3. Modify `./scripts/deployment/haveno-seednode.service` and `./scripts/deployment/haveno-seednode2.service` as needed. +4. Copy `./scripts/deployment/haveno-seednode.service` to `/etc/systemd/system` (if you are the very first seed in a new network also copy `./scripts/deployment/haveno-seednode2.service` to `/etc/systemd/system`). +5. Run `sudo systemctl start haveno-seednode.service` to start the seednode and also run `sudo systemctl start haveno-seednode2.service` if you are the very first seed in a new network and copied haveno-seednode2.service to your systemd folder. +6. Run `journalctl -u haveno-seednode.service -b -f` which will print the log and show the `.onion` address of the seed node. Press `Ctrl+C` to stop printing the log and record the `.onion` address given. +7. Add the `.onion` address to `core/src/main/resources/xmr_<network>.seednodes` along with the port specified in the haveno-seednode.service file(s) `(ex: example.onion:1002)`. Be careful to record full addresses correctly. +8. Update all seed nodes, arbitrators, and user applications for the change to take effect. + +### Seed nodes with Proof of Work (PoW) + +> [!note] +> These instructions were written for Ubuntu with an Intel/AMD 64-bit CPU so changes may be needed for your distribution. + +### Install Tor + +Source: [Tor Project Support](https://support.torproject.org/apt/) + +1. Verify architecture `sudo dpkg --print-architecture`. +2. Create sources.list file `sudo nano /etc/apt/sources.list.d/tor.list`. +3. Paste `deb [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] https://deb.torproject.org/torproject.org <DISTRIBUTION> main`. +4. Paste `deb-src [signed-by=/usr/share/keyrings/deb.torproject.org-keyring.gpg] https://deb.torproject.org/torproject.org <DISTRIBUTION> main`. +> [!note] +> Replace `<DISTRIBUTION>` with your system codename such as "jammy" for Ubuntu 22.04. +5. Press Ctrl+X, then "y", then the enter key. +6. Add the gpg key used to sign the packages `sudo wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gpg --dearmor | tee /usr/share/keyrings/deb.torproject.org-keyring.gpg >/dev/null`. +7. Update repositories `sudo apt update`. +8. Install tor and tor debian keyring `sudo apt install tor deb.torproject.org-keyring`. +9. Replace torrc `sudo mv /etc/tor/torrc /etc/tor/torrc.default` then `sudo cp seednode/torrc /etc/tor/torrc`. +10. Stop tor `sudo systemctl stop tor`. + +For each seed node: + +1. [Build the Haveno repository](#fork-and-build-haveno). +2. [Start a local Monero node](#start-a-local-monero-node). +3. Run `sudo cat /var/lib/tor/haveno_seednode/hostname` and note down the .onion for the next step & step 10. +4. Modify `./scripts/deployment/haveno-seednode.service` and `./scripts/deployment/haveno-seednode2.service` as needed. +5. Copy `./scripts/deployment/haveno-seednode.service` to `/etc/systemd/system` (if you are the very first seed in a new network also copy `./scripts/deployment/haveno-seednode2.service` to `/etc/systemd/system`). +6. Add user to tor group `sudo usermod -aG debian-tor <user>`. +> [!note] +> Replace `<user>` above with the user that will be running the seed node (step 6 above & step 4) +7. Disconnect and reconnect SSH session or logout and back in. +8. Run `sudo systemctl start tor`. +9. Run `sudo systemctl start haveno-seednode` to start the seednode and also run `sudo systemctl start haveno-seednode2` if you are the very first seed in a new network and copied haveno-seednode2.service to your systemd folder. +10. Add the `.onion` address from step 3 to `core/src/main/resources/xmr_<network>.seednodes` along with the port specified in the haveno-seednode.service file(s) `(ex: example.onion:2002)`. Be careful to record full addresses correctly. +11. Update all seed nodes, arbitrators, and user applications for the change to take effect. + +Customize and deploy haveno-seednode.service to run a seed node as a system service. Each seed node requires a locally running Monero node. You can use the default port or configure it manually with `--xmrNode`, `--xmrNodeUsername`, and `--xmrNodePassword`. -## Register keypairs with arbitrator privileges +Rebuild all seed nodes any time the list of registered seed nodes changes. -1. Run core/src/test/java/haveno/core/util/GenerateKeypairs.java to generate public/private keypairs for arbitrator privileges. -2. Add arbitrator public keys to the corresponding network type in ArbitratorManager.java `getPubKeyList()`. +> **Notes** +> * Avoid all seed nodes going offline at the same time. If all seed nodes go offline at the same time, the network will be reset, including registered arbitrators, the network filter object, and trade history. In that case, arbitrators need to restart or re-register, and the network filter object needs to be re-applied. This should be done immediately or clients will cancel their offers due to the signing arbitrators being unregistered and no replacements being available to re-sign. +> * At least 2 seed nodes should be run because the seed nodes restart once per day. -## Register keypairs with developer privileges +## Register keypairs with privileges -Keypairs with developer privileges are able to set the network's filter object, which can filter out offers, onions, currencies, payment methods, etc. +### Register keypair(s) with developer privileges -1. Run core/src/test/java/haveno/core/util/GenerateKeypairs.java to generate public/private keypairs for developer privileges. -2. Set developer public keys in the constructor of FilterManager.java. +1. [Build the Haveno repository](#fork-and-build-haveno). +2. Generate public/private keypairs for developers: `./gradlew generateKeypairs` +3. Add the developer public keys in the constructor of FilterManager.java. +4. Update all seed nodes, arbitrators, and user applications for the change to take effect. -## Register keypairs with alert privileges +### Register keypair(s) with alert privileges -Keypairs with alert privileges are able to send alerts, e.g. to update the application. +1. [Build the Haveno repository](#fork-and-build-haveno). +2. Generate public/private keypairs for alerts: `./gradlew generateKeypairs` +2. Add the public keys in the constructor of AlertManager.java. +4. Update all seed nodes, arbitrators, and user applications for the change to take effect. -1. Run core/src/test/java/haveno/core/util/GenerateKeypairs.java to generate public/private keypairs for alert privileges. -2. Set alert public keys in the constructor of AlertManager.java. +### Register keypair(s) with private notification privileges -## Register keypairs with private notification privileges +1. [Build the Haveno repository](#fork-and-build-haveno). +2. Generate public/private keypairs for private notifications: `./gradlew generateKeypairs` +2. Add the public keys in the constructor of PrivateNotificationManager.java. +4. Update all seed nodes, arbitrators, and user applications for the change to take effect. -1. Run core/src/test/java/haveno/core/util/GenerateKeypairs.java to generate public/private keypairs for private notification privileges. -2. Set public keys in the constructor of PrivateNotification.java. +## Add arbitrators -## Set XMR address to collect trade fees +For each arbitrator: -Set the XMR address to collect trade fees in `getTradeFeeAddress()` in HavenoUtils.java. +1. [Build the Haveno repository](#fork-and-build-haveno). +2. Generate a public/private keypair for the arbitrator: `./gradlew generateKeypairs` +3. Add the public key to `getPubKeyList()` in [ArbitratorManager.java](https://github.com/haveno-dex/haveno/blob/3cdd88b56915c7f8afd4f1a39e6c1197c2665d63/core/src/main/java/haveno/core/support/dispute/arbitration/arbitrator/ArbitratorManager.java#L62). +4. Update all seed nodes, arbitrators, and user applications for the change to take effect. +5. [Start a local Monero node](#start-a-local-monero-node). +6. Start the Haveno desktop application using the application launcher or e.g. `make arbitrator-desktop-mainnet` +7. Go to the `Account` tab and then press `ctrl + r`. A prompt will open asking to enter the key to register the arbitrator. Enter your private key. -## Create and register arbitrators +The arbitrator is now registered and ready to accept requests for dispute resolution. -Before running the arbitrator, remember that at least one seednode should already be deployed and its address listed in `core/src/main/resources/xmr_<network>.seednodes`. +**Notes** +- Arbitrators must use a local Monero node with unrestricted RPC in order to submit and flush transactions from the pool. +- Arbitrators should remain online as much as possible in order to balance trades and avoid clients spending time trying to contact offline arbitrators. A VPS or dedicated machine running 24/7 is highly recommended. +- Remember that for the network to run correctly and people to be able to open and accept trades, at least one arbitrator must be registered on the network. +- IMPORTANT: Do not reuse keypairs on multiple arbitrator instances. -First rebuild Haveno: `make skip-tests`. +## Remove an arbitrator -Run `make arbitrator-desktop` to run an arbitrator on Monero's mainnet or `make arbitrator-desktop-stagenet` to run an arbitrator on Monero's stagenet. +> **Note** +> Ensure the arbitrator's trades are completed before retiring the instance. -The Haveno GUI will open. If on mainnet, ignore the error about not receiving a filter object which is not added yet. Click on the `Account` tab and then press `ctrl + r`. A prompt will open asking to enter the key to register the arbitrator. Use a key generated in the previous steps and complete the registration. The arbitrator is now registered and ready to accept requests of dispute resolution. - -Remember that for the network to run correctly and people to be able to open and accept trades, at least one arbitrator must be registered on the network. - -IMPORTANT: Do not reuse keypairs, and remember to revoke the private keypair to terminate the arbitrator. +1. Start the arbitrator's desktop application using the application launcher or e.g. `make arbitrator-desktop-mainnet` from the root of the repository. +2. Go to the `Account` tab and click the button to unregister the arbitrator. ## Set a network filter on mainnet @@ -104,32 +206,57 @@ To set the network's filter object: > **Note** > If all seed nodes are restarted at the same time, arbitrators and the filter object will become unregistered and will need to be re-registered. +## Change the default folder name for Haveno application data + +To avoid user data corruption when using multiple Haveno networks, change the default folder name for Haveno's application data on your network: + +- Change `DEFAULT_APP_NAME` in [HavenoExecutable.java](https://.com/haveno-dex/haveno/blob/1aa62863f49a15e8322a8d96e58dc0ed37dec4eb/core/src/main/java/haveno/core/app/HavenoExecutable.java#L85). +- Change `appName` throughout the [Makefile](https://github.com/haveno-dex/haveno/blob/64acf86fbea069b0ae9f9bce086f8ecce1e91b87/Makefile#L479) accordingly. + +For example, change "Haveno" to "HavenoX", which will use this application folder: + +- Linux: ~/.local/share/HavenoX/ +- macOS: ~/Library/Application Support/HavenoX/ +- Windows: ~\AppData\Roaming\HavenoX\ + +## Change the P2P network version + +To avoid interference with other networks, change `P2P_NETWORK_VERSION` in [Version.java](https://github.com/haveno-dex/haveno/blob/a7e90395d24ec3d33262dd5d09c5faec61651a51/common/src/main/java/haveno/common/app/Version.java#L83). + +For example, change it to `"B"`. + +## Set the network's release date + +Optionally set the network's approximate release date by setting `RELEASE_DATE` in HavenoUtils.java. + +This will prevent posting sell offers which no buyers can take before any buyer accounts are signed and aged, while the network bootstraps. + +After a period (default 60 days), the limit is lifted and sellers can post offers exceeding unsigned buy limits, but they will receive an informational warning for an additional period (default 6 months after release). + +The defaults can be adjusted with the related constants in HavenoUtils.java. + +## Configure trade fees + +Trade fees can be configured in HavenoUtils.java. The maker and taker fee percents can be adjusted. + +Set `ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS` to `true` for the arbitrator to assign the trade fee address, which defaults to their own wallet. + +Otherwise set `ARBITRATOR_ASSIGNS_TRADE_FEE_ADDRESS` to `false` and set the XMR address in `getGlobalTradeFeeAddress()` to collect all trade fees to a single address (e.g. a multisig wallet shared among network administrators). + ## Start users for testing -Start user1 on Monero's mainnet using `make user1-desktop` or Monero's stagenet using `make user1-desktop-stagenet`. +Start user1 on Monero's mainnet using `make user1-desktop-mainnet` or Monero's stagenet using `make user1-desktop-stagenet`. -Similarly, start user2 on Monero's mainnet using `make user2-desktop` or Monero's stagenet using `make user2-desktop-stagenet`. +Similarly, start user2 on Monero's mainnet using `make user2-desktop-mainnet` or Monero's stagenet using `make user2-desktop-stagenet`. Test trades among the users and arbitrator. ## Build Haveno installers for distribution -For mainnet, first modify [package.gradle](https://github.com/haveno-dex/haveno/blob/aeb0822f9fc72bd5a0e23d0c42c2a8f5f87625bb/desktop/package/package.gradle#L252) to remove the line with ` --arguments --baseCurrencyNetwork=XMR_STAGENET` (also remove the `+` on the preceding line). +For mainnet, first modify [package.gradle](https://github.com/haveno-dex/haveno/blob/aeb0822f9fc72bd5a0e23d0c42c2a8f5f87625bb/desktop/package/package.gradle#L252) to `--arguments --baseCurrencyNetwork=XMR_MAINNET`. Then follow these instructions: https://github.com/haveno-dex/haveno/blob/master/desktop/package/README.md. -## Deploy to a VPS - -Haveno's services should be deployed to a VPS for reliable uptime. - -Seednodes can be installed as a system service. - -Arbitrators can be started in a Screen session and then detached to run in the background. - -Some good hints about how to secure a VPS are in [Monero's meta repository](https://github.com/monero-project/meta/blob/master/SERVER_SETUP_HARDENING.md). - -TODO: gather and document scripts for VPS management - ## Send alerts to update the application <b>Upload updated installers for download</b> @@ -139,7 +266,7 @@ TODO: gather and document scripts for VPS management <b>Set the mandatory minimum version for trading (optional)</b> -If applicable, update the mandatory minimum version for trading, by entering `ctrl + f` to open the Filter window, enter a private key with developer privileges, and enter the minimum version (e.g. 1.0.11) in the field labeled "Min. version required for trading". +If applicable, update the mandatory minimum version for trading, by entering `ctrl + f` to open the Filter window, enter a private key with developer privileges, and enter the minimum version (e.g. 1.0.16) in the field labeled "Min. version required for trading". <b>Send update alert</b> @@ -149,8 +276,28 @@ Enter a private key which is registered to send alerts. Enter the alert message and new version number, then click the button to send the notification. -## Other operating tips +## Manually sign payment accounts as the arbitrator + +Arbitrators can manually sign payment accounts. First open the legacy UI. + +### Sign payment account after trade is completed + +1. Go to Portfolio > History > open trade details > click 'DETAIL DATA' button. +2. Copy the `<witness hash>,<pub key hash>` string for the buyer or seller. +3. Go to Account > `ctrl + i` > `ctrl + p`. +5. Paste the buyer or seller's `<witness hash>,<pub key hash>` string. +6. Click the "Import unsigned account age witness" button to confirm. + +### Sign payment account from dispute + +1. Go to Account > `ctrl + i` > `ctrl + s`. +2. Select payment accounts to sign from disputes. + +### Sign unsigned witness pub keys + +1. Go to Account > `ctrl + i` > `ctrl + o`. + +## Other tips -* To maintain the network, avoid all seed nodes going offline at the same time. If all seed nodes go offline at the same time, arbitrator registration and the network filter will be fully reset, so all arbitrators will need to be re-registered, and the network filter will need to be recreated. This should be done immediately or clients will cancel their offers due to the signing arbitrators being unregistered and no replacements being available to re-sign. * If a dispute does not open properly, try manually reopening the dispute with a keyboard shortcut: `ctrl + o`. -* To send a private notification to a peer: click the user icon and enter `alt + r`. Enter a private key which is registered to send private notifications. \ No newline at end of file +* To send a private notification to a peer: click the user icon and enter `alt + r`. Enter a private key which is registered to send private notifications. diff --git a/docs/developer-guide.md b/docs/developer-guide.md index ff3b9aeff0..337d44c615 100644 --- a/docs/developer-guide.md +++ b/docs/developer-guide.md @@ -14,7 +14,9 @@ This proof of concept demonstrates using Haveno's gRPC server with a web fronten ## Import Haveno into development environment -Follow [instructions](import-haveno.md) to import Haveno into a development environment. +VSCode is recommended. + +Otherwise follow [instructions](import-haveno.md) to import Haveno into a Eclipse or IntelliJ IDEA. ## Run end-to-end API tests @@ -34,19 +36,10 @@ Follow [instructions](https://github.com/haveno-dex/haveno-ts#run-tests) to run 9. Run the tests with `npm run test -- -t 'my test'` to run tests by name and `npm test` to run all tests together. Ensure all tests pass and there are no exception stacktraces in the terminals of Alice, Bob, or the arbitrator. 10. Open pull requests to the haveno and haveno-ts projects for the backend and frontend implementations. -## Manually sign accounts as the arbitrator - -1. Open legacy UI as the arbitrator. -2. Go to the 'Account' tab. -3. Open Signing tab: `ctrl+i` - a. Sign payment account: `ctrl+s`, select payment accounts to sign (sourced from disputes). - b. Sign account age witness: `ctrl+p` then enter <witness hash>,<pub key hash> (from past trade details) and click the "Import unsigned account age witness" button. - c. Sign unsigned witness pub keys: `ctrl+o` - ## Release portable Monero binaries for each platform 1. Update the release-v0.18 branch on Haveno's [monero repo](https://github.com/haveno-dex/monero) to the latest release from upstream + any customizations (e.g. a commit to speed up testnet hardforks for local development). -2. `git tag <tag> && git push haveno <tag>` +2. `git tag <tag> && git push origin <tag>` 3. Follow instructions to [build portable binaries for each platform](#build-portable-monero-binaries-for-each-platform). 4. Publish a new release at https://github.com/haveno-dex/monero/releases with the updated binaries and hashes. 5. Update the paths and hashes in build.gradle and PR. @@ -55,23 +48,26 @@ Follow [instructions](https://github.com/haveno-dex/haveno-ts#run-tests) to run Based on these instructions: https://github.com/monero-project/monero#cross-compiling -1. Install Ubuntu 20.04. -2. `sudo apt-get update && sudo apt-get upgrade` -3. `sudo apt install cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev libtinfo5 autoconf libtool libtool-bin gperf` -4. `git clone https://github.com/haveno-dex/monero.git` -5. `cd ./monero (or rename this folder)` -6. `git fetch origin && git reset --hard origin/release-v0.18` -7. `git submodule update --init --force` - > Note: -> If you get the prompt "Reversed (or previously applied) patch detected! Assume -R? [n]" then confirm 'y'. +> If during building you get the prompt "Reversed (or previously applied) patch detected! Assume -R? [n]" then confirm 'y'. -**Build for Linux** +**Prepare Linux x86_64** + +1. Install Ubuntu 20.04 on x86_64. +2. `sudo apt-get update && sudo apt-get upgrade` +3. Install monero dependencies: `sudo apt update && sudo apt install build-essential cmake pkg-config libssl-dev libzmq3-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache` +4. `sudo apt install cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev libtinfo5 autoconf libtool libtool-bin gperf git curl` +5. `git clone https://github.com/haveno-dex/monero.git` +6. `cd ./monero` (or rename to haveno-monero: `mv monero/ haveno-monero && cd ./haveno-monero`) +7. `git fetch origin && git reset --hard origin/release-v0.18` +8. `git submodule update --init --force` + +**Build for Linux x86_64** 1. `make depends target=x86_64-linux-gnu -j<num cores>` 2. `cd build/x86_64-linux-gnu/release/bin/` -3. `tar -zcvf monero-bins-haveno-linux.tar.gz monerod monero-wallet-rpc` -4. Save monero-bins-haveno-linux.tar.gz for release. +3. `tar -zcvf monero-bins-haveno-linux-x86_64.tar.gz monerod monero-wallet-rpc` +4. Save monero-bins-haveno-linux-x86_64.tar.gz for release. **Build for Mac** @@ -89,6 +85,24 @@ Based on these instructions: https://github.com/monero-project/monero#cross-comp 5. `zip monero-bins-haveno-windows.zip monerod.exe monero-wallet-rpc.exe` 6. Save monero-bins-haveno-windows.zip for release. +**Prepare Linux aarch64** + +1. Install Ubuntu 20.04 on aarch64. +2. `sudo apt-get update && sudo apt-get upgrade` +3. Install monero dependencies: `sudo apt update && sudo apt install build-essential cmake pkg-config libssl-dev libzmq3-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache` +4. `sudo apt install cmake imagemagick libcap-dev librsvg2-bin libz-dev libbz2-dev libtiff-tools python-dev libtinfo5 autoconf libtool libtool-bin gperf git curl` +5. `git clone https://github.com/haveno-dex/monero.git` +6. `cd ./monero` (or rename to haveno-monero: `mv monero/ haveno-monero && cd ./haveno-monero`) +7. `git fetch origin && git reset --hard origin/release-v0.18` +8. `git submodule update --init --force` + +**Build for Linux aarch64** + +1. `make depends target=aarch64-linux-gnu -j<num cores>` +2. `cd build/aarch64-linux-gnu/release/bin/` +3. `tar -zcvf monero-bins-haveno-linux-aarch64.tar.gz monerod monero-wallet-rpc` +4. Save monero-bins-haveno-linux-aarch64.tar.gz for release. + ## Build executable installers for each platform See [instructions](/desktop/package/README.md). diff --git a/docs/flatpak.md b/docs/flatpak.md new file mode 100644 index 0000000000..d2ecdcdf84 --- /dev/null +++ b/docs/flatpak.md @@ -0,0 +1,33 @@ +# Flatpak distribution + +The `.flatpak` binary files (known as "bundles") that +`./gradlew packageInstallers` creates can be used to download and install +Haveno, but there are several security issues that arise in Flatpak when only +using the bundle files: + +- There is no +[digital signature](https://en.wikipedia.org/wiki/Digital_signature), +if a bad actor were to upload a malicious `.flatpak` the users would have no +way to tell when upgrading. +- Upgrading isn't as easy, your users need to find the new Flatpak bundle file, +and you cannot update multiple apps easily. + - This also makes an accidental downgrade much more likely. + +Flatpak has a solution for these issues, a +[Flatpak repository](https://docs.flatpak.org/en/latest/repositories.html). +Flatpak repos store the data of their apps within an OSTree (almost like git) +repository, and the commits can be signed with a GPG key. The nature of OSTree +also allows for easy updates, as the Flatpak client can download deltas of the +changes instead of the entire file. + +If you plan on distributing Haveno as a Flatpak, it's recommended to create a +Flatpak repository as well. This guide will show you how to create a Flatpak +repository for Haveno. The official documentation states that [it's possible to +use GitHub/Lab Pages](https://docs.flatpak.org/en/latest/hosting-a-repository.html#hosting-a-repository-on-gitlab-github-pages) +to host the repository, but this hasn't been tested. The more common way is to +use a web server, or something like +[flat-manager](https://github.com/flatpak/flat-manager). + +An example Haveno flat-manager solution using `docker-compose` has been created +and documented at <https://github.com/haveno-dex/flatman-haveno-test> if you +want a quick way to get started. Note that this does require an always-on server. diff --git a/docs/installing.md b/docs/installing.md index 7c8629840a..29a15b54f5 100644 --- a/docs/installing.md +++ b/docs/installing.md @@ -1,19 +1,21 @@ -# Set up environment +# Build and run Haveno -These are the steps needed to build Haveno and test it on our test network or locally. +These are the steps to build and run Haveno using the *official test network*. + +> [!warning] +> The official Haveno repository does not support making real trades directly. +> +> To make real trades with Haveno, first find a third party network, and then use their installer or build their repository. We do not endorse any networks at this time. +> +> Alternatively, you can [create your own mainnet network](create-mainnet.md). ## Install dependencies -On Ubuntu: +On Ubuntu: `sudo apt install make wget git` - 1. `sudo apt install make wget git openjdk-11-jdk`. - 2. If `echo $JAVA_HOME` does not print the path to JDK 11, then `export JAVA_HOME=/path/to/jdk` (e.g. `export JAVA_HOME=/usr/lib/jvm/java-11-openjdk`). - -On Windows: - - 1. Download [Java JDK 11](https://adoptium.net/temurin/archive/?version=11). During installation, enable the option to set the $JAVA_HOME environment variable. - 2. Install [MSYS2](https://www.msys2.org/). - 3. Start MSYS2 MINGW64 or MSYS MINGW32 depending on your system. Use MSYS2 for all commands throughout this document. +On Windows, first install MSYS2: + 1. Install [MSYS2](https://www.msys2.org/). + 2. Start MSYS2 MINGW64 or MSYS MINGW32 depending on your system. Use MSYS2 for all commands throughout this document. 4. Update pacman: `pacman -Syy` 5. Install dependencies. During installation, use default=all by leaving the input blank and pressing enter. @@ -21,14 +23,21 @@ On Windows: 32-bit: `pacman -S mingw-w64-i686-toolchain make mingw-w64-i686-cmake git` +On all platforms, install Java JDK 21: + +``` +curl -s "https://get.sdkman.io" | bash +sdk install java 21.0.2.fx-librca +``` + ## Build Haveno -If it's the first time you are building Haveno, run the following commands to download the repository, the needed dependencies, and build the latest release: +If it's the first time you are building Haveno, run the following commands to download the repository, the needed dependencies, and build the latest release. If using a third party network, replace the repository URL with theirs: ``` git clone https://github.com/haveno-dex/haveno.git cd haveno -git checkout v0.0.9 +git checkout master make ``` @@ -37,20 +46,28 @@ make If you are updating from a previous version, run from the root of the repository: ``` -git checkout v0.0.9 +git checkout master git pull make clean && make ``` -Make sure to delete the folder with the local settings, as there are breaking changes between releases: +## Run Haveno -On **Linux**: remove everything inside `~/.local/share/haveno-*/xmr_stagenet/`, except the `wallet` folder. +> [!note] +> When you run Haveno, your application folder will be installed to: +> * Linux: `~/.local/share/Haveno/` +> * macOS: `~/Library/Application\ Support/Haveno/` +> * Windows: `~\AppData\Roaming\Haveno\` -On **Mac**: remove everything inside `~/Library/Application\ Support/haveno-*/xmr_stagenet/`, except the `wallet` folder. +### Mainnet -On **Windows**: remove everything inside `~\AppData\Roaming\haveno-*/xmr_stagenet/`, except the `wallet` folder. +If you are building a third party repository which supports mainnet, you can start Haveno with: -## Join the public test network +``` +make haveno-desktop-mainnet +``` + +### Join the public test network If you want to try Haveno in a live setup, launch a Haveno instance that will connect to other peers on our public test environment, which runs on Monero's stagenet (you won't need to download the blockchain locally). You'll be able to make test trades with other users and have a preview of Haveno's trade protocol in action. Note that development is very much ongoing. Things are slow and might break. @@ -64,11 +81,11 @@ Steps: 6. Now if you are taking a trade you'll be asked to confirm you have sent the payment outside Haveno. Confirm in the app and wait for the confirmation of received payment from the other trader. 7. Once the other trader confirms, deposits are sent back to the owners and the trade is complete. -# Run a local test network +### Run a local test network If you are a developer who wants to test Haveno in a more controlled way, follow the next steps to build a local test environment. -## Run a local XMR testnet +#### Run a local XMR testnet 1. In a new terminal window run `make monerod1-local` 1. In a new terminal window run `make monerod2-local` @@ -76,11 +93,13 @@ If you are a developer who wants to test Haveno in a more controlled way, follow `start_mining 9tsUiG9bwcU7oTbAdBwBk2PzxFtysge5qcEsHEpetmEKgerHQa1fDqH7a4FiquZmms7yM22jdifVAD7jAb2e63GSJMuhY75 1` -## Deploy +#### Deploy -If you are a *screen* user, simply run `make deploy`. This command will open all needed Haveno instances (seednode, user1, user2, arbitrator) using *screen*. If this is the first time launching the arbitrator desktop application, register the arbitrator as explained in step 3 below. +If you are a *screen* user, simply run `make deploy-screen`. This command will open all needed Haveno instances (seednode, user1, user2, arbitrator) using *screen*. -If you don't use *screen*, open 4 terminal windows and run in each one of them: +If you are a *tmux* user, simply run `make deploy-tmux`. This command will open all needed Haveno instances (seednode, user1, user2, arbitrator) using *tmux* and attach them to splitted view. + +If you don't use *screen* or *tmux*, open 4 terminal windows and run in each one of them: 1. `make seednode-local` 2. `make user1-desktop-local` or if you want to run user1 as a daemon: `make user1-daemon-local` @@ -90,7 +109,7 @@ If you don't use *screen*, open 4 terminal windows and run in each one of them: If this is the first time launching the arbitrator desktop application, register the arbitrator after the interface opens. Go to the *Account* tab and press `cmd+r`. Confirm the registration of the arbitrator. -## Fund your wallets +#### Fund your wallets When running user1 and user2, you'll see a Monero address prompted in the terminal. Send test XMR to the addresses of both user1 and user2 to be able to initiate a trade. @@ -98,6 +117,6 @@ You can fund the two wallets by mining some test XMR coins to those addresses. T monerod will start mining local testnet coins on your device using one thread. Replace `ADDRESS` with the address of user1 first, and then user2's. Run `stop_mining` to stop mining. -## Start testing +#### Start testing You are all set. Now that everything is running and your wallets are funded, you can create test trades between user1 and user2. Remember to mine a few blocks after opening and accepting the test trade so the transaction will be confirmed. diff --git a/docs/user-guide.md b/docs/user-guide.md new file mode 100644 index 0000000000..8ea7db1bac --- /dev/null +++ b/docs/user-guide.md @@ -0,0 +1,25 @@ +# User Guide + +This document is a guide for Haveno users. + +## Running a Local Monero Node + +For the best experience using Haveno, it is highly recommended to run your own local Monero node to improve security and responsiveness. + +By default, Haveno will automatically connect to a local node if it is detected. Additionally, Haveno will automatically start and connect to your local Monero node if it was last used and is currently offline. + +Otherwise, Haveno will connect to a pre-configured remote node, unless manually configured otherwise. + +## UI Scaling For High DPI Displays + +If the UI is too small on your display, you can force UI scaling to a value of your choice using one of the following approaches. The examples below scale the UI to 200%, you can replace the '2' with a value of your choice, e.g. '1.5' for 150%. + +### Edit The Application Shortcut (KDE Plasma) + +1) Open the properties of your shortcut to haveno +2) Click on Program +3) Add `JAVA_TOOL_OPTIONS=-Dglass.gtk.uiScale=2` to the environment variables + +### Launching From The Command Line + +Prepend `JAVA_TOOL_OPTIONS=-Dglass.gtk.uiScale=2` to the command you use to launch haveno (e.g. `JAVA_TOOL_OPTIONS=-Dglass.gtk.uiScale=2 haveno-desktop`). diff --git a/gradle/README.md b/gradle/README.md index b1f90bd970..243f79db58 100644 --- a/gradle/README.md +++ b/gradle/README.md @@ -8,9 +8,9 @@ Visit the [Gradle website](https://gradle.org/releases/) and decide the: Adjust the following command with tha arguments above and execute it twice: - ./gradlew wrapper --gradle-version 8.0.2 \ + ./gradlew wrapper --gradle-version 8.2.1 \ --distribution-type all \ - --gradle-distribution-sha256-sum 47a5bfed9ef814f90f8debcbbb315e8e7c654109acd224595ea39fca95c5d4da + --gradle-distribution-sha256-sum 7c3ad722e9b0ce8205b91560fd6ce8296ac3eadf065672242fd73c06b8eeb6ee The first execution should automatically update: diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 65105f6757..5bc11c0134 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.2.xsd"> +<verification-metadata xmlns="https://schema.gradle.org/dependency-verification" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd"> <configuration> <verify-metadata>false</verify-metadata> <verify-signatures>false</verify-signatures> @@ -21,9 +21,6 @@ <artifact name="logback-classic-1.1.11.jar"> <sha256 value="86a0268c3c96888d4e49d8a754b5b2173286aee100559e803efcbb0df676c66e" origin="Generated by Gradle"/> </artifact> - <artifact name="logback-classic-1.1.11.pom"> - <sha256 value="936d197f26ed8df79b5e0a8f31772924ef864162dcb5fbc82b15e02dc054b1bd" origin="Generated by Gradle"/> - </artifact> </component> <component group="ch.qos.logback" name="logback-classic" version="1.2.10"> <artifact name="logback-classic-1.2.10.jar"> @@ -37,9 +34,6 @@ <artifact name="logback-core-1.1.11.jar"> <sha256 value="58738067842476feeae5768e832cd36a0e40ce41576ba5739c3632d376bd8c86" origin="Generated by Gradle"/> </artifact> - <artifact name="logback-core-1.1.11.pom"> - <sha256 value="7199197992fb549a4b620f368a6726298360eb9ebb37e4ed16eb4e5ad2be0f25" origin="Generated by Gradle"/> - </artifact> </component> <component group="ch.qos.logback" name="logback-core" version="1.2.10"> <artifact name="logback-core-1.2.10.jar"> @@ -49,24 +43,11 @@ <sha256 value="1d32cf679d8780d7c9c915e6cc5db431d5b40c2aedc58a84a17cd023e1f0d09c" origin="Generated by Gradle"/> </artifact> </component> - <component group="ch.qos.logback" name="logback-parent" version="1.1.11"> - <artifact name="logback-parent-1.1.11.pom"> - <sha256 value="ec6a3b1ccb21e66c02e36899735c0c2171c5bd3a4ea269a28be95f9f2e8a822b" origin="Generated by Gradle"/> - </artifact> - </component> <component group="ch.qos.logback" name="logback-parent" version="1.2.10"> <artifact name="logback-parent-1.2.10.pom"> <sha256 value="ccbd8e06a67f765a1a2498a7076032ce366420c2129d680bd302633572cab354" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.auth0" name="java-jwt" version="3.10.0"> - <artifact name="java-jwt-3.10.0.jar"> - <sha256 value="dc5a83714568d955181c8f5cf9ea634573eb2fde426e05a2b1b92d2d74b86acf" origin="Generated by Gradle"/> - </artifact> - <artifact name="java-jwt-3.10.0.pom"> - <sha256 value="3e1e9d97cb5aaa14813a526bf259bbf4cd6b7eddee1a08dfc802fc4ef67094f1" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.auth0" name="java-jwt" version="3.18.3"> <artifact name="java-jwt-3.18.3.jar"> <sha256 value="e51e9c0237ca4a27b80e603081dab80e43f3847020ea1b57292df3e0d11d17db" origin="Generated by Gradle"/> @@ -93,16 +74,6 @@ <sha256 value="d8e7f6d146289aca1477195e67bb4b7be5f29bbbb5f804198d03cfba92fd8490" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.fasterxml" name="oss-parent" version="24"> - <artifact name="oss-parent-24.pom"> - <sha256 value="e3809d58570390c327efe56587d8dea3caa53186b91875e0b36226e08211f05a" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.fasterxml" name="oss-parent" version="27"> - <artifact name="oss-parent-27.pom"> - <sha256 value="b9b8f388fd628057b1249756468b86726c8fd5816ce14d313cb40003a509beeb" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.fasterxml" name="oss-parent" version="43"> <artifact name="oss-parent-43.pom"> <sha256 value="e5585cc1c37079b2e3817a8997945736f158831844d59d0e4d3a45b27611f926" origin="Generated by Gradle"/> @@ -123,37 +94,31 @@ <sha256 value="2bba89978172af1effcb4d143d09921a3f3082ca4dcf122b1ded98bf55b2ad57" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.fasterxml.jackson.core" name="jackson-annotations" version="2.13.1"> - <artifact name="jackson-annotations-2.13.1.jar"> - <sha256 value="ab607939d288e22bff4cb97acc6b25e841d82681f2bc40ce67bb35cb0ffdb06d" origin="Generated by Gradle"/> - </artifact> - <artifact name="jackson-annotations-2.13.1.pom"> - <sha256 value="28b24c6959198210ccb22908d47ef905a6f9235bb8afad60e888e7c4698865a6" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.fasterxml.jackson.core" name="jackson-annotations" version="2.13.2"> <artifact name="jackson-annotations-2.13.2.jar"> <sha256 value="7d3df5aafa2dc61ad1dbad30f411548c0184ed92d94628c63168721f08237cd4" origin="Generated by Gradle"/> </artifact> </component> + <component group="com.fasterxml.jackson.core" name="jackson-annotations" version="2.14.2"> + <artifact name="jackson-annotations-2.14.2.jar"> + <sha256 value="2c6869d505cf60dc066734b7d50339f975bd3adc635e26a78abb71acb4473c0d" origin="Generated by Gradle"/> + </artifact> + </component> <component group="com.fasterxml.jackson.core" name="jackson-core" version="2.1.3"> <artifact name="jackson-core-2.1.3.jar"> <sha256 value="754184022345800c2d066eceeaf2f7a88a7c2aaeae23eb1c76ef598854aa9157" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.fasterxml.jackson.core" name="jackson-core" version="2.13.1"> - <artifact name="jackson-core-2.13.1.jar"> - <sha256 value="8be6935cd8f9673ac684a589aaa1caecd57dee7c37ed1443d17924325799003d" origin="Generated by Gradle"/> - </artifact> - <artifact name="jackson-core-2.13.1.pom"> - <sha256 value="64fec520456c5dafe0ba940564946304fba6117068b5adf33662b10035fafe74" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.fasterxml.jackson.core" name="jackson-core" version="2.13.2"> <artifact name="jackson-core-2.13.2.jar"> <sha256 value="9bfa278ad05179fb68087851caf607652702ca25424bec8358a3716e751405c8" origin="Generated by Gradle"/> </artifact> </component> + <component group="com.fasterxml.jackson.core" name="jackson-core" version="2.14.2"> + <artifact name="jackson-core-2.14.2.jar"> + <sha256 value="b5d37a77c88277b97e3593c8740925216c06df8e4172bbde058528df04ad3e7a" origin="Generated by Gradle"/> + </artifact> + </component> <component group="com.fasterxml.jackson.core" name="jackson-databind" version="2.13.1"> <artifact name="jackson-databind-2.13.1.jar"> <sha256 value="56cfbdc9e1736b5c56b43757f6cf546ee6d49393c79383c4e495c4f7047cb506" origin="Generated by Gradle"/> @@ -167,6 +132,11 @@ <sha256 value="0d5459b7f18184c4ce8f07264b1b7feced51529e550a098d6f9e2dfe091138ad" origin="Generated by Gradle"/> </artifact> </component> + <component group="com.fasterxml.jackson.core" name="jackson-databind" version="2.14.2"> + <artifact name="jackson-databind-2.14.2.jar"> + <sha256 value="501d3abce4d18dcc381058ec593c5b94477906bba6efbac14dae40a642f77424" origin="Generated by Gradle"/> + </artifact> + </component> <component group="com.fasterxml.jackson.datatype" name="jackson-datatype-jdk8" version="2.13.1"> <artifact name="jackson-datatype-jdk8-2.13.1.jar"> <sha256 value="8fd36efc6cbda4f3f22400c1ea0d07f043fc0b8b80c9e3e4142b82e702b51118" origin="Generated by Gradle"/> @@ -183,25 +153,14 @@ <sha256 value="9267d72b3cd97b41682df569b7eb5268f50108ddd63f61c62e5b0eb36536b574" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.fasterxml.jackson.module" name="jackson-module-jaxb-annotations" version="2.13.1"> - <artifact name="jackson-module-jaxb-annotations-2.13.1.jar"> - <sha256 value="b717db30f0bc14ad6545d2620468fe7fd9ceded0a09f639f35fac7f40e075e4c" origin="Generated by Gradle"/> - </artifact> - <artifact name="jackson-module-jaxb-annotations-2.13.1.pom"> - <sha256 value="a75f536ece8eb298f648aa0738099d9494b75123ddeba141440bcbfdda9d27ea" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.fasterxml.jackson.module" name="jackson-module-jaxb-annotations" version="2.13.2"> <artifact name="jackson-module-jaxb-annotations-2.13.2.jar"> <sha256 value="7fdf1769b4feddbd73d89da47dc07b2e8230860700da00885a92bf7d66205376" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.fasterxml.jackson.module" name="jackson-module-parameter-names" version="2.13.1"> - <artifact name="jackson-module-parameter-names-2.13.1.jar"> - <sha256 value="6deafd562297685e748cdb44ceef0d8853eec30859b18c7f7021747b44be5e67" origin="Generated by Gradle"/> - </artifact> - <artifact name="jackson-module-parameter-names-2.13.1.pom"> - <sha256 value="f9385ea7fbe6d3731aa965eff11cc4c1e94ea00a1265c2cc1ba605d7010ebfcd" origin="Generated by Gradle"/> + <component group="com.fasterxml.jackson.module" name="jackson-module-parameter-names" version="2.14.2"> + <artifact name="jackson-module-parameter-names-2.14.2.jar"> + <sha256 value="b4e3fbea545a155a14dcb8a65c46b57ad8d0fb9627c84f789858263f05299330" origin="Generated by Gradle"/> </artifact> </component> <component group="com.fasterxml.jackson.module" name="jackson-modules-base" version="2.13.1"> @@ -214,14 +173,6 @@ <sha256 value="b7774955491262076d4fec12de392628a541e0560018142a0a6e38f72bb96010" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.JesusMcCloud" name="jtorctl" version="9b5ba2036b"> - <artifact name="jtorctl-9b5ba2036b.jar"> - <sha256 value="b2bdfe9758e4c82ff1b10e7c3098981bf55ea3e5f161ee7990ac125003a6cdbe" origin="Generated by Gradle"/> - </artifact> - <artifact name="jtorctl-9b5ba2036b.pom"> - <sha256 value="218fbc37a57bcf888af917220c31acea39197859cc47519c12f1151fa4a27812" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.github.bisq-network" name="bitcoinj" version="2a80db4"> <artifact name="bitcoinj-2a80db4.jar"> <sha256 value="65ed08fa5777ea4a08599bdd575e7dc1f4ba2d4d5835472551439d6f6252e68a" origin="Generated by Gradle"/> @@ -277,203 +228,84 @@ <sha256 value="6306d89cfdb12bd0b6436390de71cef31879985da10d071a3bdad56bf287bbbb" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor" version="6797461310f077bbea4f43a3a509c077b0ed8c34"> - <artifact name="tor-6797461310f077bbea4f43a3a509c077b0ed8c34.jar"> - <sha256 value="1536211d3f204059e2ad49c136978b36ebaa19e62103fcd46dcb926842fa0718" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-6797461310f077bbea4f43a3a509c077b0ed8c34.pom"> - <sha256 value="7a0ccbecf1471f6be02fb034c006e36b7a6fd249544521c653fed09fbbcec0b1" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.netlayer" name="tor" version="2b459dc"> + <artifact name="tor-2b459dc.jar"> + <sha256 value="d8aba69568795826bd1139b6854b479d9af9fc945eccf2b15d7f9ecb304c5cc4" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor" version="8db4a13"> - <artifact name="tor-8db4a13.jar"> - <sha256 value="37198bc56e8fe112f8c80441544a2b9731929dae586bda841a4a926fdc04f457" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-8db4a13.pom"> - <sha256 value="d1cb5d57710c43642771681d8b1c9039c722fb949bdc5a2022389f5a81501f42" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.netlayer" name="tor.external" version="2b459dc"> + <artifact name="tor.external-2b459dc.jar"> + <sha256 value="6646b6ce9312a16f6b4b61ee91512b8725b55a2f7204aec29f64974207fd5015" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor.external" version="0.7.2"> - <artifact name="tor.external-0.7.2.jar"> - <sha256 value="45daf9b30f753c49b62cf56226539e824886ce1ff430e03dbef1bddff919cbfc" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor.external-0.7.2.pom"> - <sha256 value="605e15f473aa7163c4dfa75b0fa17a96466d24c6e3d7a66925b29aadde98dfb4" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.netlayer" name="tor.native" version="2b459dc"> + <artifact name="tor.native-2b459dc.jar"> + <sha256 value="dc5850e232f2c579d948213a3ea1ce536f56bcc49045a43d3bc63f1e065f1c94" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor.external" version="6797461310f077bbea4f43a3a509c077b0ed8c34"> - <artifact name="tor.external-6797461310f077bbea4f43a3a509c077b0ed8c34.jar"> - <sha256 value="d79dee1380fcc912dd9f321e6689b99129a90c6b30085b3f86a0b81830ecee71" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor.external-6797461310f077bbea4f43a3a509c077b0ed8c34.pom"> - <sha256 value="949ab51a912ba5c126ffda083da2f0366bc9eda36afc5358183e040fee24d86f" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="580d31bdcf1fabccd38456aa084044064d89d5c1"> + <artifact name="tor-binary-geoip-580d31bdcf1fabccd38456aa084044064d89d5c1.jar"> + <sha256 value="5a1795e95128e8c6fb3381d1c31ac39f2ec4e4fc3a0262f3f9ac3c7987e0c87e" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor.external" version="8db4a13"> - <artifact name="tor.external-8db4a13.jar"> - <sha256 value="e1d6b8fe73891207701c6b14317be789fd4acd25f7b499425d2471598d9a22ac" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor.external-8db4a13.pom"> - <sha256 value="11918499210e0c12e9d517596eedb34b897021686cf8a1efd8ea87ae3b7e184d" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="580d31bdcf1fabccd38456aa084044064d89d5c1"> + <artifact name="tor-binary-linux32-580d31bdcf1fabccd38456aa084044064d89d5c1.jar"> + <sha256 value="2516ce5549ef5687ef7f855db5940574fc9232ff3ba531fbc216275b8d51ae85" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor.native" version="0.7.2"> - <artifact name="tor.native-0.7.2.jar"> - <sha256 value="ebb37e76fa14461be1ab2750daa3f8e5b78c8ff0d2adb72832ca0d38a1fb8f0d" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor.native-0.7.2.pom"> - <sha256 value="021ab6d438023653afee96c0fab1262eed6b7522fce76e114593d55e6d7d9928" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="580d31bdcf1fabccd38456aa084044064d89d5c1"> + <artifact name="tor-binary-linux64-580d31bdcf1fabccd38456aa084044064d89d5c1.jar"> + <sha256 value="afc7ad5e1bc57e73aae55d9b022ff63f41f7c73a9a7603d4c24975288432daa1" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor.native" version="6797461310f077bbea4f43a3a509c077b0ed8c34"> - <artifact name="tor.native-6797461310f077bbea4f43a3a509c077b0ed8c34.jar"> - <sha256 value="7ab70a9948fffea33da9fee161c5783a74aeb1531e3fda09995c47bb5e2de0f5" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor.native-6797461310f077bbea4f43a3a509c077b0ed8c34.pom"> - <sha256 value="17ba4bb22d00441e286dde286045d68190003e849f49871bdac96a5b41478533" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="580d31bdcf1fabccd38456aa084044064d89d5c1"> + <artifact name="tor-binary-macos-580d31bdcf1fabccd38456aa084044064d89d5c1.jar"> + <sha256 value="5bfb2eaf7efe5d280d6b68e222c910cc6ae2a925e3d06fa35c6b5295ebf94651" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.netlayer" name="tor.native" version="8db4a13"> - <artifact name="tor.native-8db4a13.jar"> - <sha256 value="aa3edf9c27071fdc2b7d55b00dbc7c6cd5dc9aa9f87aafa4be0805f818a466be" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor.native-8db4a13.pom"> - <sha256 value="13e497b9fa97fc994e907aaad69ed81c5433380887a8ac7237bc18e8da48683b" origin="Generated by Gradle"/> + <component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="580d31bdcf1fabccd38456aa084044064d89d5c1"> + <artifact name="tor-binary-windows-580d31bdcf1fabccd38456aa084044064d89d5c1.jar"> + <sha256 value="b5fbe9f9e2681b0cfdd0d8a26c7b216c38acfea74fe2103633fe7e81b6cc4bf7" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary" version="6d1fd95"> - <artifact name="tor-binary-6d1fd95.pom"> - <sha256 value="ac20fe51c6473ecaa440458c8255294ff2b30cfed45918527742315bb3d74a86" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.netlayer" name="tor" version="e2ce2a142c"> + <artifact name="tor-e2ce2a142c.jar"> + <sha256 value="4c3c207bb4644891170cfabda0fd4fcba354ac7e6527c594da39f7c910cd3b15" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary" version="787183b147286d783a6392bb9ffcd8ba920d6fff"> - <artifact name="tor-binary-787183b147286d783a6392bb9ffcd8ba920d6fff.pom"> - <sha256 value="4e127121fefb50fed62a83d5fbd31064b9f16f1a528571675e0ec3042376dab3" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.netlayer" name="tor.external" version="e2ce2a142c"> + <artifact name="tor.external-e2ce2a142c.jar"> + <sha256 value="e523b77adbb419e5ed382a1689e1d9a53ec44b626fc016e6df676adfb4a45846" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary" version="b9c6227"> - <artifact name="tor-binary-b9c6227.pom"> - <sha256 value="f1ef0c2b2a1df585f057b96b62b05e2e7d7953353b64e29ac798810ff2919b42" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.netlayer" name="tor.native" version="e2ce2a142c"> + <artifact name="tor.native-e2ce2a142c.jar"> + <sha256 value="69127bee3ff9863c83dfb03d7eead27eb54247feafb66e2620f884d538b0735a" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="6d1fd95"> - <artifact name="tor-binary-geoip-6d1fd95.jar"> - <sha256 value="5a55df3a5bed0aa57165e9bae9ecda8b14d5e85b97dd1a266fa77602fbdaec54" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-geoip-6d1fd95.pom"> - <sha256 value="14fbcfc4de8e07b8c5bf7c1e279704905cc98795e7460cf558288ce1eaaf1927" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-geoip" version="4e38c9d5cc22266fe06cc42578020bc0a50c783f"> + <artifact name="tor-binary-geoip-4e38c9d5cc22266fe06cc42578020bc0a50c783f.jar"> + <sha256 value="0e15608759436eb787e4be127d9d0be224cfaaa568f1979f3c982dbfa5fe57a6" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="787183b147286d783a6392bb9ffcd8ba920d6fff"> - <artifact name="tor-binary-geoip-787183b147286d783a6392bb9ffcd8ba920d6fff.jar"> - <sha256 value="e1f0a9708ad5fc5373db84fb14570d36eff842eb71e99c0930db64617604a2bf" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-geoip-787183b147286d783a6392bb9ffcd8ba920d6fff.pom"> - <sha256 value="a6f45951fb73b57c9ac37d389f5adcfecde5f06c2e50d1a8381e640261e5a6b5" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-linux32" version="4e38c9d5cc22266fe06cc42578020bc0a50c783f"> + <artifact name="tor-binary-linux32-4e38c9d5cc22266fe06cc42578020bc0a50c783f.jar"> + <sha256 value="f8c1dc435e9ce9fa4539aa7a140cae0606a30cdde6be34c3500ffd27b5ddb7ea" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-geoip" version="b9c6227"> - <artifact name="tor-binary-geoip-b9c6227.jar"> - <sha256 value="cfefbf2d8591b5dd321ec17a02a3682d21763cf50525fa5496c9ec8968413c4e" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-geoip-b9c6227.pom"> - <sha256 value="197d034216b332fcfaa7111442ac4a23bddc60fb71fefba1c736fe9844c1001b" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-linux64" version="4e38c9d5cc22266fe06cc42578020bc0a50c783f"> + <artifact name="tor-binary-linux64-4e38c9d5cc22266fe06cc42578020bc0a50c783f.jar"> + <sha256 value="5707079632e6f7f68690b303244b88a25a50bbc622269d69af54ebdfcdb87041" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="6d1fd95"> - <artifact name="tor-binary-linux32-6d1fd95.jar"> - <sha256 value="fe8b0ddb1c109b453adf9b055e067be04b6ca4cda9d2b33c875b99d2092f0eae" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-linux32-6d1fd95.pom"> - <sha256 value="0ae70e17d9566c88204d02de32c1646d672e78711da97124d23fd397a1da9d13" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-macos" version="4e38c9d5cc22266fe06cc42578020bc0a50c783f"> + <artifact name="tor-binary-macos-4e38c9d5cc22266fe06cc42578020bc0a50c783f.jar"> + <sha256 value="6595d99fa317d899182840c898f0df07babb7479cca66b5ee3dbd8f571fd82c6" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="787183b147286d783a6392bb9ffcd8ba920d6fff"> - <artifact name="tor-binary-linux32-787183b147286d783a6392bb9ffcd8ba920d6fff.jar"> - <sha256 value="b1e8b3f83b08c839a4282a32ef75be69db3ec3061b3472e367606782b861cb55" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-linux32-787183b147286d783a6392bb9ffcd8ba920d6fff.pom"> - <sha256 value="4166e686e18b875fe09e34e19ea294a5841b9d0354072e60fb7779b813c9ff45" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux32" version="b9c6227"> - <artifact name="tor-binary-linux32-b9c6227.jar"> - <sha256 value="b82b6595f78ef52a44e58000fe5d7f679681739451872f5bbd123e5dbd2af050" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-linux32-b9c6227.pom"> - <sha256 value="a01902c476556a0529413b0f3810e954a5eb8a7cdc1a9cc604ec2d24ceca91ce" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="6d1fd95"> - <artifact name="tor-binary-linux64-6d1fd95.jar"> - <sha256 value="7f58d31dd684b2e361e2980ba23922cadd5d9d8f8dbab9b3a2c6737741b21f7e" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-linux64-6d1fd95.pom"> - <sha256 value="48f0435519eae6ff6af88656a64502320befc392b2c5d59ac2fb47412c9ba52d" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="787183b147286d783a6392bb9ffcd8ba920d6fff"> - <artifact name="tor-binary-linux64-787183b147286d783a6392bb9ffcd8ba920d6fff.jar"> - <sha256 value="4e956beca59ffce771d0fa40a0b20181c3531d278ff0f1d474a378c0fa9bc76b" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-linux64-787183b147286d783a6392bb9ffcd8ba920d6fff.pom"> - <sha256 value="1f98896ea3822644bebd3c3278497684504e291df03531bf72f072ab2d6b44a1" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-linux64" version="b9c6227"> - <artifact name="tor-binary-linux64-b9c6227.jar"> - <sha256 value="d5c1d54b2c2323ac1124435be633c7822a28e6fe9160486d03102cc2b444df24" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-linux64-b9c6227.pom"> - <sha256 value="ee305ee12585057bcce380710e4a5ae3a3ed43e1701f5e565f15b75854e3e715" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="6d1fd95"> - <artifact name="tor-binary-macos-6d1fd95.jar"> - <sha256 value="a23802ff66d4ac01366ebe712879e2f51df960572dc34db269588da87453a70d" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-macos-6d1fd95.pom"> - <sha256 value="0c1b6633882ca625f50c78b960714baa81ef286b5dfc26886145f7960feab738" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="787183b147286d783a6392bb9ffcd8ba920d6fff"> - <artifact name="tor-binary-macos-787183b147286d783a6392bb9ffcd8ba920d6fff.jar"> - <sha256 value="9b4114bd7699951dc6b04a10398bd6acc17a966db48c7fa79e302cc0b6fe7ecf" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-macos-787183b147286d783a6392bb9ffcd8ba920d6fff.pom"> - <sha256 value="6b8f372ac6dc38c06575612cc00f5e6d804d80dfe761f8ca0d1aa4562da9d2dd" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-macos" version="b9c6227"> - <artifact name="tor-binary-macos-b9c6227.jar"> - <sha256 value="6216d66241e020fec1a55648d7176ef64959e094c493df8f49e7e8e8f62fe1e1" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-macos-b9c6227.pom"> - <sha256 value="143a9bfc539101d8293b7d151d6a952135fa5ad76d752639d2ed72fb9c9c494d" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="6d1fd95"> - <artifact name="tor-binary-windows-6d1fd95.jar"> - <sha256 value="8e0dee7429228aa0c9f7a36f40f303a016ed8dfb40fea77382f7076c13fc27f1" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-windows-6d1fd95.pom"> - <sha256 value="08dd80bd3c5e6c6b031ea3e28d8819adec875593a8f1fb9101c0f952f8307b80" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="787183b147286d783a6392bb9ffcd8ba920d6fff"> - <artifact name="tor-binary-windows-787183b147286d783a6392bb9ffcd8ba920d6fff.jar"> - <sha256 value="eebd616315cb7263f07837d5a95c96fdcd627f7fcbfc69e9ca7b840495895197" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-windows-787183b147286d783a6392bb9ffcd8ba920d6fff.pom"> - <sha256 value="fa1cc1b84e4705b9102f269a3ec2602e00ed8dae035d99f60a70194551dc8e08" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.github.bisq-network.tor-binary" name="tor-binary-windows" version="b9c6227"> - <artifact name="tor-binary-windows-b9c6227.jar"> - <sha256 value="28a1031d7610863f774eedbd00b83b06b132781c31077b805033299de3e3a263" origin="Generated by Gradle"/> - </artifact> - <artifact name="tor-binary-windows-b9c6227.pom"> - <sha256 value="e067cfa37ee54a2f31d05391319e46484366fda4ef0ee28c3483194b02025e8f" origin="Generated by Gradle"/> + <component group="com.github.haveno-dex.tor-binary" name="tor-binary-windows" version="4e38c9d5cc22266fe06cc42578020bc0a50c783f"> + <artifact name="tor-binary-windows-4e38c9d5cc22266fe06cc42578020bc0a50c783f.jar"> + <sha256 value="fe0707365a9c0cae638cac7cd883488ba87f489e6ebd88d2d9890ed9e8acf15e" origin="Generated by Gradle"/> </artifact> </component> <component group="com.github.johnrengelman" name="shadow" version="8.1.1"> @@ -481,14 +313,6 @@ <sha256 value="084197555590a53bb21b59508a3330559f536ddb448eafd1ec675f5462036fcf" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.github.mmazi" name="rescu" version="2.0.2"> - <artifact name="rescu-2.0.2.jar"> - <sha256 value="bbc3a16d19468f76f9a6906453508bff2c33df5caaae349c4e3b796440bb199a" origin="Generated by Gradle"/> - </artifact> - <artifact name="rescu-2.0.2.pom"> - <sha256 value="3e979bc1d06e5f92fe961e262a9e5ebd013ccfae9c0abdfe1eca11838df64a05" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.github.mmazi" name="rescu" version="2.1.0"> <artifact name="rescu-2.1.0.jar"> <sha256 value="7d4d4498f052019407b200839bff61d1cdb0a34fb78fd31bbb8accae5f650805" origin="Generated by Gradle"/> @@ -584,11 +408,6 @@ <sha256 value="b14873c309bb45d4b4e35da405f0296b1af48f164b809bebaa603354e618daa7" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.auth" name="google-auth-library-credentials" version="0.17.1"> - <artifact name="google-auth-library-credentials-0.17.1.jar"> - <sha256 value="aaeea9333fff9b763715bca0174ec76c4f9551b5731c89a95f263cdc82b4b56e" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.auth" name="google-auth-library-credentials" version="0.22.2"> <artifact name="google-auth-library-credentials-0.22.2.jar"> <sha256 value="e42c2cbe642744f55bd2a081e6f60f126e691129e7148daec3af79deab4ac65a" origin="Generated by Gradle"/> @@ -642,32 +461,16 @@ <sha256 value="c6221763bd79c4f1c3dc7f750b5f29a0bb38b367b81314c4f71896e340c40825" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.code.gson" name="gson" version="2.8.2"> - <artifact name="gson-2.8.2.jar"> - <sha256 value="b7134929f7cc7c04021ec1cc27ef63ab907e410cf0588e397b8851181eb91092" origin="Generated by Gradle"/> - </artifact> - <artifact name="gson-2.8.2.pom"> - <sha256 value="91b9f17a54e6c340c8d3ea4b359401170706eb26a82d51909abe6ba80081aed8" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.code.gson" name="gson" version="2.8.5"> <artifact name="gson-2.8.5.jar"> <sha256 value="233a0149fc365c9f6edbd683cfe266b19bdc773be98eabdaf6b3c924b48e7d81" origin="Generated by Gradle"/> </artifact> - <artifact name="gson-2.8.5.pom"> - <sha256 value="b8308557a7fccc92d9fe7c8cd0599258b361285d2ecde7689eda98843255a092" origin="Generated by Gradle"/> - </artifact> </component> <component group="com.google.code.gson" name="gson" version="2.8.6"> <artifact name="gson-2.8.6.jar"> <sha256 value="c8fb4839054d280b3033f800d1f5a97de2f028eb8ba2eb458ad287e536f3f25f" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.code.gson" name="gson-parent" version="2.8.2"> - <artifact name="gson-parent-2.8.2.pom"> - <sha256 value="cf5c43860b53ba5a95c19bc6525cc43d3488a6fe3df2f649c0099a613a0640e3" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.code.gson" name="gson-parent" version="2.8.5"> <artifact name="gson-parent-2.8.5.pom"> <sha256 value="8f1fec72b91a71ea39ec39f5f778c4d1124b6b097c6d55b3a50b554a52237b27" origin="Generated by Gradle"/> @@ -678,37 +481,16 @@ <sha256 value="721cb91842b46fa056847d104d5225c8b8e1e8b62263b993051e1e5a0137b7ec" origin="Generated by Gradle"/> </artifact> </component> + <component group="com.google.errorprone" name="error_prone_annotations" version="2.18.0"> + <artifact name="error_prone_annotations-2.18.0.jar"> + <sha256 value="9e6814cb71816988a4fd1b07a993a8f21bb7058d522c162b1de849e19bea54ae" origin="Generated by Gradle"/> + </artifact> + </component> <component group="com.google.errorprone" name="error_prone_annotations" version="2.2.0"> <artifact name="error_prone_annotations-2.2.0.jar"> <sha256 value="6ebd22ca1b9d8ec06d41de8d64e0596981d9607b42035f9ed374f9de271a481a" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.errorprone" name="error_prone_annotations" version="2.3.4"> - <artifact name="error_prone_annotations-2.3.4.jar"> - <sha256 value="baf7d6ea97ce606c53e11b6854ba5f2ce7ef5c24dddf0afa18d1260bd25b002c" origin="Generated by Gradle"/> - </artifact> - <artifact name="error_prone_annotations-2.3.4.pom"> - <sha256 value="1326738a4b4f7ccacf607b866a11fb85193ef60f6a59461187ce7265f9be5bed" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.google.errorprone" name="error_prone_annotations" version="2.5.1"> - <artifact name="error_prone_annotations-2.5.1.jar"> - <sha256 value="ff80626baaf12a09342befd4e84cba9d50662f5fcd7f7a9b3490a6b7cf87e66c" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.google.errorprone" name="error_prone_annotations" version="2.9.0"> - <artifact name="error_prone_annotations-2.9.0.jar"> - <sha256 value="f947bdc33ae27a6b4aa44799e6c21e1944797bd0010ba43eb82d11446e163694" origin="Generated by Gradle"/> - </artifact> - <artifact name="error_prone_annotations-2.9.0.pom"> - <sha256 value="a48ee055c9f475846e21b87029df8982b9f7b5e93cc2656fca8d1bda471408ce" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="com.google.errorprone" name="error_prone_parent" version="2.3.4"> - <artifact name="error_prone_parent-2.3.4.pom"> - <sha256 value="40495b437a60d2398f0fdfc054b89d9c394a82347a274a0721c2e950a4302186" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.errorprone" name="error_prone_parent" version="2.9.0"> <artifact name="error_prone_parent-2.9.0.pom"> <sha256 value="520b123d085975b563e34d04400c6263896f858867ce7fc478dd37f491eae3b4" origin="Generated by Gradle"/> @@ -719,11 +501,6 @@ <sha256 value="f34f8a6bd8b576a94d80e9743785512b87f2df2495fa3853b850a264dc47924e" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.gradle" name="osdetector-gradle-plugin" version="1.6.0"> - <artifact name="osdetector-gradle-plugin-1.6.0.jar"> - <sha256 value="e074d3daa0ca0e5a0c6e2c98fcd9da6645ac520c8d091612ae58bdcde65d0585" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.gradle" name="osdetector-gradle-plugin" version="1.7.3"> <artifact name="osdetector-gradle-plugin-1.7.3.jar"> <sha256 value="6b4692f913a21b1fb603169ee78ba8f3e4ab2af9d762af9ca88b79126c1c0ad1" origin="Generated by Gradle"/> @@ -737,11 +514,6 @@ <sha256 value="e96042ce78fecba0da2be964522947c87b40a291b5fd3cd672a434924103c4b9" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.guava" name="guava" version="18.0"> - <artifact name="guava-18.0.jar"> - <sha256 value="d664fbfc03d2e5ce9cab2a44fb01f1d0bf9dfebeccc1a473b1f9ea31f79f6f99" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.guava" name="guava" version="20.0"> <artifact name="guava-20.0.jar"> <sha256 value="36a666e3b71ae7f0f0dca23654b67e086e6c93d192f60ba5dfd5519db6c288c8" origin="Generated by Gradle"/> @@ -752,32 +524,21 @@ <sha256 value="e1c814fd04492a27c38e0317eabeaa1b3e950ec8010239e400fe90ad6c9107b4" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.guava" name="guava" version="28.2-jre"> - <artifact name="guava-28.2-jre.jar"> - <sha256 value="fc3aa363ad87223d1fbea584eee015a862150f6d34c71f24dc74088a635f08ef" origin="Generated by Gradle"/> - </artifact> - <artifact name="guava-28.2-jre.pom"> - <sha256 value="c0805261548dc61ca4c982b59bfaad6503e43190f5e5e444e90b2cf6ab72db94" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.guava" name="guava" version="30.1-android"> <artifact name="guava-30.1-android.jar"> <sha256 value="ea0b5a62b707482eee5cf305c8f35ef91cf4ceaff504f011a5c49c41355f5781" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.guava" name="guava" version="30.1.1-jre"> - <artifact name="guava-30.1.1-jre.jar"> - <sha256 value="44ce229ce26d880bf3afc362bbfcec34d7e6903d195bbb1db9f3b6e0d9834f06" origin="Generated by Gradle"/> - </artifact> - <artifact name="guava-30.1.1-jre.pom"> - <sha256 value="6d18c9188ad4b7855fb7fea6f1793754b41fa1747811ae1e3d753d6fcc9dcc59" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.guava" name="guava" version="31.1-jre"> <artifact name="guava-31.1-jre.jar"> <sha256 value="a42edc9cab792e39fe39bb94f3fca655ed157ff87a8af78e1d6ba5b07c4a00ab" origin="Generated by Gradle"/> </artifact> </component> + <component group="com.google.guava" name="guava" version="32.1.1-jre"> + <artifact name="guava-32.1.1-jre.jar"> + <sha256 value="91fbba37f1c8b251cf9ea9e7d3a369eb79eb1e6a5df1d4bbf483dd0380740281" origin="Generated by Gradle"/> + </artifact> + </component> <component group="com.google.guava" name="guava-jdk5" version="17.0"> <artifact name="guava-jdk5-17.0.jar"> <sha256 value="59bf456547b6dda3ced968cb56f7f2d3e14474e2de2960a32c47e31c1e456c61" origin="Generated by Gradle"/> @@ -788,11 +549,6 @@ <sha256 value="f8698ab46ca996ce889c1afc8ca4f25eb8ac6b034dc898d4583742360016cc04" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.guava" name="guava-parent" version="28.2-jre"> - <artifact name="guava-parent-28.2-jre.pom"> - <sha256 value="504a6d18eb81ba6d5a255a262bd823f0168c7f47814d4b524f5fa303ea5617c2" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.guava" name="guava-parent" version="30.1.1-jre"> <artifact name="guava-parent-30.1.1-jre.pom"> <sha256 value="0422bd45ca2497bfa18aad2698324965ed70da0907b8a7d459b7ab3b5eed3834" origin="Generated by Gradle"/> @@ -831,9 +587,9 @@ <sha256 value="2527e9d1eac4822ba94f6fffe4f0b6d6e757e4a33ece5406674f60b7f6494b06" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.inject" name="guice" version="5.1.0"> - <artifact name="guice-5.1.0.jar"> - <sha256 value="4130e50bfac48099c860f0d903b91860c81a249c90f38245f8fed58fc817bc26" origin="Generated by Gradle"/> + <component group="com.google.inject" name="guice" version="7.0.0"> + <artifact name="guice-7.0.0.jar"> + <sha256 value="de5b0e359bd7b03ca42806b368846efd95484380fe05ae2a4ea71bc338c59c00" origin="Generated by Gradle"/> </artifact> </component> <component group="com.google.j2objc" name="j2objc-annotations" version="1.1"> @@ -845,8 +601,10 @@ <artifact name="j2objc-annotations-1.3.jar"> <sha256 value="21af30c92267bd6122c0e0b4d20cccb6641a37eaf956c6540ec471d584e64a7b" origin="Generated by Gradle"/> </artifact> - <artifact name="j2objc-annotations-1.3.pom"> - <sha256 value="5faca824ba115bee458730337dfdb2fcea46ba2fd774d4304edbf30fa6a3f055" origin="Generated by Gradle"/> + </component> + <component group="com.google.j2objc" name="j2objc-annotations" version="2.8"> + <artifact name="j2objc-annotations-2.8.jar"> + <sha256 value="f02a95fa1a5e95edb3ed859fd0fb7df709d121a35290eff8b74dce2ab7f4d6ed" origin="Generated by Gradle"/> </artifact> </component> <component group="com.google.oauth-client" name="google-oauth-client" version="1.23.0"> @@ -854,34 +612,16 @@ <sha256 value="48af1eefee0b6e9e131fc8c65a91df96064144c608187e4344eb7e4f8201006a" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.protobuf" name="protobuf-bom" version="3.10.0"> - <artifact name="protobuf-bom-3.10.0.pom"> - <sha256 value="32ff2307dafc658d0b55b2ad841d625aea5606bb9b0316605165cd6980503243" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.protobuf" name="protobuf-bom" version="3.19.1"> <artifact name="protobuf-bom-3.19.1.pom"> <sha256 value="96623d7afc374800cfdc4eb1e49efdb1b17d762fbe9c7de0e46980de14473170" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.protobuf" name="protobuf-gradle-plugin" version="0.8.10"> - <artifact name="protobuf-gradle-plugin-0.8.10.jar"> - <sha256 value="3287f2efd60a4d3ee8a95ea6d0cf5223507e231e8661c873f84aad5fcd79e1ef" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.protobuf" name="protobuf-gradle-plugin" version="0.8.17"> <artifact name="protobuf-gradle-plugin-0.8.17.jar"> <sha256 value="233eae7e9a5d5f344aacca30bcd2788d348765c0a391eff6d998809a9596d89c" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.protobuf" name="protobuf-java" version="3.10.0"> - <artifact name="protobuf-java-3.10.0.jar"> - <sha256 value="161d7d61a8cb3970891c299578702fd079646e032329d6c2cabf998d191437c9" origin="Generated by Gradle"/> - </artifact> - <artifact name="protobuf-java-3.10.0.pom"> - <sha256 value="b404c1b093ec9dea888e02c8dfe8662759586b94efa4f97061cdfc1bbfa15af0" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.protobuf" name="protobuf-java" version="3.19.1"> <artifact name="protobuf-java-3.19.1.jar"> <sha256 value="24f7d0d91797ed230a6d3da93cd80590a4c3aa9a27249f6025b5c6da078edde7" origin="Generated by Gradle"/> @@ -900,28 +640,15 @@ <sha256 value="8bd8a5de6d7e05dce16c8198c8013ebd9c703e10db957fb6dfab0ad24bcd8adc" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.protobuf" name="protobuf-parent" version="3.10.0"> - <artifact name="protobuf-parent-3.10.0.pom"> - <sha256 value="6dd84a508125fffdefbd583fae12bf166aa902511b570ca54fa9efa45f6dfe80" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.protobuf" name="protobuf-parent" version="3.19.1"> <artifact name="protobuf-parent-3.19.1.pom"> <sha256 value="83d413b2a79d6357d2ca78fd623143424e8f6ecc72cfa83bf2ae2ae258a93a44" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.google.protobuf" name="protoc" version="3.10.0"> - <artifact name="protoc-3.10.0-linux-x86_64.exe"> - <sha256 value="eed3ea189a99e3ad4e4209332e7161b255dc8f39bbde4c8e9fc25535f0f6f4f5" origin="Generated by Gradle"/> - </artifact> - <artifact name="protoc-3.10.0-osx-x86_64.exe"> - <sha256 value="a73d5bc8a2a4ab2a541901aa5ce81beacf8a7be5635be06a99c88f5ec10e840f" origin="Generated by Gradle"/> - </artifact> - <artifact name="protoc-3.10.0-windows-x86_64.exe"> - <sha256 value="996fe8523c4d6b70f6e390c9105fbe76023e8fc7aac0ad5e316ec0a48ad9a9b2" origin="Generated by Gradle"/> - </artifact> - </component> <component group="com.google.protobuf" name="protoc" version="3.19.1"> + <artifact name="protoc-3.19.1-linux-aarch_64.exe"> + <sha256 value="e18b554834c8c039223b83f3024afb8af9166666b4b9e54d83dcebfe8e28a929" origin="Generated by Gradle"/> + </artifact> <artifact name="protoc-3.19.1-linux-x86_64.exe"> <sha256 value="0b1099f537d44ee862b0c3708f32f1d66cfd76e2e2c1437f0c57a98476c20605" origin="Generated by Gradle"/> </artifact> @@ -953,9 +680,9 @@ <sha256 value="73ca7d715e90c8d2c2635cc284543b038245a34f70790660ed590e157b8714a2" origin="Generated by Gradle"/> </artifact> </component> - <component group="com.gradle" name="gradle-enterprise-gradle-plugin" version="3.12.4"> - <artifact name="gradle-enterprise-gradle-plugin-3.12.4.jar"> - <sha256 value="6d4be23b57303f3619bf061f3961022f673a6b74b955098fd04ad2cffc0b7109" origin="Generated by Gradle"/> + <component group="com.gradle" name="gradle-enterprise-gradle-plugin" version="3.16.1"> + <artifact name="gradle-enterprise-gradle-plugin-3.16.1.jar"> + <sha256 value="989cfe6b6a47b530971add6d55c043ecc1eded4144a66a981be5770ffee3de1c" origin="Generated by Gradle"/> </artifact> </component> <component group="com.jfoenix" name="jfoenix" version="9.0.10"> @@ -1003,26 +730,10 @@ <sha256 value="7d938c81789028045c08c065e94be75fc280527620d5bd62b519d5838532368a" origin="Generated by Gradle"/> </artifact> </component> - <component group="commons-codec" name="commons-codec" version="1.10"> - <artifact name="commons-codec-1.10.jar"> - <sha256 value="4241dfa94e711d435f29a4604a3e2de5c4aa3c165e23bd066be6fc1fc4309569" origin="Generated by Gradle"/> - </artifact> - <artifact name="commons-codec-1.10.pom"> - <sha256 value="bdb8db7012d112a6e3ea8fdb7c510b300d99eff0819d27dddba9c43397ea4cfb" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="commons-codec" name="commons-codec" version="1.11"> - <artifact name="commons-codec-1.11.jar"> - <sha256 value="e599d5318e97aa48f42136a2927e6dfa4e8881dff0e6c8e3109ddbbff51d7b7d" origin="Generated by Gradle"/> - </artifact> - </component> <component group="commons-codec" name="commons-codec" version="1.13"> <artifact name="commons-codec-1.13.jar"> <sha256 value="61f7a3079e92b9fdd605238d0295af5fd11ac411a0a0af48deace1f6c5ffa072" origin="Generated by Gradle"/> </artifact> - <artifact name="commons-codec-1.13.pom"> - <sha256 value="c2e2a902d38230cf3031d0b434d5de2614fa0ff26d384b6d282aab56c7d3fc69" origin="Generated by Gradle"/> - </artifact> </component> <component group="commons-codec" name="commons-codec" version="1.15"> <artifact name="commons-codec-1.15.jar"> @@ -1103,11 +814,6 @@ <sha256 value="4728eddd64e6ae3e1f205a775c6a327b24bd990b86d528584a17450a8b5f00d6" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.github.monero-ecosystem" name="monero-java" version="0.8.6"> - <artifact name="monero-java-0.8.6.jar"> - <sha256 value="5e4e31fadb62422c394b28b89d2532f74a1f2bc30df7fcb3e93b263a5f33fcc8" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.github.resilience4j" name="resilience4j-all" version="1.7.0"> <artifact name="resilience4j-all-1.7.0.jar"> <sha256 value="46c17f491886c0152d957cd04b00b871f39df09d2bd01067d650e2bc89451b04" origin="Generated by Gradle"/> @@ -1172,12 +878,9 @@ <sha256 value="c92e2ca40a3f2474d61e56831aeb379cf8ae3dddeea61b4a828cee2d99f71f38" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-api" version="1.25.0"> - <artifact name="grpc-api-1.25.0.jar"> - <sha256 value="a269094009588213ab5386a6fb92426b8056a130b2653d3b4e59e971f2f1ef08" origin="Generated by Gradle"/> - </artifact> - <artifact name="grpc-api-1.25.0.pom"> - <sha256 value="8aa2955fdb4a893dacd88a4de00812e841fd5f9b1c184263b7e60aa53d59b568" origin="Generated by Gradle"/> + <component group="io.github.woodser" name="monero-java" version="0.8.33"> + <artifact name="monero-java-0.8.33.jar"> + <sha256 value="f9a02386ec0870b13a512bf5f72da464c9507e1a1ed6982716bff87641f94e81" origin="Generated by Gradle"/> </artifact> </component> <component group="io.grpc" name="grpc-api" version="1.42.1"> @@ -1188,24 +891,11 @@ <sha256 value="e371abe8a43de8416afa1a970466d833d1974f86ed620a5f548ab5aac4610188" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-auth" version="1.25.0"> - <artifact name="grpc-auth-1.25.0.jar"> - <sha256 value="782ae07923d53b56f54326e7b32480b425eb3df71deb5a4a33bbfc6487e706a4" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="grpc-auth" version="1.42.1"> <artifact name="grpc-auth-1.42.1.jar"> <sha256 value="fbfeae9b1b8b913f82a8ed5c20d4536a404464bfd385fd8ecd5a7dac9207ce30" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-context" version="1.25.0"> - <artifact name="grpc-context-1.25.0.jar"> - <sha256 value="f4c8f878c320f6fb56c1c14692618f6df8253314b556176e32727afbc5921a73" origin="Generated by Gradle"/> - </artifact> - <artifact name="grpc-context-1.25.0.pom"> - <sha256 value="7658b40a601548133a6ca8c93fa88761aa55f13359d179fc688694844d5702a8" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="grpc-context" version="1.42.1"> <artifact name="grpc-context-1.42.1.jar"> <sha256 value="8810d6dc294b8c025c152a0093a2c62406ed79778f52ebbb28ab51640c1a4504" origin="Generated by Gradle"/> @@ -1219,14 +909,6 @@ <sha256 value="a8327173b619137ea1b32da4cb06bf3728a5e9b6b40c6249b5c33dcc2eb6a572" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-core" version="1.25.0"> - <artifact name="grpc-core-1.25.0.jar"> - <sha256 value="d67fa113fd9cc45a02710f9c41dda9c15191448c14e9e96fcc21839a41345d4c" origin="Generated by Gradle"/> - </artifact> - <artifact name="grpc-core-1.25.0.pom"> - <sha256 value="84c3213dd54b7f06b8592ac685c75ff03115cec3ed825c5de14658d7ecab69be" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="grpc-core" version="1.42.1"> <artifact name="grpc-core-1.42.1.jar"> <sha256 value="0ae05bd478bbcfbd99840fac07cadbab100f597ceae2f8d122536778a26fed1f" origin="Generated by Gradle"/> @@ -1240,14 +922,6 @@ <sha256 value="65558b1f7145ad285acbb57e3fe7129bfd8660104ed4f874223043d615925105" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-netty-shaded" version="1.25.0"> - <artifact name="grpc-netty-shaded-1.25.0.jar"> - <sha256 value="9edfd45da473d2efbb5683fc3eaf1857e82d2148033d82dd558a7ac38731ea33" origin="Generated by Gradle"/> - </artifact> - <artifact name="grpc-netty-shaded-1.25.0.pom"> - <sha256 value="26a27dd8a7bb5ce04eae4455fd260c914cd6d9d8a2cad1a804c58563ff5fd01f" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="grpc-netty-shaded" version="1.42.1"> <artifact name="grpc-netty-shaded-1.42.1.jar"> <sha256 value="154ff51536c888708afb2d8437df09a8bc5fe2607b01b2ffd2c1980c353ad168" origin="Generated by Gradle"/> @@ -1261,14 +935,6 @@ <sha256 value="3f7365986cb37edd66a5550938650a753de7d54571e3670c3aa414752f436c8b" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-protobuf" version="1.25.0"> - <artifact name="grpc-protobuf-1.25.0.jar"> - <sha256 value="454dae7e246dac25526ed5b795d97a5dafedd3cc2042cfc810f02051d7d3e3cb" origin="Generated by Gradle"/> - </artifact> - <artifact name="grpc-protobuf-1.25.0.pom"> - <sha256 value="76399ced4a9af69b83a2ca0d5df85d0f94b0401c1f9005b84c6987185216e6f8" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="grpc-protobuf" version="1.42.1"> <artifact name="grpc-protobuf-1.42.1.jar"> <sha256 value="272ddd7486c11d4e4b4a534953b9dbf94ee752c5a87f9d390d50d2c14f0d7bac" origin="Generated by Gradle"/> @@ -1282,14 +948,6 @@ <sha256 value="326a4fc6a2adc214f80d45a9b35024ac63e96d9c8d870a43bd48fa6322111027" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="grpc-protobuf-lite" version="1.25.0"> - <artifact name="grpc-protobuf-lite-1.25.0.jar"> - <sha256 value="9ba9aaa3e6997a04c707793c25e3ec88c6bad86f8d6f6b8b7a1a0c33ea2429d8" origin="Generated by Gradle"/> - </artifact> - <artifact name="grpc-protobuf-lite-1.25.0.pom"> - <sha256 value="ff6b3de50e680ba7a40b39981717f485351513d1de3e299866ff94cfaed51573" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="grpc-protobuf-lite" version="1.42.1"> <artifact name="grpc-protobuf-lite-1.42.1.jar"> <sha256 value="bb258c38d98a1de473569c56b66f31f101e528feb5b790215b41117573e6885d" origin="Generated by Gradle"/> @@ -1319,18 +977,10 @@ <sha256 value="b8ba8a78520802dc168285d6bf4c85c6558e095eca853713fdbcbc4453875151" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.grpc" name="protoc-gen-grpc-java" version="1.25.0"> - <artifact name="protoc-gen-grpc-java-1.25.0-linux-x86_64.exe"> - <sha256 value="a712c0af4a0f7261a4880398072da6b482beca2307c2e5c42592d96841ca0ec2" origin="Generated by Gradle"/> - </artifact> - <artifact name="protoc-gen-grpc-java-1.25.0-osx-x86_64.exe"> - <sha256 value="83cc359bce8a615571c6fafc2979a143364b77a53f5b89a194aa8609c0c0c9fa" origin="Generated by Gradle"/> - </artifact> - <artifact name="protoc-gen-grpc-java-1.25.0-windows-x86_64.exe"> - <sha256 value="3186347362277c18082fac6de2525ca8311becbe29e95414fe55559b8dd2fbff" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.grpc" name="protoc-gen-grpc-java" version="1.42.1"> + <artifact name="protoc-gen-grpc-java-1.42.1-linux-aarch_64.exe"> + <sha256 value="9da908610c3006b9a8d27d790a93ad961fb881dda3335b4b4a3810425eff913b" origin="Generated by Gradle"/> + </artifact> <artifact name="protoc-gen-grpc-java-1.42.1-linux-x86_64.exe"> <sha256 value="5596b69eb69ed508bc69307f14340be702bdee2ff0ed33c1cafde02aefc9faaf" origin="Generated by Gradle"/> </artifact> @@ -1445,14 +1095,6 @@ <sha256 value="3d2953b189b70cc37eb7ee9d23cede6e7fc1af0291593b9cc5eace180d7bf6df" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.perfmark" name="perfmark-api" version="0.19.0"> - <artifact name="perfmark-api-0.19.0.jar"> - <sha256 value="b734ba2149712409a44eabdb799f64768578fee0defe1418bb108fe32ea43e1a" origin="Generated by Gradle"/> - </artifact> - <artifact name="perfmark-api-0.19.0.pom"> - <sha256 value="e73b2e78a5d4a8a6fd50dfb7241586c385165115296297112954bf44e81e646c" origin="Generated by Gradle"/> - </artifact> - </component> <component group="io.perfmark" name="perfmark-api" version="0.23.0"> <artifact name="perfmark-api-0.23.0.jar"> <sha256 value="c705b5c10c18ff3032b9e81742bc2f6b0e5607f6a6dfc0c8ad0cff75d4913042" origin="Generated by Gradle"/> @@ -1486,14 +1128,9 @@ <sha256 value="393e745d222f86885a0456bba71ab25297dbeab625df286199d20b6a7daa99dd" origin="Generated by Gradle"/> </artifact> </component> - <component group="io.spring.gradle" name="dependency-management-plugin" version="1.0.11.RELEASE"> - <artifact name="dependency-management-plugin-1.0.11.RELEASE.jar"> - <sha256 value="39ab7c3aa351b700dc8a61c4aa66dc34239f0b7ed62adc66c7ce9e4072d6ac88" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="io.spring.gradle" name="dependency-management-plugin" version="1.0.4.RELEASE"> - <artifact name="dependency-management-plugin-1.0.4.RELEASE.jar"> - <sha256 value="37e2b4345ee0b0078d39c24424ab952672d37994ba86135d44c2e76279864f5a" origin="Generated by Gradle"/> + <component group="io.spring.gradle" name="dependency-management-plugin" version="1.1.4"> + <artifact name="dependency-management-plugin-1.1.4.jar"> + <sha256 value="8a59af77648dd07e6b6751d271db2fa1d02bf2e6cf7e9ab37fb9b08ecc9b43a1" origin="Generated by Gradle"/> </artifact> </component> <component group="io.vavr" name="vavr" version="0.10.2"> @@ -1517,11 +1154,6 @@ <sha256 value="91359b2cba15324405169d1e2d1ef4b2d016e394d6eae58677c4f0f87f33cb87" origin="Generated by Gradle"/> </artifact> </component> - <component group="jakarta.activation" name="jakarta.activation-api" version="1.2.1"> - <artifact name="jakarta.activation-api-1.2.1.jar"> - <sha256 value="8b0a0f52fa8b05c5431921a063ed866efaa41dadf2e3a7ee3e1961f2b0d9645b" origin="Generated by Gradle"/> - </artifact> - </component> <component group="jakarta.activation" name="jakarta.activation-api" version="1.2.2"> <artifact name="jakarta.activation-api-1.2.2.jar"> <sha256 value="a187a939103aef5849a7af84bd7e27be2d120c410af291437375ffe061f4f09d" origin="Generated by Gradle"/> @@ -1543,12 +1175,9 @@ <sha256 value="ba6874767f5415c5e0f644fab80e1bad5feab6d18150f22638067681866feaaf" origin="Generated by Gradle"/> </artifact> </component> - <component group="jakarta.ws.rs" name="jakarta.ws.rs-api" version="2.1.5"> - <artifact name="jakarta.ws.rs-api-2.1.5.jar"> - <sha256 value="3587738aaf6d5e4f1e3f01cc249cb061badf7490f7e647b2ae26d0a7efa6e173" origin="Generated by Gradle"/> - </artifact> - <artifact name="jakarta.ws.rs-api-2.1.5.pom"> - <sha256 value="23987ad51189efe6997c9e293b88385cb5cf0e7ad4e54ce24bb0ceb173dda3d4" origin="Generated by Gradle"/> + <component group="jakarta.inject" name="jakarta.inject-api" version="2.0.1"> + <artifact name="jakarta.inject-api-2.0.1.jar"> + <sha256 value="f7dc98062fccf14126abb751b64fab12c312566e8cbdc8483598bffcea93af7c" origin="Generated by Gradle"/> </artifact> </component> <component group="jakarta.ws.rs" name="jakarta.ws.rs-api" version="2.1.6"> @@ -1559,11 +1188,6 @@ <sha256 value="291c18a6dcc54766397774a5c12a2bc9a2f337f4aed62d3f9fbf6c06483b1f36" origin="Generated by Gradle"/> </artifact> </component> - <component group="jakarta.xml.bind" name="jakarta.xml.bind-api" version="2.3.2"> - <artifact name="jakarta.xml.bind-api-2.3.2.jar"> - <sha256 value="69156304079bdeed9fc0ae3b39389f19b3cc4ba4443bc80508995394ead742ea" origin="Generated by Gradle"/> - </artifact> - </component> <component group="jakarta.xml.bind" name="jakarta.xml.bind-api" version="2.3.3"> <artifact name="jakarta.xml.bind-api-2.3.3.jar"> <sha256 value="c04539f472e9a6dd0c7685ea82d677282269ab8e7baca2e14500e381e0c6cec5" origin="Generated by Gradle"/> @@ -1590,14 +1214,6 @@ <sha256 value="46a4a251ca406e78e4853d7a2bae83282844a4992851439ee9a1f23716f06b97" origin="Generated by Gradle"/> </artifact> </component> - <component group="javax.cache" name="cache-api" version="1.0.0"> - <artifact name="cache-api-1.0.0.jar"> - <sha256 value="d2836213144722e2eb1d7461f6e2ea3349d6fbbf9cd5f345c7133bc29bd39ca1" origin="Generated by Gradle"/> - </artifact> - <artifact name="cache-api-1.0.0.pom"> - <sha256 value="424dd1d4e7e92bffb4bb9f18acf7f53835d218fb9788336b5fdc69cff5c675ef" origin="Generated by Gradle"/> - </artifact> - </component> <component group="javax.cache" name="cache-api" version="1.1.1"> <artifact name="cache-api-1.1.1.jar"> <sha256 value="9f34e007edfa82a7b2a2e1b969477dcf5099ce7f4f926fb54ce7e27c4a0cd54b" origin="Generated by Gradle"/> @@ -1658,66 +1274,14 @@ <sha256 value="f47aeef86821e52b2b18758978bd045f03d722292e32e747082122c6228952e0" origin="Generated by Gradle"/> </artifact> </component> - <component group="net.bytebuddy" name="byte-buddy" version="1.10.15"> - <artifact name="byte-buddy-1.10.15.jar"> - <sha256 value="79be97529a296fca4a885c4652814a939ae37f1a86a6b13bd29d0725fa4e5711" origin="Generated by Gradle"/> - </artifact> - <artifact name="byte-buddy-1.10.15.pom"> - <sha256 value="1cef6524cccce1b5a5fd6b884433cc455d2f20ea0e81340015fdfe58529c6d99" origin="Generated by Gradle"/> + <component group="net.bytebuddy" name="byte-buddy" version="1.14.11"> + <artifact name="byte-buddy-1.14.11.jar"> + <sha256 value="62ae28187ed2b062813da6a9d567bfee733c341582699b62dd980230729a0313" origin="Generated by Gradle"/> </artifact> </component> - <component group="net.bytebuddy" name="byte-buddy" version="1.11.19"> - <artifact name="byte-buddy-1.11.19.jar"> - <sha256 value="4cd1038ca54507323bf04742634f618bb1624914df47a8b4a4dcfa797bd6a8d5" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy" version="1.11.22"> - <artifact name="byte-buddy-1.11.22.jar"> - <sha256 value="d95656262ebce2fbff31b8c041af7170ad8a3cee843cec8f75cdb21f20b4bd96" origin="Generated by Gradle"/> - </artifact> - <artifact name="byte-buddy-1.11.22.pom"> - <sha256 value="49e054f69779b67cfee7781253abd073043e7b19ffce1a10cc92c548f5e20110" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy" version="1.14.1"> - <artifact name="byte-buddy-1.14.1.jar"> - <sha256 value="63479f9a0a1b28f98313230d688a46b02bd80d09a700e127482d0bd635b47bad" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy-agent" version="1.10.15"> - <artifact name="byte-buddy-agent-1.10.15.jar"> - <sha256 value="15cecd0ca128d0517d99b5bb8682b4f187c73a68eeff4a1797168322bc0ebc5c" origin="Generated by Gradle"/> - </artifact> - <artifact name="byte-buddy-agent-1.10.15.pom"> - <sha256 value="00623295bd3b07abd8e6734950c5b3e4ba0c6545c7439ae1a101adbc40c0748d" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy-agent" version="1.11.19"> - <artifact name="byte-buddy-agent-1.11.19.jar"> - <sha256 value="871ba7021f8c335a14b47012f1bfe2cf8caa7c0b5a57dd1e00ee2b9e1f143fc0" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy-agent" version="1.11.22"> - <artifact name="byte-buddy-agent-1.11.22.jar"> - <sha256 value="38e8a07d4e2b35de35084cd7aae122e778cf21b528d5fed91f1d974d72be566e" origin="Generated by Gradle"/> - </artifact> - <artifact name="byte-buddy-agent-1.11.22.pom"> - <sha256 value="64218a12c36e897b7b62118486c13f9a804568ffc516ca5d9f72dd264dd3a8b3" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy-agent" version="1.14.1"> - <artifact name="byte-buddy-agent-1.14.1.jar"> - <sha256 value="f4809b9d0f00e71be98a61a25b3e14437f53f6821485694011beeb25e9231dde" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy-parent" version="1.10.15"> - <artifact name="byte-buddy-parent-1.10.15.pom"> - <sha256 value="95f928ce833c13bbdfc166e411b408a510012920481a93aa2bf74bee5fd56db1" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="net.bytebuddy" name="byte-buddy-parent" version="1.11.22"> - <artifact name="byte-buddy-parent-1.11.22.pom"> - <sha256 value="adaee3b3e5d63a0f50d1d9aa097103e552e94bed0c58e9e3e3612c720489160d" origin="Generated by Gradle"/> + <component group="net.bytebuddy" name="byte-buddy-agent" version="1.14.11"> + <artifact name="byte-buddy-agent-1.14.11.jar"> + <sha256 value="2f537a621a64fa7013d68c695a76a34ee8d79dad74e635caca16dd56257aeb80" origin="Generated by Gradle"/> </artifact> </component> <component group="net.glxn" name="qrgen" version="1.3"> @@ -1725,24 +1289,19 @@ <sha256 value="c85d9d8512d91e8ad11fe56259a7825bd50ce0245447e236cf168d1b17591882" origin="Generated by Gradle"/> </artifact> </component> - <component group="net.java" name="jvnet-parent" version="3"> - <artifact name="jvnet-parent-3.pom"> - <sha256 value="30f5789efa39ddbf96095aada3fc1260c4561faf2f714686717cb2dc5049475a" origin="Generated by Gradle"/> - </artifact> - </component> <component group="net.java" name="jvnet-parent" version="5"> <artifact name="jvnet-parent-5.pom"> <sha256 value="1af699f8d9ddab67f9a0d202fbd7915eb0362a5a6dfd5ffc54cafa3465c9cb0a" origin="Generated by Gradle"/> </artifact> </component> - <component group="net.java.dev.jna" name="jna" version="5.7.0"> - <artifact name="jna-5.7.0.jar"> - <sha256 value="c34e3e002cca6e197379c105b554255cc0638101ed7a09ef00334dade0013621" origin="Generated by Gradle"/> + <component group="net.java.dev.jna" name="jna" version="5.13.0"> + <artifact name="jna-5.13.0.jar"> + <sha256 value="66d4f819a062a51a1d5627bffc23fac55d1677f0e0a1feba144aabdd670a64bb" origin="Generated by Gradle"/> </artifact> </component> - <component group="net.java.dev.jna" name="jna-platform" version="5.7.0"> - <artifact name="jna-platform-5.7.0.jar"> - <sha256 value="42e020705692eddbd285e2b72ef0ff468f51a926382569c45f4e9cea4602ad1e" origin="Generated by Gradle"/> + <component group="net.java.dev.jna" name="jna-platform" version="5.13.0"> + <artifact name="jna-platform-5.13.0.jar"> + <sha256 value="474d7b88f6e97009b6ec1d98c3024dd95c23187c65dabfbc35331bcac3d173dd" origin="Generated by Gradle"/> </artifact> </component> <component group="net.jcip" name="jcip-annotations" version="1.0"> @@ -1789,41 +1348,11 @@ <sha256 value="4c518b87d4bdff8b44cd8cbc1af816e944b62a3fe5b80b781501cf1f4759bbc4" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache" name="apache" version="13"> - <artifact name="apache-13.pom"> - <sha256 value="ff513db0361fd41237bef4784968bc15aae478d4ec0a9496f811072ccaf3841d" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache" name="apache" version="15"> - <artifact name="apache-15.pom"> - <sha256 value="36c2f2f979ac67b450c0cb480e4e9baf6b40f3a681f22ba9692287d1139ad494" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache" name="apache" version="18"> - <artifact name="apache-18.pom"> - <sha256 value="7831307285fd475bbc36b20ae38e7882f11c3153b1d5930f852d44eda8f33c17" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache" name="apache" version="19"> - <artifact name="apache-19.pom"> - <sha256 value="91f7a33096ea69bac2cbaf6d01feb934cac002c48d8c8cfa9c240b40f1ec21df" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache" name="apache" version="21"> - <artifact name="apache-21.pom"> - <sha256 value="af10c108da014f17cafac7b52b2b4b5a3a1c18265fa2af97a325d9143537b380" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache" name="apache" version="23"> <artifact name="apache-23.pom"> <sha256 value="bc10624e0623f36577fac5639ca2936d3240ed152fb6d8d533ab4d270543491c" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache" name="apache" version="9"> - <artifact name="apache-9.pom"> - <sha256 value="4946e60a547c8eda69f3bc23c5b6f0dadcf8469ea49b1d1da7de34aecfcf18dd" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.ant" name="ant" version="1.10.13"> <artifact name="ant-1.10.13.jar"> <sha256 value="befbfc79e744e9892cfa7db96df3b6e82dc17d2571af42aa427976fc22299838" origin="Generated by Gradle"/> @@ -1834,14 +1363,6 @@ <sha256 value="cd7695b3bfb6964ab71b6a0b31dad60005ae77fe502132364679aacf08f77970" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.commons" name="commons-compress" version="1.18"> - <artifact name="commons-compress-1.18.jar"> - <sha256 value="5f2df1e467825e4cac5996d44890c4201c000b43c0b23cffc0782d28a0beb9b0" origin="Generated by Gradle"/> - </artifact> - <artifact name="commons-compress-1.18.pom"> - <sha256 value="672c5fe92bd3eab43e8d53338cad5ca073b6529de4eb2b38859a3eaa6c9e8119" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.commons" name="commons-compress" version="1.21"> <artifact name="commons-compress-1.21.jar"> <sha256 value="6aecfd5459728a595601cfa07258d131972ffc39b492eb48bdd596577a2f244a" origin="Generated by Gradle"/> @@ -1854,9 +1375,6 @@ <artifact name="commons-lang3-3.11.jar"> <sha256 value="4ee380259c068d1dbe9e84ab52186f2acd65de067ec09beff731fca1697fdb16" origin="Generated by Gradle"/> </artifact> - <artifact name="commons-lang3-3.11.pom"> - <sha256 value="980d665d83fed04665134f0578e507442a0e750691073784391b0a7988724a75" origin="Generated by Gradle"/> - </artifact> </component> <component group="org.apache.commons" name="commons-lang3" version="3.12.0"> <artifact name="commons-lang3-3.12.0.jar"> @@ -1866,36 +1384,6 @@ <sha256 value="82d31f1dcc4583effd744e979165b16da64bf86bca623fc5d1b03ed94f45c85a" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.commons" name="commons-parent" version="34"> - <artifact name="commons-parent-34.pom"> - <sha256 value="3a2e69d06d641d1f3b293126dc9e2e4ea6563bf8c36c87e0ab6fa4292d04b79c" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.commons" name="commons-parent" version="35"> - <artifact name="commons-parent-35.pom"> - <sha256 value="7098a1ab8336ecd4c9dc21cbbcac869f82c66f64b8ac4f7988d41b4fcb44e49a" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.commons" name="commons-parent" version="42"> - <artifact name="commons-parent-42.pom"> - <sha256 value="cd313494c670b483ec256972af1698b330e598f807002354eb765479f604b09c" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.commons" name="commons-parent" version="47"> - <artifact name="commons-parent-47.pom"> - <sha256 value="8a8ecb570553bf9f1ffae211a8d4ca9ee630c17afe59293368fba7bd9b42fcb7" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.commons" name="commons-parent" version="48"> - <artifact name="commons-parent-48.pom"> - <sha256 value="1e1f7de9370a7b7901f128f1dacd1422be74e3f47f9558b0f79e04c0637ca0b4" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.commons" name="commons-parent" version="51"> - <artifact name="commons-parent-51.pom"> - <sha256 value="9b779d18b22d8de559605558e7bb0a0a31b3f00c2abb9c878117c398aacabeca" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.commons" name="commons-parent" version="52"> <artifact name="commons-parent-52.pom"> <sha256 value="75dbe8f34e98e4c3ff42daae4a2f9eb4cbcd3b5f1047d54460ace906dbb4502e" origin="Generated by Gradle"/> @@ -1905,70 +1393,31 @@ <artifact name="httpclient-4.5.12.jar"> <sha256 value="bc5f065aba5dd815ee559dd24d9bcb797fb102ff9cfa036f5091ebc529bd3b93" origin="Generated by Gradle"/> </artifact> - <artifact name="httpclient-4.5.12.pom"> - <sha256 value="419ad1b24a77baa2288ab60ae057b4cf78dbc2c11d27c7204d5cb6779a451527" origin="Generated by Gradle"/> - </artifact> </component> <component group="org.apache.httpcomponents" name="httpclient" version="4.5.13"> <artifact name="httpclient-4.5.13.jar"> <sha256 value="6fe9026a566c6a5001608cf3fc32196641f6c1e5e1986d1037ccdbd5f31ef743" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.httpcomponents" name="httpclient" version="4.5.5"> - <artifact name="httpclient-4.5.5.jar"> - <sha256 value="7e97724443ad2a25ad8c73183431d47cc7946271bcbbdfa91a8a17522a566573" origin="Generated by Gradle"/> - </artifact> - <artifact name="httpclient-4.5.5.pom"> - <sha256 value="db3b0198e11f3aa5fa51310c915b818c134a8cbcb82fc81ddf95ba2313862626" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.httpcomponents" name="httpcomponents-client" version="4.5.12"> <artifact name="httpcomponents-client-4.5.12.pom"> <sha256 value="8f889a53593c027bea003fdbe89399546d7beefa1f60e1756015f10f502b016a" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.httpcomponents" name="httpcomponents-client" version="4.5.5"> - <artifact name="httpcomponents-client-4.5.5.pom"> - <sha256 value="1445d012158f941731a6062c7eab740093ea2745b46b54de236b3f7787e99bf3" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.httpcomponents" name="httpcomponents-core" version="4.4.13"> <artifact name="httpcomponents-core-4.4.13.pom"> <sha256 value="c554e7008e4517c7ef54e005cc8b74f4c87a54a0ea2c6f57be5d0569df51936b" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.httpcomponents" name="httpcomponents-core" version="4.4.9"> - <artifact name="httpcomponents-core-4.4.9.pom"> - <sha256 value="32e66095a919456fc76a10c7865e70c9a14c62bbba847026420a055652366b18" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.httpcomponents" name="httpcomponents-parent" version="10"> - <artifact name="httpcomponents-parent-10.pom"> - <sha256 value="caaf967d94afb21753f36082c6086206bd1f48825ff596932cceba72b65d39fa" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.apache.httpcomponents" name="httpcomponents-parent" version="11"> - <artifact name="httpcomponents-parent-11.pom"> - <sha256 value="a901f87b115c55070c7ee43efff63e20e7b02d30af2443ae292bf1f4e532d3aa" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.httpcomponents" name="httpcomponents-parent" version="12"> <artifact name="httpcomponents-parent-12.pom"> <sha256 value="4209f09593212987c29d6801917309dd5e6f71b53b2b1d0e0f0efb984ad11fa1" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.httpcomponents" name="httpcomponents-parent" version="9"> - <artifact name="httpcomponents-parent-9.pom"> - <sha256 value="2656c7e40bdbe6b6f958798f7d6918b50b544df0e23b52ce3731b9ccc20b5f8c" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.apache.httpcomponents" name="httpcore" version="4.4.13"> <artifact name="httpcore-4.4.13.jar"> <sha256 value="e06e89d40943245fcfa39ec537cdbfce3762aecde8f9c597780d2b00c2b43424" origin="Generated by Gradle"/> </artifact> - <artifact name="httpcore-4.4.13.pom"> - <sha256 value="8f812d9fa7b72a3d4aa7f825278932a5df344b42a6d8398905879431a1bf9a97" origin="Generated by Gradle"/> - </artifact> </component> <component group="org.apache.httpcomponents" name="httpcore" version="4.4.9"> <artifact name="httpcore-4.4.9.jar"> @@ -1988,9 +1437,9 @@ <sha256 value="9355f3876baf82fec13ced22c12b62d57536230836406d359459128e4f73ed51" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.apache.httpcomponents.client5" name="httpclient5-parent" version="5.0"> - <artifact name="httpclient5-parent-5.0.pom"> - <sha256 value="0765e5534209b92e17efd93eee94348cf6de7f3045723d12d0818884b9fab028" origin="Generated by Gradle"/> + <component group="org.apache.httpcomponents.client5" name="httpclient5" version="5.2.3"> + <artifact name="httpclient5-5.2.3.jar"> + <sha256 value="7cf4c7e60338aa334e8699f2423af1c93bdc3a3121f2df22378d61222fa5910c" origin="Generated by Gradle"/> </artifact> </component> <component group="org.apache.httpcomponents.client5" name="httpclient5-parent" version="5.1.2"> @@ -2008,6 +1457,11 @@ <sha256 value="293321cbf594d79ea8a0cb0214f75f146d17f088be17ad5ce11c2fe864df124c" origin="Generated by Gradle"/> </artifact> </component> + <component group="org.apache.httpcomponents.core5" name="httpcore5" version="5.2.4"> + <artifact name="httpcore5-5.2.4.jar"> + <sha256 value="a7f62496113f66f9e27c26b84c44f5ce4555c6270083cdf2d45f255336cd52af" origin="Generated by Gradle"/> + </artifact> + </component> <component group="org.apache.httpcomponents.core5" name="httpcore5-h2" version="5.1.3"> <artifact name="httpcore5-h2-5.1.3.jar"> <sha256 value="d0e78ba15aa8ebe77982b660ac4b09a95d6e035dbdbea762577dc1c8e2935807" origin="Generated by Gradle"/> @@ -2018,6 +1472,11 @@ <sha256 value="5a087fb8c619979d492a83546f351ddadf32b28cc6a32923229f3fc777171578" origin="Generated by Gradle"/> </artifact> </component> + <component group="org.apache.httpcomponents.core5" name="httpcore5-h2" version="5.2.4"> + <artifact name="httpcore5-h2-5.2.4.jar"> + <sha256 value="dc1a95e73eb04db93451533d390ce02c53b301a10dc343d08c862f2934b3d30e" origin="Generated by Gradle"/> + </artifact> + </component> <component group="org.apache.httpcomponents.core5" name="httpcore5-parent" version="5.0"> <artifact name="httpcore5-parent-5.0.pom"> <sha256 value="b0dfd9fdc009aa5ca9a737ad9e4bef258f7dc32c0589f1dee0465bbc1a280864" origin="Generated by Gradle"/> @@ -2172,14 +1631,6 @@ <sha256 value="11d134b245e9cacc474514d2d66b5b8618f8039a1465cdc55bbc0b34e0008b7a" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.checkerframework" name="checker-qual" version="2.10.0"> - <artifact name="checker-qual-2.10.0.jar"> - <sha256 value="d261fde25d590f6b69db7721d469ac1b0a19a17ccaaaa751c31f0d8b8260b894" origin="Generated by Gradle"/> - </artifact> - <artifact name="checker-qual-2.10.0.pom"> - <sha256 value="246e47e395f8d7a8c12b7222b166bc3a1d3809bc3a3d30de97470aa38d952a4b" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.checkerframework" name="checker-qual" version="2.5.2"> <artifact name="checker-qual-2.5.2.jar"> <sha256 value="64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a" origin="Generated by Gradle"/> @@ -2190,12 +1641,9 @@ <sha256 value="25fda6f3eb2ee2139ff5d7d3992667d526ebf1b0fb87df36fc75aa35679e6dab" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.checkerframework" name="checker-qual" version="3.8.0"> - <artifact name="checker-qual-3.8.0.jar"> - <sha256 value="c88c2e6a5fdaeb9f26fcf879264042de8a9ee9d376e2477838feaabcfa44dda6" origin="Generated by Gradle"/> - </artifact> - <artifact name="checker-qual-3.8.0.pom"> - <sha256 value="7e6d59e2d3bc01b1f04fa3667193a6d4170199b14fba53a7a8e36bf7602239a7" origin="Generated by Gradle"/> + <component group="org.checkerframework" name="checker-qual" version="3.33.0"> + <artifact name="checker-qual-3.33.0.jar"> + <sha256 value="e316255bbfcd9fe50d165314b85abb2b33cb2a66a93c491db648e498a82c2de1" origin="Generated by Gradle"/> </artifact> </component> <component group="org.codehaus.groovy" name="groovy-bom" version="3.0.9"> @@ -2538,12 +1986,9 @@ <sha256 value="836069ca9e8ee3c56e48376222da291263f137bd3fd16d84fdd47efcc3f286e2" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.junit.jupiter" name="junit-jupiter-api" version="5.7.0"> - <artifact name="junit-jupiter-api-5.7.0.jar"> - <sha256 value="b03f78e0daeed2d77a0af9bcd662b4cdb9693f7ee72e01a539b508b84c63d182" origin="Generated by Gradle"/> - </artifact> - <artifact name="junit-jupiter-api-5.7.0.pom"> - <sha256 value="a0f823d513c8d4692935f24c2fe6e77cc4a7b6147a9e8a518f722e50bbf86138" origin="Generated by Gradle"/> + <component group="org.junit.jupiter" name="junit-jupiter-api" version="5.10.1"> + <artifact name="junit-jupiter-api-5.10.1.jar"> + <sha256 value="60d5c398c32dc7039b99282514ad6064061d8417cf959a1f6bd2038cc907c913" origin="Generated by Gradle"/> </artifact> </component> <component group="org.junit.jupiter" name="junit-jupiter-api" version="5.9.2"> @@ -2551,12 +1996,9 @@ <sha256 value="f767a170f97127b0ad3582bf3358eabbbbe981d9f96411853e629d9276926fd5" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.junit.jupiter" name="junit-jupiter-engine" version="5.7.0"> - <artifact name="junit-jupiter-engine-5.7.0.jar"> - <sha256 value="dfa26af94644ac2612dde6625852fcb550a0d21caa243257de54cba738ba87af" origin="Generated by Gradle"/> - </artifact> - <artifact name="junit-jupiter-engine-5.7.0.pom"> - <sha256 value="b702e250875d331ee3c6b88f37299fbe951f43992f4b2e4a8f144e2e4cf2c7e8" origin="Generated by Gradle"/> + <component group="org.junit.jupiter" name="junit-jupiter-engine" version="5.10.1"> + <artifact name="junit-jupiter-engine-5.10.1.jar"> + <sha256 value="02930dfe495f93fe70b26550ace3a28f7e1b900c84426c2e4626ce020c7282d6" origin="Generated by Gradle"/> </artifact> </component> <component group="org.junit.jupiter" name="junit-jupiter-engine" version="5.9.2"> @@ -2564,12 +2006,9 @@ <sha256 value="74cfc49388f760413ff348ca2c9ab39527484b57deecd157f2275a5f8a5fe971" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.junit.jupiter" name="junit-jupiter-params" version="5.7.0"> - <artifact name="junit-jupiter-params-5.7.0.jar"> - <sha256 value="ca9f555c37b9bf79effd2e834af549e4feb52ad8ac9e348fe5b430d4d8a482b7" origin="Generated by Gradle"/> - </artifact> - <artifact name="junit-jupiter-params-5.7.0.pom"> - <sha256 value="23873e305a9751109839ad08b6b37dfadd1036f43b359b3b1b7bd2601fc73260" origin="Generated by Gradle"/> + <component group="org.junit.jupiter" name="junit-jupiter-params" version="5.10.1"> + <artifact name="junit-jupiter-params-5.10.1.jar"> + <sha256 value="c8cf62debcbb354deefe1ffd0671eff785514907567d22a615ff8a8de4522b21" origin="Generated by Gradle"/> </artifact> </component> <component group="org.junit.jupiter" name="junit-jupiter-params" version="5.9.2"> @@ -2577,6 +2016,11 @@ <sha256 value="bde91900a5ce5d6663bb44bc708494b35daefcd73e1bb7afa61a4affe38ea97d" origin="Generated by Gradle"/> </artifact> </component> + <component group="org.junit.platform" name="junit-platform-commons" version="1.10.1"> + <artifact name="junit-platform-commons-1.10.1.jar"> + <sha256 value="7d9855ee3f3f71f015eb1479559bf923783243c24fbfbd8b29bed8e8099b5672" origin="Generated by Gradle"/> + </artifact> + </component> <component group="org.junit.platform" name="junit-platform-commons" version="1.7.0"> <artifact name="junit-platform-commons-1.7.0.jar"> <sha256 value="5330ee87cc7586e6e25175a34e9251624ff12ff525269d3415d0b4ca519b6fea" origin="Generated by Gradle"/> @@ -2598,20 +2042,9 @@ <sha256 value="624a3d745ef1d28e955a6a67af8edba0fdfc5c9bad680a73f67a70bb950a683d" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.junit.platform" name="junit-platform-engine" version="1.7.0"> - <artifact name="junit-platform-engine-1.7.0.jar"> - <sha256 value="75f21a20dc594afdc875736725b408cec6d0344874d29f34b2dd3075500236f2" origin="Generated by Gradle"/> - </artifact> - <artifact name="junit-platform-engine-1.7.0.pom"> - <sha256 value="225b99c5032fd1cb8cecda2e8b5a7526d6a5f81fb98a29a57557f7f5ccda9d12" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.junit.platform" name="junit-platform-engine" version="1.8.2"> - <artifact name="junit-platform-engine-1.8.2.jar"> - <sha256 value="0b7d000f8c3e8e5f7d6b819649936e7b9938314e87c8f983805218ea57567e59" origin="Generated by Gradle"/> - </artifact> - <artifact name="junit-platform-engine-1.8.2.pom"> - <sha256 value="0168643266060ed928ef5a81823003ecfae79a9a8c0bbfd76f4201c6c9d771c5" origin="Generated by Gradle"/> + <component group="org.junit.platform" name="junit-platform-engine" version="1.10.1"> + <artifact name="junit-platform-engine-1.10.1.jar"> + <sha256 value="baa48e470d6dee7369a0a8820c51da89c1463279eda6e13a304d11f45922c760" origin="Generated by Gradle"/> </artifact> </component> <component group="org.junit.platform" name="junit-platform-engine" version="1.9.2"> @@ -2989,9 +2422,14 @@ <sha256 value="9146f147483ae9dfdb226eb928e81926122fadc1665648262e6e095d15762ebf" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.mockito" name="mockito-core" version="5.2.0"> - <artifact name="mockito-core-5.2.0.jar"> - <sha256 value="46e3f8dacd8ec62c8aa6fb11f8867624fb44a03e97fdfc628609346d5dc7e159" origin="Generated by Gradle"/> + <component group="org.mockito" name="mockito-core" version="5.10.0"> + <artifact name="mockito-core-5.10.0.jar"> + <sha256 value="0323f591b04d3a0d7ca9ebeebb9e9f34a07c0ec9169b7444ee3951b71d4cad56" origin="Generated by Gradle"/> + </artifact> + </component> + <component group="org.mockito" name="mockito-junit-jupiter" version="5.10.0"> + <artifact name="mockito-junit-jupiter-5.10.0.jar"> + <sha256 value="24ae25cde73401edf029790534fe9f92c1304eb52e46a9e57cf2b6b937ae8c43" origin="Generated by Gradle"/> </artifact> </component> <component group="org.objenesis" name="objenesis" version="3.1"> @@ -3025,87 +2463,93 @@ <sha256 value="0859ba0d5cfeefb13964e5862c036faa48a0bccff4932638fb13fe3445df33f7" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.openjfx" name="javafx" version="16"> - <artifact name="javafx-16.pom"> - <sha256 value="18d9784212d04475bfe4a5f4038e0fc78146f9a721eb6b9a52955d3b4b20d3ca" origin="Generated by Gradle"/> + <component group="org.openjfx" name="javafx-base" version="21.0.2"> + <artifact name="javafx-base-21.0.2-linux.jar"> + <sha256 value="a8f3674bac12b07acda55191579586cfe9f842b91bf06bee08b14d06397a3ffd" origin="Generated by Gradle"/> + </artifact> + <artifact name="javafx-base-21.0.2-mac-aarch64.jar"> + <sha256 value="41d00909245d4af11ef53962171abe01c36ac02b916a6b37cc3860d48b3c471e" origin="Generated by Gradle"/> + </artifact> + <artifact name="javafx-base-21.0.2-mac.jar"> + <sha256 value="94e7dee515ab829a3911cf5d5ccb00c7144056190195cc1725d052f70a21ffe5" origin="Generated by Gradle"/> + </artifact> + <artifact name="javafx-base-21.0.2-win.jar"> + <sha256 value="c7628cdb5bd36029d7cb8fd087ac2f69c407f8f4b959f416eddaaf50a6f57323" origin="Generated by Gradle"/> + </artifact> + <artifact name="javafx-base-21.0.2.jar"> + <sha256 value="6437ceabf3c0da57ccc08b1cd5430f655923cfef0bcfdae89273f4a267912fbd" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.openjfx" name="javafx-base" version="16"> - <artifact name="javafx-base-16-linux.jar"> - <sha256 value="b825e220d685ecbd77e76f2cd52793132e6c9a10e23ee3361673cb29033413c0" origin="Generated by Gradle"/> + <component group="org.openjfx" name="javafx-controls" version="21.0.2"> + <artifact name="javafx-controls-21.0.2-linux.jar"> + <sha256 value="c6ddb7e90c0fe256c212fd331d297a03a4840c61a6b330893ffc54c2d7c6326b" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-base-16-mac.jar"> - <sha256 value="8cb4a023706d392d0a733aaee41be839e8418448ab0090a8115a9b909d595c77" origin="Generated by Gradle"/> + <artifact name="javafx-controls-21.0.2-mac-aarch64.jar"> + <sha256 value="5b6a41895b1fa5e2a52acc08f7be9494e87d3ed307b76fd2c698b4eadbc5ab35" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-base-16-win.jar"> - <sha256 value="23abcdffb6f92d8b37531080682034d01c177f1229118a2f7646331c51c6ed63" origin="Generated by Gradle"/> + <artifact name="javafx-controls-21.0.2-mac.jar"> + <sha256 value="6cd73004e5ef92ce7be00c4f2ac4be2ab26fdd4a8dba3a58cf95d261a10f352b" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-base-16.jar"> - <sha256 value="036955291b3633b6e11106df315f7a561218d31dcb4280078fe4d2414925f557" origin="Generated by Gradle"/> + <artifact name="javafx-controls-21.0.2-win.jar"> + <sha256 value="3be19bed6f59f0c6fa022d9ecc7a7b9ab5a062867864054f78e1bd4836037093" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-base-16.pom"> - <sha256 value="09fe0f2eda8b6f3d4c55b28e32b6b7b2782847add96a686d3048753baa781901" origin="Generated by Gradle"/> + <artifact name="javafx-controls-21.0.2.jar"> + <sha256 value="0673842ff63bfe06476ee095a6b25bb0a1d074d87b9f8d42148ecb5b036081b0" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.openjfx" name="javafx-controls" version="16"> - <artifact name="javafx-controls-16-linux.jar"> - <sha256 value="fd0aba38a0dde9836845c6d671501f4c30e6cff6f2d72748f75742dbcfc74df9" origin="Generated by Gradle"/> + <component group="org.openjfx" name="javafx-fxml" version="21.0.2"> + <artifact name="javafx-fxml-21.0.2-linux.jar"> + <sha256 value="24fefcf2354e183c5a5decb65f090c1fe896f88ec7f7a3730f473bd251a4ee19" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-controls-16-mac.jar"> - <sha256 value="4add6fdf120ab9c784dc6e700c158d411d9371aaba7bbb61ad9f9d016f2cce44" origin="Generated by Gradle"/> + <artifact name="javafx-fxml-21.0.2-mac-aarch64.jar"> + <sha256 value="c6521279f68bdbc5bba3082c6b3c50b5100c919aa34fedff66246bca89fd9201" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-controls-16-win.jar"> - <sha256 value="a7f6e4757163c38a5e6cf26b426e9daf788ad1b57513111d362b3bbbc298d13b" origin="Generated by Gradle"/> + <artifact name="javafx-fxml-21.0.2-mac.jar"> + <sha256 value="c599615e11b2d8ed9d68afa8f82b749fc46bc5eb0ee1611097c15f312e34950d" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-controls-16.jar"> - <sha256 value="dfdbe63f9717b2cd84c9fd34b28a8ddffdbe25cc1e4c2ff9f171f07ca725e0f4" origin="Generated by Gradle"/> + <artifact name="javafx-fxml-21.0.2-win.jar"> + <sha256 value="7bb4c8c58ebd241e425206bd5cb79e9cf0f624701ab85cf7802d4b91f68e1ce5" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.openjfx" name="javafx-fxml" version="16"> - <artifact name="javafx-fxml-16-linux.jar"> - <sha256 value="65249a5a47357283f21c5fa85b2e91255f7e5b0b86a2ec3dd2cc220541d7ae0b" origin="Generated by Gradle"/> + <component group="org.openjfx" name="javafx-graphics" version="21.0.2"> + <artifact name="javafx-graphics-21.0.2-linux.jar"> + <sha256 value="a1951e6db7616f143b2a4bc31e6cae26960e7956658015839f60830a9cf5016b" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-fxml-16-mac.jar"> - <sha256 value="b722e590930180ff7c43d34281202251e1fe8d1f81b16098cda78600780b7f46" origin="Generated by Gradle"/> + <artifact name="javafx-graphics-21.0.2-mac-aarch64.jar"> + <sha256 value="098e545644378ad521f03686464d0be202c99d11b2a234cf4d51dd5d11287e61" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-fxml-16-win.jar"> - <sha256 value="e8313ffb783c26acbbc1267448bbfdf2f05126e5845a06c6f29a43db7483606d" origin="Generated by Gradle"/> + <artifact name="javafx-graphics-21.0.2-mac.jar"> + <sha256 value="289fab031737ad5a4a5eabd9d5c7f52b6e2a506cab9dcab0356eb37c08a73a2e" origin="Generated by Gradle"/> + </artifact> + <artifact name="javafx-graphics-21.0.2-win.jar"> + <sha256 value="55947b98e30424b831f8e1f0e80656355d244f2d57df679841a2e07cbbd84729" origin="Generated by Gradle"/> + </artifact> + <artifact name="javafx-graphics-21.0.2.jar"> + <sha256 value="3d4585f884bf64094b0771a78c5046b62eb8db9f15cc01cdc4136d72f26d4188" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.openjfx" name="javafx-graphics" version="16"> - <artifact name="javafx-graphics-16-linux.jar"> - <sha256 value="a2f5e1ea5aeb3ae57e63a1c853a4edf1e38b6f2fe76997ab864ad8b3c54bed53" origin="Generated by Gradle"/> + <component group="org.openjfx" name="javafx-swing" version="21.0.2"> + <artifact name="javafx-swing-21.0.2-linux.jar"> + <sha256 value="67a4369cd556ed9b8b6970116e5f5f7f55ef64e54aaddbcc3f7950f7590631b5" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-graphics-16-mac.jar"> - <sha256 value="23a67ad877f283039a20dd827f68988c1f952fe4958d039c006762883f1f04ab" origin="Generated by Gradle"/> + <artifact name="javafx-swing-21.0.2-mac.jar"> + <sha256 value="2f047f7a4e5bc8e9603c23b168b472590a0a0607ba16b6c62d5f9b4f361d12ad" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-graphics-16-win.jar"> - <sha256 value="78124668c64db443cf3e105b9c2f6d7061e7c72ad5ad2de63a13adc46ef2ca8c" origin="Generated by Gradle"/> + <artifact name="javafx-swing-21.0.2-mac.jar-aarch64"> + <sha256 value="5e6b5f10350915d92e2df8d602646eccf9b7f62c56fe04849a6b6f647d50fb74" origin="Generated by Gradle"/> </artifact> - <artifact name="javafx-graphics-16.jar"> - <sha256 value="77533b2922a853a3e1350c8e6650f6cf746000d20efef69119c6324086883b95" origin="Generated by Gradle"/> - </artifact> - <artifact name="javafx-graphics-16.pom"> - <sha256 value="b8fb99688eccae62be724bd72b34dfff1f8e1cddbe44649f5ef9a082e520c47e" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.openjfx" name="javafx-swing" version="16"> - <artifact name="javafx-swing-16-linux.jar"> - <sha256 value="ffb495dbbf314f56784828b91ee2cc304bd891b862b79fdd7f3338e6cffd74f7" origin="Generated by Gradle"/> - </artifact> - <artifact name="javafx-swing-16-mac.jar"> - <sha256 value="6b49d1754f9c987b48244c8c9612214f05229a67b7bd43f4ba98f76b4617ae56" origin="Generated by Gradle"/> - </artifact> - <artifact name="javafx-swing-16-win.jar"> - <sha256 value="5244ee1fe470507cebeaf1111937168556163a0b90e6bf9bba5c16b4c3280012" origin="Generated by Gradle"/> + <artifact name="javafx-swing-21.0.2-win.jar"> + <sha256 value="d34a842a7e6fe4712f691dc578503376da8206352fefb17350005e89164db9ec" origin="Generated by Gradle"/> </artifact> </component> <component group="org.opentest4j" name="opentest4j" version="1.2.0"> <artifact name="opentest4j-1.2.0.jar"> <sha256 value="58812de60898d976fb81ef3b62da05c6604c18fd4a249f5044282479fc286af2" origin="Generated by Gradle"/> </artifact> - <artifact name="opentest4j-1.2.0.pom"> - <sha256 value="a96e671816c1ff8803bdec74c9241f025bdfb277da5d2b4ee02266405936f994" origin="Generated by Gradle"/> + </component> + <component group="org.opentest4j" name="opentest4j" version="1.3.0"> + <artifact name="opentest4j-1.3.0.jar"> + <sha256 value="48e2df636cab6563ced64dcdff8abb2355627cb236ef0bf37598682ddf742f1b" origin="Generated by Gradle"/> </artifact> </component> <component group="org.ow2" name="ow2" version="1.5"> @@ -3156,12 +2600,9 @@ <sha256 value="bca2bb252c6ec5db92584af7ab26f787b14a155f587c3e30ec1e1da0d4164694" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.projectlombok" name="lombok" version="1.18.24"> - <artifact name="lombok-1.18.24.jar"> - <sha256 value="d3584bc2db03f059f984fb0a9c119aac1fa0da578a448e69fc3f68b36584c749" origin="Generated by Gradle"/> - </artifact> - <artifact name="lombok-1.18.24.pom"> - <sha256 value="2ab23568c9a823eb7a9d1171abbe5e2d2c6872e1a2db6878ef030c6d5ca47710" origin="Generated by Gradle"/> + <component group="org.projectlombok" name="lombok" version="1.18.30"> + <artifact name="lombok-1.18.30.jar"> + <sha256 value="14151b47582d570b4de16a147ece3bdbd19ace4aee5bde3a5578c87db9ecb998" origin="Generated by Gradle"/> </artifact> </component> <component group="org.reflections" name="reflections" version="0.10.2"> @@ -3221,34 +2662,16 @@ <sha256 value="d3ef575e3e4979678dc01bf1dcce51021493b4d11fb7f1be8ad982877c16a1c0" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.slf4j" name="slf4j-parent" version="1.7.25"> - <artifact name="slf4j-parent-1.7.25.pom"> - <sha256 value="18f5c52120db036e88d6136f8839c832d074bdda95c756c6f429249d2db54ac6" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.slf4j" name="slf4j-parent" version="1.7.33"> <artifact name="slf4j-parent-1.7.33.pom"> <sha256 value="7da72f04110b30ac1deea7d2d64d69499930dc07813cb686d1e2ee8cced667d0" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.sonatype.oss" name="oss-parent" version="7"> - <artifact name="oss-parent-7.pom"> - <sha256 value="b51f8867c92b6a722499557fc3a1fdea77bdf9ef574722fe90ce436a29559454" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.sonatype.oss" name="oss-parent" version="9"> <artifact name="oss-parent-9.pom"> <sha256 value="fb40265f982548212ff82e362e59732b2187ec6f0d80182885c14ef1f982827a" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework" name="spring-aop" version="4.3.14.RELEASE"> - <artifact name="spring-aop-4.3.14.RELEASE.jar"> - <sha256 value="045bd5b0e8f5567432b4a2228ac5a1b0f5d9b62b393e352a99ae025ff6ab1e12" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-aop-4.3.14.RELEASE.pom"> - <sha256 value="feadd2a533a5013b23eadba846fdc9c9961d580cfb4236d51f49e91aaf874dbb" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.springframework" name="spring-aop" version="5.3.15"> <artifact name="spring-aop-5.3.15.jar"> <sha256 value="58cf948758d31e2ac8636dfa27cd4211a7a89e54e16f7318c0ec3f964c83b2b7" origin="Generated by Gradle"/> @@ -3257,14 +2680,6 @@ <sha256 value="4dadfefd863348b5af002c8a68b1dd6d9f80e0465dea44429041cba68feb886c" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework" name="spring-beans" version="4.3.14.RELEASE"> - <artifact name="spring-beans-4.3.14.RELEASE.jar"> - <sha256 value="62ba63c30d30a221b69ce77d5d626554af1d61dc736cebd45ba7c688ee1048ab" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-beans-4.3.14.RELEASE.pom"> - <sha256 value="ae2f90dba31e8ec9b2896afed10b2ea216f2775f94b4efe6faa8da3420b81976" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.springframework" name="spring-beans" version="5.3.15"> <artifact name="spring-beans-5.3.15.jar"> <sha256 value="f4facec88ada2e86be062f90b3f1d39fd6660de7ecc2dc45afc45fb31e9699b2" origin="Generated by Gradle"/> @@ -3273,14 +2688,6 @@ <sha256 value="2229926331e98a89d3b1c04ac465aa96cc7a1e05608176971a8435d9c09e139d" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework" name="spring-context" version="4.3.14.RELEASE"> - <artifact name="spring-context-4.3.14.RELEASE.jar"> - <sha256 value="532eefed557776476cdc19bed3ff773fb9335dd064fdd4b05d5cbff843cffdb4" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-context-4.3.14.RELEASE.pom"> - <sha256 value="7757ae5afd1e113d094a2ca37a4e83ff3f500d60be9c9c225e38c8ff1664ac0f" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.springframework" name="spring-context" version="5.3.15"> <artifact name="spring-context-5.3.15.jar"> <sha256 value="b23c4e897e846750d6409982c077f237074534df51eae0e2c589c9783950bf7b" origin="Generated by Gradle"/> @@ -3289,28 +2696,9 @@ <sha256 value="455e3dfe81dcd4381e1b64277e06e969f052c6752a7a915bba917a494eda82e7" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework" name="spring-core" version="4.3.14.RELEASE"> - <artifact name="spring-core-4.3.14.RELEASE.jar"> - <sha256 value="461e35d0dd65e7dedcc9ce5dfc88692768d02216c33d9abe9cac50b5671e1480" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-core-4.3.14.RELEASE.pom"> - <sha256 value="b6919ef5b3f29b82d584be03b73dcfa8a626f9c229c785962db979ed79796e66" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.springframework" name="spring-core" version="5.3.15"> - <artifact name="spring-core-5.3.15.jar"> - <sha256 value="cf3cb24e0f051e338159ad4a60e156d34b082422a80ece3f045bbc6e8c6246ea" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-core-5.3.15.pom"> - <sha256 value="3fc50bf76d4c0fffb95236f95d7009d36db494190fe6684badd42bfecc4040b9" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.springframework" name="spring-expression" version="4.3.14.RELEASE"> - <artifact name="spring-expression-4.3.14.RELEASE.jar"> - <sha256 value="932e0e19bd9838aa3f10ea5be8e4fc90c1a2dc13af6ec389a1bd6ef1a213f7d7" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-expression-4.3.14.RELEASE.pom"> - <sha256 value="a19aa551f8c9b8ccf90650745eba5eef63b8f845ad594a3bf654cb6b75b8960e" origin="Generated by Gradle"/> + <component group="org.springframework" name="spring-core" version="6.0.10"> + <artifact name="spring-core-6.0.10.jar"> + <sha256 value="1c0a6bf9cccfa8bbe6ab49c13963c1abb2edff81d88b1af7462617ddc7c0975d" origin="Generated by Gradle"/> </artifact> </component> <component group="org.springframework" name="spring-expression" version="5.3.15"> @@ -3321,22 +2709,14 @@ <sha256 value="e2179e3e5346d1b093d4b0bf8356e445e6252de1cea903977f96bcd104397294" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework" name="spring-framework-bom" version="4.3.14.RELEASE"> - <artifact name="spring-framework-bom-4.3.14.RELEASE.pom"> - <sha256 value="3bb35a75ac3723622bbe1c134595697665384ad3c27c5831619ffa78deec0f20" origin="Generated by Gradle"/> - </artifact> - </component> <component group="org.springframework" name="spring-framework-bom" version="5.3.15"> <artifact name="spring-framework-bom-5.3.15.pom"> <sha256 value="eda6cbdee12aa6f80c3d5bc770d9dfc71db9c99b603d1c6f91686946b2b2608b" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework" name="spring-jcl" version="5.3.15"> - <artifact name="spring-jcl-5.3.15.jar"> - <sha256 value="504afd1b05616160ddeecd57537864fd96abd5067f952071c4c8e1246338d123" origin="Generated by Gradle"/> - </artifact> - <artifact name="spring-jcl-5.3.15.pom"> - <sha256 value="65e3c591eb9378152d1625eda67e710073815618d767446b9bc3a781a4bbeda0" origin="Generated by Gradle"/> + <component group="org.springframework" name="spring-jcl" version="6.0.10"> + <artifact name="spring-jcl-6.0.10.jar"> + <sha256 value="323209c83374e9e4c0785311334862fef23755b24c3c0ef94af57313336d6c30" origin="Generated by Gradle"/> </artifact> </component> <component group="org.springframework" name="spring-web" version="4.3.14.RELEASE"> @@ -3411,9 +2791,9 @@ <sha256 value="a25102e9d90c5c0e33e2304aa0b899e5c7d65fc20bb8c162f1d85ffc67c2ddbc" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework.boot" name="spring-boot-buildpack-platform" version="2.6.3"> - <artifact name="spring-boot-buildpack-platform-2.6.3.jar"> - <sha256 value="34aea693bb4c84a7eee6051a14a9a12374a21dc26b4413570bd30363ec976ebc" origin="Generated by Gradle"/> + <component group="org.springframework.boot" name="spring-boot-buildpack-platform" version="3.2.3"> + <artifact name="spring-boot-buildpack-platform-3.2.3.jar"> + <sha256 value="391e87b9d75217c62477a0c193e94db6cabde1ecdf6013946bca89022c69d608" origin="Generated by Gradle"/> </artifact> </component> <component group="org.springframework.boot" name="spring-boot-dependencies" version="1.5.10.RELEASE"> @@ -3426,24 +2806,14 @@ <sha256 value="efae8b2c6051e3b7c9cfc953139eb5142f8c5c3af5c75178b7eaa793e7f2d5ca" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework.boot" name="spring-boot-gradle-plugin" version="1.5.10.RELEASE"> - <artifact name="spring-boot-gradle-plugin-1.5.10.RELEASE.jar"> - <sha256 value="f430e1db7b8746c6feeee5cc8b5ff664e0fae3b760983d0a35d71642997f974d" origin="Generated by Gradle"/> + <component group="org.springframework.boot" name="spring-boot-gradle-plugin" version="3.2.3"> + <artifact name="spring-boot-gradle-plugin-3.2.3.jar"> + <sha256 value="3b2b7891535f2830c6d264b267b2410b9900203c45bf3a97590acc8e8188823e" origin="Generated by Gradle"/> </artifact> </component> - <component group="org.springframework.boot" name="spring-boot-gradle-plugin" version="2.6.3"> - <artifact name="spring-boot-gradle-plugin-2.6.3.jar"> - <sha256 value="98c3ea15d56e9d76b2a4b2672771251752beb0aa5a89991f6b5227e51b665262" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.springframework.boot" name="spring-boot-loader-tools" version="1.5.10.RELEASE"> - <artifact name="spring-boot-loader-tools-1.5.10.RELEASE.jar"> - <sha256 value="32ac263748bbc6a128c732402579f26849b37d62e0ef4c457c34dfceea0bfc71" origin="Generated by Gradle"/> - </artifact> - </component> - <component group="org.springframework.boot" name="spring-boot-loader-tools" version="2.6.3"> - <artifact name="spring-boot-loader-tools-2.6.3.jar"> - <sha256 value="28246505aea783cc7ea279a91200803e53d0a37b27854fe498d3bdfa0c71a623" origin="Generated by Gradle"/> + <component group="org.springframework.boot" name="spring-boot-loader-tools" version="3.2.3"> + <artifact name="spring-boot-loader-tools-3.2.3.jar"> + <sha256 value="3bb672690a24a866cd488802d8ff5846fd48ba783a10a25c5bd6fc3eea27f154" origin="Generated by Gradle"/> </artifact> </component> <component group="org.springframework.boot" name="spring-boot-parent" version="1.5.10.RELEASE"> diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7454180f2a..033e24c4cd 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1a703c8b43..a80b22ce5c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=47a5bfed9ef814f90f8debcbbb315e8e7c654109acd224595ea39fca95c5d4da -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787337..fcb6fca147 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +130,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in @@ -205,6 +213,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32c4..93e3f59f13 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/media/donate_bitcoin.png b/media/donate_bitcoin.png new file mode 100644 index 0000000000..ac25c2c2c8 Binary files /dev/null and b/media/donate_bitcoin.png differ diff --git a/media/donate_monero.png b/media/donate_monero.png new file mode 100644 index 0000000000..35b3e21d8f Binary files /dev/null and b/media/donate_monero.png differ diff --git a/media/qrbtc.png b/media/qrbtc.png deleted file mode 100644 index 66e90ebd7d..0000000000 Binary files a/media/qrbtc.png and /dev/null differ diff --git a/media/qrhaveno.png b/media/qrhaveno.png deleted file mode 100644 index 347b04a597..0000000000 Binary files a/media/qrhaveno.png and /dev/null differ diff --git a/p2p/src/main/java/haveno/network/DnsLookupException.java b/p2p/src/main/java/haveno/network/DnsLookupException.java index 367b90bfd7..3142659a19 100644 --- a/p2p/src/main/java/haveno/network/DnsLookupException.java +++ b/p2p/src/main/java/haveno/network/DnsLookupException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network; diff --git a/p2p/src/main/java/haveno/network/DnsLookupTor.java b/p2p/src/main/java/haveno/network/DnsLookupTor.java index be5bd85b15..a0bbb75cf3 100644 --- a/p2p/src/main/java/haveno/network/DnsLookupTor.java +++ b/p2p/src/main/java/haveno/network/DnsLookupTor.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network; diff --git a/p2p/src/main/java/haveno/network/Socks5DnsDiscovery.java b/p2p/src/main/java/haveno/network/Socks5DnsDiscovery.java index 880c56d248..9b8894bd25 100644 --- a/p2p/src/main/java/haveno/network/Socks5DnsDiscovery.java +++ b/p2p/src/main/java/haveno/network/Socks5DnsDiscovery.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network; import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; +import haveno.common.util.SingleThreadExecutorUtils; import haveno.common.util.Utilities; import lombok.extern.slf4j.Slf4j; import org.bitcoinj.core.NetworkParameters; @@ -32,7 +33,6 @@ import java.net.InetSocketAddress; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** @@ -83,9 +83,9 @@ public class Socks5DnsDiscovery extends MultiplexingDiscovery { // Attempted workaround for reported bugs on Linux in which gethostbyname does not appear to be properly // thread safe and can cause segfaults on some libc versions. if (Utilities.isLinux()) - return Executors.newSingleThreadExecutor(new ContextPropagatingThreadFactory("DNS seed lookups")); + return SingleThreadExecutorUtils.getSingleThreadExecutor(new ContextPropagatingThreadFactory("DNS seed lookups")); else - return Executors.newFixedThreadPool(seeds.size(), new DaemonThreadFactory("DNS seed lookups")); + return Utilities.getFixedThreadPoolExecutor(seeds.size(), new DaemonThreadFactory("DNS seed lookups")); } /** diff --git a/p2p/src/main/java/haveno/network/Socks5MultiDiscovery.java b/p2p/src/main/java/haveno/network/Socks5MultiDiscovery.java index e25911eae3..bbe4a3f3c7 100644 --- a/p2p/src/main/java/haveno/network/Socks5MultiDiscovery.java +++ b/p2p/src/main/java/haveno/network/Socks5MultiDiscovery.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network; diff --git a/p2p/src/main/java/haveno/network/Socks5ProxyProvider.java b/p2p/src/main/java/haveno/network/Socks5ProxyProvider.java index 8029e5014d..f9c498f08e 100644 --- a/p2p/src/main/java/haveno/network/Socks5ProxyProvider.java +++ b/p2p/src/main/java/haveno/network/Socks5ProxyProvider.java @@ -1,43 +1,43 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network; import com.google.inject.Inject; +import com.google.inject.name.Named; import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; import haveno.common.config.Config; import haveno.network.p2p.network.NetworkNode; +import java.net.UnknownHostException; +import javax.annotation.Nullable; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.annotation.Nullable; -import javax.inject.Named; -import java.net.UnknownHostException; - /** - * Provides Socks5Proxies for the bitcoin network and http requests + * Provides Socks5Proxies for the monero network and http requests * <p/> - * By default there is only used the haveno internal Tor proxy, which is used for the P2P network, Btc network - * (if Tor for btc is enabled) and http requests (if Tor for http requests is enabled). + * By default there is only used the haveno internal Tor proxy, which is used for the P2P network, xmr network + * (if Tor for xmr is enabled) and http requests (if Tor for http requests is enabled). * If the user provides a socks5ProxyHttpAddress it will be used for http requests. - * If the user provides a socks5ProxyBtcAddress, this will be used for the btc network. - * If socks5ProxyBtcAddress is present but no socks5ProxyHttpAddress the socks5ProxyBtcAddress will be used for http + * If the user provides a socks5ProxyXmrAddress, this will be used for the xmr network. + * If socks5ProxyXmrAddress is present but no socks5ProxyHttpAddress the socks5ProxyXmrAddress will be used for http * requests. - * If no socks5ProxyBtcAddress and no socks5ProxyHttpAddress is defined (default) we use socks5ProxyInternal. + * If no socks5ProxyXmrAddress and no socks5ProxyHttpAddress is defined (default) we use socks5ProxyInternal. */ public class Socks5ProxyProvider { private static final Logger log = LoggerFactory.getLogger(Socks5ProxyProvider.class); @@ -47,23 +47,23 @@ public class Socks5ProxyProvider { // proxy used for btc network @Nullable - private final Socks5Proxy socks5ProxyBtc; + private final Socks5Proxy socks5ProxyXmr; // if defined proxy used for http requests @Nullable private final Socks5Proxy socks5ProxyHttp; @Inject - public Socks5ProxyProvider(@Named(Config.SOCKS_5_PROXY_BTC_ADDRESS) String socks5ProxyBtcAddress, + public Socks5ProxyProvider(@Named(Config.SOCKS_5_PROXY_XMR_ADDRESS) String socks5ProxyXmrAddress, @Named(Config.SOCKS_5_PROXY_HTTP_ADDRESS) String socks5ProxyHttpAddress) { - socks5ProxyBtc = getProxyFromAddress(socks5ProxyBtcAddress); + socks5ProxyXmr = getProxyFromAddress(socks5ProxyXmrAddress); socks5ProxyHttp = getProxyFromAddress(socks5ProxyHttpAddress); } @Nullable public Socks5Proxy getSocks5Proxy() { - if (socks5ProxyBtc != null) - return socks5ProxyBtc; + if (socks5ProxyXmr != null) + return socks5ProxyXmr; else if (socks5ProxyInternalFactory != null) return getSocks5ProxyInternal(); else @@ -71,8 +71,8 @@ public class Socks5ProxyProvider { } @Nullable - public Socks5Proxy getSocks5ProxyBtc() { - return socks5ProxyBtc; + public Socks5Proxy getSocks5ProxyXmr() { + return socks5ProxyXmr; } @Nullable @@ -97,8 +97,7 @@ public class Socks5ProxyProvider { try { return new Socks5Proxy(tokens[0], Integer.valueOf(tokens[1])); } catch (UnknownHostException e) { - log.error(e.getMessage()); - e.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(e)); } } else { log.error("Incorrect format for socks5ProxyAddress. Should be: host:port.\n" + diff --git a/p2p/src/main/java/haveno/network/Socks5SeedOnionDiscovery.java b/p2p/src/main/java/haveno/network/Socks5SeedOnionDiscovery.java index 0f677cf94e..5696c44f6b 100644 --- a/p2p/src/main/java/haveno/network/Socks5SeedOnionDiscovery.java +++ b/p2p/src/main/java/haveno/network/Socks5SeedOnionDiscovery.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network; diff --git a/p2p/src/main/java/haveno/network/crypto/DecryptedDataTuple.java b/p2p/src/main/java/haveno/network/crypto/DecryptedDataTuple.java index 2a72afb9a0..68bb0c1964 100644 --- a/p2p/src/main/java/haveno/network/crypto/DecryptedDataTuple.java +++ b/p2p/src/main/java/haveno/network/crypto/DecryptedDataTuple.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.crypto; diff --git a/p2p/src/main/java/haveno/network/crypto/EncryptionService.java b/p2p/src/main/java/haveno/network/crypto/EncryptionService.java index b0e6fa7b8d..994111dec0 100644 --- a/p2p/src/main/java/haveno/network/crypto/EncryptionService.java +++ b/p2p/src/main/java/haveno/network/crypto/EncryptionService.java @@ -1,25 +1,27 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.crypto; +import com.google.inject.Inject; import com.google.protobuf.InvalidProtocolBufferException; import haveno.common.crypto.CryptoException; import haveno.common.crypto.Encryption; +import static haveno.common.crypto.Encryption.decryptSecretKey; import haveno.common.crypto.Hash; import haveno.common.crypto.KeyRing; import haveno.common.crypto.PubKeyRing; @@ -29,15 +31,11 @@ import haveno.common.proto.ProtobufferException; import haveno.common.proto.network.NetworkEnvelope; import haveno.common.proto.network.NetworkProtoResolver; import haveno.network.p2p.DecryptedMessageWithPubKey; -import lombok.extern.slf4j.Slf4j; - -import javax.crypto.SecretKey; -import javax.inject.Inject; import java.security.KeyPair; import java.security.PrivateKey; import java.security.PublicKey; - -import static haveno.common.crypto.Encryption.decryptSecretKey; +import javax.crypto.SecretKey; +import lombok.extern.slf4j.Slf4j; @Slf4j public class EncryptionService { diff --git a/p2p/src/main/java/haveno/network/crypto/EncryptionServiceModule.java b/p2p/src/main/java/haveno/network/crypto/EncryptionServiceModule.java index 7ed104480f..bc09820812 100644 --- a/p2p/src/main/java/haveno/network/crypto/EncryptionServiceModule.java +++ b/p2p/src/main/java/haveno/network/crypto/EncryptionServiceModule.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.crypto; diff --git a/p2p/src/main/java/haveno/network/http/FakeDnsResolver.java b/p2p/src/main/java/haveno/network/http/FakeDnsResolver.java index d2e232c5d4..3bda21a83f 100644 --- a/p2p/src/main/java/haveno/network/http/FakeDnsResolver.java +++ b/p2p/src/main/java/haveno/network/http/FakeDnsResolver.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; diff --git a/p2p/src/main/java/haveno/network/http/HttpClient.java b/p2p/src/main/java/haveno/network/http/HttpClient.java index 7027ddaefc..9ebff36390 100644 --- a/p2p/src/main/java/haveno/network/http/HttpClient.java +++ b/p2p/src/main/java/haveno/network/http/HttpClient.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; @@ -39,5 +39,7 @@ public interface HttpClient { boolean hasPendingRequest(); + void cancelPendingRequest(); + void shutDown(); } diff --git a/p2p/src/main/java/haveno/network/http/HttpClientImpl.java b/p2p/src/main/java/haveno/network/http/HttpClientImpl.java index 17185d60e1..62f9fca581 100644 --- a/p2p/src/main/java/haveno/network/http/HttpClientImpl.java +++ b/p2p/src/main/java/haveno/network/http/HttpClientImpl.java @@ -1,26 +1,43 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; + +import haveno.common.ThreadUtils; import haveno.common.app.Version; import haveno.common.util.Utilities; import haveno.network.Socks5ProxyProvider; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import javax.annotation.Nullable; import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -39,23 +56,6 @@ import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContexts; -import javax.annotation.Nullable; -import javax.inject.Inject; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - // TODO close connection if failing @Slf4j public class HttpClientImpl implements HttpClient { @@ -65,6 +65,7 @@ public class HttpClientImpl implements HttpClient { private HttpURLConnection connection; @Nullable private CloseableHttpClient closeableHttpClient; + private static final long SHUTDOWN_TIMEOUT_MS = 5000l; @Getter @Setter @@ -88,6 +89,18 @@ public class HttpClientImpl implements HttpClient { @Override public void shutDown() { + try { + ThreadUtils.awaitTask(() -> { + doShutDown(connection, closeableHttpClient); + connection = null; + closeableHttpClient = null; + }, SHUTDOWN_TIMEOUT_MS); + } catch (Exception e) { + // ignore + } + } + + private void doShutDown(HttpURLConnection connection, CloseableHttpClient closeableHttpClient) { try { if (connection != null) { connection.getInputStream().close(); @@ -135,6 +148,12 @@ public class HttpClientImpl implements HttpClient { } } + public void cancelPendingRequest() { + if (!hasPendingRequest) return; + shutDown(); + hasPendingRequest = false; + } + private String requestWithoutProxy(String baseUrl, String param, HttpMethod httpMethod, diff --git a/p2p/src/main/java/haveno/network/http/HttpException.java b/p2p/src/main/java/haveno/network/http/HttpException.java index a920ddf414..d6b9447e0a 100644 --- a/p2p/src/main/java/haveno/network/http/HttpException.java +++ b/p2p/src/main/java/haveno/network/http/HttpException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; diff --git a/p2p/src/main/java/haveno/network/http/HttpMethod.java b/p2p/src/main/java/haveno/network/http/HttpMethod.java index e740d7d1d1..eb3e7b8575 100644 --- a/p2p/src/main/java/haveno/network/http/HttpMethod.java +++ b/p2p/src/main/java/haveno/network/http/HttpMethod.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; diff --git a/p2p/src/main/java/haveno/network/http/SocksConnectionSocketFactory.java b/p2p/src/main/java/haveno/network/http/SocksConnectionSocketFactory.java index a7f090e68b..75efeccdab 100644 --- a/p2p/src/main/java/haveno/network/http/SocksConnectionSocketFactory.java +++ b/p2p/src/main/java/haveno/network/http/SocksConnectionSocketFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; diff --git a/p2p/src/main/java/haveno/network/http/SocksSSLConnectionSocketFactory.java b/p2p/src/main/java/haveno/network/http/SocksSSLConnectionSocketFactory.java index a43b4c47f7..ac2b0bfe6f 100644 --- a/p2p/src/main/java/haveno/network/http/SocksSSLConnectionSocketFactory.java +++ b/p2p/src/main/java/haveno/network/http/SocksSSLConnectionSocketFactory.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.http; diff --git a/p2p/src/main/java/haveno/network/p2p/AckMessage.java b/p2p/src/main/java/haveno/network/p2p/AckMessage.java index 48a1cf6973..7a7a0ff990 100644 --- a/p2p/src/main/java/haveno/network/p2p/AckMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/AckMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/AckMessageSourceType.java b/p2p/src/main/java/haveno/network/p2p/AckMessageSourceType.java index 3395027244..acea619f4d 100644 --- a/p2p/src/main/java/haveno/network/p2p/AckMessageSourceType.java +++ b/p2p/src/main/java/haveno/network/p2p/AckMessageSourceType.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; @@ -24,5 +24,6 @@ public enum AckMessageSourceType { ARBITRATION_MESSAGE, MEDIATION_MESSAGE, TRADE_CHAT_MESSAGE, - REFUND_MESSAGE + REFUND_MESSAGE, + LOG_TRANSFER } diff --git a/p2p/src/main/java/haveno/network/p2p/AnonymousMessage.java b/p2p/src/main/java/haveno/network/p2p/AnonymousMessage.java index a9f556f8e3..095e1b04ae 100644 --- a/p2p/src/main/java/haveno/network/p2p/AnonymousMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/AnonymousMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/BootstrapListener.java b/p2p/src/main/java/haveno/network/p2p/BootstrapListener.java index 1b0c53f651..932ced6136 100644 --- a/p2p/src/main/java/haveno/network/p2p/BootstrapListener.java +++ b/p2p/src/main/java/haveno/network/p2p/BootstrapListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; @@ -40,11 +40,11 @@ public abstract class BootstrapListener implements P2PServiceListener { } @Override - public void onDataReceived() { + public void onUpdatedDataReceived() { } @Override - public abstract void onUpdatedDataReceived(); + public abstract void onDataReceived(); @Override public void onRequestCustomBridges() { diff --git a/p2p/src/main/java/haveno/network/p2p/BundleOfEnvelopes.java b/p2p/src/main/java/haveno/network/p2p/BundleOfEnvelopes.java index 573699db2b..1c9fa35ea1 100644 --- a/p2p/src/main/java/haveno/network/p2p/BundleOfEnvelopes.java +++ b/p2p/src/main/java/haveno/network/p2p/BundleOfEnvelopes.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/CloseConnectionMessage.java b/p2p/src/main/java/haveno/network/p2p/CloseConnectionMessage.java index d01ef359bf..a14225e803 100644 --- a/p2p/src/main/java/haveno/network/p2p/CloseConnectionMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/CloseConnectionMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/DecryptedDirectMessageListener.java b/p2p/src/main/java/haveno/network/p2p/DecryptedDirectMessageListener.java index 09d49726b9..d68eee3fbb 100644 --- a/p2p/src/main/java/haveno/network/p2p/DecryptedDirectMessageListener.java +++ b/p2p/src/main/java/haveno/network/p2p/DecryptedDirectMessageListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/DecryptedMessageWithPubKey.java b/p2p/src/main/java/haveno/network/p2p/DecryptedMessageWithPubKey.java index 91675e4ae8..a081578ac3 100644 --- a/p2p/src/main/java/haveno/network/p2p/DecryptedMessageWithPubKey.java +++ b/p2p/src/main/java/haveno/network/p2p/DecryptedMessageWithPubKey.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/DirectMessage.java b/p2p/src/main/java/haveno/network/p2p/DirectMessage.java index 6821362e39..0f3e03d2ce 100644 --- a/p2p/src/main/java/haveno/network/p2p/DirectMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/DirectMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/ExtendedDataSizePermission.java b/p2p/src/main/java/haveno/network/p2p/ExtendedDataSizePermission.java index 522e3ba92a..455da755fe 100644 --- a/p2p/src/main/java/haveno/network/p2p/ExtendedDataSizePermission.java +++ b/p2p/src/main/java/haveno/network/p2p/ExtendedDataSizePermission.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/FileTransferPart.java b/p2p/src/main/java/haveno/network/p2p/FileTransferPart.java new file mode 100644 index 0000000000..9cc04cefd9 --- /dev/null +++ b/p2p/src/main/java/haveno/network/p2p/FileTransferPart.java @@ -0,0 +1,106 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + +package haveno.network.p2p; + +import haveno.common.app.Version; +import haveno.common.proto.network.NetworkEnvelope; + +import com.google.protobuf.ByteString; + +import lombok.EqualsAndHashCode; +import lombok.Value; + +@EqualsAndHashCode(callSuper = true) +@Value +public class FileTransferPart extends NetworkEnvelope implements ExtendedDataSizePermission, SendersNodeAddressMessage { + NodeAddress senderNodeAddress; + public String uid; + public String tradeId; + public int traderId; + public long seqNumOrFileLength; + public ByteString messageData; // if message_data is empty it is the first message, requesting file upload permission + + public FileTransferPart(NodeAddress senderNodeAddress, + String tradeId, + int traderId, + String uid, + long seqNumOrFileLength, + ByteString messageData) { + this(senderNodeAddress, tradeId, traderId, uid, seqNumOrFileLength, messageData, Version.getP2PMessageVersion()); + } + + public boolean isInitialRequest() { + return messageData.size() == 0; + } + + /////////////////////////////////////////////////////////////////////////////////////////// + // PROTO BUFFER + /////////////////////////////////////////////////////////////////////////////////////////// + + private FileTransferPart(NodeAddress senderNodeAddress, + String tradeId, + int traderId, + String uid, + long seqNumOrFileLength, + ByteString messageData, + String messageVersion) { + super(messageVersion); + this.senderNodeAddress = senderNodeAddress; + this.tradeId = tradeId; + this.traderId = traderId; + this.uid = uid; + this.seqNumOrFileLength = seqNumOrFileLength; + this.messageData = messageData; + } + + @Override + public protobuf.NetworkEnvelope toProtoNetworkEnvelope() { + return getNetworkEnvelopeBuilder() + .setFileTransferPart(protobuf.FileTransferPart.newBuilder() + .setSenderNodeAddress(senderNodeAddress.toProtoMessage()) + .setTradeId(tradeId) + .setTraderId(traderId) + .setUid(uid) + .setSeqNumOrFileLength(seqNumOrFileLength) + .setMessageData(messageData) + .build()) + .build(); + } + + public static FileTransferPart fromProto(protobuf.FileTransferPart proto, String messageVersion) { + return new FileTransferPart( + NodeAddress.fromProto(proto.getSenderNodeAddress()), + proto.getTradeId(), + proto.getTraderId(), + proto.getUid(), + proto.getSeqNumOrFileLength(), + proto.getMessageData(), + messageVersion); + } + + @Override + public String toString() { + return "FileTransferPart{" + + "\n senderNodeAddress='" + senderNodeAddress.getAddressForDisplay() + '\'' + + ",\n uid='" + uid + '\'' + + ",\n tradeId='" + tradeId + '\'' + + ",\n traderId='" + traderId + '\'' + + ",\n seqNumOrFileLength=" + seqNumOrFileLength + + "\n} " + super.toString(); + } +} diff --git a/p2p/src/main/java/haveno/network/p2p/InitialDataRequest.java b/p2p/src/main/java/haveno/network/p2p/InitialDataRequest.java index 1ac3d06a52..a0e6147ba4 100644 --- a/p2p/src/main/java/haveno/network/p2p/InitialDataRequest.java +++ b/p2p/src/main/java/haveno/network/p2p/InitialDataRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/InitialDataResponse.java b/p2p/src/main/java/haveno/network/p2p/InitialDataResponse.java index e00f0f2149..7f8597de2d 100644 --- a/p2p/src/main/java/haveno/network/p2p/InitialDataResponse.java +++ b/p2p/src/main/java/haveno/network/p2p/InitialDataResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/NetworkNodeProvider.java b/p2p/src/main/java/haveno/network/p2p/NetworkNodeProvider.java index 5bdaa2cc38..798d162357 100644 --- a/p2p/src/main/java/haveno/network/p2p/NetworkNodeProvider.java +++ b/p2p/src/main/java/haveno/network/p2p/NetworkNodeProvider.java @@ -1,40 +1,38 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.name.Named; +import haveno.common.config.Config; +import haveno.common.proto.network.NetworkProtoResolver; +import haveno.network.p2p.network.BanFilter; import haveno.network.p2p.network.BridgeAddressProvider; import haveno.network.p2p.network.LocalhostNetworkNode; -import haveno.network.p2p.network.BanFilter; import haveno.network.p2p.network.NetworkNode; import haveno.network.p2p.network.NewTor; import haveno.network.p2p.network.RunningTor; +import haveno.network.p2p.network.DirectBindTor; import haveno.network.p2p.network.TorMode; -import haveno.network.p2p.network.TorNetworkNode; - -import haveno.common.config.Config; -import haveno.common.proto.network.NetworkProtoResolver; - -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Provider; - +import haveno.network.p2p.network.TorNetworkNodeDirectBind; +import haveno.network.p2p.network.TorNetworkNodeNetlayer; import java.io.File; - import javax.annotation.Nullable; public class NetworkNodeProvider implements Provider<NetworkNode> { @@ -48,9 +46,11 @@ public class NetworkNodeProvider implements Provider<NetworkNode> { @Named(Config.MAX_CONNECTIONS) int maxConnections, @Named(Config.USE_LOCALHOST_FOR_P2P) boolean useLocalhostForP2P, @Named(Config.NODE_PORT) int port, + @Named(Config.HIDDEN_SERVICE_ADDRESS) String hiddenServiceAddress, @Named(Config.TOR_DIR) File torDir, @Nullable @Named(Config.TORRC_FILE) File torrcFile, @Named(Config.TORRC_OPTIONS) String torrcOptions, + @Named(Config.TOR_CONTROL_HOST) String controlHost, @Named(Config.TOR_CONTROL_PORT) int controlPort, @Named(Config.TOR_CONTROL_PASSWORD) String password, @Nullable @Named(Config.TOR_CONTROL_COOKIE_FILE) File cookieFile, @@ -63,11 +63,17 @@ public class NetworkNodeProvider implements Provider<NetworkNode> { torDir, torrcFile, torrcOptions, + controlHost, controlPort, + hiddenServiceAddress, password, cookieFile, useSafeCookieAuthentication); - networkNode = new TorNetworkNode(port, networkProtoResolver, streamIsolation, torMode, banFilter, maxConnections); + if (torMode instanceof NewTor || torMode instanceof RunningTor) { + networkNode = new TorNetworkNodeNetlayer(port, networkProtoResolver, torMode, banFilter, maxConnections, streamIsolation, controlHost); + } else { + networkNode = new TorNetworkNodeDirectBind(port, networkProtoResolver, banFilter, maxConnections, hiddenServiceAddress); + } } } @@ -75,13 +81,19 @@ public class NetworkNodeProvider implements Provider<NetworkNode> { File torDir, @Nullable File torrcFile, String torrcOptions, + String controlHost, int controlPort, + String hiddenServiceAddress, String password, @Nullable File cookieFile, boolean useSafeCookieAuthentication) { - return controlPort != Config.UNSPECIFIED_PORT ? - new RunningTor(torDir, controlPort, password, cookieFile, useSafeCookieAuthentication) : - new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider); + if (!hiddenServiceAddress.equals("")) { + return new DirectBindTor(); + } else if (controlPort != Config.UNSPECIFIED_PORT) { + return new RunningTor(torDir, controlHost, controlPort, password, cookieFile, useSafeCookieAuthentication); + } else { + return new NewTor(torDir, torrcFile, torrcOptions, bridgeAddressProvider); + } } @Override diff --git a/p2p/src/main/java/haveno/network/p2p/NetworkNotReadyException.java b/p2p/src/main/java/haveno/network/p2p/NetworkNotReadyException.java index 275442f066..3939fc05e3 100644 --- a/p2p/src/main/java/haveno/network/p2p/NetworkNotReadyException.java +++ b/p2p/src/main/java/haveno/network/p2p/NetworkNotReadyException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/NodeAddress.java b/p2p/src/main/java/haveno/network/p2p/NodeAddress.java index 047b421b20..37fe311ffb 100644 --- a/p2p/src/main/java/haveno/network/p2p/NodeAddress.java +++ b/p2p/src/main/java/haveno/network/p2p/NodeAddress.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; @@ -74,19 +74,27 @@ public final class NodeAddress implements PersistablePayload, NetworkPayload, Us return hostName + ":" + port; } - public String getHostNameWithoutPostFix() { + public String getAddressForDisplay() { + if (hostName.endsWith(".onion")) return getHostNameForDisplay(); + else return shortenAddressForDisplay(getFullAddress()); + } + + private String getHostNameWithoutPostFix() { return hostName.replace(".onion", ""); } // tor v3 onions are too long to display for example in a table grid, so this convenience method // produces a display-friendly format which includes [first 7]..[last 7] characters. // tor v2 and localhost will be displayed in full, as they are 16 chars or fewer. - public String getHostNameForDisplay() { - String work = getHostNameWithoutPostFix(); - if (work.length() > 16) { - return work.substring(0, 7) + ".." + work.substring(work.length() - 7); + private String getHostNameForDisplay() { + return shortenAddressForDisplay(getHostNameWithoutPostFix()); + } + + private String shortenAddressForDisplay(String address) { + if (address.length() > 16) { + return address.substring(0, 7) + ".." + address.substring(address.length() - 7); } - return work; + return address; } // We use just a few chars from the full address to blur the potential receiver for sent network_messages diff --git a/p2p/src/main/java/haveno/network/p2p/P2PModule.java b/p2p/src/main/java/haveno/network/p2p/P2PModule.java index f71b96e9e8..b13c2ccba7 100644 --- a/p2p/src/main/java/haveno/network/p2p/P2PModule.java +++ b/p2p/src/main/java/haveno/network/p2p/P2PModule.java @@ -1,26 +1,45 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; import com.google.inject.Singleton; import com.google.inject.TypeLiteral; +import static com.google.inject.name.Names.named; +import static com.google.inject.util.Providers.of; import haveno.common.app.AppModule; import haveno.common.config.Config; +import static haveno.common.config.Config.BAN_LIST; +import static haveno.common.config.Config.MAX_CONNECTIONS; +import static haveno.common.config.Config.NODE_PORT; +import static haveno.common.config.Config.HIDDEN_SERVICE_ADDRESS; +import static haveno.common.config.Config.REPUBLISH_MAILBOX_ENTRIES; +import static haveno.common.config.Config.SOCKS_5_PROXY_HTTP_ADDRESS; +import static haveno.common.config.Config.SOCKS_5_PROXY_XMR_ADDRESS; +import static haveno.common.config.Config.TORRC_FILE; +import static haveno.common.config.Config.TORRC_OPTIONS; +import static haveno.common.config.Config.TOR_CONTROL_COOKIE_FILE; +import static haveno.common.config.Config.TOR_CONTROL_HOST; +import static haveno.common.config.Config.TOR_CONTROL_PASSWORD; +import static haveno.common.config.Config.TOR_CONTROL_PORT; +import static haveno.common.config.Config.TOR_CONTROL_USE_SAFE_COOKIE_AUTH; +import static haveno.common.config.Config.TOR_DIR; +import static haveno.common.config.Config.TOR_STREAM_ISOLATION; +import static haveno.common.config.Config.USE_LOCALHOST_FOR_P2P; import haveno.network.Socks5ProxyProvider; import haveno.network.http.HttpClient; import haveno.network.http.HttpClientImpl; @@ -35,29 +54,10 @@ import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.persistence.AppendOnlyDataStoreService; import haveno.network.p2p.storage.persistence.ProtectedDataStoreService; import haveno.network.p2p.storage.persistence.ResourceDataStoreService; - import java.io.File; import java.time.Clock; import java.util.List; -import static com.google.inject.name.Names.named; -import static com.google.inject.util.Providers.of; -import static haveno.common.config.Config.BAN_LIST; -import static haveno.common.config.Config.MAX_CONNECTIONS; -import static haveno.common.config.Config.NODE_PORT; -import static haveno.common.config.Config.REPUBLISH_MAILBOX_ENTRIES; -import static haveno.common.config.Config.SOCKS_5_PROXY_BTC_ADDRESS; -import static haveno.common.config.Config.SOCKS_5_PROXY_HTTP_ADDRESS; -import static haveno.common.config.Config.TORRC_FILE; -import static haveno.common.config.Config.TORRC_OPTIONS; -import static haveno.common.config.Config.TOR_CONTROL_COOKIE_FILE; -import static haveno.common.config.Config.TOR_CONTROL_PASSWORD; -import static haveno.common.config.Config.TOR_CONTROL_PORT; -import static haveno.common.config.Config.TOR_CONTROL_USE_SAFE_COOKIE_AUTH; -import static haveno.common.config.Config.TOR_DIR; -import static haveno.common.config.Config.TOR_STREAM_ISOLATION; -import static haveno.common.config.Config.USE_LOCALHOST_FOR_P2P; - public class P2PModule extends AppModule { public P2PModule(Config config) { @@ -88,14 +88,16 @@ public class P2PModule extends AppModule { bind(File.class).annotatedWith(named(TOR_DIR)).toInstance(config.torDir); bind(int.class).annotatedWith(named(NODE_PORT)).toInstance(config.nodePort); + bind(String.class).annotatedWith(named(HIDDEN_SERVICE_ADDRESS)).toInstance(config.hiddenServiceAddress); bindConstant().annotatedWith(named(MAX_CONNECTIONS)).to(config.maxConnections); bind(new TypeLiteral<List<String>>(){}).annotatedWith(named(BAN_LIST)).toInstance(config.banList); - bindConstant().annotatedWith(named(SOCKS_5_PROXY_BTC_ADDRESS)).to(config.socks5ProxyBtcAddress); + bindConstant().annotatedWith(named(SOCKS_5_PROXY_XMR_ADDRESS)).to(config.socks5ProxyXmrAddress); bindConstant().annotatedWith(named(SOCKS_5_PROXY_HTTP_ADDRESS)).to(config.socks5ProxyHttpAddress); bind(File.class).annotatedWith(named(TORRC_FILE)).toProvider(of(config.torrcFile)); // allow null value bindConstant().annotatedWith(named(TORRC_OPTIONS)).to(config.torrcOptions); + bindConstant().annotatedWith(named(TOR_CONTROL_HOST)).to(config.torControlHost); bindConstant().annotatedWith(named(TOR_CONTROL_PORT)).to(config.torControlPort); bindConstant().annotatedWith(named(TOR_CONTROL_PASSWORD)).to(config.torControlPassword); bind(File.class).annotatedWith(named(TOR_CONTROL_COOKIE_FILE)).toProvider(of(config.torControlCookieFile)); diff --git a/p2p/src/main/java/haveno/network/p2p/P2PService.java b/p2p/src/main/java/haveno/network/p2p/P2PService.java index c517dc86bc..117ed4a494 100644 --- a/p2p/src/main/java/haveno/network/p2p/P2PService.java +++ b/p2p/src/main/java/haveno/network/p2p/P2PService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; @@ -57,6 +57,8 @@ import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleIntegerProperty; import lombok.Getter; + +import org.apache.commons.lang3.exception.ExceptionUtils; import org.fxmisc.easybind.EasyBind; import org.fxmisc.easybind.Subscription; import org.fxmisc.easybind.monadic.MonadicBinding; @@ -189,6 +191,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis } private void doShutDown() { + log.info("P2PService doShutDown started"); if (p2PDataStorage != null) { p2PDataStorage.shutDown(); @@ -298,7 +301,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis @Override public void onUpdatedDataReceived() { - applyIsBootstrapped(P2PServiceListener::onUpdatedDataReceived); + p2pServiceListeners.forEach(P2PServiceListener::onUpdatedDataReceived); } @Override @@ -313,7 +316,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis @Override public void onDataReceived() { - p2pServiceListeners.forEach(P2PServiceListener::onDataReceived); + applyIsBootstrapped(P2PServiceListener::onDataReceived); + } private void applyIsBootstrapped(Consumer<P2PServiceListener> listenerHandler) { @@ -382,12 +386,16 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis // DirectMessages /////////////////////////////////////////////////////////////////////////////////////////// - // TODO OfferAvailabilityResponse is called twice! public void sendEncryptedDirectMessage(NodeAddress peerNodeAddress, PubKeyRing pubKeyRing, NetworkEnvelope message, SendDirectMessageListener sendDirectMessageListener) { + sendEncryptedDirectMessage(peerNodeAddress, pubKeyRing, message, sendDirectMessageListener, null); + } + + public void sendEncryptedDirectMessage(NodeAddress peerNodeAddress, PubKeyRing pubKeyRing, NetworkEnvelope message, + SendDirectMessageListener sendDirectMessageListener, Integer timeoutSeconds) { checkNotNull(peerNodeAddress, "PeerAddress must not be null (sendEncryptedDirectMessage)"); if (isBootstrapped()) { - doSendEncryptedDirectMessage(peerNodeAddress, pubKeyRing, message, sendDirectMessageListener); + doSendEncryptedDirectMessage(peerNodeAddress, pubKeyRing, message, sendDirectMessageListener, timeoutSeconds); } else { throw new NetworkNotReadyException(); } @@ -396,7 +404,8 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis private void doSendEncryptedDirectMessage(@NotNull NodeAddress peersNodeAddress, PubKeyRing pubKeyRing, NetworkEnvelope message, - SendDirectMessageListener sendDirectMessageListener) { + SendDirectMessageListener sendDirectMessageListener, + Integer timeoutSeconds) { log.debug("Send encrypted direct message {} to peer {}", message.getClass().getSimpleName(), peersNodeAddress); @@ -417,7 +426,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis networkNode.getNodeAddress(), encryptionService.encryptAndSign(pubKeyRing, message)); - SettableFuture<Connection> future = networkNode.sendMessage(peersNodeAddress, sealedMsg); + SettableFuture<Connection> future = networkNode.sendMessage(peersNodeAddress, sealedMsg, timeoutSeconds); Futures.addCallback(future, new FutureCallback<>() { @Override public void onSuccess(@Nullable Connection connection) { @@ -426,15 +435,12 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis @Override public void onFailure(@NotNull Throwable throwable) { - log.error(throwable.toString()); - throwable.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(throwable)); sendDirectMessageListener.onFault(throwable.toString()); } }, MoreExecutors.directExecutor()); } catch (CryptoException e) { - e.printStackTrace(); - log.error(message.toString()); - log.error(e.toString()); + log.error("Error sending encrypted direct message, message={}, error={}\n", message.toString(), e.getMessage(), e); sendDirectMessageListener.onFault(e.toString()); } } @@ -557,6 +563,7 @@ public class P2PService implements SetupListener, MessageListener, ConnectionLis return keyRing; } + // TODO: this is unreliable and unused, because peer sometimes reports no TRADE_STATISTICS_3 capability, causing valid trades to be unpublished public Optional<Capabilities> findPeersCapabilities(NodeAddress peer) { return networkNode.getConfirmedConnections().stream() .filter(e -> e.getPeersNodeAddressOptional().isPresent()) diff --git a/p2p/src/main/java/haveno/network/p2p/P2PServiceListener.java b/p2p/src/main/java/haveno/network/p2p/P2PServiceListener.java index da97654d02..dd82d6a76c 100644 --- a/p2p/src/main/java/haveno/network/p2p/P2PServiceListener.java +++ b/p2p/src/main/java/haveno/network/p2p/P2PServiceListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/PrefixedSealedAndSignedMessage.java b/p2p/src/main/java/haveno/network/p2p/PrefixedSealedAndSignedMessage.java index 5fc38f49cd..ff3d4d3e1e 100644 --- a/p2p/src/main/java/haveno/network/p2p/PrefixedSealedAndSignedMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/PrefixedSealedAndSignedMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/SendDirectMessageListener.java b/p2p/src/main/java/haveno/network/p2p/SendDirectMessageListener.java index bf25c76806..9baede4fc1 100644 --- a/p2p/src/main/java/haveno/network/p2p/SendDirectMessageListener.java +++ b/p2p/src/main/java/haveno/network/p2p/SendDirectMessageListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/SendMailboxMessageListener.java b/p2p/src/main/java/haveno/network/p2p/SendMailboxMessageListener.java index b73bf43e13..bbf819c089 100644 --- a/p2p/src/main/java/haveno/network/p2p/SendMailboxMessageListener.java +++ b/p2p/src/main/java/haveno/network/p2p/SendMailboxMessageListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/SendersNodeAddressMessage.java b/p2p/src/main/java/haveno/network/p2p/SendersNodeAddressMessage.java index 03ac17f86f..a4e384d3ac 100644 --- a/p2p/src/main/java/haveno/network/p2p/SendersNodeAddressMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/SendersNodeAddressMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/SupportedCapabilitiesMessage.java b/p2p/src/main/java/haveno/network/p2p/SupportedCapabilitiesMessage.java index b8823fddad..d3aa057f64 100644 --- a/p2p/src/main/java/haveno/network/p2p/SupportedCapabilitiesMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/SupportedCapabilitiesMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/UidMessage.java b/p2p/src/main/java/haveno/network/p2p/UidMessage.java index c88756fe9e..69c6e04376 100644 --- a/p2p/src/main/java/haveno/network/p2p/UidMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/UidMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxMap.java b/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxMap.java index b21ff71beb..8df1af0955 100644 --- a/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxMap.java +++ b/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxMap.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mailbox; diff --git a/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxService.java b/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxService.java index 7d6fd9292b..45f5eaed7a 100644 --- a/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxService.java +++ b/p2p/src/main/java/haveno/network/p2p/mailbox/IgnoredMailboxService.java @@ -1,29 +1,28 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mailbox; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.persistence.PersistenceManager; import haveno.common.proto.persistable.PersistedDataHost; import haveno.network.p2p.storage.payload.MailboxStoragePayload; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * We persist failed attempts to decrypt mailbox messages (expected if mailbox message was not addressed to us). * This improves performance at processing mailbox messages. diff --git a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxItem.java b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxItem.java index b56eeeddbe..2f97055fc6 100644 --- a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxItem.java +++ b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxItem.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mailbox; diff --git a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessage.java b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessage.java index 0203cffa5b..08499925f0 100644 --- a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mailbox; diff --git a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageList.java b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageList.java index 3d3d1d0c72..451d3e7e7f 100644 --- a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageList.java +++ b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mailbox; @@ -63,8 +63,7 @@ public class MailboxMessageList extends PersistableList<MailboxItem> { try { return MailboxItem.fromProto(e, networkProtoResolver); } catch (ProtobufferException protobufferException) { - protobufferException.printStackTrace(); - log.error("Error at MailboxItem.fromProto: {}", protobufferException.toString()); + log.error("Error at MailboxItem.fromProto: {}", protobufferException.toString(), protobufferException); return null; } }) diff --git a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageService.java b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageService.java index 5249a7caf2..c447b3fccf 100644 --- a/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageService.java +++ b/p2p/src/main/java/haveno/network/p2p/mailbox/MailboxMessageService.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -18,10 +35,15 @@ package haveno.network.p2p.mailbox; import com.google.common.base.Joiner; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.google.inject.name.Named; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.common.crypto.CryptoException; @@ -53,13 +75,6 @@ import haveno.network.p2p.storage.payload.MailboxStoragePayload; import haveno.network.p2p.storage.payload.ProtectedMailboxStorageEntry; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; import haveno.network.utils.CapabilityUtils; -import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; import java.security.PublicKey; import java.time.Clock; import java.util.ArrayDeque; @@ -78,9 +93,9 @@ import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; +import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.NotNull; /** * Responsible for handling of mailbox messages. @@ -104,6 +119,7 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j public class MailboxMessageService implements HashMapChangedListener, PersistedDataHost { private static final long REPUBLISH_DELAY_SEC = TimeUnit.MINUTES.toSeconds(2); + private static final long MAX_SERIALIZED_SIZE = 50000; private final NetworkNode networkNode; private final PeerManager peerManager; @@ -122,6 +138,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD private boolean isBootstrapped; private boolean allServicesInitialized; private boolean initAfterBootstrapped; + private static Comparator<MailboxMessage> mailboxMessageComparator; @Inject public MailboxMessageService(NetworkNode networkNode, @@ -180,10 +197,12 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD // persisted data the messages, they would add those again and distribute then later at requests to peers. // Those outdated messages would then stay in the network until TTL triggers removal. // By not applying large messages we reduce the impact of such cases at costs of extra loading costs if the message is still alive. - if (serializedSize < 20000) { - mailboxItemsByUid.put(mailboxItem.getUid(), mailboxItem); - mailboxMessageList.add(mailboxItem); - totalSize.getAndAdd(serializedSize); + if (serializedSize < MAX_SERIALIZED_SIZE) { + synchronized (mailboxMessageList) { + mailboxItemsByUid.put(mailboxItem.getUid(), mailboxItem); + mailboxMessageList.add(mailboxItem); + totalSize.getAndAdd(serializedSize); + } // We add it to our map so that it get added to the excluded key set we send for // the initial data requests. So that helps to lower the load for mailbox messages at @@ -316,8 +335,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD } }, MoreExecutors.directExecutor()); } catch (CryptoException e) { - log.error("sendEncryptedMessage failed"); - e.printStackTrace(); + log.error("sendEncryptedMessage failed: {}\n", e.getMessage(), e); sendMailboxMessageListener.onFault("sendEncryptedMailboxMessage failed " + e); } } @@ -329,9 +347,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD */ public void removeMailboxMsg(MailboxMessage mailboxMessage) { if (isBootstrapped) { - // We need to delay a bit to not get a ConcurrentModificationException as we might iterate over - // mailboxMessageList while getting called. - UserThread.execute(() -> { + synchronized (mailboxMessageList) { String uid = mailboxMessage.getUid(); if (!mailboxItemsByUid.containsKey(uid)) { return; @@ -348,7 +364,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD // call removeMailboxItemFromMap here. The onRemoved only removes foreign mailBoxMessages. log.trace("## removeMailboxMsg uid={}", uid); removeMailboxItemFromLocalStore(uid); - }); + } } else { // In case the network was not ready yet we try again later UserThread.runAfter(() -> removeMailboxMsg(mailboxMessage), 30); @@ -396,7 +412,24 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD .forEach(this::removeMailboxItemFromLocalStore); } + public static void setMailboxMessageComparator(Comparator<MailboxMessage> comparator) { + mailboxMessageComparator = comparator; + } + public static class DecryptedMessageWithPubKeyComparator implements Comparator<DecryptedMessageWithPubKey> { + + @Override + public int compare(DecryptedMessageWithPubKey m1, DecryptedMessageWithPubKey m2) { + if (m1.getNetworkEnvelope() instanceof MailboxMessage) { + if (m2.getNetworkEnvelope() instanceof MailboxMessage) return mailboxMessageComparator.compare((MailboxMessage) m1.getNetworkEnvelope(), (MailboxMessage) m2.getNetworkEnvelope()); + else return 1; + } else { + return m2.getNetworkEnvelope() instanceof MailboxMessage ? -1 : 0; + } + } + } + + /////////////////////////////////////////////////////////////////////////////////////////// // Private /////////////////////////////////////////////////////////////////////////////////////////// @@ -428,7 +461,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD Futures.addCallback(future, new FutureCallback<>() { public void onSuccess(Set<MailboxItem> decryptedMailboxMessageWithEntries) { - UserThread.execute(() -> decryptedMailboxMessageWithEntries.forEach(e -> handleMailboxItem(e))); + new Thread(() -> handleMailboxItems(decryptedMailboxMessageWithEntries)).start(); } public void onFailure(@NotNull Throwable throwable) { @@ -470,16 +503,42 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD return new MailboxItem(protectedMailboxStorageEntry, null); } + private void handleMailboxItems(Set<MailboxItem> mailboxItems) { + + // sort mailbox items + List<MailboxItem> mailboxItemsSorted = mailboxItems.stream() + .filter(e -> !e.isMine()) + .collect(Collectors.toList()); + mailboxItemsSorted.addAll(mailboxItems.stream() + .filter(e -> e.isMine()) + .sorted(new MailboxItemComparator()) + .collect(Collectors.toList())); + + // handle mailbox items + mailboxItemsSorted.forEach(e -> handleMailboxItem(e)); + } + + private static class MailboxItemComparator implements Comparator<MailboxItem> { + private DecryptedMessageWithPubKeyComparator comparator = new DecryptedMessageWithPubKeyComparator(); + + @Override + public int compare(MailboxItem m1, MailboxItem m2) { + return comparator.compare(m1.getDecryptedMessageWithPubKey(), m2.getDecryptedMessageWithPubKey()); + } + } + private void handleMailboxItem(MailboxItem mailboxItem) { String uid = mailboxItem.getUid(); - if (!mailboxItemsByUid.containsKey(uid)) { - mailboxItemsByUid.put(uid, mailboxItem); - mailboxMessageList.add(mailboxItem); - log.trace("## handleMailboxItem uid={}\nhash={}", - uid, - P2PDataStorage.get32ByteHashAsByteArray(mailboxItem.getProtectedMailboxStorageEntry().getProtectedStoragePayload())); + synchronized (mailboxMessageList) { + if (!mailboxItemsByUid.containsKey(uid)) { + mailboxItemsByUid.put(uid, mailboxItem); + mailboxMessageList.add(mailboxItem); + log.trace("## handleMailboxItem uid={}\nhash={}", + uid, + P2PDataStorage.get32ByteHashAsByteArray(mailboxItem.getProtectedMailboxStorageEntry().getProtectedStoragePayload())); - requestPersistence(); + requestPersistence(); + } } // In case we had the item already stored we still prefer to apply it again to the domain. @@ -584,8 +643,7 @@ public class MailboxMessageService implements HashMapChangedListener, PersistedD log.info("The mailboxEntry was already removed earlier."); } } catch (CryptoException e) { - e.printStackTrace(); - log.error("Could not remove ProtectedMailboxStorageEntry from network. Error: {}", e.toString()); + log.error("Could not remove ProtectedMailboxStorageEntry from network. Error: {}\n", e.toString(), e); } } diff --git a/p2p/src/main/java/haveno/network/p2p/messaging/DecryptedMailboxListener.java b/p2p/src/main/java/haveno/network/p2p/messaging/DecryptedMailboxListener.java index 225468c892..196633faf1 100644 --- a/p2p/src/main/java/haveno/network/p2p/messaging/DecryptedMailboxListener.java +++ b/p2p/src/main/java/haveno/network/p2p/messaging/DecryptedMailboxListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.messaging; diff --git a/p2p/src/main/java/haveno/network/p2p/network/BanFilter.java b/p2p/src/main/java/haveno/network/p2p/network/BanFilter.java index 0c1b2dea99..86c63153df 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/BanFilter.java +++ b/p2p/src/main/java/haveno/network/p2p/network/BanFilter.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/BridgeAddressProvider.java b/p2p/src/main/java/haveno/network/p2p/network/BridgeAddressProvider.java index 65dfb47d2c..f2dba22e19 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/BridgeAddressProvider.java +++ b/p2p/src/main/java/haveno/network/p2p/network/BridgeAddressProvider.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/CloseConnectionReason.java b/p2p/src/main/java/haveno/network/p2p/network/CloseConnectionReason.java index 3db04c29f3..4e7afa967d 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/CloseConnectionReason.java +++ b/p2p/src/main/java/haveno/network/p2p/network/CloseConnectionReason.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -44,7 +44,7 @@ public enum CloseConnectionReason { // illegal requests RULE_VIOLATION(true, false), - PEER_BANNED(true, false), + PEER_BANNED(false, false), INVALID_CLASS_RECEIVED(false, false), MANDATORY_CAPABILITIES_NOT_SUPPORTED(false, false); diff --git a/p2p/src/main/java/haveno/network/p2p/network/Connection.java b/p2p/src/main/java/haveno/network/p2p/network/Connection.java index bd887e2cc1..8165ecd0b3 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/Connection.java +++ b/p2p/src/main/java/haveno/network/p2p/network/Connection.java @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -17,6 +34,22 @@ package haveno.network.p2p.network; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.util.concurrent.Uninterruptibles; +import com.google.inject.Inject; +import com.google.protobuf.InvalidProtocolBufferException; +import haveno.common.Proto; +import haveno.common.ThreadUtils; +import haveno.common.app.Capabilities; +import haveno.common.app.HasCapabilities; +import haveno.common.app.Version; +import haveno.common.config.Config; +import haveno.common.proto.ProtobufferException; +import haveno.common.proto.network.NetworkEnvelope; +import haveno.common.proto.network.NetworkProtoResolver; +import haveno.common.util.SingleThreadExecutorUtils; +import haveno.common.util.Utilities; import haveno.network.p2p.BundleOfEnvelopes; import haveno.network.p2p.CloseConnectionMessage; import haveno.network.p2p.ExtendedDataSizePermission; @@ -30,39 +63,16 @@ import haveno.network.p2p.storage.messages.AddPersistableNetworkPayloadMessage; import haveno.network.p2p.storage.messages.RemoveDataMessage; import haveno.network.p2p.storage.payload.CapabilityRequiringPayload; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; - -import haveno.common.Proto; -import haveno.common.UserThread; -import haveno.common.app.Capabilities; -import haveno.common.app.HasCapabilities; -import haveno.common.app.Version; -import haveno.common.config.Config; -import haveno.common.proto.ProtobufferException; -import haveno.common.proto.network.NetworkEnvelope; -import haveno.common.proto.network.NetworkProtoResolver; -import haveno.common.util.SingleThreadExecutorUtils; -import haveno.common.util.Utilities; - -import com.google.protobuf.InvalidProtocolBufferException; - -import javax.inject.Inject; - -import com.google.common.util.concurrent.Uninterruptibles; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; - -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; - import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.InvalidClassException; import java.io.OptionalDataException; import java.io.StreamCorruptedException; - +import java.lang.ref.WeakReference; +import java.net.Socket; +import java.net.SocketException; +import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -77,17 +87,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.stream.Collectors; - -import java.lang.ref.WeakReference; - +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.jetbrains.annotations.Nullable; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - /** * Connection is created by the server thread or by sendMessage from NetworkNode. * All handlers are called on User thread. @@ -109,6 +116,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { //TODO decrease limits again after testing private static final int SOCKET_TIMEOUT = (int) TimeUnit.SECONDS.toMillis(240); private static final int SHUTDOWN_TIMEOUT = 100; + private static final String THREAD_ID = Connection.class.getSimpleName(); public static int getPermittedMessageSize() { return PERMITTED_MESSAGE_SIZE; @@ -164,16 +172,23 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { private final Capabilities capabilities = new Capabilities(); + // throttle logs of reported invalid requests + private static final long LOG_THROTTLE_INTERVAL_MS = 30000; // throttle logging rule violations and warnings to once every 30 seconds + private static long lastLoggedInvalidRequestReportTs = 0; + private static int numThrottledInvalidRequestReports = 0; + private static long lastLoggedWarningTs = 0; + private static int numThrottledWarnings = 0; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////////////////////////////////////// Connection(Socket socket, - MessageListener messageListener, - ConnectionListener connectionListener, - @Nullable NodeAddress peersNodeAddress, - NetworkProtoResolver networkProtoResolver, - @Nullable BanFilter banFilter) { + MessageListener messageListener, + ConnectionListener connectionListener, + @Nullable NodeAddress peersNodeAddress, + NetworkProtoResolver networkProtoResolver, + @Nullable BanFilter banFilter) { this.socket = socket; this.connectionListener = connectionListener; this.banFilter = banFilter; @@ -199,7 +214,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { // When you construct an ObjectInputStream, in the constructor the class attempts to read a header that // the associated ObjectOutputStream on the other end of the connection has written. // It will not return until that header has been read. - protoOutputStream = new SynchronizedProtoOutputStream(socket.getOutputStream(), statistic); + protoOutputStream = new ProtoOutputStream(socket.getOutputStream(), statistic); protoInputStream = socket.getInputStream(); // We create a thread for handling inputStream data executorService.submit(this); @@ -207,11 +222,10 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (peersNodeAddress != null) { setPeersNodeAddress(peersNodeAddress); if (banFilter != null && banFilter.isPeerBanned(peersNodeAddress)) { - log.warn("We created an outbound connection with a banned peer"); - reportInvalidRequest(RuleViolation.PEER_BANNED); + reportInvalidRequest(RuleViolation.PEER_BANNED, "We created an outbound connection with a banned peer"); } } - UserThread.execute(() -> connectionListener.onConnection(this)); + ThreadUtils.execute(() -> connectionListener.onConnection(this), THREAD_ID); } catch (Throwable e) { handleException(e); } @@ -238,9 +252,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (banFilter != null && peersNodeAddressOptional.isPresent() && banFilter.isPeerBanned(peersNodeAddressOptional.get())) { - log.warn("We tried to send a message to a banned peer. message={}", - networkEnvelope.getClass().getSimpleName()); - reportInvalidRequest(RuleViolation.PEER_BANNED); + String errorMessage = "We tried to send a message to a banned peer. message=" + networkEnvelope.getClass().getSimpleName(); + reportInvalidRequest(RuleViolation.PEER_BANNED, errorMessage); return; } @@ -255,7 +268,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { long elapsed = now - lastSendTimeStamp; if (elapsed < getSendMsgThrottleTrigger()) { log.debug("We got 2 sendMessage requests in less than {} ms. We set the thread to sleep " + - "for {} ms to avoid flooding our peer. lastSendTimeStamp={}, now={}, elapsed={}, networkEnvelope={}", + "for {} ms to avoid flooding our peer. lastSendTimeStamp={}, now={}, elapsed={}, networkEnvelope={}", getSendMsgThrottleTrigger(), getSendMsgThrottleSleep(), lastSendTimeStamp, now, elapsed, networkEnvelope.getClass().getSimpleName()); @@ -266,8 +279,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (!stopped) { protoOutputStream.writeEnvelope(networkEnvelope); - UserThread.execute(() -> messageListeners.forEach(e -> e.onMessageSent(networkEnvelope, this))); - UserThread.execute(() -> connectionStatistics.addSendMsgMetrics(System.currentTimeMillis() - ts, networkEnvelopeSize)); + ThreadUtils.execute(() -> messageListeners.forEach(e -> e.onMessageSent(networkEnvelope, this)), THREAD_ID); + ThreadUtils.execute(() -> connectionStatistics.addSendMsgMetrics(System.currentTimeMillis() - ts, networkEnvelopeSize), THREAD_ID); } } catch (Throwable t) { handleException(t); @@ -396,7 +409,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (networkEnvelope instanceof BundleOfEnvelopes) { onBundleOfEnvelopes((BundleOfEnvelopes) networkEnvelope, connection); } else { - UserThread.execute(() -> messageListeners.forEach(e -> e.onMessage(networkEnvelope, connection))); + ThreadUtils.execute(() -> messageListeners.forEach(e -> e.onMessage(networkEnvelope, connection)), THREAD_ID); } } @@ -409,7 +422,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (networkEnvelope instanceof SendersNodeAddressMessage) { boolean isValid = processSendersNodeAddressMessage((SendersNodeAddressMessage) networkEnvelope); if (!isValid) { - log.warn("Received an invalid {} at processing BundleOfEnvelopes", networkEnvelope.getClass().getSimpleName()); + throttleWarn("Received an invalid " + networkEnvelope.getClass().getSimpleName() + " at processing BundleOfEnvelopes"); continue; } } @@ -432,10 +445,12 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { envelopesToProcess.add(networkEnvelope); } } - envelopesToProcess.forEach(envelope -> UserThread.execute(() -> - messageListeners.forEach(listener -> listener.onMessage(envelope, connection)))); + envelopesToProcess.forEach(envelope -> ThreadUtils.execute(() -> { + messageListeners.forEach(listener -> listener.onMessage(envelope, connection)); + }, THREAD_ID)); } + /////////////////////////////////////////////////////////////////////////////////////////// // Setters /////////////////////////////////////////////////////////////////////////////////////////// @@ -455,6 +470,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { peersNodeAddressProperty.set(peerNodeAddress); } + /////////////////////////////////////////////////////////////////////////////////////////// // Getters /////////////////////////////////////////////////////////////////////////////////////////// @@ -497,11 +513,10 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { Uninterruptibles.sleepUninterruptibly(200, TimeUnit.MILLISECONDS); } catch (Throwable t) { - log.error(t.getMessage()); - t.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(t)); } finally { stopped = true; - UserThread.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler)); + ThreadUtils.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler), THREAD_ID); } }, "Connection:SendCloseConnectionMessage-" + this.uid).start(); } else { @@ -511,37 +526,33 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { } else { //TODO find out why we get called that log.debug("stopped was already at shutDown call"); - UserThread.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler)); + ThreadUtils.execute(() -> doShutDown(closeConnectionReason, shutDownCompleteHandler), THREAD_ID); } } private void doShutDown(CloseConnectionReason closeConnectionReason, @Nullable Runnable shutDownCompleteHandler) { - // Use UserThread.execute as it's not clear if that is called from a non-UserThread - UserThread.execute(() -> connectionListener.onDisconnect(closeConnectionReason, this)); + ThreadUtils.execute(() -> connectionListener.onDisconnect(closeConnectionReason, this), THREAD_ID); try { protoOutputStream.onConnectionShutdown(); socket.close(); } catch (SocketException e) { log.trace("SocketException at shutdown might be expected {}", e.getMessage()); } catch (IOException e) { - log.error("Exception at shutdown. " + e.getMessage()); - e.printStackTrace(); + log.error("Exception at shutdown. {}\n", e.getMessage(), e); } finally { capabilitiesListeners.clear(); try { protoInputStream.close(); } catch (IOException e) { - log.error(e.getMessage()); - e.printStackTrace(); + log.error(ExceptionUtils.getStackTrace(e)); } Utilities.shutdownAndAwaitTermination(executorService, SHUTDOWN_TIMEOUT, TimeUnit.MILLISECONDS); log.debug("Connection shutdown complete {}", this); - // Use UserThread.execute as it's not clear if that is called from a non-UserThread if (shutDownCompleteHandler != null) - UserThread.execute(shutDownCompleteHandler); + ThreadUtils.execute(shutDownCompleteHandler, THREAD_ID); } } @@ -599,37 +610,56 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { * Runs in same thread as Connection */ - public boolean reportInvalidRequest(RuleViolation ruleViolation) { - log.info("We got reported the ruleViolation {} at connection with address{} and uid {}", ruleViolation, this.getPeersNodeAddressProperty(), this.getUid()); + public boolean reportInvalidRequest(RuleViolation ruleViolation, String errorMessage) { + return Connection.reportInvalidRequest(this, ruleViolation, errorMessage); + } + + private static synchronized boolean reportInvalidRequest(Connection connection, RuleViolation ruleViolation, String errorMessage) { + + // determine if report should be logged to avoid spamming the logs + boolean logReport = System.currentTimeMillis() - lastLoggedInvalidRequestReportTs > LOG_THROTTLE_INTERVAL_MS; + + // count the number of unlogged reports since last log entry + if (!logReport) numThrottledInvalidRequestReports++; + + // handle report + if (logReport) log.warn("We got reported the ruleViolation {} at connection with address={}, uid={}, errorMessage={}", ruleViolation, connection.getPeersNodeAddressProperty(), connection.getUid(), errorMessage); int numRuleViolations; - numRuleViolations = ruleViolations.getOrDefault(ruleViolation, 0); - + numRuleViolations = connection.ruleViolations.getOrDefault(ruleViolation, 0); numRuleViolations++; - ruleViolations.put(ruleViolation, numRuleViolations); - + connection.ruleViolations.put(ruleViolation, numRuleViolations); if (numRuleViolations >= ruleViolation.maxTolerance) { - log.warn("We close connection as we received too many corrupt requests. " + + if (logReport) log.warn("We close connection as we received too many corrupt requests. " + "ruleViolations={} " + - "connection with address{} and uid {}", ruleViolations, peersNodeAddressProperty, uid); - this.ruleViolation = ruleViolation; + "connection with address {} and uid {}", connection.ruleViolations, connection.peersNodeAddressProperty, connection.uid); + connection.ruleViolation = ruleViolation; if (ruleViolation == RuleViolation.PEER_BANNED) { - log.debug("We close connection due RuleViolation.PEER_BANNED. peersNodeAddress={}", - getPeersNodeAddressOptional()); - shutDown(CloseConnectionReason.PEER_BANNED); + if (logReport) log.debug("We close connection due RuleViolation.PEER_BANNED. peersNodeAddress={}", connection.getPeersNodeAddressOptional()); + connection.shutDown(CloseConnectionReason.PEER_BANNED); } else if (ruleViolation == RuleViolation.INVALID_CLASS) { - log.warn("We close connection due RuleViolation.INVALID_CLASS"); - shutDown(CloseConnectionReason.INVALID_CLASS_RECEIVED); + if (logReport) log.warn("We close connection due RuleViolation.INVALID_CLASS"); + connection.shutDown(CloseConnectionReason.INVALID_CLASS_RECEIVED); } else { - log.warn("We close connection due RuleViolation.RULE_VIOLATION"); - shutDown(CloseConnectionReason.RULE_VIOLATION); + if (logReport) log.warn("We close connection due RuleViolation.RULE_VIOLATION"); + connection.shutDown(CloseConnectionReason.RULE_VIOLATION); } + resetReportedInvalidRequestsThrottle(logReport); return true; } else { + resetReportedInvalidRequestsThrottle(logReport); return false; } } + private static synchronized void resetReportedInvalidRequestsThrottle(boolean logReport) { + if (logReport) { + if (numThrottledInvalidRequestReports > 0) log.warn("We received {} other reports of invalid requests since the last log entry", numThrottledInvalidRequestReports); + numThrottledInvalidRequestReports = 0; + lastLoggedInvalidRequestReportTs = System.currentTimeMillis(); + } + } + private void handleException(Throwable e) { CloseConnectionReason closeConnectionReason; @@ -643,25 +673,22 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { else closeConnectionReason = CloseConnectionReason.RESET; - log.info("SocketException (expected if connection lost). closeConnectionReason={}; connection={}", closeConnectionReason, this); + throttleWarn("SocketException (expected if connection lost). closeConnectionReason=" + closeConnectionReason + "; connection=" + this); } else if (e instanceof SocketTimeoutException || e instanceof TimeoutException) { closeConnectionReason = CloseConnectionReason.SOCKET_TIMEOUT; - log.info("Shut down caused by exception {} on connection={}", e, this); + throttleWarn("Shut down caused by exception " + e.getMessage() + " on connection=" + this); } else if (e instanceof EOFException) { closeConnectionReason = CloseConnectionReason.TERMINATED; - log.warn("Shut down caused by exception {} on connection={}", e, this); + throttleWarn("Shut down caused by exception " + e.getMessage() + " on connection=" + this); } else if (e instanceof OptionalDataException || e instanceof StreamCorruptedException) { closeConnectionReason = CloseConnectionReason.CORRUPTED_DATA; - log.warn("Shut down caused by exception {} on connection={}", e, this); + throttleWarn("Shut down caused by exception " + e.getMessage() + " on connection=" + this); } else { // TODO sometimes we get StreamCorruptedException, OptionalDataException, IllegalStateException closeConnectionReason = CloseConnectionReason.UNKNOWN_EXCEPTION; - log.warn("Unknown reason for exception at socket: {}\n\t" + - "peer={}\n\t" + - "Exception={}", - socket.toString(), - this.peersNodeAddressOptional, - e.toString()); + throttleWarn("Unknown reason for exception at socket: " + socket.toString() + "\n\t" + + "peer=" + this.peersNodeAddressOptional + "\n\t" + + "Exception=" + e.toString()); } shutDown(closeConnectionReason); } @@ -682,8 +709,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { } if (banFilter != null && banFilter.isPeerBanned(senderNodeAddress)) { - log.warn("We got a message from a banned peer. message={}", sendersNodeAddressMessage.getClass().getSimpleName()); - reportInvalidRequest(RuleViolation.PEER_BANNED); + String errorMessage = "We got a message from a banned peer. message=" + sendersNodeAddressMessage.getClass().getSimpleName(); + reportInvalidRequest(RuleViolation.PEER_BANNED, errorMessage); return false; } @@ -715,7 +742,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { try { if (socket != null && socket.isClosed()) { - log.warn("Socket is null or closed socket={}", socket); + throttleWarn("Socket is null or closed socket=" + socket); shutDown(CloseConnectionReason.SOCKET_CLOSED); return; } @@ -727,7 +754,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (socket != null && socket.isClosed()) { - log.warn("Socket is null or closed socket={}", socket); + throttleWarn("Socket is null or closed socket=" + socket); shutDown(CloseConnectionReason.SOCKET_CLOSED); return; } @@ -737,9 +764,9 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { return; } if (protoInputStream.read() == -1) { - log.warn("proto is null because protoInputStream.read()=-1 (EOF). That is expected if client got stopped without proper shutdown."); + throttleWarn("proto is null because protoInputStream.read()=-1 (EOF). That is expected if client got stopped without proper shutdown."); } else { - log.warn("proto is null. protoInputStream.read()=" + protoInputStream.read()); + throttleWarn("proto is null. protoInputStream.read()=" + protoInputStream.read()); } shutDown(CloseConnectionReason.NO_PROTO_BUFFER_ENV); return; @@ -748,8 +775,8 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (banFilter != null && peersNodeAddressOptional.isPresent() && banFilter.isPeerBanned(peersNodeAddressOptional.get())) { - log.warn("We got a message from a banned peer. proto={}", Utilities.toTruncatedString(proto)); - reportInvalidRequest(RuleViolation.PEER_BANNED); + String errorMessage = "We got a message from a banned peer. proto=" + Utilities.toTruncatedString(proto); + reportInvalidRequest(RuleViolation.PEER_BANNED, errorMessage); return; } @@ -758,7 +785,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { long elapsed = now - lastReadTimeStamp; if (elapsed < 10) { log.debug("We got 2 network messages received in less than 10 ms. We set the thread to sleep " + - "for 20 ms to avoid getting flooded by our peer. lastReadTimeStamp={}, now={}, elapsed={}", + "for 20 ms to avoid getting flooded by our peer. lastReadTimeStamp={}, now={}, elapsed={}", lastReadTimeStamp, now, elapsed); Thread.sleep(20); } @@ -784,30 +811,28 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (networkEnvelope instanceof AddPersistableNetworkPayloadMessage && !((AddPersistableNetworkPayloadMessage) networkEnvelope).getPersistableNetworkPayload().verifyHashSize()) { - log.warn("PersistableNetworkPayload.verifyHashSize failed. hashSize={}; object={}", - ((AddPersistableNetworkPayloadMessage) networkEnvelope).getPersistableNetworkPayload().getHash().length, - Utilities.toTruncatedString(proto)); - if (reportInvalidRequest(RuleViolation.MAX_MSG_SIZE_EXCEEDED)) + String errorMessage = "PersistableNetworkPayload.verifyHashSize failed. hashSize=" + + ((AddPersistableNetworkPayloadMessage) networkEnvelope).getPersistableNetworkPayload().getHash().length + "; object=" + + Utilities.toTruncatedString(proto); + if (reportInvalidRequest(RuleViolation.MAX_MSG_SIZE_EXCEEDED, errorMessage)) return; } if (exceeds) { - log.warn("size > MAX_MSG_SIZE. size={}; object={}", size, Utilities.toTruncatedString(proto)); - - if (reportInvalidRequest(RuleViolation.MAX_MSG_SIZE_EXCEEDED)) + String errorMessage = "size > MAX_MSG_SIZE. size=" + size + "; object=" + Utilities.toTruncatedString(proto); + if (reportInvalidRequest(RuleViolation.MAX_MSG_SIZE_EXCEEDED, errorMessage)) return; } - if (violatesThrottleLimit() && reportInvalidRequest(RuleViolation.THROTTLE_LIMIT_EXCEEDED)) + if (violatesThrottleLimit() && reportInvalidRequest(RuleViolation.THROTTLE_LIMIT_EXCEEDED, "Violates throttle limit")) return; // Check P2P network ID + String errorMessage = "RuleViolation.WRONG_NETWORK_ID. version of message=" + proto.getMessageVersion() + + ", app version=" + Version.getP2PMessageVersion() + + ", proto.toTruncatedString=" + Utilities.toTruncatedString(proto.toString()); if (!proto.getMessageVersion().equals(Version.getP2PMessageVersion()) - && reportInvalidRequest(RuleViolation.WRONG_NETWORK_ID)) { - log.warn("RuleViolation.WRONG_NETWORK_ID. version of message={}, app version={}, " + - "proto.toTruncatedString={}", proto.getMessageVersion(), - Version.getP2PMessageVersion(), - Utilities.toTruncatedString(proto.toString())); + && reportInvalidRequest(RuleViolation.WRONG_NETWORK_ID, errorMessage)) { return; } @@ -823,8 +848,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { if (CloseConnectionReason.PEER_BANNED.name().equals(proto.getCloseConnectionMessage().getReason())) { log.warn("We got shut down because we are banned by the other peer. " + - "(InputHandler.run CloseConnectionMessage). Peer: {}", - getPeersNodeAddressOptional()); + "(InputHandler.run CloseConnectionMessage). Peer: {}", getPeersNodeAddressOptional()); } shutDown(CloseConnectionReason.CLOSE_REQUESTED_BY_PEER); return; @@ -843,20 +867,16 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { } if (!(networkEnvelope instanceof SendersNodeAddressMessage) && peersNodeAddressOptional.isEmpty()) { - log.info("We got a {} from a peer with yet unknown address on connection with uid={}", - networkEnvelope.getClass().getSimpleName(), uid); + log.info("We got a {} from a peer with yet unknown address on connection with uid={}", networkEnvelope.getClass().getSimpleName(), uid); } - onMessage(networkEnvelope, this); - UserThread.execute(() -> connectionStatistics.addReceivedMsgMetrics(System.currentTimeMillis() - ts, size)); + ThreadUtils.execute(() -> onMessage(networkEnvelope, this), THREAD_ID); + ThreadUtils.execute(() -> connectionStatistics.addReceivedMsgMetrics(System.currentTimeMillis() - ts, size), THREAD_ID); } } catch (InvalidClassException e) { - log.error(e.getMessage()); - e.printStackTrace(); - reportInvalidRequest(RuleViolation.INVALID_CLASS); + reportInvalidRequest(RuleViolation.INVALID_CLASS, e.getMessage()); } catch (ProtobufferException | NoClassDefFoundError | InvalidProtocolBufferException e) { - log.error(e.getMessage()); - reportInvalidRequest(RuleViolation.INVALID_DATA_TYPE); + reportInvalidRequest(RuleViolation.INVALID_DATA_TYPE, e.getMessage()); } catch (Throwable t) { handleException(t); } @@ -897,7 +917,7 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { capabilitiesListeners.forEach(weakListener -> { SupportedCapabilitiesListener supportedCapabilitiesListener = weakListener.get(); if (supportedCapabilitiesListener != null) { - UserThread.execute(() -> supportedCapabilitiesListener.onChanged(supportedCapabilities)); + ThreadUtils.execute(() -> supportedCapabilitiesListener.onChanged(supportedCapabilities), THREAD_ID); } }); return false; @@ -915,4 +935,16 @@ public class Connection implements HasCapabilities, Runnable, MessageListener { NodeAddress nodeAddress = getSenderNodeAddress(networkEnvelope); return nodeAddress == null ? "null" : nodeAddress.getFullAddress(); } + + private synchronized void throttleWarn(String msg) { + boolean logWarning = System.currentTimeMillis() - lastLoggedWarningTs > LOG_THROTTLE_INTERVAL_MS; + if (logWarning) { + log.warn(msg); + if (numThrottledWarnings > 0) log.warn("{} warnings were throttled since the last log entry", numThrottledWarnings); + numThrottledWarnings = 0; + lastLoggedWarningTs = System.currentTimeMillis(); + } else { + numThrottledWarnings++; + } + } } diff --git a/p2p/src/main/java/haveno/network/p2p/network/ConnectionListener.java b/p2p/src/main/java/haveno/network/p2p/network/ConnectionListener.java index e433ef8b55..732efb462a 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/ConnectionListener.java +++ b/p2p/src/main/java/haveno/network/p2p/network/ConnectionListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/ConnectionState.java b/p2p/src/main/java/haveno/network/p2p/network/ConnectionState.java index 2b53073e0a..1e3add859c 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/ConnectionState.java +++ b/p2p/src/main/java/haveno/network/p2p/network/ConnectionState.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -47,6 +47,16 @@ public class ConnectionState implements MessageListener { @Setter private static int expectedRequests = 6; + // We have 2 GetDataResponses and 3 GetHashResponses. If node is a lite node it also has a GetBlocksResponse if + // blocks are missing. + private static final int MIN_EXPECTED_RESPONSES = 5; + private static int expectedInitialDataResponses = MIN_EXPECTED_RESPONSES; + + // If app runs in LiteNode mode there is one more expected request for the getBlocks request, so we increment standard value. + public static void incrementExpectedInitialDataResponses() { + expectedInitialDataResponses += 1; + } + private final Connection connection; @Getter @@ -121,7 +131,7 @@ public class ConnectionState implements MessageListener { } private void maybeResetInitialDataExchangeType() { - if (numInitialDataResponses >= expectedRequests) { + if (numInitialDataResponses >= expectedInitialDataResponses) { // We have received the expected messages from initial data requests. We delay a bit the reset // to give time for processing the response and more tolerance to edge cases where we expect more responses. // Reset to PEER does not mean disconnection as well, but just that this connection has lower priority and @@ -165,7 +175,7 @@ public class ConnectionState implements MessageListener { ",\n numInitialDataResponses=" + numInitialDataResponses + ",\n lastInitialDataMsgTimeStamp=" + lastInitialDataMsgTimeStamp + ",\n isSeedNode=" + isSeedNode + - ",\n expectedRequests=" + expectedRequests + + ",\n expectedInitialDataResponses=" + expectedInitialDataResponses + "\n}"; } } diff --git a/p2p/src/main/java/haveno/network/p2p/network/ConnectionStatistics.java b/p2p/src/main/java/haveno/network/p2p/network/ConnectionStatistics.java index e250f695a5..0a641b1945 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/ConnectionStatistics.java +++ b/p2p/src/main/java/haveno/network/p2p/network/ConnectionStatistics.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/DefaultPluggableTransports.java b/p2p/src/main/java/haveno/network/p2p/network/DefaultPluggableTransports.java index 700ad01779..7a709c9c26 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/DefaultPluggableTransports.java +++ b/p2p/src/main/java/haveno/network/p2p/network/DefaultPluggableTransports.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/DirectBindTor.java b/p2p/src/main/java/haveno/network/p2p/network/DirectBindTor.java new file mode 100644 index 0000000000..f890f9835a --- /dev/null +++ b/p2p/src/main/java/haveno/network/p2p/network/DirectBindTor.java @@ -0,0 +1,22 @@ +package haveno.network.p2p.network; + +import lombok.extern.slf4j.Slf4j; +import org.berndpruenster.netlayer.tor.Tor; + +@Slf4j +public class DirectBindTor extends TorMode { + + public DirectBindTor() { + super(null); + } + + @Override + public Tor getTor() { + return null; + } + + @Override + public String getHiddenServiceDirectory() { + return null; + } +} diff --git a/p2p/src/main/java/haveno/network/p2p/network/HavenoRuntimeException.java b/p2p/src/main/java/haveno/network/p2p/network/HavenoRuntimeException.java index 6225654bc9..a6b4adbbf9 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/HavenoRuntimeException.java +++ b/p2p/src/main/java/haveno/network/p2p/network/HavenoRuntimeException.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/InboundConnection.java b/p2p/src/main/java/haveno/network/p2p/network/InboundConnection.java index fc594ec999..5e923258e6 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/InboundConnection.java +++ b/p2p/src/main/java/haveno/network/p2p/network/InboundConnection.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/LocalhostNetworkNode.java b/p2p/src/main/java/haveno/network/p2p/network/LocalhostNetworkNode.java index 051f5e99bc..26005988e2 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/LocalhostNetworkNode.java +++ b/p2p/src/main/java/haveno/network/p2p/network/LocalhostNetworkNode.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -76,8 +76,7 @@ public class LocalhostNetworkNode extends NetworkNode { try { startServer(new ServerSocket(servicePort)); } catch (IOException e) { - e.printStackTrace(); - log.error("Exception at startServer: " + e.getMessage()); + log.error("Exception at startServer: {}\n", e.getMessage(), e); } setupListeners.stream().forEach(SetupListener::onHiddenServicePublished); }, simulateTorDelayTorNode, TimeUnit.MILLISECONDS); diff --git a/p2p/src/main/java/haveno/network/p2p/network/MessageListener.java b/p2p/src/main/java/haveno/network/p2p/network/MessageListener.java index 07cda27d8e..0ee8db23bd 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/MessageListener.java +++ b/p2p/src/main/java/haveno/network/p2p/network/MessageListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/NetworkNode.java b/p2p/src/main/java/haveno/network/p2p/network/NetworkNode.java index 16ad234127..f24fdf6f92 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/NetworkNode.java +++ b/p2p/src/main/java/haveno/network/p2p/network/NetworkNode.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -38,6 +38,7 @@ import com.google.common.util.concurrent.SettableFuture; import javafx.beans.property.ObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.SimpleObjectProperty; +import lombok.Getter; import java.net.ServerSocket; import java.net.Socket; @@ -48,6 +49,7 @@ import java.util.Date; import java.util.HashSet; import java.util.Optional; import java.util.Set; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; @@ -81,7 +83,8 @@ public abstract class NetworkNode implements MessageListener { private final ListeningExecutorService sendMessageExecutor; private Server server; - private volatile boolean shutDownInProgress; + @Getter + private volatile boolean isShutDownStarted; // accessed from different threads private final CopyOnWriteArraySet<OutboundConnection> outBoundConnections = new CopyOnWriteArraySet<>(); protected final ObjectProperty<NodeAddress> nodeAddressProperty = new SimpleObjectProperty<>(); @@ -120,6 +123,11 @@ public abstract class NetworkNode implements MessageListener { public SettableFuture<Connection> sendMessage(@NotNull NodeAddress peersNodeAddress, NetworkEnvelope networkEnvelope) { + return sendMessage(peersNodeAddress, networkEnvelope, null); + } + + public SettableFuture<Connection> sendMessage(@NotNull NodeAddress peersNodeAddress, + NetworkEnvelope networkEnvelope, Integer timeoutSeconds) { log.debug("Send {} to {}. Message details: {}", networkEnvelope.getClass().getSimpleName(), peersNodeAddress, Utilities.toTruncatedString(networkEnvelope)); @@ -136,107 +144,109 @@ public abstract class NetworkNode implements MessageListener { log.debug("We have not found any connection for peerAddress {}.\n\t" + "We will create a new outbound connection.", peersNodeAddress); - SettableFuture<Connection> resultFuture = SettableFuture.create(); - ListenableFuture<Connection> future = connectionExecutor.submit(() -> { - Thread.currentThread().setName("NetworkNode.connectionExecutor:SendMessage-to-" - + Utilities.toTruncatedString(peersNodeAddress.getFullAddress(), 15)); - if (peersNodeAddress.equals(getNodeAddress())) { - log.warn("We are sending a message to ourselves"); - } - - OutboundConnection outboundConnection; - // can take a while when using tor - long startTs = System.currentTimeMillis(); - - log.debug("Start create socket to peersNodeAddress {}", peersNodeAddress.getFullAddress()); - - Socket socket = createSocket(peersNodeAddress); - long duration = System.currentTimeMillis() - startTs; - log.info("Socket creation to peersNodeAddress {} took {} ms", peersNodeAddress.getFullAddress(), - duration); - - if (duration > CREATE_SOCKET_TIMEOUT) - throw new TimeoutException("A timeout occurred when creating a socket."); - - // Tor needs sometimes quite long to create a connection. To avoid that we get too many - // connections with the same peer we check again if we still don't have any connection for that node address. - Connection existingConnection = getInboundConnection(peersNodeAddress); - if (existingConnection == null) - existingConnection = getOutboundConnection(peersNodeAddress); - - if (existingConnection != null) { - log.debug("We found in the meantime a connection for peersNodeAddress {}, " + - "so we use that for sending the message.\n" + - "That can happen if Tor needs long for creating a new outbound connection.\n" + - "We might have got a new inbound or outbound connection.", - peersNodeAddress.getFullAddress()); - - try { - socket.close(); - } catch (Throwable throwable) { - if (!shutDownInProgress) { - log.error("Error at closing socket " + throwable); - } + SettableFuture<Connection> resultFuture = SettableFuture.create(); + CompletableFuture<Connection> future = CompletableFuture.supplyAsync(() -> { + try { + Thread.currentThread().setName("NetworkNode.connectionExecutor:SendMessage-to-" + + Utilities.toTruncatedString(peersNodeAddress.getFullAddress(), 15)); + if (peersNodeAddress.equals(getNodeAddress())) { + log.warn("We are sending a message to ourselves"); } - existingConnection.sendMessage(networkEnvelope); - return existingConnection; - } else { - ConnectionListener connectionListener = new ConnectionListener() { - @Override - public void onConnection(Connection connection) { - if (!connection.isStopped()) { - outBoundConnections.add((OutboundConnection) connection); - printOutBoundConnections(); - connectionListeners.forEach(e -> e.onConnection(connection)); + + OutboundConnection outboundConnection; + // can take a while when using tor + long startTs = System.currentTimeMillis(); + + log.debug("Start create socket to peersNodeAddress {}", peersNodeAddress.getFullAddress()); + + Socket socket = createSocket(peersNodeAddress); + long duration = System.currentTimeMillis() - startTs; + log.info("Socket creation to peersNodeAddress {} took {} ms", peersNodeAddress.getFullAddress(), + duration); + + if (duration > CREATE_SOCKET_TIMEOUT) + throw new TimeoutException("A timeout occurred when creating a socket."); + + // Tor needs sometimes quite long to create a connection. To avoid that we get too many + // connections with the same peer we check again if we still don't have any connection for that node address. + Connection existingConnection = getInboundConnection(peersNodeAddress); + if (existingConnection == null) + existingConnection = getOutboundConnection(peersNodeAddress); + + if (existingConnection != null) { + log.debug("We found in the meantime a connection for peersNodeAddress {}, " + + "so we use that for sending the message.\n" + + "That can happen if Tor needs long for creating a new outbound connection.\n" + + "We might have got a new inbound or outbound connection.", + peersNodeAddress.getFullAddress()); + + try { + socket.close(); + } catch (Throwable throwable) { + if (!isShutDownStarted) { + log.error("Error at closing socket " + throwable); } } + existingConnection.sendMessage(networkEnvelope); + return existingConnection; + } else { + ConnectionListener connectionListener = new ConnectionListener() { + @Override + public void onConnection(Connection connection) { + if (!connection.isStopped()) { + outBoundConnections.add((OutboundConnection) connection); + printOutBoundConnections(); + connectionListeners.forEach(e -> e.onConnection(connection)); + } + } - @Override - public void onDisconnect(CloseConnectionReason closeConnectionReason, - Connection connection) { - // noinspection SuspiciousMethodCalls - outBoundConnections.remove(connection); - printOutBoundConnections(); - connectionListeners.forEach(e -> e.onDisconnect(closeConnectionReason, connection)); + @Override + public void onDisconnect(CloseConnectionReason closeConnectionReason, + Connection connection) { + // noinspection SuspiciousMethodCalls + outBoundConnections.remove(connection); + printOutBoundConnections(); + connectionListeners.forEach(e -> e.onDisconnect(closeConnectionReason, connection)); + } + }; + outboundConnection = new OutboundConnection(socket, + NetworkNode.this, + connectionListener, + peersNodeAddress, + networkProtoResolver, + banFilter); + + if (log.isDebugEnabled()) { + log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + + "NetworkNode created new outbound connection:" + + "\nmyNodeAddress=" + getNodeAddress() + + "\npeersNodeAddress=" + peersNodeAddress + + "\nuid=" + outboundConnection.getUid() + + "\nmessage=" + networkEnvelope + + "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); } - }; - outboundConnection = new OutboundConnection(socket, - NetworkNode.this, - connectionListener, - peersNodeAddress, - networkProtoResolver, - banFilter); - - if (log.isDebugEnabled()) { - log.debug("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n" + - "NetworkNode created new outbound connection:" - + "\nmyNodeAddress=" + getNodeAddress() - + "\npeersNodeAddress=" + peersNodeAddress - + "\nuid=" + outboundConnection.getUid() - + "\nmessage=" + networkEnvelope - + "\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n"); + // can take a while when using tor + outboundConnection.sendMessage(networkEnvelope); + return outboundConnection; } - // can take a while when using tor - outboundConnection.sendMessage(networkEnvelope); - return outboundConnection; + } catch (Exception e) { + throw new RuntimeException(e); } + }, connectionExecutor); + + // handle future with timeout + if (timeoutSeconds != null) future.orTimeout(timeoutSeconds, TimeUnit.SECONDS); + future.exceptionally(throwable -> { + log.debug("onFailure at sendMessage: peersNodeAddress={}\n\tmessage={}\n\tthrowable={}", peersNodeAddress, networkEnvelope.getClass().getSimpleName(), throwable.toString()); + UserThread.execute(() -> { + if (!resultFuture.setException(throwable)) { + // In case the setException returns false we need to cancel the future. + resultFuture.cancel(true); + } + }); + return null; }); - - Futures.addCallback(future, new FutureCallback<>() { - public void onSuccess(Connection connection) { - UserThread.execute(() -> resultFuture.set(connection)); - } - - public void onFailure(@NotNull Throwable throwable) { - log.debug("onFailure at sendMessage: peersNodeAddress={}\n\tmessage={}\n\tthrowable={}", peersNodeAddress, networkEnvelope.getClass().getSimpleName(), throwable.toString()); - UserThread.execute(() -> { - if (!resultFuture.setException(throwable)) { - // In case the setException returns false we need to cancel the future. - resultFuture.cancel(true); - } - }); - } - }, MoreExecutors.directExecutor()); + future.thenAccept(resultFuture::set); return resultFuture; } @@ -306,27 +316,25 @@ public abstract class NetworkNode implements MessageListener { } public void onFailure(@NotNull Throwable throwable) { - UserThread.execute(() -> { - if (!resultFuture.setException(throwable)) { - // In case the setException returns false we need to cancel the future. - resultFuture.cancel(true); - } - }); + UserThread.execute(() -> resolveWithException(resultFuture, throwable)); } }, MoreExecutors.directExecutor()); } catch (RejectedExecutionException exception) { - log.error("RejectedExecutionException at sendMessage: ", exception); - UserThread.execute(() -> { - if (!resultFuture.setException(exception)) { - // In case the setException returns false we need to cancel the future. - resultFuture.cancel(true); - } - }); + if (!executor.isShutdown()) { + log.error("RejectedExecutionException at sendMessage: ", exception); + UserThread.execute(() -> resolveWithException(resultFuture, exception)); + } } return resultFuture; } + private void resolveWithException(SettableFuture<?> future, Throwable exception) { + if (!future.setException(exception)) { + future.cancel(true); // In case the setException returns false we need to cancel the future. + } + } + public ReadOnlyObjectProperty<NodeAddress> nodeAddressProperty() { return nodeAddressProperty; } @@ -355,8 +363,9 @@ public abstract class NetworkNode implements MessageListener { } public void shutDown(Runnable shutDownCompleteHandler) { - if (!shutDownInProgress) { - shutDownInProgress = true; + log.info("NetworkNode shutdown started"); + if (!isShutDownStarted) { + isShutDownStarted = true; if (server != null) { server.shutDown(); server = null; diff --git a/p2p/src/main/java/haveno/network/p2p/network/NewTor.java b/p2p/src/main/java/haveno/network/p2p/network/NewTor.java index 021d49b8a4..e7119656ce 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/NewTor.java +++ b/p2p/src/main/java/haveno/network/p2p/network/NewTor.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/OutboundConnection.java b/p2p/src/main/java/haveno/network/p2p/network/OutboundConnection.java index a4a0769e2b..f704ccf77a 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/OutboundConnection.java +++ b/p2p/src/main/java/haveno/network/p2p/network/OutboundConnection.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/PeerType.java b/p2p/src/main/java/haveno/network/p2p/network/PeerType.java index 7e693b55da..3086f7b553 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/PeerType.java +++ b/p2p/src/main/java/haveno/network/p2p/network/PeerType.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/ProtoOutputStream.java b/p2p/src/main/java/haveno/network/p2p/network/ProtoOutputStream.java index b87284044e..3530ff2d0c 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/ProtoOutputStream.java +++ b/p2p/src/main/java/haveno/network/p2p/network/ProtoOutputStream.java @@ -1,65 +1,100 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; -import haveno.common.proto.network.NetworkEnvelope; import haveno.network.p2p.peers.keepalive.messages.KeepAliveMessage; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import javax.annotation.concurrent.NotThreadSafe; +import haveno.common.proto.network.NetworkEnvelope; + import java.io.IOException; import java.io.OutputStream; -@NotThreadSafe +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.annotation.concurrent.ThreadSafe; + +@ThreadSafe class ProtoOutputStream { private static final Logger log = LoggerFactory.getLogger(ProtoOutputStream.class); - private final OutputStream delegate; + private final OutputStream outputStream; private final Statistic statistic; - ProtoOutputStream(OutputStream delegate, Statistic statistic) { - this.delegate = delegate; + private final AtomicBoolean isConnectionActive = new AtomicBoolean(true); + private final Lock lock = new ReentrantLock(); + + ProtoOutputStream(OutputStream outputStream, Statistic statistic) { + this.outputStream = outputStream; this.statistic = statistic; } void writeEnvelope(NetworkEnvelope envelope) { + lock.lock(); + try { writeEnvelopeOrThrow(envelope); } catch (IOException e) { + if (!isConnectionActive.get()) { + // Connection was closed by us. + return; + } + log.error("Failed to write envelope", e); throw new HavenoRuntimeException("Failed to write envelope", e); + + } finally { + lock.unlock(); } } void onConnectionShutdown() { + isConnectionActive.set(false); + + boolean acquiredLock = tryToAcquireLock(); + if (!acquiredLock) { + return; + } + try { - delegate.close(); + outputStream.close(); } catch (Throwable t) { log.error("Failed to close connection", t); + + } finally { + lock.unlock(); } } private void writeEnvelopeOrThrow(NetworkEnvelope envelope) throws IOException { + long ts = System.currentTimeMillis(); protobuf.NetworkEnvelope proto = envelope.toProtoNetworkEnvelope(); - proto.writeDelimitedTo(delegate); - delegate.flush(); - + proto.writeDelimitedTo(outputStream); + outputStream.flush(); + long duration = System.currentTimeMillis() - ts; + if (duration > 10000) { + log.info("Sending {} to peer took {} sec.", envelope.getClass().getSimpleName(), duration / 1000d); + } statistic.addSentBytes(proto.getSerializedSize()); statistic.addSentMessage(envelope); @@ -67,4 +102,13 @@ class ProtoOutputStream { statistic.updateLastActivityTimestamp(); } } + + private boolean tryToAcquireLock() { + long shutdownTimeout = Connection.getShutdownTimeout(); + try { + return lock.tryLock(shutdownTimeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + return false; + } + } } diff --git a/p2p/src/main/java/haveno/network/p2p/network/RuleViolation.java b/p2p/src/main/java/haveno/network/p2p/network/RuleViolation.java index 1a767d0e0a..46c00f4dad 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/RuleViolation.java +++ b/p2p/src/main/java/haveno/network/p2p/network/RuleViolation.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/RunningTor.java b/p2p/src/main/java/haveno/network/p2p/network/RunningTor.java index 647f93987e..801ebcc9e4 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/RunningTor.java +++ b/p2p/src/main/java/haveno/network/p2p/network/RunningTor.java @@ -1,30 +1,32 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; +import java.io.File; + +import java.util.Date; import lombok.extern.slf4j.Slf4j; import org.berndpruenster.netlayer.tor.ExternalTor; import org.berndpruenster.netlayer.tor.Tor; import org.berndpruenster.netlayer.tor.TorCtlException; -import java.io.File; -import java.io.IOException; -import java.util.Date; +import java.net.ConnectException; +import java.net.UnknownHostException; /** * This class creates a brand new instance of the Tor onion router. @@ -39,15 +41,21 @@ import java.util.Date; @Slf4j public class RunningTor extends TorMode { + private final String controlHost; private final int controlPort; private final String password; private final File cookieFile; private final boolean useSafeCookieAuthentication; - public RunningTor(final File torDir, final int controlPort, final String password, final File cookieFile, - final boolean useSafeCookieAuthentication) { + public RunningTor(final File torDir, + final String controlHost, + final int controlPort, + final String password, + final File cookieFile, + final boolean useSafeCookieAuthentication) { super(torDir); + this.controlHost = controlHost; this.controlPort = controlPort; this.password = password; this.cookieFile = cookieFile; @@ -55,26 +63,49 @@ public class RunningTor extends TorMode { } @Override - public Tor getTor() throws IOException, TorCtlException { + public Tor getTor() throws TorCtlException { long ts1 = new Date().getTime(); + boolean retry = true; + long twoMinutesInMilli = 1000 * 60 * 2; - log.info("Connecting to running tor"); + while (retry && ((new Date().getTime() - ts1) <= twoMinutesInMilli)) { + retry = false; + try { + log.info("Connecting to running tor"); - Tor result; - if (!password.isEmpty()) - result = new ExternalTor(controlPort, password); - else if (cookieFile != null && cookieFile.exists()) - result = new ExternalTor(controlPort, cookieFile, useSafeCookieAuthentication); - else - result = new ExternalTor(controlPort); + Tor result; + if (!password.isEmpty()) + result = new ExternalTor(controlHost, controlPort, password); + else if (cookieFile != null && cookieFile.exists()) + result = new ExternalTor(controlHost, controlPort, cookieFile, useSafeCookieAuthentication); + else + result = new ExternalTor(controlHost, controlPort); - log.info( - "\n################################################################\n" - + "Connecting to Tor successful after {} ms. Start publishing hidden service.\n" - + "################################################################", - (new Date().getTime() - ts1)); // takes usually a few seconds + boolean isTorBootstrapped = result.control.waitUntilBootstrapped(); + if (!isTorBootstrapped) { + log.error("Couldn't bootstrap Tor."); + } - return result; + log.info( + "\n################################################################\n" + + "Connecting to Tor successful after {} ms. Start publishing hidden service.\n" + + "################################################################", + (new Date().getTime() - ts1)); // takes usually a few seconds + + return result; + } catch (Exception e) { + // netlayer throws UnknownHostException when tor docker container is not ready yet. + // netlayer throws ConnectException before tor container bind to control port. + if (e instanceof UnknownHostException || e instanceof ConnectException) { + log.warn("Couldn't connect to Tor control port. Retrying...", e); + retry = true; + } + + log.error("Couldn't connect to Tor.", e); + } + } + + return null; } @Override diff --git a/p2p/src/main/java/haveno/network/p2p/network/Server.java b/p2p/src/main/java/haveno/network/p2p/network/Server.java index f0af0c04b5..437e3d2f88 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/Server.java +++ b/p2p/src/main/java/haveno/network/p2p/network/Server.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -97,11 +97,10 @@ class Server implements Runnable { } } catch (IOException e) { if (isServerActive()) - e.printStackTrace(); + log.error("Error executing server loop: {}\n", e.getMessage(), e); } } catch (Throwable t) { - log.error("Executing task failed. " + t.getMessage()); - t.printStackTrace(); + log.error("Executing task failed: {}\n", t.getMessage(), t); } } diff --git a/p2p/src/main/java/haveno/network/p2p/network/SetupListener.java b/p2p/src/main/java/haveno/network/p2p/network/SetupListener.java index 76e1528a76..711f544ad8 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/SetupListener.java +++ b/p2p/src/main/java/haveno/network/p2p/network/SetupListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/Statistic.java b/p2p/src/main/java/haveno/network/p2p/network/Statistic.java index 91515868ca..0c21c9f872 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/Statistic.java +++ b/p2p/src/main/java/haveno/network/p2p/network/Statistic.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -70,7 +70,7 @@ public class Statistic { totalReceivedBytesPerSec.set(((double) totalReceivedBytes.get()) / passed); }, 1); - // We log statistics every 5 minutes + // We log statistics every 60 minutes UserThread.runPeriodically(() -> { String ls = System.lineSeparator(); log.info("Accumulated network statistics:" + ls + @@ -79,14 +79,14 @@ public class Statistic { "Number of sent messages per sec: {};" + ls + "Bytes received: {}" + ls + "Number of received messages/Received messages: {} / {};" + ls + - "Number of received messages per sec: {};" + ls, + "Number of received messages per sec: {}" + ls, Utilities.readableFileSize(totalSentBytes.get()), numTotalSentMessages.get(), totalSentMessages, numTotalSentMessagesPerSec.get(), Utilities.readableFileSize(totalReceivedBytes.get()), numTotalReceivedMessages.get(), totalReceivedMessages, numTotalReceivedMessagesPerSec.get()); - }, TimeUnit.MINUTES.toSeconds(5)); + }, TimeUnit.MINUTES.toSeconds(60)); } public static LongProperty totalSentBytesProperty() { @@ -236,6 +236,30 @@ public class Statistic { return roundTripTime; } + public static long getTotalSentBytes() { + return totalSentBytes.get(); + } + + public static double getTotalSentBytesPerSec() { + return totalSentBytesPerSec.get(); + } + + public static long getTotalReceivedBytes() { + return totalReceivedBytes.get(); + } + + public static double getTotalReceivedBytesPerSec() { + return totalReceivedBytesPerSec.get(); + } + + public static double numTotalReceivedMessagesPerSec() { + return numTotalReceivedMessagesPerSec.get(); + } + + public static double getNumTotalSentMessagesPerSec() { + return numTotalSentMessagesPerSec.get(); + } + @Override public String toString() { return "Statistic{" + diff --git a/p2p/src/main/java/haveno/network/p2p/network/SupportedCapabilitiesListener.java b/p2p/src/main/java/haveno/network/p2p/network/SupportedCapabilitiesListener.java index cd5ba14fbb..6dfbd736da 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/SupportedCapabilitiesListener.java +++ b/p2p/src/main/java/haveno/network/p2p/network/SupportedCapabilitiesListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/SynchronizedProtoOutputStream.java b/p2p/src/main/java/haveno/network/p2p/network/SynchronizedProtoOutputStream.java deleted file mode 100644 index eaa64e4a81..0000000000 --- a/p2p/src/main/java/haveno/network/p2p/network/SynchronizedProtoOutputStream.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of Haveno. - * - * Haveno is free software: you can redistribute it and/or modify it - * under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at - * your option) any later version. - * - * Haveno is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public - * License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. - */ - -package haveno.network.p2p.network; - -import haveno.common.proto.network.NetworkEnvelope; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.concurrent.ThreadSafe; -import java.io.OutputStream; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; - -@ThreadSafe -class SynchronizedProtoOutputStream extends ProtoOutputStream { - private static final Logger log = LoggerFactory.getLogger(SynchronizedProtoOutputStream.class); - - private final ExecutorService executorService; - - SynchronizedProtoOutputStream(OutputStream delegate, Statistic statistic) { - super(delegate, statistic); - this.executorService = Executors.newSingleThreadExecutor(); - } - - @Override - void writeEnvelope(NetworkEnvelope envelope) { - Future<?> future = executorService.submit(() -> super.writeEnvelope(envelope)); - try { - future.get(); - } catch (InterruptedException e) { - Thread currentThread = Thread.currentThread(); - currentThread.interrupt(); - String msg = "Thread " + currentThread + " was interrupted. InterruptedException=" + e; - log.error(msg); - throw new HavenoRuntimeException(msg, e); - } catch (ExecutionException e) { - String msg = "Failed to write envelope. ExecutionException " + e; - log.error(msg); - throw new HavenoRuntimeException(msg, e); - } - } - - void onConnectionShutdown() { - try { - executorService.shutdownNow(); - super.onConnectionShutdown(); - } catch (Throwable t) { - log.error("Failed to handle connection shutdown. Throwable={}", t.toString()); - } - } -} diff --git a/p2p/src/main/java/haveno/network/p2p/network/TorMode.java b/p2p/src/main/java/haveno/network/p2p/network/TorMode.java index d76f9a7d40..69191381fd 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/TorMode.java +++ b/p2p/src/main/java/haveno/network/p2p/network/TorMode.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNode.java b/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNode.java index f0a622bd7d..3a2bfd610e 100644 --- a/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNode.java +++ b/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNode.java @@ -1,65 +1,43 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; import haveno.network.p2p.NodeAddress; -import haveno.network.utils.Utils; -import haveno.common.Timer; -import haveno.common.UserThread; import haveno.common.proto.network.NetworkProtoResolver; import haveno.common.util.SingleThreadExecutorUtils; -import org.berndpruenster.netlayer.tor.HiddenServiceSocket; -import org.berndpruenster.netlayer.tor.Tor; -import org.berndpruenster.netlayer.tor.TorCtlException; -import org.berndpruenster.netlayer.tor.TorSocket; - import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; -import java.security.SecureRandom; - import java.net.Socket; import java.io.IOException; -import java.util.Base64; import java.util.concurrent.ExecutorService; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.Nullable; -import static com.google.common.base.Preconditions.checkArgument; - @Slf4j -public class TorNetworkNode extends NetworkNode { - private static final long SHUT_DOWN_TIMEOUT = 2; +public abstract class TorNetworkNode extends NetworkNode { - private HiddenServiceSocket hiddenServiceSocket; - private Timer shutDownTimeoutTimer; - private Tor tor; - private TorMode torMode; - private boolean streamIsolation; - private Socks5Proxy socksProxy; - private boolean shutDownInProgress; - private boolean shutDownComplete; - private final ExecutorService executor; + protected final ExecutorService executor; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -67,14 +45,9 @@ public class TorNetworkNode extends NetworkNode { public TorNetworkNode(int servicePort, NetworkProtoResolver networkProtoResolver, - boolean useStreamIsolation, - TorMode torMode, @Nullable BanFilter banFilter, int maxConnections) { super(servicePort, networkProtoResolver, banFilter, maxConnections); - this.torMode = torMode; - this.streamIsolation = useStreamIsolation; - executor = SingleThreadExecutorUtils.getSingleThreadExecutor("StartTor"); } @@ -84,121 +57,19 @@ public class TorNetworkNode extends NetworkNode { @Override public void start(@Nullable SetupListener setupListener) { - torMode.doRollingBackup(); - if (setupListener != null) addSetupListener(setupListener); - createTorAndHiddenService(Utils.findFreeSystemPort(), servicePort); - } - - @Override - protected Socket createSocket(NodeAddress peerNodeAddress) throws IOException { - checkArgument(peerNodeAddress.getHostName().endsWith(".onion"), "PeerAddress is not an onion address"); - // If streamId is null stream isolation gets deactivated. - // Hidden services use stream isolation by default, so we pass null. - return new TorSocket(peerNodeAddress.getHostName(), peerNodeAddress.getPort(), null); - } - - public Socks5Proxy getSocksProxy() { - try { - String stream = null; - if (streamIsolation) { - byte[] bytes = new byte[512]; // tor.getProxy creates a Sha256 hash - new SecureRandom().nextBytes(bytes); - stream = Base64.getEncoder().encodeToString(bytes); - } - - if (socksProxy == null || streamIsolation) { - tor = Tor.getDefault(); - socksProxy = tor != null ? tor.getProxy(stream) : null; - } - return socksProxy; - } catch (Throwable t) { - log.error("Error at getSocksProxy", t); - return null; - } + createTorAndHiddenService(); } public void shutDown(@Nullable Runnable shutDownCompleteHandler) { - log.info("TorNetworkNode shutdown started"); - if (shutDownComplete) { - log.info("TorNetworkNode shutdown already completed"); - if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); - return; - } - if (shutDownInProgress) { - log.warn("Ignoring request to shut down because shut down is in progress"); - return; - } - shutDownInProgress = true; - - shutDownTimeoutTimer = UserThread.runAfter(() -> { - log.error("A timeout occurred at shutDown"); - shutDownComplete = true; - if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); - executor.shutdownNow(); - }, SHUT_DOWN_TIMEOUT); - - super.shutDown(() -> { - try { - tor = Tor.getDefault(); - if (tor != null) { - tor.shutdown(); - tor = null; - log.info("Tor shutdown completed"); - } - executor.shutdownNow(); - } catch (Throwable e) { - log.error("Shutdown torNetworkNode failed with exception", e); - } finally { - shutDownTimeoutTimer.stop(); - shutDownComplete = true; - if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); - } - }); + super.shutDown(shutDownCompleteHandler); } - /////////////////////////////////////////////////////////////////////////////////////////// - // Create tor and hidden service - /////////////////////////////////////////////////////////////////////////////////////////// + public abstract Socks5Proxy getSocksProxy(); - private void createTorAndHiddenService(int localPort, int servicePort) { - executor.submit(() -> { - try { - Tor.setDefault(torMode.getTor()); - long ts = System.currentTimeMillis(); - hiddenServiceSocket = new HiddenServiceSocket(localPort, torMode.getHiddenServiceDirectory(), servicePort); - nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" + hiddenServiceSocket.getHiddenServicePort())); - UserThread.execute(() -> setupListeners.forEach(SetupListener::onTorNodeReady)); - hiddenServiceSocket.addReadyListener(socket -> { - log.info("\n################################################################\n" + - "Tor hidden service published after {} ms. Socket={}\n" + - "################################################################", - System.currentTimeMillis() - ts, socket); - UserThread.execute(() -> { - nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" - + hiddenServiceSocket.getHiddenServicePort())); - startServer(socket); - setupListeners.forEach(SetupListener::onHiddenServicePublished); - }); - return null; - }); - } catch (TorCtlException e) { - log.error("Starting tor node failed", e); - if (e.getCause() instanceof IOException) { - UserThread.execute(() -> setupListeners.forEach(s -> s.onSetupFailed(new RuntimeException(e.getMessage())))); - } else { - UserThread.execute(() -> setupListeners.forEach(SetupListener::onRequestCustomBridges)); - log.warn("We shutdown as starting tor with the default bridges failed. We request user to add custom bridges."); - shutDown(null); - } - } catch (IOException e) { - log.error("Could not connect to running Tor", e); - UserThread.execute(() -> setupListeners.forEach(s -> s.onSetupFailed(new RuntimeException(e.getMessage())))); - } catch (Throwable ignore) { - } - return null; - }); - } + protected abstract Socket createSocket(NodeAddress peerNodeAddress) throws IOException; + + protected abstract void createTorAndHiddenService(); } diff --git a/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNodeDirectBind.java b/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNodeDirectBind.java new file mode 100644 index 0000000000..8333af3f8b --- /dev/null +++ b/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNodeDirectBind.java @@ -0,0 +1,114 @@ +package haveno.network.p2p.network; + +import haveno.common.util.Hex; +import haveno.network.p2p.NodeAddress; + +import haveno.common.UserThread; +import haveno.common.proto.network.NetworkProtoResolver; + +import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; + +import java.net.Socket; +import java.net.InetAddress; +import java.net.ServerSocket; + +import java.io.IOException; + +import java.nio.charset.StandardCharsets; + +import lombok.extern.slf4j.Slf4j; + +import org.jetbrains.annotations.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; + +@Slf4j +public class TorNetworkNodeDirectBind extends TorNetworkNode { + + private static final int TOR_DATA_PORT = 9050; // TODO: config option? + private final String serviceAddress; + + public TorNetworkNodeDirectBind(int servicePort, + NetworkProtoResolver networkProtoResolver, + @Nullable BanFilter banFilter, + int maxConnections, + String hiddenServiceAddress) { + super(servicePort, networkProtoResolver, banFilter, maxConnections); + this.serviceAddress = hiddenServiceAddress; + } + + @Override + public void shutDown(@Nullable Runnable shutDownCompleteHandler) { + super.shutDown(() -> { + log.info("TorNetworkNodeDirectBind shutdown completed"); + if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); + }); + } + + @Override + public Socks5Proxy getSocksProxy() { + Socks5Proxy proxy = new Socks5Proxy(InetAddress.getLoopbackAddress(), TOR_DATA_PORT); + proxy.resolveAddrLocally(false); + return proxy; + } + + @Override + protected Socket createSocket(NodeAddress peerNodeAddress) throws IOException { + // https://datatracker.ietf.org/doc/html/rfc1928 SOCKS5 Protocol + try { + checkArgument(peerNodeAddress.getHostName().endsWith(".onion"), "PeerAddress is not an onion address"); + Socket sock = new Socket(InetAddress.getLoopbackAddress(), TOR_DATA_PORT); + sock.getOutputStream().write(Hex.decode("050100")); + String response = Hex.encode(sock.getInputStream().readNBytes(2)); + if (!response.equalsIgnoreCase("0500")) { + return null; + } + String connect_details = "050100033E" + Hex.encode(peerNodeAddress.getHostName().getBytes(StandardCharsets.UTF_8)); + StringBuilder connect_port = new StringBuilder(Integer.toHexString(peerNodeAddress.getPort())); + while (connect_port.length() < 4) connect_port.insert(0, "0"); + connect_details = connect_details + connect_port; + sock.getOutputStream().write(Hex.decode(connect_details)); + response = Hex.encode(sock.getInputStream().readNBytes(10)); + if (response.substring(0, 2).equalsIgnoreCase("05") && response.substring(2, 4).equalsIgnoreCase("00")) { + return sock; // success + } + if (response.substring(2, 4).equalsIgnoreCase("04")) { + log.warn("Host unreachable: {}", peerNodeAddress); + } else { + log.warn("SOCKS error code received {} expected 00", response.substring(2, 4)); + } + if (!response.substring(0, 2).equalsIgnoreCase("05")) { + log.warn("unexpected response, this isn't a SOCKS5 proxy?: {} {}", response, response.substring(0, 2)); + } + } catch (Exception e) { + log.warn(e.toString()); + } + throw new IOException("createSocket failed"); + } + + @Override + protected void createTorAndHiddenService() { + executor.submit(() -> { + try { + // listener for incoming messages at the hidden service + ServerSocket socket = new ServerSocket(servicePort); + nodeAddressProperty.set(new NodeAddress(serviceAddress + ":" + servicePort)); + log.info("\n################################################################\n" + + "Bound to Tor hidden service: {} Port: {}\n" + + "################################################################", + serviceAddress, servicePort); + UserThread.execute(() -> setupListeners.forEach(SetupListener::onTorNodeReady)); + UserThread.runAfter(() -> { + nodeAddressProperty.set(new NodeAddress(serviceAddress + ":" + servicePort)); + startServer(socket); + setupListeners.forEach(SetupListener::onHiddenServicePublished); + }, 3); + return null; + } catch (IOException e) { + log.error("Could not connect to external Tor", e); + UserThread.execute(() -> setupListeners.forEach(s -> s.onSetupFailed(new RuntimeException(e.getMessage())))); + } + return null; + }); + } +} diff --git a/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNodeNetlayer.java b/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNodeNetlayer.java new file mode 100644 index 0000000000..b4d7e9785c --- /dev/null +++ b/p2p/src/main/java/haveno/network/p2p/network/TorNetworkNodeNetlayer.java @@ -0,0 +1,174 @@ +package haveno.network.p2p.network; + +import haveno.common.Timer; +import haveno.network.p2p.NodeAddress; + +import haveno.common.UserThread; +import haveno.common.proto.network.NetworkProtoResolver; + +import haveno.network.utils.Utils; +import org.berndpruenster.netlayer.tor.HiddenServiceSocket; +import org.berndpruenster.netlayer.tor.Tor; +import org.berndpruenster.netlayer.tor.TorCtlException; +import org.berndpruenster.netlayer.tor.TorSocket; + +import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy; + +import java.security.SecureRandom; + +import java.net.Socket; + +import java.io.IOException; + +import java.util.Base64; + +import lombok.extern.slf4j.Slf4j; + +import org.jetbrains.annotations.Nullable; + +import static com.google.common.base.Preconditions.checkArgument; + +@Slf4j +public class TorNetworkNodeNetlayer extends TorNetworkNode { + + private static final long SHUT_DOWN_TIMEOUT = 2; + + private HiddenServiceSocket hiddenServiceSocket; + private boolean streamIsolation; + private Socks5Proxy socksProxy; + protected TorMode torMode; + private Tor tor; + private final String torControlHost; + private Timer shutDownTimeoutTimer; + private boolean shutDownInProgress; + private boolean shutDownComplete; + + public TorNetworkNodeNetlayer(int servicePort, + NetworkProtoResolver networkProtoResolver, + TorMode torMode, + @Nullable BanFilter banFilter, + int maxConnections, + boolean useStreamIsolation, + String torControlHost) { + super(servicePort, networkProtoResolver, banFilter, maxConnections); + this.torControlHost = torControlHost; + this.streamIsolation = useStreamIsolation; + this.torMode = torMode; + } + + @Override + public void start(@Nullable SetupListener setupListener) { + torMode.doRollingBackup(); + super.start(setupListener); + } + + @Override + public void shutDown(@Nullable Runnable shutDownCompleteHandler) { + log.info("TorNetworkNodeNetlayer shutdown started"); + if (shutDownComplete) { + log.info("TorNetworkNodeNetlayer shutdown already completed"); + if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); + return; + } + if (shutDownInProgress) { + log.warn("Ignoring request to shut down because shut down is in progress"); + return; + } + shutDownInProgress = true; + + shutDownTimeoutTimer = UserThread.runAfter(() -> { + log.error("A timeout occurred at shutDown"); + shutDownComplete = true; + if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); + executor.shutdownNow(); + }, SHUT_DOWN_TIMEOUT); + + super.shutDown(() -> { + try { + tor = Tor.getDefault(); + if (tor != null) { + tor.shutdown(); + tor = null; + log.info("Tor shutdown completed"); + } + executor.shutdownNow(); + } catch (Throwable e) { + log.error("Shutdown TorNetworkNodeNetlayer failed with exception", e); + } finally { + shutDownTimeoutTimer.stop(); + shutDownComplete = true; + if (shutDownCompleteHandler != null) shutDownCompleteHandler.run(); + } + }); + } + + @Override + protected Socket createSocket(NodeAddress peerNodeAddress) throws IOException { + checkArgument(peerNodeAddress.getHostName().endsWith(".onion"), "PeerAddress is not an onion address"); + // If streamId is null stream isolation gets deactivated. + // Hidden services use stream isolation by default, so we pass null. + return new TorSocket(peerNodeAddress.getHostName(), peerNodeAddress.getPort(), torControlHost, null); + } + + @Override + public Socks5Proxy getSocksProxy() { + try { + String stream = null; + if (streamIsolation) { + byte[] bytes = new byte[512]; // tor.getProxy creates a Sha256 hash + new SecureRandom().nextBytes(bytes); + stream = Base64.getEncoder().encodeToString(bytes); + } + + if (socksProxy == null || streamIsolation) { + tor = Tor.getDefault(); + socksProxy = tor != null ? tor.getProxy(torControlHost, stream) : null; + } + return socksProxy; + } catch (Throwable t) { + log.error("Error at getSocksProxy", t); + return null; + } + } + + @Override + protected void createTorAndHiddenService() { + int localPort = Utils.findFreeSystemPort(); + executor.submit(() -> { + try { + Tor.setDefault(torMode.getTor()); + long ts = System.currentTimeMillis(); + hiddenServiceSocket = new HiddenServiceSocket(localPort, torMode.getHiddenServiceDirectory(), servicePort); + nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" + hiddenServiceSocket.getHiddenServicePort())); + UserThread.execute(() -> setupListeners.forEach(SetupListener::onTorNodeReady)); + hiddenServiceSocket.addReadyListener(socket -> { + log.info("\n################################################################\n" + + "Tor hidden service published after {} ms. Socket={}\n" + + "################################################################", + System.currentTimeMillis() - ts, socket); + UserThread.execute(() -> { + nodeAddressProperty.set(new NodeAddress(hiddenServiceSocket.getServiceName() + ":" + + hiddenServiceSocket.getHiddenServicePort())); + startServer(socket); + setupListeners.forEach(SetupListener::onHiddenServicePublished); + }); + return null; + }); + } catch (TorCtlException e) { + log.error("Starting tor node failed", e); + if (e.getCause() instanceof IOException) { + UserThread.execute(() -> setupListeners.forEach(s -> s.onSetupFailed(new RuntimeException(e.getMessage())))); + } else { + UserThread.execute(() -> setupListeners.forEach(SetupListener::onRequestCustomBridges)); + log.warn("We shutdown as starting tor with the default bridges failed. We request user to add custom bridges."); + shutDown(null); + } + } catch (IOException e) { + log.error("Could not connect to running Tor", e); + UserThread.execute(() -> setupListeners.forEach(s -> s.onSetupFailed(new RuntimeException(e.getMessage())))); + } catch (Throwable ignore) { + } + return null; + }); + } +} diff --git a/p2p/src/main/java/haveno/network/p2p/peers/BroadcastHandler.java b/p2p/src/main/java/haveno/network/p2p/peers/BroadcastHandler.java index 8dcab4b56d..fca906ff1c 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/BroadcastHandler.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/BroadcastHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers; @@ -74,6 +74,7 @@ public class BroadcastHandler implements PeerManager.Listener { private final NetworkNode networkNode; private final PeerManager peerManager; + @Nullable private final ResultHandler resultHandler; private final String uid; @@ -283,6 +284,9 @@ public class BroadcastHandler implements PeerManager.Listener { return; } + log.warn("Broadcast to " + connection.getPeersNodeAddressOptional() + " failed. ", throwable); + numOfFailedBroadcasts.incrementAndGet(); + maybeNotifyListeners(broadcastRequestsForConnection); checkForCompletion(); } @@ -348,7 +352,13 @@ public class BroadcastHandler implements PeerManager.Listener { sendMessageFutures.stream() .filter(future -> !future.isCancelled() && !future.isDone()) - .forEach(future -> future.cancel(true)); + .forEach(future -> { + try { + future.cancel(true); + } catch (Exception e) { + if (!networkNode.isShutDownStarted()) throw e; + } + }); sendMessageFutures.clear(); peerManager.removeListener(this); diff --git a/p2p/src/main/java/haveno/network/p2p/peers/Broadcaster.java b/p2p/src/main/java/haveno/network/p2p/peers/Broadcaster.java index 109e192fcb..647182feeb 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/Broadcaster.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/Broadcaster.java @@ -1,37 +1,33 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers; -import haveno.network.p2p.NodeAddress; -import haveno.network.p2p.network.NetworkNode; -import haveno.network.p2p.storage.messages.BroadcastMessage; - +import com.google.common.util.concurrent.ListeningExecutorService; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.config.Config; import haveno.common.util.Utilities; - -import javax.inject.Inject; -import javax.inject.Named; - -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; - +import haveno.network.p2p.NodeAddress; +import haveno.network.p2p.network.NetworkNode; +import haveno.network.p2p.storage.messages.BroadcastMessage; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -41,7 +37,6 @@ import java.util.concurrent.TimeUnit; import lombok.Value; import lombok.extern.slf4j.Slf4j; - import org.jetbrains.annotations.Nullable; @Slf4j @@ -57,6 +52,7 @@ public class Broadcaster implements BroadcastHandler.ResultHandler { private Runnable shutDownResultHandler; private final ListeningExecutorService executor; + /////////////////////////////////////////////////////////////////////////////////////////// // Constructor /////////////////////////////////////////////////////////////////////////////////////////// @@ -96,6 +92,7 @@ public class Broadcaster implements BroadcastHandler.ResultHandler { } private void doShutDown() { + log.info("Broadcaster doShutDown started"); broadcastHandlers.forEach(BroadcastHandler::cancel); if (timer != null) { timer.stop(); diff --git a/p2p/src/main/java/haveno/network/p2p/peers/PeerManager.java b/p2p/src/main/java/haveno/network/p2p/peers/PeerManager.java index 457457deed..c8426af987 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/PeerManager.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/PeerManager.java @@ -1,23 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers; import com.google.common.annotations.VisibleForTesting; +import static com.google.common.base.Preconditions.checkArgument; +import com.google.inject.Inject; +import com.google.inject.name.Named; import haveno.common.ClockWatcher; import haveno.common.Timer; import haveno.common.UserThread; @@ -37,12 +40,6 @@ import haveno.network.p2p.network.RuleViolation; import haveno.network.p2p.peers.peerexchange.Peer; import haveno.network.p2p.peers.peerexchange.PeerList; import haveno.network.p2p.seed.SeedNodeRepository; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; @@ -56,8 +53,9 @@ import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; +import javax.annotation.Nullable; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; @Slf4j public final class PeerManager implements ConnectionListener, PersistedDataHost { @@ -79,6 +77,7 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost private static final boolean PRINT_REPORTED_PEERS_DETAILS = true; private Timer printStatisticsTimer; private boolean shutDownRequested; + private int numOnConnections; /////////////////////////////////////////////////////////////////////////////////////////// @@ -169,7 +168,7 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost }; clockWatcher.addListener(clockWatcherListener); - printStatisticsTimer = UserThread.runPeriodically(this::printStatistics, TimeUnit.MINUTES.toSeconds(5)); + printStatisticsTimer = UserThread.runPeriodically(this::printStatistics, TimeUnit.MINUTES.toSeconds(60)); } public void shutDown() { @@ -211,6 +210,8 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost doHouseKeeping(); + numOnConnections++; + if (lostAllConnections) { lostAllConnections = false; stopped = false; @@ -226,14 +227,15 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost @Override public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) { - log.info("onDisconnect called: nodeAddress={}, closeConnectionReason={}", + log.debug("onDisconnect called: nodeAddress={}, closeConnectionReason={}", connection.getPeersNodeAddressOptional(), closeConnectionReason); handleConnectionFault(connection); boolean previousLostAllConnections = lostAllConnections; lostAllConnections = networkNode.getAllConnections().isEmpty(); - if (lostAllConnections) { + // At start-up we ignore if we would lose a connection and would fall back to no connections + if (lostAllConnections && numOnConnections > 2) { stopped = true; if (!shutDownRequested) { @@ -365,19 +367,21 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost // We check if the reported msg is not violating our rules if (peers.size() <= (MAX_REPORTED_PEERS + maxConnectionsAbsolute + 10)) { - reportedPeers.addAll(peers); - purgeReportedPeersIfExceeds(); + synchronized (reportedPeers) { + reportedPeers.addAll(peers); + purgeReportedPeersIfExceeds(); - getPersistedPeers().addAll(peers); - purgePersistedPeersIfExceeds(); - requestPersistence(); + getPersistedPeers().addAll(peers); + purgePersistedPeersIfExceeds(); + requestPersistence(); - printReportedPeers(); + printReportedPeers(); + } } else { // If a node is trying to send too many list we treat it as rule violation. // Reported list include the connected list. We use the max value and give some extra headroom. // Will trigger a shutdown after 2nd time sending too much - connection.reportInvalidRequest(RuleViolation.TOO_MANY_REPORTED_PEERS_SENT); + connection.reportInvalidRequest(RuleViolation.TOO_MANY_REPORTED_PEERS_SENT, "Too many reported peers sent"); } } @@ -553,7 +557,7 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost if (!candidates.isEmpty()) { Connection connection = candidates.remove(0); - log.info("checkMaxConnections: Num candidates for shut down={}. We close oldest connection to peer {}", + log.info("checkMaxConnections: Num candidates (inbound/peer) for shut down={}. We close oldest connection to peer {}", candidates.size(), connection.getPeersNodeAddressOptional()); if (!connection.isStopped()) { connection.shutDown(CloseConnectionReason.TOO_MANY_CONNECTIONS_OPEN, @@ -589,8 +593,11 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost /////////////////////////////////////////////////////////////////////////////////////////// private void removeReportedPeer(Peer reportedPeer) { - reportedPeers.remove(reportedPeer); - printReportedPeers(); + synchronized (reportedPeers) { + reportedPeers.remove(reportedPeer); + printReportedPeers(); + } + } private void removeReportedPeer(NodeAddress nodeAddress) { @@ -611,35 +618,39 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost private void purgeReportedPeersIfExceeds() { - int size = reportedPeers.size(); - if (size > MAX_REPORTED_PEERS) { - log.info("We have already {} reported peers which exceeds our limit of {}." + - "We remove random peers from the reported peers list.", size, MAX_REPORTED_PEERS); - int diff = size - MAX_REPORTED_PEERS; - List<Peer> list = new ArrayList<>(reportedPeers); - // we don't use sorting by lastActivityDate to keep it more random - for (int i = 0; i < diff; i++) { - if (!list.isEmpty()) { - Peer toRemove = list.remove(new Random().nextInt(list.size())); - removeReportedPeer(toRemove); + synchronized (reportedPeers) { + int size = reportedPeers.size(); + if (size > MAX_REPORTED_PEERS) { + log.info("We have already {} reported peers which exceeds our limit of {}." + + "We remove random peers from the reported peers list.", size, MAX_REPORTED_PEERS); + int diff = size - MAX_REPORTED_PEERS; + List<Peer> list = new ArrayList<>(reportedPeers); + // we don't use sorting by lastActivityDate to keep it more random + for (int i = 0; i < diff; i++) { + if (!list.isEmpty()) { + Peer toRemove = list.remove(new Random().nextInt(list.size())); + removeReportedPeer(toRemove); + } } + } else { + log.trace("No need to purge reported peers.\n\tWe don't have more then {} reported peers yet.", MAX_REPORTED_PEERS); } - } else { - log.trace("No need to purge reported peers.\n\tWe don't have more then {} reported peers yet.", MAX_REPORTED_PEERS); } } private void printReportedPeers() { - if (!reportedPeers.isEmpty()) { - if (PRINT_REPORTED_PEERS_DETAILS) { - StringBuilder result = new StringBuilder("\n\n------------------------------------------------------------\n" + - "Collected reported peers:"); - List<Peer> reportedPeersClone = new ArrayList<>(reportedPeers); - reportedPeersClone.forEach(e -> result.append("\n").append(e)); - result.append("\n------------------------------------------------------------\n"); - log.trace(result.toString()); + synchronized (reportedPeers) { + if (!reportedPeers.isEmpty()) { + if (PRINT_REPORTED_PEERS_DETAILS) { + StringBuilder result = new StringBuilder("\n\n------------------------------------------------------------\n" + + "Collected reported peers:"); + List<Peer> reportedPeersClone = new ArrayList<>(reportedPeers); + reportedPeersClone.forEach(e -> result.append("\n").append(e)); + result.append("\n------------------------------------------------------------\n"); + log.trace(result.toString()); + } + log.debug("Number of reported peers: {}", reportedPeers.size()); } - log.debug("Number of reported peers: {}", reportedPeers.size()); } } @@ -765,7 +776,9 @@ public final class PeerManager implements ConnectionListener, PersistedDataHost // If not found in connection we look up if we got the Capabilities set from any of the // reported or persisted peers Set<Peer> persistedAndReported = new HashSet<>(getPersistedPeers()); - persistedAndReported.addAll(getReportedPeers()); + synchronized (reportedPeers) { + persistedAndReported.addAll(reportedPeers); + } Optional<Peer> candidate = persistedAndReported.stream() .filter(peer -> peer.getNodeAddress().equals(peersNodeAddress)) .filter(peer -> !peer.getCapabilities().isEmpty()) diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/GetDataRequestHandler.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/GetDataRequestHandler.java index e9a1807538..9023815d80 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/GetDataRequestHandler.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/GetDataRequestHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata; @@ -37,16 +37,16 @@ import java.util.concurrent.atomic.AtomicBoolean; @Slf4j public class GetDataRequestHandler { - private static final long TIMEOUT = 180; + private static final long TIMEOUT = 240; - private static final int MAX_ENTRIES = 10000; + private static final int MAX_ENTRIES = 5000; /////////////////////////////////////////////////////////////////////////////////////////// // Listener /////////////////////////////////////////////////////////////////////////////////////////// public interface Listener { - void onComplete(); + void onComplete(int serializedSize); void onFault(String errorMessage, Connection connection); } @@ -94,15 +94,11 @@ public class GetDataRequestHandler { connection.getCapabilities()); if (wasPersistableNetworkPayloadsTruncated.get()) { - log.warn("The getData request from peer with {} caused too much PersistableNetworkPayload " + - "entries to get delivered. We limited the entries for the response to {} entries", - connectionInfo, MAX_ENTRIES); + log.info("The getDataResponse for peer {} got truncated.", connectionInfo); } if (wasProtectedStorageEntriesTruncated.get()) { - log.warn("The getData request from peer with {} caused too much ProtectedStorageEntry " + - "entries to get delivered. We limited the entries for the response to {} entries", - connectionInfo, MAX_ENTRIES); + log.info("The getDataResponse for peer {} got truncated.", connectionInfo); } log.info("The getDataResponse to peer with {} contains {} ProtectedStorageEntries and {} PersistableNetworkPayloads", @@ -126,8 +122,8 @@ public class GetDataRequestHandler { if (!stopped) { log.trace("Send DataResponse to {} succeeded. getDataResponse={}", connection.getPeersNodeAddressOptional(), getDataResponse); + listener.onComplete(getDataResponse.toProtoNetworkEnvelope().getSerializedSize()); cleanup(); - listener.onComplete(); } else { log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call."); } @@ -136,7 +132,7 @@ public class GetDataRequestHandler { @Override public void onFailure(@NotNull Throwable throwable) { if (!stopped) { - String errorMessage = "Sending getDataRequest to " + connection + + String errorMessage = "Sending getDataResponse to " + connection + " failed. That is expected if the peer is offline. getDataResponse=" + getDataResponse + "." + "Exception: " + throwable.getMessage(); handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, connection); diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataHandler.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataHandler.java index ba47b839a4..f155c0e8ce 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataHandler.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata; @@ -50,7 +50,7 @@ import java.util.concurrent.atomic.AtomicInteger; @Slf4j class RequestDataHandler implements MessageListener { - private static final long TIMEOUT = 180; + private static final long TIMEOUT = 240; private NodeAddress peersNodeAddress; private String getDataRequestType; @@ -69,7 +69,7 @@ class RequestDataHandler implements MessageListener { /////////////////////////////////////////////////////////////////////////////////////////// public interface Listener { - void onComplete(); + void onComplete(boolean wasTruncated); @SuppressWarnings("UnusedParameters") void onFault(String errorMessage, @SuppressWarnings("SameParameterValue") @Nullable Connection connection); @@ -138,35 +138,40 @@ class RequestDataHandler implements MessageListener { } getDataRequestType = getDataRequest.getClass().getSimpleName(); - log.info("We send a {} to peer {}. ", getDataRequestType, nodeAddress); + log.info("\n\n>> We send a {} to peer {}\n", getDataRequestType, nodeAddress); networkNode.addMessageListener(this); - SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, getDataRequest); - //noinspection UnstableApiUsage - Futures.addCallback(future, new FutureCallback<>() { - @Override - public void onSuccess(Connection connection) { - if (!stopped) { - log.trace("Send {} to {} succeeded.", getDataRequest, nodeAddress); - } else { - log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call." + - "Might be caused by a previous timeout."); - } - } - @Override - public void onFailure(@NotNull Throwable throwable) { - if (!stopped) { - String errorMessage = "Sending getDataRequest to " + nodeAddress + - " failed. That is expected if the peer is offline.\n\t" + - "getDataRequest=" + getDataRequest + "." + - "\n\tException=" + throwable.getMessage(); - handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE); - } else { - log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call. " + - "Might be caused by a previous timeout."); + try { + SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, getDataRequest); + //noinspection UnstableApiUsage + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(Connection connection) { + if (!stopped) { + log.trace("Send {} to {} succeeded.", getDataRequest, nodeAddress); + } else { + log.trace("We have stopped already. We ignore that networkNode.sendMessage.onSuccess call." + + "Might be caused by a previous timeout."); + } } - } - }, MoreExecutors.directExecutor()); + + @Override + public void onFailure(@NotNull Throwable throwable) { + if (!stopped) { + String errorMessage = "Sending getDataRequest to " + nodeAddress + + " failed. That is expected if the peer is offline.\n\t" + + "getDataRequest=" + getDataRequest + "." + + "\n\tException=" + throwable.getMessage(); + handleFault(errorMessage, nodeAddress, CloseConnectionReason.SEND_MSG_FAILURE); + } else { + log.trace("We have stopped already. We ignore that networkNode.sendMessage.onFailure call. " + + "Might be caused by a previous timeout."); + } + } + }, MoreExecutors.directExecutor()); + } catch (Exception e) { + if (!networkNode.isShutDownStarted()) throw e; + } } else { log.warn("We have stopped already. We ignore that requestData call."); } @@ -197,8 +202,7 @@ class RequestDataHandler implements MessageListener { connection.getPeersNodeAddressOptional().get()); cleanup(); - listener.onComplete(); - // firstRequest = false; + listener.onComplete(getDataResponse.isWasTruncated()); } else { log.warn("Nonce not matching. That can happen rarely if we get a response after a canceled " + "handshake (timeout causes connection close but peer might have sent a msg before " + @@ -239,7 +243,7 @@ class RequestDataHandler implements MessageListener { StringBuilder sb = new StringBuilder(); String sep = System.lineSeparator(); sb.append(sep).append("#################################################################").append(sep); - sb.append("Connected to node: ").append(peersNodeAddress.getFullAddress()).append(sep); + sb.append("Data provided by node: ").append(peersNodeAddress.getFullAddress()).append(sep); int items = dataSet.size() + persistableNetworkPayloadSet.size(); sb.append("Received ").append(items).append(" instances from a ") .append(getDataRequestType).append(sep); @@ -249,7 +253,7 @@ class RequestDataHandler implements MessageListener { .append(" / ") .append(Utilities.readableFileSize(value.second.get())) .append(sep)); - sb.append("#################################################################"); + sb.append("#################################################################\n"); log.info(sb.toString()); } diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataManager.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataManager.java index 5a62959e12..39277f6d58 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataManager.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/RequestDataManager.java @@ -1,22 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata; +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.Inject; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.app.Version; @@ -32,10 +35,6 @@ import haveno.network.p2p.peers.getdata.messages.GetDataRequest; import haveno.network.p2p.peers.peerexchange.Peer; import haveno.network.p2p.seed.SeedNodeRepository; import haveno.network.p2p.storage.P2PDataStorage; -import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.Nullable; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -43,11 +42,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; +import lombok.extern.slf4j.Slf4j; +import org.jetbrains.annotations.Nullable; @Slf4j public class RequestDataManager implements MessageListener, ConnectionListener, PeerManager.Listener { @@ -57,8 +56,10 @@ public class RequestDataManager implements MessageListener, ConnectionListener, private static int NUM_SEEDS_FOR_PRELIMINARY_REQUEST = 2; // how many seeds additional to the first responding PreliminaryGetDataRequest seed we request the GetUpdatedDataRequest from private static int NUM_ADDITIONAL_SEEDS_FOR_UPDATE_REQUEST = 1; + private static int MAX_REPEATED_REQUESTS = 30; private boolean isPreliminaryDataRequest = true; + /////////////////////////////////////////////////////////////////////////////////////////// // Listener /////////////////////////////////////////////////////////////////////////////////////////// @@ -77,6 +78,12 @@ public class RequestDataManager implements MessageListener, ConnectionListener, } } + public interface ResponseListener { + void onSuccess(int serializedSize); + + void onFault(); + } + /////////////////////////////////////////////////////////////////////////////////////////// // Class fields @@ -86,6 +93,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, private final P2PDataStorage dataStorage; private final PeerManager peerManager; private final List<NodeAddress> seedNodeAddresses; + private final List<ResponseListener> responseListeners = new CopyOnWriteArrayList<>(); // As we use Guice injection we cannot set the listener in our constructor but the P2PService calls the setListener // in it's constructor so we can guarantee it is not null. @@ -96,8 +104,9 @@ public class RequestDataManager implements MessageListener, ConnectionListener, private Optional<NodeAddress> nodeAddressOfPreliminaryDataRequest = Optional.empty(); private Timer retryTimer; private boolean dataUpdateRequested; + private boolean allDataReceived; private boolean stopped; - + private int numRepeatedRequests = 0; /////////////////////////////////////////////////////////////////////////////////////////// // Constructor @@ -126,6 +135,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, if (seedNodeRepository.isSeedNode(myAddress)) { NUM_SEEDS_FOR_PRELIMINARY_REQUEST = 3; NUM_ADDITIONAL_SEEDS_FOR_UPDATE_REQUEST = 2; + MAX_REPEATED_REQUESTS = 100; } } }); @@ -201,6 +211,10 @@ public class RequestDataManager implements MessageListener, ConnectionListener, return nodeAddressOfPreliminaryDataRequest; } + public void addResponseListener(ResponseListener responseListener) { + responseListeners.add(responseListener); + } + /////////////////////////////////////////////////////////////////////////////////////////// // ConnectionListener implementation @@ -268,9 +282,11 @@ public class RequestDataManager implements MessageListener, ConnectionListener, GetDataRequestHandler getDataRequestHandler = new GetDataRequestHandler(networkNode, dataStorage, new GetDataRequestHandler.Listener() { @Override - public void onComplete() { + public void onComplete(int serializedSize) { getDataRequestHandlers.remove(uid); log.trace("requestDataHandshake completed.\n\tConnection={}", connection); + + responseListeners.forEach(listener -> listener.onSuccess(serializedSize)); } @Override @@ -280,6 +296,8 @@ public class RequestDataManager implements MessageListener, ConnectionListener, log.trace("GetDataRequestHandler failed.\n\tConnection={}\n\t" + "ErrorMessage={}", connection, errorMessage); peerManager.handleConnectionFault(connection); + + responseListeners.forEach(ResponseListener::onFault); } else { log.warn("We have stopped already. We ignore that getDataRequestHandler.handle.onFault call."); } @@ -315,7 +333,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, RequestDataHandler requestDataHandler = new RequestDataHandler(networkNode, dataStorage, peerManager, new RequestDataHandler.Listener() { @Override - public void onComplete() { + public void onComplete(boolean wasTruncated) { log.trace("RequestDataHandshake of outbound connection complete. nodeAddress={}", nodeAddress); stopRetryTimer(); @@ -338,7 +356,27 @@ public class RequestDataManager implements MessageListener, ConnectionListener, checkNotNull(listener).onUpdatedDataReceived(); } - checkNotNull(listener).onDataReceived(); + if (wasTruncated) { + if (numRepeatedRequests < MAX_REPEATED_REQUESTS) { + // If we had allDataReceived already set to true but get a response with truncated flag, + // we still repeat the request to that node for higher redundancy. Otherwise, one seed node + // providing incomplete data would stop others to fill the gaps. + log.info("DataResponse did not contain all data, so we repeat request until we got all data"); + UserThread.runAfter(() -> requestData(nodeAddress, remainingNodeAddresses), 2); + } else if (!allDataReceived) { + allDataReceived = true; + log.warn("\n#################################################################\n" + + "Loading initial data from {} did not complete after 20 repeated requests. \n" + + "#################################################################\n", nodeAddress); + checkNotNull(listener).onDataReceived(); + } + } else if (!allDataReceived) { + allDataReceived = true; + log.info("\n\n#################################################################\n" + + "Loading initial data from {} completed\n" + + "#################################################################\n", nodeAddress); + checkNotNull(listener).onDataReceived(); + } } @Override @@ -379,6 +417,7 @@ public class RequestDataManager implements MessageListener, ConnectionListener, } }); handlerMap.put(nodeAddress, requestDataHandler); + numRepeatedRequests++; requestDataHandler.requestData(nodeAddress, isPreliminaryDataRequest); } else { log.warn("We have started already a requestDataHandshake to peer. nodeAddress=" + nodeAddress + "\n" + diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataRequest.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataRequest.java index fe2b6e898d..623724dd12 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataRequest.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataResponse.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataResponse.java index e44b0b60f0..40774ffebf 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataResponse.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetDataResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetUpdatedDataRequest.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetUpdatedDataRequest.java index 10dc57cef3..9a2a993845 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetUpdatedDataRequest.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/GetUpdatedDataRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java index 27bca59e18..21cf169b27 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/getdata/messages/PreliminaryGetDataRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.getdata.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveHandler.java b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveHandler.java index 54673fca7c..07ea9397a5 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveHandler.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.keepalive; @@ -40,8 +40,10 @@ import java.util.concurrent.TimeUnit; class KeepAliveHandler implements MessageListener { private static final Logger log = LoggerFactory.getLogger(KeepAliveHandler.class); - private static final int DELAY_MS = 10_000; + private static final long LOG_THROTTLE_INTERVAL_MS = 60000; // throttle logging warnings to once every 60 seconds + private static long lastLoggedWarningTs = 0; + private static int numThrottledWarnings = 0; /////////////////////////////////////////////////////////////////////////////////////////// @@ -147,9 +149,8 @@ class KeepAliveHandler implements MessageListener { cleanup(); listener.onComplete(); } else { - log.warn("Nonce not matching. That should never happen.\n\t" + - "We drop that message. nonce={} / requestNonce={}", - nonce, pong.getRequestNonce()); + throttleWarn("Nonce not matching. That should never happen.\n" + + "\tWe drop that message. nonce=" + nonce + ", requestNonce=" + pong.getRequestNonce() + ", peerNodeAddress=" + connection.getPeersNodeAddressOptional().orElseGet(null)); } } else { log.trace("We have stopped already. We ignore that onMessage call."); @@ -167,4 +168,16 @@ class KeepAliveHandler implements MessageListener { delayTimer = null; } } + + private synchronized void throttleWarn(String msg) { + boolean logWarning = System.currentTimeMillis() - lastLoggedWarningTs > LOG_THROTTLE_INTERVAL_MS; + if (logWarning) { + log.warn(msg); + if (numThrottledWarnings > 0) log.warn("{} warnings were throttled since the last log entry", numThrottledWarnings); + numThrottledWarnings = 0; + lastLoggedWarningTs = System.currentTimeMillis(); + } else { + numThrottledWarnings++; + } + } } diff --git a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveManager.java b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveManager.java index d1772dc8bc..5a80a67a94 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveManager.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/KeepAliveManager.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.keepalive; @@ -20,6 +20,7 @@ package haveno.network.p2p.peers.keepalive; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; +import com.google.inject.Inject; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.proto.network.NetworkEnvelope; @@ -33,13 +34,11 @@ import haveno.network.p2p.network.OutboundConnection; import haveno.network.p2p.peers.PeerManager; import haveno.network.p2p.peers.keepalive.messages.Ping; import haveno.network.p2p.peers.keepalive.messages.Pong; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.inject.Inject; import java.util.HashMap; import java.util.Map; import java.util.Random; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class KeepAliveManager implements MessageListener, ConnectionListener, PeerManager.Listener { private static final Logger log = LoggerFactory.getLogger(KeepAliveManager.class); diff --git a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/KeepAliveMessage.java b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/KeepAliveMessage.java index d675956c99..c5ba84056d 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/KeepAliveMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/KeepAliveMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.keepalive.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Ping.java b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Ping.java index 233a4c1a0a..f841124038 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Ping.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Ping.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.keepalive.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Pong.java b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Pong.java index 73f0f5f8a7..5c4646e415 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Pong.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/keepalive/messages/Pong.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.keepalive.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/GetPeersRequestHandler.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/GetPeersRequestHandler.java index 365358bb2b..094f15131a 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/GetPeersRequestHandler.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/GetPeersRequestHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/Peer.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/Peer.java index d062314597..2183b4ecc1 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/Peer.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/Peer.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange; @@ -33,7 +33,7 @@ import java.util.Date; @Getter @Slf4j public final class Peer implements HasCapabilities, NetworkPayload, PersistablePayload, SupportedCapabilitiesListener { - private static final int MAX_FAILED_CONNECTION_ATTEMPTS = 5; + private static final int MAX_FAILED_CONNECTION_ATTEMPTS = 8; private final NodeAddress nodeAddress; private final long date; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeHandler.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeHandler.java index 4aedf4e446..0b10307ccb 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeHandler.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeHandler.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange; @@ -45,6 +45,9 @@ class PeerExchangeHandler implements MessageListener { // We want to keep timeout short here private static final long TIMEOUT = 90; private static final int DELAY_MS = 500; + private static final long LOG_THROTTLE_INTERVAL_MS = 60000; // throttle logging warnings to once every 60 seconds + private static long lastLoggedWarningTs = 0; + private static int numThrottledWarnings = 0; /////////////////////////////////////////////////////////////////////////////////////////// @@ -115,35 +118,39 @@ class PeerExchangeHandler implements MessageListener { TIMEOUT, TimeUnit.SECONDS); } - SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, getPeersRequest); - Futures.addCallback(future, new FutureCallback<Connection>() { - @Override - public void onSuccess(Connection connection) { - if (!stopped) { - //TODO - /*if (!connection.getPeersNodeAddressOptional().isPresent()) { - connection.setPeersNodeAddress(nodeAddress); - log.warn("sendGetPeersRequest: !connection.getPeersNodeAddressOptional().isPresent()"); - }*/ - - PeerExchangeHandler.this.connection = connection; - connection.addMessageListener(PeerExchangeHandler.this); - } else { - log.trace("We have stopped that handler already. We ignore that sendGetPeersRequest.onSuccess call."); + try { + SettableFuture<Connection> future = networkNode.sendMessage(nodeAddress, getPeersRequest); + Futures.addCallback(future, new FutureCallback<Connection>() { + @Override + public void onSuccess(Connection connection) { + if (!stopped) { + //TODO + /*if (!connection.getPeersNodeAddressOptional().isPresent()) { + connection.setPeersNodeAddress(nodeAddress); + log.warn("sendGetPeersRequest: !connection.getPeersNodeAddressOptional().isPresent()"); + }*/ + + PeerExchangeHandler.this.connection = connection; + connection.addMessageListener(PeerExchangeHandler.this); + } else { + log.trace("We have stopped that handler already. We ignore that sendGetPeersRequest.onSuccess call."); + } } - } - - @Override - public void onFailure(@NotNull Throwable throwable) { - if (!stopped) { - String errorMessage = "Sending getPeersRequest to " + nodeAddress + - " failed. That is expected if the peer is offline. Exception=" + throwable.getMessage(); - handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, nodeAddress); - } else { - log.trace("We have stopped that handler already. We ignore that sendGetPeersRequest.onFailure call."); + + @Override + public void onFailure(@NotNull Throwable throwable) { + if (!stopped) { + String errorMessage = "Sending getPeersRequest to " + nodeAddress + + " failed. That is expected if the peer is offline. Exception=" + throwable.getMessage(); + handleFault(errorMessage, CloseConnectionReason.SEND_MSG_FAILURE, nodeAddress); + } else { + log.trace("We have stopped that handler already. We ignore that sendGetPeersRequest.onFailure call."); + } } - } - }, MoreExecutors.directExecutor()); + }, MoreExecutors.directExecutor()); + } catch (Exception e) { + if (!networkNode.isShutDownStarted()) throw e; + } } else { log.debug("My node address is still null at sendGetPeersRequest. We ignore that call."); } @@ -169,9 +176,8 @@ class PeerExchangeHandler implements MessageListener { cleanup(); listener.onComplete(); } else { - log.warn("Nonce not matching. That should never happen.\n\t" + - "We drop that message. nonce={} / requestNonce={}", - nonce, getPeersResponse.getRequestNonce()); + throttleWarn("Nonce not matching. That should never happen.\n" + + "\tWe drop that message. nonce=" + nonce + ", requestNonce=" + getPeersResponse.getRequestNonce() + ", peerNodeAddress=" + connection.getPeersNodeAddressOptional().orElseGet(null)); } } else { log.trace("We have stopped that handler already. We ignore that onMessage call."); @@ -212,4 +218,15 @@ class PeerExchangeHandler implements MessageListener { } } + private synchronized void throttleWarn(String msg) { + boolean logWarning = System.currentTimeMillis() - lastLoggedWarningTs > LOG_THROTTLE_INTERVAL_MS; + if (logWarning) { + log.warn(msg); + if (numThrottledWarnings > 0) log.warn("{} warnings were throttled since the last log entry", numThrottledWarnings); + numThrottledWarnings = 0; + lastLoggedWarningTs = System.currentTimeMillis(); + } else { + numThrottledWarnings++; + } + } } diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeManager.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeManager.java index ec7d3b60f1..a6a637fbff 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeManager.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerExchangeManager.java @@ -1,23 +1,24 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange; import com.google.common.base.Preconditions; +import com.google.inject.Inject; import haveno.common.Timer; import haveno.common.UserThread; import haveno.common.proto.network.NetworkEnvelope; @@ -30,10 +31,6 @@ import haveno.network.p2p.network.NetworkNode; import haveno.network.p2p.peers.PeerManager; import haveno.network.p2p.peers.peerexchange.messages.GetPeersRequest; import haveno.network.p2p.seed.SeedNodeRepository; -import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; -import javax.inject.Inject; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -46,6 +43,8 @@ import java.util.Random; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; +import javax.annotation.Nullable; +import lombok.extern.slf4j.Slf4j; @Slf4j public class PeerExchangeManager implements MessageListener, ConnectionListener, PeerManager.Listener { @@ -131,7 +130,7 @@ public class PeerExchangeManager implements MessageListener, ConnectionListener, @Override public void onDisconnect(CloseConnectionReason closeConnectionReason, Connection connection) { - log.info("onDisconnect closeConnectionReason={}, nodeAddressOpt={}", closeConnectionReason, connection.getPeersNodeAddressOptional()); + log.debug("onDisconnect closeConnectionReason={}, nodeAddressOpt={}", closeConnectionReason, connection.getPeersNodeAddressOptional()); closeHandler(connection); if (retryTimer == null) { diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerList.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerList.java index ae5e5006db..bf1029094f 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerList.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/PeerList.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersRequest.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersRequest.java index b95435421d..0f9cd58da9 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersRequest.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersRequest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersResponse.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersResponse.java index 8b19607b30..67f0f6bf82 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersResponse.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/GetPeersResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/PeerExchangeMessage.java b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/PeerExchangeMessage.java index c12704c88c..ee63bafee4 100644 --- a/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/PeerExchangeMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/peers/peerexchange/messages/PeerExchangeMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers.peerexchange.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/seed/SeedNodeRepository.java b/p2p/src/main/java/haveno/network/p2p/seed/SeedNodeRepository.java index 2755ae9726..020c46eb42 100644 --- a/p2p/src/main/java/haveno/network/p2p/seed/SeedNodeRepository.java +++ b/p2p/src/main/java/haveno/network/p2p/seed/SeedNodeRepository.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.seed; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/HashMapChangedListener.java b/p2p/src/main/java/haveno/network/p2p/storage/HashMapChangedListener.java index 89031c130c..4c8b939634 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/HashMapChangedListener.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/HashMapChangedListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/P2PDataStorage.java b/p2p/src/main/java/haveno/network/p2p/storage/P2PDataStorage.java index 45017c9967..40be21ef32 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/P2PDataStorage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/P2PDataStorage.java @@ -1,22 +1,42 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; +import com.google.inject.Inject; +import com.google.inject.name.Named; +import com.google.protobuf.ByteString; +import haveno.common.Timer; +import haveno.common.UserThread; +import haveno.common.app.Capabilities; +import haveno.common.crypto.CryptoException; +import haveno.common.crypto.Hash; +import haveno.common.crypto.Sig; +import haveno.common.persistence.PersistenceManager; +import haveno.common.proto.network.GetDataResponsePriority; +import haveno.common.proto.network.NetworkEnvelope; +import haveno.common.proto.network.NetworkPayload; +import haveno.common.proto.persistable.PersistablePayload; +import haveno.common.proto.persistable.PersistedDataHost; +import haveno.common.util.Hex; +import haveno.common.util.Tuple2; +import haveno.common.util.Utilities; import haveno.network.p2p.NodeAddress; import haveno.network.p2p.network.CloseConnectionReason; import haveno.network.p2p.network.Connection; @@ -54,43 +74,9 @@ import haveno.network.p2p.storage.persistence.ProtectedDataStoreService; import haveno.network.p2p.storage.persistence.RemovedPayloadsService; import haveno.network.p2p.storage.persistence.ResourceDataStoreService; import haveno.network.p2p.storage.persistence.SequenceNumberMap; - -import haveno.common.Timer; -import haveno.common.UserThread; -import haveno.common.app.Capabilities; -import haveno.common.crypto.CryptoException; -import haveno.common.crypto.Hash; -import haveno.common.crypto.Sig; -import haveno.common.persistence.PersistenceManager; -import haveno.common.proto.network.GetDataResponsePriority; -import haveno.common.proto.network.NetworkEnvelope; -import haveno.common.proto.network.NetworkPayload; -import haveno.common.proto.persistable.PersistablePayload; -import haveno.common.proto.persistable.PersistedDataHost; -import haveno.common.util.Hex; -import haveno.common.util.Tuple2; -import haveno.common.util.Utilities; - -import com.google.protobuf.ByteString; - -import com.google.inject.name.Named; - -import javax.inject.Inject; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Maps; - -import org.fxmisc.easybind.EasyBind; -import org.fxmisc.easybind.monadic.MonadicBinding; - -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; - import java.security.KeyPair; import java.security.PublicKey; - import java.time.Clock; - import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -111,14 +97,16 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; - +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javax.annotation.Nullable; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; - -import javax.annotation.Nullable; +import org.fxmisc.easybind.EasyBind; +import org.fxmisc.easybind.monadic.MonadicBinding; @Slf4j public class P2PDataStorage implements MessageListener, ConnectionListener, PersistedDataHost { @@ -247,7 +235,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers appendOnlyDataStoreService.readFromResourcesSync(postFix); protectedDataStoreService.readFromResourcesSync(postFix); resourceDataStoreService.readFromResourcesSync(postFix); - + map.putAll(protectedDataStoreService.getMap()); } } @@ -831,9 +819,9 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers synchronized (map) { ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload(); ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload); - + //log.trace("## call addProtectedStorageEntry hash={}, map={}", hashOfPayload, printMap()); - + // We do that check early as it is a very common case for returning, so we return early // If we have seen a more recent operation for this payload and we have a payload locally, ignore it ProtectedStorageEntry storedEntry = map.get(hashOfPayload); @@ -841,13 +829,13 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers log.trace("## hasSequenceNrIncreased is false. hash={}", hashOfPayload); return false; } - + if (hasAlreadyRemovedAddOncePayload(protectedStoragePayload, hashOfPayload)) { log.trace("## We have already removed that AddOncePayload by a previous removeDataMessage. " + "We ignore that message. ProtectedStoragePayload: {}", protectedStoragePayload.toString()); return false; } - + // To avoid that expired data get stored and broadcast we check for expire date. if (protectedStorageEntry.isExpired(clock)) { String peer = sender != null ? sender.getFullAddress() : "sender is null"; @@ -855,7 +843,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers peer, protectedStorageEntry.getProtectedStoragePayload().getClass().getSimpleName()); return false; } - + // We want to allow add operations for equal sequence numbers if we don't have the payload locally. This is // the case for non-persistent Payloads that need to be reconstructed from peer and seed nodes each startup. MapValue sequenceNumberMapValue = sequenceNumberMap.get(hashOfPayload); @@ -864,36 +852,36 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers log.trace("## sequenceNr too low hash={}", hashOfPayload); return false; } - + // Verify the ProtectedStorageEntry is well formed and valid for the add operation if (!protectedStorageEntry.isValidForAddOperation()) { log.trace("## !isValidForAddOperation hash={}", hashOfPayload); return false; } - + // If we have already seen an Entry with the same hash, verify the metadata is equal if (storedEntry != null && !protectedStorageEntry.matchesRelevantPubKey(storedEntry)) { log.trace("## !matchesRelevantPubKey hash={}", hashOfPayload); return false; } - + // Test against filterPredicate set from FilterManager if (filterPredicate != null && !filterPredicate.test(protectedStorageEntry.getProtectedStoragePayload())) { log.debug("filterPredicate test failed. hashOfPayload={}", hashOfPayload); return false; } - + // This is an updated entry. Record it and signal listeners. map.put(hashOfPayload, protectedStorageEntry); hashMapChangedListeners.forEach(e -> e.onAdded(Collections.singletonList(protectedStorageEntry))); - + // Record the updated sequence number and persist it. Higher delay so we can batch more items. sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.getSequenceNumber(), this.clock.millis())); requestPersistence(); - + //log.trace("## ProtectedStorageEntry added to map. hash={}, map={}", hashOfPayload, printMap()); - + // Optionally, broadcast the add/update depending on the calling environment if (allowBroadcast) { broadcaster.broadcast(new AddDataMessage(protectedStorageEntry), sender, listener); @@ -902,7 +890,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers // Persist ProtectedStorageEntries carrying PersistablePayload payloads if (protectedStoragePayload instanceof PersistablePayload) protectedDataStoreService.put(hashOfPayload, protectedStorageEntry); - + return true; } } @@ -951,13 +939,13 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers try { ByteArray hashOfPayload = new ByteArray(refreshTTLMessage.getHashOfPayload()); ProtectedStorageEntry storedData = map.get(hashOfPayload); - + if (storedData == null) { log.debug("We don't have data for that refresh message in our map. That is expected if we missed the data publishing."); - + return false; } - + ProtectedStorageEntry storedEntry = map.get(hashOfPayload); ProtectedStorageEntry updatedEntry = new ProtectedStorageEntry( storedEntry.getProtectedStoragePayload(), @@ -965,29 +953,28 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers refreshTTLMessage.getSequenceNumber(), refreshTTLMessage.getSignature(), this.clock); - - + + // If we have seen a more recent operation for this payload, we ignore the current one if (!hasSequenceNrIncreased(updatedEntry.getSequenceNumber(), hashOfPayload)) return false; - + // Verify the updated ProtectedStorageEntry is well formed and valid for update if (!updatedEntry.isValidForAddOperation()) return false; - + // Update the hash map with the updated entry map.put(hashOfPayload, updatedEntry); - + // Record the latest sequence number and persist it sequenceNumberMap.put(hashOfPayload, new MapValue(updatedEntry.getSequenceNumber(), this.clock.millis())); requestPersistence(); - + // Always broadcast refreshes broadcaster.broadcast(refreshTTLMessage, sender); - + } catch (IllegalArgumentException e) { - log.error("refreshTTL failed, missing data: {}", e.toString()); - e.printStackTrace(); + log.error("refreshTTL failed, missing data: {}\n", e.toString(), e); return false; } return true; @@ -1007,29 +994,29 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers synchronized (map) { ProtectedStoragePayload protectedStoragePayload = protectedStorageEntry.getProtectedStoragePayload(); ByteArray hashOfPayload = get32ByteHashAsByteArray(protectedStoragePayload); - + // If we have seen a more recent operation for this payload, ignore this one if (!hasSequenceNrIncreased(protectedStorageEntry.getSequenceNumber(), hashOfPayload)) return false; - + // Verify the ProtectedStorageEntry is well formed and valid for the remove operation if (!protectedStorageEntry.isValidForRemoveOperation()) return false; - + // If we have already seen an Entry with the same hash, verify the metadata is the same ProtectedStorageEntry storedEntry = map.get(hashOfPayload); if (storedEntry != null && !protectedStorageEntry.matchesRelevantPubKey(storedEntry)) return false; - + // Record the latest sequence number and persist it sequenceNumberMap.put(hashOfPayload, new MapValue(protectedStorageEntry.getSequenceNumber(), this.clock.millis())); requestPersistence(); - + // Update that we have seen this AddOncePayload so the next time it is seen it fails verification if (protectedStoragePayload instanceof AddOncePayload) { removedPayloadsService.addHash(hashOfPayload); } - + if (storedEntry != null) { // Valid remove entry, do the remove and signal listeners removeFromMapAndDataStore(protectedStorageEntry, hashOfPayload); @@ -1039,13 +1026,13 @@ public class P2PDataStorage implements MessageListener, ConnectionListener, Pers // broadcast the remove to peers so they can update their state appropriately } */ printData("after remove"); - + if (protectedStorageEntry instanceof ProtectedMailboxStorageEntry) { broadcaster.broadcast(new RemoveMailboxDataMessage((ProtectedMailboxStorageEntry) protectedStorageEntry), sender); } else { broadcaster.broadcast(new RemoveDataMessage(protectedStorageEntry), sender); } - + return true; } } diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/AddDataMessage.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/AddDataMessage.java index efa56080ff..bf2cf75164 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/AddDataMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/AddDataMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/AddOncePayload.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/AddOncePayload.java index 35b371d5a2..580745ed3b 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/AddOncePayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/AddOncePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/AddPersistableNetworkPayloadMessage.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/AddPersistableNetworkPayloadMessage.java index 5008480716..df1705add5 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/AddPersistableNetworkPayloadMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/AddPersistableNetworkPayloadMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/BroadcastMessage.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/BroadcastMessage.java index fe68940704..31b3400091 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/BroadcastMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/BroadcastMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/RefreshOfferMessage.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/RefreshOfferMessage.java index c760183a6e..b62d9e8a4d 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/RefreshOfferMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/RefreshOfferMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveDataMessage.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveDataMessage.java index 8e9b6ad702..eb9c0acbc6 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveDataMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveDataMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveMailboxDataMessage.java b/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveMailboxDataMessage.java index 4d8b1fe84b..b6d8dc07d0 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveMailboxDataMessage.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/messages/RemoveMailboxDataMessage.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/CapabilityRequiringPayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/CapabilityRequiringPayload.java index 029b387073..478c033a39 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/CapabilityRequiringPayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/CapabilityRequiringPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/DateSortedTruncatablePayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/DateSortedTruncatablePayload.java index 2a87928109..3c59f7376b 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/DateSortedTruncatablePayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/DateSortedTruncatablePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/DateTolerantPayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/DateTolerantPayload.java index c428d09f63..0e7c960f00 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/DateTolerantPayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/DateTolerantPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/ExpirablePayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/ExpirablePayload.java index 01811827c7..e4a01849dd 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/ExpirablePayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/ExpirablePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/MailboxStoragePayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/MailboxStoragePayload.java index d1070760c1..2c0419b9ba 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/MailboxStoragePayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/MailboxStoragePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableNetworkPayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableNetworkPayload.java index 63ff2ff7c5..ebd34f5af5 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableNetworkPayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableNetworkPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableProtectedPayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableProtectedPayload.java index 2a405d68b7..39e3c55760 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableProtectedPayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/PersistableProtectedPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProcessOncePersistableNetworkPayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProcessOncePersistableNetworkPayload.java index f7dadb5afd..87ef119545 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProcessOncePersistableNetworkPayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProcessOncePersistableNetworkPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntry.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntry.java index a8c5b0804a..4bb2146e0a 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntry.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntry.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStorageEntry.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStorageEntry.java index f4cebe260f..02c7775bb9 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStorageEntry.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStorageEntry.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; @@ -22,6 +22,7 @@ import com.google.protobuf.ByteString; import com.google.protobuf.Message; import haveno.common.crypto.CryptoException; import haveno.common.crypto.Sig; +import haveno.common.proto.network.GetDataResponsePriority; import haveno.common.proto.network.NetworkPayload; import haveno.common.proto.network.NetworkProtoResolver; import haveno.common.proto.persistable.PersistablePayload; @@ -141,6 +142,10 @@ public class ProtectedStorageEntry implements NetworkPayload, PersistablePayload (clock.millis() - creationTimeStamp) > ((ExpirablePayload) protectedStoragePayload).getTTL(); } + public GetDataResponsePriority getGetDataResponsePriority() { + return protectedStoragePayload.getGetDataResponsePriority(); + } + /* * Returns true if the Entry is valid for an add operation. For non-mailbox Entrys, the entry owner must * match the payload owner. diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStoragePayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStoragePayload.java index 91cf2348b2..f8abe05c61 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStoragePayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/ProtectedStoragePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/payload/RequiresOwnerIsOnlinePayload.java b/p2p/src/main/java/haveno/network/p2p/storage/payload/RequiresOwnerIsOnlinePayload.java index 11ff9d7c51..48c148389e 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/payload/RequiresOwnerIsOnlinePayload.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/payload/RequiresOwnerIsOnlinePayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreListener.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreListener.java index 5e76291afe..acc3c69881 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreListener.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreListener.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreService.java index 6aabfe761d..6431aa9502 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/AppendOnlyDataStoreService.java @@ -1,32 +1,26 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; import com.google.common.annotations.VisibleForTesting; +import com.google.inject.Inject; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; -import lombok.Getter; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; - -import org.jetbrains.annotations.NotNull; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -34,6 +28,11 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +import org.jetbrains.annotations.NotNull; + /** * Used for PersistableNetworkPayload data which gets appended to a map storage. */ diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/HistoricalDataStoreService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/HistoricalDataStoreService.java index 900a88c8c6..c74790c50e 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/HistoricalDataStoreService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/HistoricalDataStoreService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; @@ -79,7 +79,7 @@ public abstract class HistoricalDataStoreService<T extends PersistableNetworkPay "As our historical store is a newer version we add the data to our result map." : "As the requester version is not older as our historical store we do not " + "add the data to the result map."; - log.info("The requester had version {}. Our historical data store has version {}.\n{}", + log.trace("The requester had version {}. Our historical data store has version {}.\n{}", requestersVersion, storeVersion, details); return newVersion; }) @@ -141,7 +141,7 @@ public abstract class HistoricalDataStoreService<T extends PersistableNetworkPay @Override protected void readFromResources(String postFix, Runnable completeHandler) { readStore(persisted -> { - log.info("We have created the {} store for the live data and filled it with {} entries from the persisted data.", + log.debug("We have created the {} store for the live data and filled it with {} entries from the persisted data.", getFileName(), getMapOfLiveData().size()); // Now we add our historical data stores. @@ -181,7 +181,7 @@ public abstract class HistoricalDataStoreService<T extends PersistableNetworkPay persistenceManager.readPersisted(fileName, persisted -> { storesByVersion.put(version, persisted); allHistoricalPayloads.putAll(persisted.getMap()); - log.info("We have read from {} {} historical items.", fileName, persisted.getMap().size()); + log.debug("We have read from {} {} historical items.", fileName, persisted.getMap().size()); pruneStore(persisted, version); completeHandler.run(); }, @@ -195,11 +195,11 @@ public abstract class HistoricalDataStoreService<T extends PersistableNetworkPay mapOfLiveData.keySet().removeAll(historicalStore.getMap().keySet()); int postLive = mapOfLiveData.size(); if (preLive > postLive) { - log.info("We pruned data from our live data store which are already contained in the historical data store with version {}. " + + log.debug("We pruned data from our live data store which are already contained in the historical data store with version {}. " + "The live map had {} entries before pruning and has {} entries afterwards.", version, preLive, postLive); } else { - log.info("No pruning from historical data store with version {} was applied", version); + log.debug("No pruning from historical data store with version {} was applied", version); } requestPersistence(); } diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/MapStoreService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/MapStoreService.java index 2780f8ccf4..8e08e86201 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/MapStoreService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/MapStoreService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/PersistableNetworkPayloadStore.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/PersistableNetworkPayloadStore.java index 3683a4f8f7..0d7820780f 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/PersistableNetworkPayloadStore.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/PersistableNetworkPayloadStore.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/ProtectedDataStoreService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/ProtectedDataStoreService.java index 8e1291b274..a26c2be2c5 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/ProtectedDataStoreService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/ProtectedDataStoreService.java @@ -1,35 +1,34 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; import com.google.common.annotations.VisibleForTesting; +import com.google.inject.Inject; import haveno.common.proto.persistable.PersistableEnvelope; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; /** * Used for data which can be added and removed. ProtectedStorageEntry is used for verifying ownership. diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsMap.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsMap.java index e05a42fa07..ae7bb91993 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsMap.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsMap.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsService.java index 902ae73fb9..6908696c13 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/RemovedPayloadsService.java @@ -1,31 +1,30 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; +import com.google.inject.Inject; +import com.google.inject.Singleton; import haveno.common.persistence.PersistenceManager; import haveno.common.proto.persistable.PersistedDataHost; import haveno.network.p2p.storage.P2PDataStorage; import haveno.network.p2p.storage.payload.MailboxStoragePayload; import lombok.extern.slf4j.Slf4j; -import javax.inject.Inject; -import javax.inject.Singleton; - /** * We persist the hashes and timestamp when a AddOncePayload payload got removed. This protects that it could be * added again for instance if the sequence number map would be inconsistent/deleted or when we receive data from diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/ResourceDataStoreService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/ResourceDataStoreService.java index b10573c8cb..c5cbc90f93 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/ResourceDataStoreService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/ResourceDataStoreService.java @@ -1,30 +1,29 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; import com.google.common.annotations.VisibleForTesting; +import com.google.inject.Inject; import haveno.common.proto.persistable.PersistableEnvelope; -import lombok.extern.slf4j.Slf4j; - -import javax.inject.Inject; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; +import lombok.extern.slf4j.Slf4j; /** * Used for handling data from resource files. diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/SequenceNumberMap.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/SequenceNumberMap.java index b8dffb7143..f774c4c3c4 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/SequenceNumberMap.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/SequenceNumberMap.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; diff --git a/p2p/src/main/java/haveno/network/p2p/storage/persistence/StoreService.java b/p2p/src/main/java/haveno/network/p2p/storage/persistence/StoreService.java index a2115316f1..17c940add8 100644 --- a/p2p/src/main/java/haveno/network/p2p/storage/persistence/StoreService.java +++ b/p2p/src/main/java/haveno/network/p2p/storage/persistence/StoreService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.persistence; @@ -109,18 +109,17 @@ public abstract class StoreService<T extends PersistableEnvelope> { File destinationFile = new File(Paths.get(absolutePathOfStorageDir, fileName).toString()); if (!destinationFile.exists()) { try { - log.info("We copy resource to file: resourceFileName={}, destinationFile={}", resourceFileName, destinationFile); + log.debug("We copy resource to file: resourceFileName={}, destinationFile={}", resourceFileName, destinationFile); FileUtil.resourceToFile(resourceFileName, destinationFile); return true; } catch (ResourceNotFoundException e) { - log.info("Could not find resourceFile " + resourceFileName + ". That is expected if none is provided yet."); + log.debug("Could not find resourceFile " + resourceFileName + ". That is expected if none is provided yet."); } catch (Throwable e) { log.error("Could not copy resourceFile " + resourceFileName + " to " + - destinationFile.getAbsolutePath() + ".\n" + e.getMessage()); - e.printStackTrace(); + destinationFile.getAbsolutePath() + ".\n", e); } } else { - log.info("No resource file was copied. {} exists already.", fileName); + log.debug("No resource file was copied. {} exists already.", fileName); } return false; } diff --git a/p2p/src/main/java/haveno/network/utils/CapabilityUtils.java b/p2p/src/main/java/haveno/network/utils/CapabilityUtils.java index f6c3369cc7..480bd581c6 100644 --- a/p2p/src/main/java/haveno/network/utils/CapabilityUtils.java +++ b/p2p/src/main/java/haveno/network/utils/CapabilityUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.utils; diff --git a/p2p/src/main/java/haveno/network/utils/Utils.java b/p2p/src/main/java/haveno/network/utils/Utils.java index b99bce0a80..bbe8873c3f 100644 --- a/p2p/src/main/java/haveno/network/utils/Utils.java +++ b/p2p/src/main/java/haveno/network/utils/Utils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.utils; diff --git a/p2p/src/test/java/haveno/network/crypto/EncryptionServiceTests.java b/p2p/src/test/java/haveno/network/crypto/EncryptionServiceTests.java index 56cb53688b..144adf6a32 100644 --- a/p2p/src/test/java/haveno/network/crypto/EncryptionServiceTests.java +++ b/p2p/src/test/java/haveno/network/crypto/EncryptionServiceTests.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.crypto; diff --git a/p2p/src/test/java/haveno/network/p2p/DummySeedNode.java b/p2p/src/test/java/haveno/network/p2p/DummySeedNode.java index 3b575eece2..b9ebaa96af 100644 --- a/p2p/src/test/java/haveno/network/p2p/DummySeedNode.java +++ b/p2p/src/test/java/haveno/network/p2p/DummySeedNode.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/test/java/haveno/network/p2p/MockNode.java b/p2p/src/test/java/haveno/network/p2p/MockNode.java index 5d7fda70b6..94ab1a52b8 100644 --- a/p2p/src/test/java/haveno/network/p2p/MockNode.java +++ b/p2p/src/test/java/haveno/network/p2p/MockNode.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/test/java/haveno/network/p2p/PeerServiceTest.java b/p2p/src/test/java/haveno/network/p2p/PeerServiceTest.java index 42fc011ba0..d7d6a363e4 100644 --- a/p2p/src/test/java/haveno/network/p2p/PeerServiceTest.java +++ b/p2p/src/test/java/haveno/network/p2p/PeerServiceTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/test/java/haveno/network/p2p/TestUtils.java b/p2p/src/test/java/haveno/network/p2p/TestUtils.java index 41f30ddfb3..e6b71f8fad 100644 --- a/p2p/src/test/java/haveno/network/p2p/TestUtils.java +++ b/p2p/src/test/java/haveno/network/p2p/TestUtils.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p; diff --git a/p2p/src/test/java/haveno/network/p2p/mocks/MockMailboxPayload.java b/p2p/src/test/java/haveno/network/p2p/mocks/MockMailboxPayload.java index afda8b64da..70993bf318 100644 --- a/p2p/src/test/java/haveno/network/p2p/mocks/MockMailboxPayload.java +++ b/p2p/src/test/java/haveno/network/p2p/mocks/MockMailboxPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/mocks/MockPayload.java b/p2p/src/test/java/haveno/network/p2p/mocks/MockPayload.java index c838639ab9..a0eb0af529 100644 --- a/p2p/src/test/java/haveno/network/p2p/mocks/MockPayload.java +++ b/p2p/src/test/java/haveno/network/p2p/mocks/MockPayload.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/network/LocalhostNetworkNodeTest.java b/p2p/src/test/java/haveno/network/p2p/network/LocalhostNetworkNodeTest.java index f6f0ca15fd..29afdf0b3b 100644 --- a/p2p/src/test/java/haveno/network/p2p/network/LocalhostNetworkNodeTest.java +++ b/p2p/src/test/java/haveno/network/p2p/network/LocalhostNetworkNodeTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; diff --git a/p2p/src/test/java/haveno/network/p2p/network/TorNetworkNodeTest.java b/p2p/src/test/java/haveno/network/p2p/network/TorNetworkNodeTest.java index 2269c0204b..54bbc7ee1a 100644 --- a/p2p/src/test/java/haveno/network/p2p/network/TorNetworkNodeTest.java +++ b/p2p/src/test/java/haveno/network/p2p/network/TorNetworkNodeTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.network; @@ -50,8 +50,13 @@ public class TorNetworkNodeTest { public void testTorNodeBeforeSecondReady() throws InterruptedException, IOException { latch = new CountDownLatch(1); int port = 9001; - TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); + TorNetworkNode node1 = new TorNetworkNodeNetlayer(port, + TestUtils.getNetworkProtoResolver(), + new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), + null, + 12, + false, + "127.0.0.1"); node1.start(new SetupListener() { @Override public void onTorNodeReady() { @@ -77,8 +82,13 @@ public class TorNetworkNodeTest { latch = new CountDownLatch(1); int port2 = 9002; - TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); + TorNetworkNode node2 = new TorNetworkNodeNetlayer(port2, + TestUtils.getNetworkProtoResolver(), + new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), + null, + 12, + false, + "127.0.0.1"); node2.start(new SetupListener() { @Override public void onTorNodeReady() { @@ -135,8 +145,13 @@ public class TorNetworkNodeTest { public void testTorNodeAfterBothReady() throws InterruptedException, IOException { latch = new CountDownLatch(2); int port = 9001; - TorNetworkNode node1 = new TorNetworkNode(port, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); + TorNetworkNode node1 = new TorNetworkNodeNetlayer(port, + TestUtils.getNetworkProtoResolver(), + new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), + null, + 12, + false, + "127.0.0.1"); node1.start(new SetupListener() { @Override public void onTorNodeReady() { @@ -161,8 +176,12 @@ public class TorNetworkNodeTest { }); int port2 = 9002; - TorNetworkNode node2 = new TorNetworkNode(port2, TestUtils.getNetworkProtoResolver(), false, - new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), null, 12); + TorNetworkNode node2 = new TorNetworkNodeNetlayer(port2, TestUtils.getNetworkProtoResolver(), + new NewTor(new File("torNode_" + port), null, "", this::getBridgeAddresses), + null, + 12, + false, + "127.0.0.1"); node2.start(new SetupListener() { @Override public void onTorNodeReady() { diff --git a/p2p/src/test/java/haveno/network/p2p/peers/PeerManagerTest.java b/p2p/src/test/java/haveno/network/p2p/peers/PeerManagerTest.java index 5ba5570593..e3303a0969 100644 --- a/p2p/src/test/java/haveno/network/p2p/peers/PeerManagerTest.java +++ b/p2p/src/test/java/haveno/network/p2p/peers/PeerManagerTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.peers; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageBuildGetDataResponseTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageBuildGetDataResponseTest.java index 4b50fff594..1af5685506 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageBuildGetDataResponseTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageBuildGetDataResponseTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; @@ -33,10 +33,10 @@ import haveno.network.p2p.storage.payload.CapabilityRequiringPayload; import haveno.network.p2p.storage.payload.PersistableNetworkPayload; import haveno.network.p2p.storage.payload.ProtectedStorageEntry; import haveno.network.p2p.storage.payload.ProtectedStoragePayload; +import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; @@ -45,6 +45,10 @@ import java.util.HashSet; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +import org.mockito.junit.jupiter.MockitoExtension; +import org.mockito.junit.jupiter.MockitoSettings; +import org.mockito.quality.Strictness; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -54,6 +58,8 @@ import static org.mockito.Mockito.when; import static org.mockito.Mockito.withSettings; public class P2PDataStorageBuildGetDataResponseTest { + @ExtendWith(MockitoExtension.class) + @MockitoSettings(strictness = Strictness.LENIENT) // there are unused stubs in TestState & elsewhere abstract static class P2PDataStorageBuildGetDataResponseTestBase { // GIVEN null & non-null supportedCapabilities private TestState testState; @@ -67,7 +73,6 @@ public class P2PDataStorageBuildGetDataResponseTest { @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); this.testState = new TestState(); this.localNodeAddress = new NodeAddress("localhost", 8080); diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageClientAPITest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageClientAPITest.java index 9990cfa7be..fcdd22a1d7 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageClientAPITest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageClientAPITest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageGetDataIntegrationTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageGetDataIntegrationTest.java index 47c27400cd..f5e558ee1c 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageGetDataIntegrationTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageGetDataIntegrationTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageOnMessageHandlerTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageOnMessageHandlerTest.java index 80a7a99f27..c258f3115c 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageOnMessageHandlerTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageOnMessageHandlerTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoragePersistableNetworkPayloadTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoragePersistableNetworkPayloadTest.java index 8d1bafe44b..9322ef136f 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoragePersistableNetworkPayloadTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoragePersistableNetworkPayloadTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; @@ -30,7 +30,6 @@ import java.util.Optional; import java.util.stream.Stream; import static haveno.network.p2p.storage.TestState.SavedTestState; -import static haveno.network.p2p.storage.TestState.getTestNodeAddress; import static java.util.stream.Stream.of; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; @@ -67,8 +66,9 @@ public class P2PDataStoragePersistableNetworkPayloadTest { @BeforeEach public void setup() { - persistableNetworkPayload = createInstance(); - testState = new TestState(); + this.persistableNetworkPayload = this.createInstance(); + + this.testState = new TestState(); } void assertAndDoAdd(PersistableNetworkPayload persistableNetworkPayload, @@ -82,14 +82,15 @@ public class P2PDataStoragePersistableNetworkPayloadTest { if (testCase == TestCase.PUBLIC_API) { assertEquals(expectedReturnValue, - testState.mockedStorage.addPersistableNetworkPayload(persistableNetworkPayload, getTestNodeAddress(), reBroadcast)); + this.testState.mockedStorage.addPersistableNetworkPayload(persistableNetworkPayload, TestState.getTestNodeAddress(), reBroadcast)); } else { // onMessage - Connection mockedConnection = mock(); - when(mockedConnection.getPeersNodeAddressOptional()).thenReturn(Optional.of(getTestNodeAddress())); + Connection mockedConnection = mock(Connection.class); + when(mockedConnection.getPeersNodeAddressOptional()).thenReturn(Optional.of(TestState.getTestNodeAddress())); testState.mockedStorage.onMessage(new AddPersistableNetworkPayloadMessage(persistableNetworkPayload), mockedConnection); } - testState.verifyPersistableAdd(beforeState, persistableNetworkPayload, expectedHashMapAndDataStoreUpdated, expectedListenersSignaled, expectedBroadcast); + + this.testState.verifyPersistableAdd(beforeState, persistableNetworkPayload, expectedHashMapAndDataStoreUpdated, expectedListenersSignaled, expectedBroadcast); } static Stream<Object[]> data() { @@ -103,16 +104,17 @@ public class P2PDataStoragePersistableNetworkPayloadTest { @MethodSource("data") @ParameterizedTest(name = "{index}: Test with TestCase={0} allowBroadcast={1} reBroadcast={2} checkDate={3}") public void addPersistableNetworkPayload(TestCase testCase, boolean reBroadcast) { - assertAndDoAdd(persistableNetworkPayload, testCase, reBroadcast, true, true, true, true); + // First add should succeed regardless of parameters + assertAndDoAdd(this.persistableNetworkPayload, testCase, reBroadcast, true, true, true, true); } @MethodSource("data") @ParameterizedTest(name = "{index}: Test with TestCase={0} allowBroadcast={1} reBroadcast={2} checkDate={3}") public void addPersistableNetworkPayloadDuplicate(TestCase testCase, boolean reBroadcast) { - assertAndDoAdd(persistableNetworkPayload, testCase, reBroadcast, true, true, true, true); + assertAndDoAdd(this.persistableNetworkPayload, testCase, reBroadcast, true, true, true, true); // We return true and broadcast if reBroadcast is set - // assertAndDoAdd(persistableNetworkPayload, testCase, reBroadcast, reBroadcast, false, false, reBroadcast); + // assertAndDoAdd(this.persistableNetworkPayload, testCase, reBroadcast, reBroadcast, false, false, reBroadcast); } } diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProcessGetDataResponse.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProcessGetDataResponse.java index 3a2c7b4106..1ec2c53d04 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProcessGetDataResponse.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProcessGetDataResponse.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; @@ -28,7 +28,6 @@ import haveno.network.p2p.storage.payload.ProtectedStorageEntry; import haveno.network.p2p.storage.payload.ProtectedStoragePayload; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; @@ -47,7 +46,6 @@ public class P2PDataStorageProcessGetDataResponse { @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); this.testState = new TestState(); this.peerNodeAddress = new NodeAddress("peer", 8080); @@ -108,7 +106,7 @@ public class P2PDataStorageProcessGetDataResponse { // XXXBUGXXX: We signal listeners w/ non ProcessOncePersistableNetworkPayloads @Test public void processGetDataResponse_newPNPUpdatesState() { - PersistableNetworkPayload persistableNetworkPayload = new PersistableNetworkPayloadStub(new byte[] { 1 }); + PersistableNetworkPayload persistableNetworkPayload = new PersistableNetworkPayloadStub(new byte[]{1}); GetDataResponse getDataResponse = buildGetDataResponse(persistableNetworkPayload); @@ -134,7 +132,7 @@ public class P2PDataStorageProcessGetDataResponse { // TESTCASE: GetDataResponse w/ existing PNP changes no state @Test public void processGetDataResponse_duplicatePNPDoesNothing() { - PersistableNetworkPayload persistableNetworkPayload = new PersistableNetworkPayloadStub(new byte[] { 1 }); + PersistableNetworkPayload persistableNetworkPayload = new PersistableNetworkPayloadStub(new byte[]{1}); this.testState.mockedStorage.addPersistableNetworkPayload(persistableNetworkPayload, this.peerNodeAddress, false); @@ -149,7 +147,7 @@ public class P2PDataStorageProcessGetDataResponse { // TESTCASE: GetDataResponse w/ missing PNP is added with no broadcast or listener signal (ProcessOncePersistableNetworkPayload) @Test public void processGetDataResponse_newPNPUpdatesState_LazyProcessed() { - PersistableNetworkPayload persistableNetworkPayload = new LazyPersistableNetworkPayloadStub(new byte[] { 1 }); + PersistableNetworkPayload persistableNetworkPayload = new LazyPersistableNetworkPayloadStub(new byte[]{1}); GetDataResponse getDataResponse = buildGetDataResponse(persistableNetworkPayload); @@ -162,7 +160,7 @@ public class P2PDataStorageProcessGetDataResponse { // TESTCASE: GetDataResponse w/ existing PNP changes no state (ProcessOncePersistableNetworkPayload) @Test public void processGetDataResponse_duplicatePNPDoesNothing_LazyProcessed() { - PersistableNetworkPayload persistableNetworkPayload = new LazyPersistableNetworkPayloadStub(new byte[] { 1 }); + PersistableNetworkPayload persistableNetworkPayload = new LazyPersistableNetworkPayloadStub(new byte[]{1}); this.testState.mockedStorage.addPersistableNetworkPayload(persistableNetworkPayload, this.peerNodeAddress, false); @@ -177,7 +175,7 @@ public class P2PDataStorageProcessGetDataResponse { // TESTCASE: Second call to processGetDataResponse adds PNP for non-ProcessOncePersistableNetworkPayloads @Test public void processGetDataResponse_secondProcessNewPNPUpdatesState() { - PersistableNetworkPayload addFromFirstProcess = new PersistableNetworkPayloadStub(new byte[] { 1 }); + PersistableNetworkPayload addFromFirstProcess = new PersistableNetworkPayloadStub(new byte[]{1}); GetDataResponse getDataResponse = buildGetDataResponse(addFromFirstProcess); TestState.SavedTestState beforeState = this.testState.saveTestState(addFromFirstProcess); @@ -185,7 +183,7 @@ public class P2PDataStorageProcessGetDataResponse { this.testState.verifyPersistableAdd( beforeState, addFromFirstProcess, true, true, false); - PersistableNetworkPayload addFromSecondProcess = new PersistableNetworkPayloadStub(new byte[] { 2 }); + PersistableNetworkPayload addFromSecondProcess = new PersistableNetworkPayloadStub(new byte[]{2}); getDataResponse = buildGetDataResponse(addFromSecondProcess); beforeState = this.testState.saveTestState(addFromSecondProcess); this.testState.mockedStorage.processGetDataResponse(getDataResponse, this.peerNodeAddress); @@ -196,7 +194,7 @@ public class P2PDataStorageProcessGetDataResponse { // TESTCASE: Second call to processGetDataResponse does not add any PNP (LazyProcessed) @Test public void processGetDataResponse_secondProcessNoPNPUpdates_LazyProcessed() { - PersistableNetworkPayload addFromFirstProcess = new LazyPersistableNetworkPayloadStub(new byte[] { 1 }); + PersistableNetworkPayload addFromFirstProcess = new LazyPersistableNetworkPayloadStub(new byte[]{1}); GetDataResponse getDataResponse = buildGetDataResponse(addFromFirstProcess); TestState.SavedTestState beforeState = this.testState.saveTestState(addFromFirstProcess); @@ -204,7 +202,7 @@ public class P2PDataStorageProcessGetDataResponse { this.testState.verifyPersistableAdd( beforeState, addFromFirstProcess, true, false, false); - PersistableNetworkPayload addFromSecondProcess = new LazyPersistableNetworkPayloadStub(new byte[] { 2 }); + PersistableNetworkPayload addFromSecondProcess = new LazyPersistableNetworkPayloadStub(new byte[]{2}); getDataResponse = buildGetDataResponse(addFromSecondProcess); beforeState = this.testState.saveTestState(addFromSecondProcess); this.testState.mockedStorage.processGetDataResponse(getDataResponse, this.peerNodeAddress); diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProtectedStorageEntryTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProtectedStorageEntryTest.java index f26c18e5ec..219936ba02 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProtectedStorageEntryTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageProtectedStorageEntryTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRemoveExpiredTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRemoveExpiredTest.java index 3f78de8405..3a7afc26aa 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRemoveExpiredTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRemoveExpiredTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRequestDataTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRequestDataTest.java index d99d82d930..e6496d3343 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRequestDataTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStorageRequestDataTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; @@ -30,7 +30,6 @@ import haveno.network.p2p.storage.payload.ProtectedStorageEntry; import haveno.network.p2p.storage.payload.ProtectedStoragePayload; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.MockitoAnnotations; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; @@ -49,7 +48,6 @@ public class P2PDataStorageRequestDataTest { @BeforeEach public void setUp() { - MockitoAnnotations.initMocks(this); this.testState = new TestState(); this.localNodeAddress = new NodeAddress("localhost", 8080); @@ -115,8 +113,8 @@ public class P2PDataStorageRequestDataTest { // correct GetDataRequestMessage with both sets of keys. @Test public void buildPreliminaryGetDataRequest_FilledP2PDataStore() throws NoSuchAlgorithmException { - PersistableNetworkPayload toAdd1 = new PersistableNetworkPayloadStub(new byte[] { 1 }); - PersistableNetworkPayload toAdd2 = new PersistableNetworkPayloadStub(new byte[] { 2 }); + PersistableNetworkPayload toAdd1 = new PersistableNetworkPayloadStub(new byte[]{1}); + PersistableNetworkPayload toAdd2 = new PersistableNetworkPayloadStub(new byte[]{2}); ProtectedStorageEntry toAdd3 = getProtectedStorageEntryForAdd(); ProtectedStorageEntry toAdd4 = getProtectedStorageEntryForAdd(); @@ -143,8 +141,8 @@ public class P2PDataStorageRequestDataTest { // correct GetDataRequestMessage with both sets of keys. @Test public void requestData_FilledP2PDataStore_GetUpdatedDataRequest() throws NoSuchAlgorithmException { - PersistableNetworkPayload toAdd1 = new PersistableNetworkPayloadStub(new byte[] { 1 }); - PersistableNetworkPayload toAdd2 = new PersistableNetworkPayloadStub(new byte[] { 2 }); + PersistableNetworkPayload toAdd1 = new PersistableNetworkPayloadStub(new byte[]{1}); + PersistableNetworkPayload toAdd2 = new PersistableNetworkPayloadStub(new byte[]{2}); ProtectedStorageEntry toAdd3 = getProtectedStorageEntryForAdd(); ProtectedStorageEntry toAdd4 = getProtectedStorageEntryForAdd(); diff --git a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoreDisconnectTest.java b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoreDisconnectTest.java index 653213688e..f31380695b 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoreDisconnectTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/P2PDataStoreDisconnectTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/TestState.java b/p2p/src/test/java/haveno/network/p2p/storage/TestState.java index d43acc54f7..332fb2534e 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/TestState.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/TestState.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/messages/AddDataMessageTest.java b/p2p/src/test/java/haveno/network/p2p/storage/messages/AddDataMessageTest.java index 99181e01ba..2f23e13f81 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/messages/AddDataMessageTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/messages/AddDataMessageTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.messages; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/AppendOnlyDataStoreServiceFake.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/AppendOnlyDataStoreServiceFake.java index 210c9e70bc..b7e0b3fd30 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/AppendOnlyDataStoreServiceFake.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/AppendOnlyDataStoreServiceFake.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/ClockFake.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/ClockFake.java index 42d59dd7a7..b718b1e515 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/ClockFake.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/ClockFake.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/DateTolerantPayloadStub.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/DateTolerantPayloadStub.java index 45f311089a..08c79cc586 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/DateTolerantPayloadStub.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/DateTolerantPayloadStub.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/ExpirableProtectedStoragePayloadStub.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/ExpirableProtectedStoragePayloadStub.java index 42ff179283..e26ae9e39e 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/ExpirableProtectedStoragePayloadStub.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/ExpirableProtectedStoragePayloadStub.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/MapStoreServiceFake.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/MapStoreServiceFake.java index 0c47de65dc..f1e79910da 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/MapStoreServiceFake.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/MapStoreServiceFake.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/MockData.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/MockData.java index e1af047566..584ce94739 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/MockData.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/MockData.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableExpirableProtectedStoragePayloadStub.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableExpirableProtectedStoragePayloadStub.java index c7a3f123c7..1e40c6876d 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableExpirableProtectedStoragePayloadStub.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableExpirableProtectedStoragePayloadStub.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableNetworkPayloadStub.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableNetworkPayloadStub.java index 013dc5a3c2..b49e19603b 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableNetworkPayloadStub.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/PersistableNetworkPayloadStub.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/mocks/ProtectedStoragePayloadStub.java b/p2p/src/test/java/haveno/network/p2p/storage/mocks/ProtectedStoragePayloadStub.java index c1fa361ba4..26559fbaaf 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/mocks/ProtectedStoragePayloadStub.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/mocks/ProtectedStoragePayloadStub.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.mocks; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntryTest.java b/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntryTest.java index 9f313835ef..58e6480e8a 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntryTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedMailboxStorageEntryTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedStorageEntryTest.java b/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedStorageEntryTest.java index 3b056ef219..a9e20c4253 100644 --- a/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedStorageEntryTest.java +++ b/p2p/src/test/java/haveno/network/p2p/storage/payload/ProtectedStorageEntryTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.p2p.storage.payload; diff --git a/p2p/src/test/java/haveno/network/utils/UtilsTest.java b/p2p/src/test/java/haveno/network/utils/UtilsTest.java index c255197ebf..1ddf3669e3 100644 --- a/p2p/src/test/java/haveno/network/utils/UtilsTest.java +++ b/p2p/src/test/java/haveno/network/utils/UtilsTest.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.network.utils; diff --git a/proto/src/main/proto/grpc.proto b/proto/src/main/proto/grpc.proto index 7a21d02c09..c9b8a75445 100644 --- a/proto/src/main/proto/grpc.proto +++ b/proto/src/main/proto/grpc.proto @@ -1,3 +1,20 @@ +/* + * This file is part of Bisq. + * + * Bisq is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * Bisq is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public + * License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. + */ + /* * This file is part of Haveno. * @@ -280,10 +297,10 @@ message SendNotificationReply { } /////////////////////////////////////////////////////////////////////////////////////////// -// MoneroConnections +// XmrConnections /////////////////////////////////////////////////////////////////////////////////////////// -service MoneroConnections { +service XmrConnections { rpc AddConnection (AddConnectionRequest) returns (AddConnectionReply) { } rpc RemoveConnection(RemoveConnectionRequest) returns (RemoveConnectionReply) { @@ -298,14 +315,16 @@ service MoneroConnections { } rpc CheckConnections(CheckConnectionsRequest) returns (CheckConnectionsReply) { } - rpc StartCheckingConnections(StartCheckingConnectionsRequest) returns (StartCheckingConnectionsReply) { + rpc StartCheckingConnection(StartCheckingConnectionRequest) returns (StartCheckingConnectionReply) { } - rpc StopCheckingConnections(StopCheckingConnectionsRequest) returns (StopCheckingConnectionsReply) { + rpc StopCheckingConnection(StopCheckingConnectionRequest) returns (StopCheckingConnectionReply) { } rpc GetBestAvailableConnection(GetBestAvailableConnectionRequest) returns (GetBestAvailableConnectionReply) { } rpc SetAutoSwitch(SetAutoSwitchRequest) returns (SetAutoSwitchReply) { } + rpc GetAutoSwitch(GetAutoSwitchRequest) returns (GetAutoSwitchReply) { + } } message UrlConnection { @@ -371,15 +390,15 @@ message CheckConnectionsReply { repeated UrlConnection connections = 1; } -message StartCheckingConnectionsRequest { +message StartCheckingConnectionRequest { int32 refresh_period = 1; // milliseconds } -message StartCheckingConnectionsReply {} +message StartCheckingConnectionReply {} -message StopCheckingConnectionsRequest {} +message StopCheckingConnectionRequest {} -message StopCheckingConnectionsReply {} +message StopCheckingConnectionReply {} message GetBestAvailableConnectionRequest {} @@ -393,46 +412,52 @@ message SetAutoSwitchRequest { message SetAutoSwitchReply {} +message GetAutoSwitchRequest {} + +message GetAutoSwitchReply { + bool auto_switch = 1; +} + /////////////////////////////////////////////////////////////////////////////////////////// -// MoneroNode +// XmrNode /////////////////////////////////////////////////////////////////////////////////////////// -service MoneroNode { - rpc IsMoneroNodeOnline (IsMoneroNodeOnlineRequest) returns (IsMoneroNodeOnlineReply) { +service XmrNode { + rpc IsXmrNodeOnline (IsXmrNodeOnlineRequest) returns (IsXmrNodeOnlineReply) { } - rpc GetMoneroNodeSettings (GetMoneroNodeSettingsRequest) returns (GetMoneroNodeSettingsReply) { + rpc GetXmrNodeSettings (GetXmrNodeSettingsRequest) returns (GetXmrNodeSettingsReply) { } - rpc StartMoneroNode (StartMoneroNodeRequest) returns (StartMoneroNodeReply) { + rpc StartXmrNode (StartXmrNodeRequest) returns (StartXmrNodeReply) { } - rpc StopMoneroNode (StopMoneroNodeRequest) returns (StopMoneroNodeReply) { + rpc StopXmrNode (StopXmrNodeRequest) returns (StopXmrNodeReply) { } } -message IsMoneroNodeOnlineRequest { +message IsXmrNodeOnlineRequest { } -message IsMoneroNodeOnlineReply { +message IsXmrNodeOnlineReply { bool is_running = 1; } -message GetMoneroNodeSettingsRequest { +message GetXmrNodeSettingsRequest { } -message GetMoneroNodeSettingsReply { - MoneroNodeSettings settings = 1; // pb.proto +message GetXmrNodeSettingsReply { + XmrNodeSettings settings = 1; // pb.proto } -message StartMoneroNodeRequest { - MoneroNodeSettings settings = 1; +message StartXmrNodeRequest { + XmrNodeSettings settings = 1; } -message StartMoneroNodeReply { +message StartXmrNodeReply { } -message StopMoneroNodeRequest { +message StopXmrNodeRequest { } -message StopMoneroNodeReply { +message StopXmrNodeReply { } /////////////////////////////////////////////////////////////////////////////////////////// @@ -496,10 +521,12 @@ message PostOfferRequest { double market_price_margin_pct = 5; uint64 amount = 6 [jstype = JS_STRING]; uint64 min_amount = 7 [jstype = JS_STRING]; - double buyer_security_deposit_pct = 8; + double security_deposit_pct = 8; string trigger_price = 9; bool reserve_exact_amount = 10; string payment_account_id = 11; + bool is_private_offer = 12; + bool buyer_as_taker_without_deposit = 13; } message PostOfferReply { @@ -521,26 +548,32 @@ message OfferInfo { double market_price_margin_pct = 5; uint64 amount = 6 [jstype = JS_STRING]; uint64 min_amount = 7 [jstype = JS_STRING]; - string volume = 8; - string min_volume = 9; - uint64 buyer_security_deposit = 10 [jstype = JS_STRING]; - string trigger_price = 11; - string payment_account_id = 12; - string payment_method_id = 13; - string payment_method_short_name = 14; - string base_currency_code = 15; - string counter_currency_code = 16; - uint64 date = 17; - string state = 18; - uint64 seller_security_deposit = 19 [jstype = JS_STRING]; - uint64 maker_fee = 20 [jstype = JS_STRING]; - bool is_activated = 21; - bool is_my_offer = 22; - string owner_node_address = 23; - string pub_key_ring = 24; - string version_nr = 25; - int32 protocol_version = 26; - string arbitrator_signer = 27; + double maker_fee_pct = 8; + double taker_fee_pct = 9; + double penalty_fee_pct = 10; + double buyer_security_deposit_pct = 11; + double seller_security_deposit_pct = 12; + string volume = 13; + string min_volume = 14; + string trigger_price = 15; + string payment_account_id = 16; + string payment_method_id = 17; + string payment_method_short_name = 18; + string base_currency_code = 19; + string counter_currency_code = 20; + uint64 date = 21; + string state = 22; + bool is_activated = 23; + bool is_my_offer = 24; + string owner_node_address = 25; + string pub_key_ring = 26; + string version_nr = 27; + int32 protocol_version = 28; + string arbitrator_signer = 29; + string split_output_tx_hash = 30; + uint64 split_output_tx_fee = 31 [jstype = JS_STRING]; + bool is_private_offer = 32; + string challenge = 33; } message AvailabilityResultWithDescription { @@ -565,6 +598,8 @@ service PaymentAccounts { } rpc CreateCryptoCurrencyPaymentAccount (CreateCryptoCurrencyPaymentAccountRequest) returns (CreateCryptoCurrencyPaymentAccountReply) { } + rpc DeletePaymentAccount (DeletePaymentAccountRequest) returns (DeletePaymentAccountReply) { + } rpc GetCryptoCurrencyPaymentMethods (GetCryptoCurrencyPaymentMethodsRequest) returns (GetCryptoCurrencyPaymentMethodsReply) { } rpc ValidateFormField (ValidateFormFieldRequest) returns (ValidateFormFieldReply) { @@ -618,6 +653,13 @@ message CreateCryptoCurrencyPaymentAccountRequest { bool trade_instant = 4; } +message DeletePaymentAccountRequest { + string payment_account_id = 1; +} + +message DeletePaymentAccountReply { +} + message CreateCryptoCurrencyPaymentAccountReply { PaymentAccount payment_account = 1; } @@ -747,6 +789,7 @@ message TakeOfferRequest { string offer_id = 1; string payment_account_id = 2; uint64 amount = 3 [jstype = JS_STRING]; + string challenge = 4; } message TakeOfferReply { @@ -828,51 +871,56 @@ message TradeInfo { string short_id = 3; uint64 date = 4; string role = 5; - uint64 taker_fee = 6 [jstype = JS_STRING]; - string taker_fee_tx_id = 7; - string payout_tx_id = 8; - uint64 amount = 9 [jstype = JS_STRING]; - uint64 buyer_security_deposit = 10 [jstype = JS_STRING]; - uint64 seller_security_deposit = 11 [jstype = JS_STRING]; - string price = 12; - string arbitrator_node_address = 13; - string trade_peer_node_address = 14; - string state = 15; - string phase = 16; - string period_state = 17; - string payout_state = 18; - string dispute_state = 19; - bool is_deposits_published = 20; - bool is_deposits_confirmed = 21; - bool is_deposits_unlocked = 22; - bool is_payment_sent = 23; - bool is_payment_received = 24; - bool is_payout_published = 25; - bool is_payout_confirmed = 26; - bool is_payout_unlocked = 27; - bool is_completed = 28; - string contract_as_json = 29; - ContractInfo contract = 30; - string trade_volume = 31; - string maker_deposit_tx_id = 32; - string taker_deposit_tx_id = 33; + uint64 amount = 6 [jstype = JS_STRING]; + uint64 maker_fee = 7 [jstype = JS_STRING]; + uint64 taker_fee = 8 [jstype = JS_STRING]; + uint64 buyer_security_deposit = 9 [jstype = JS_STRING]; + uint64 seller_security_deposit = 10 [jstype = JS_STRING]; + uint64 buyer_deposit_tx_fee = 11 [jstype = JS_STRING]; + uint64 seller_deposit_tx_fee = 12 [jstype = JS_STRING]; + uint64 buyer_payout_tx_fee = 13 [jstype = JS_STRING]; + uint64 seller_payout_tx_fee = 14 [jstype = JS_STRING]; + uint64 buyer_payout_amount = 15 [jstype = JS_STRING]; + uint64 seller_payout_amount = 16 [jstype = JS_STRING]; + string price = 17; + string arbitrator_node_address = 18; + string trade_peer_node_address = 19; + string state = 20; + string phase = 21; + string period_state = 22; + string payout_state = 23; + string dispute_state = 24; + bool is_deposits_published = 25; + bool is_deposits_confirmed = 26; + bool is_deposits_unlocked = 27; + bool is_payment_sent = 28; + bool is_payment_received = 29; + bool is_payout_published = 30; + bool is_payout_confirmed = 31; + bool is_payout_unlocked = 32; + bool is_completed = 33; + string contract_as_json = 34; + ContractInfo contract = 35; + string trade_volume = 36; + string maker_deposit_tx_id = 37; + string taker_deposit_tx_id = 38; + string payout_tx_id = 39; } message ContractInfo { string buyer_node_address = 1; string seller_node_address = 2; - reserved 3; // was mediator_node_address - reserved 4; // was refund_agent_node_address - bool is_buyer_maker_and_seller_taker = 5; - string maker_account_id = 6; - string taker_account_id = 7; - PaymentAccountPayload maker_payment_account_payload = 8; - PaymentAccountPayload taker_payment_account_payload = 9; - string maker_payout_address_string = 10; - string taker_payout_address_string = 11; - uint64 lock_time = 12; - - string arbitrator_node_address = 100; + string arbitrator_node_address = 3; + reserved 4; // was mediator_node_address + reserved 5; // was refund_agent_node_address + bool is_buyer_maker_and_seller_taker = 6; + string maker_account_id = 7; + string taker_account_id = 8; + PaymentAccountPayload maker_payment_account_payload = 9; + PaymentAccountPayload taker_payment_account_payload = 10; + string maker_payout_address_string = 11; + string taker_payout_address_string = 12; + uint64 lock_time = 13; } diff --git a/proto/src/main/proto/pb.proto b/proto/src/main/proto/pb.proto index 6221af7ebf..b52274ae57 100644 --- a/proto/src/main/proto/pb.proto +++ b/proto/src/main/proto/pb.proto @@ -64,6 +64,8 @@ message NetworkEnvelope { MediatedPayoutTxSignatureMessage mediated_payout_tx_signature_message = 37; MediatedPayoutTxPublishedMessage mediated_payout_tx_published_message = 38; + + FileTransferPart file_transfer_part = 39; } } @@ -100,6 +102,15 @@ message GetUpdatedDataRequest { string version = 4; } +message FileTransferPart { + NodeAddress sender_node_address = 1; + string uid = 2; + string trade_id = 3; + int32 trader_id = 4; + int64 seq_num_or_file_length = 5; + bytes message_data = 6; +} + message GetPeersRequest { NodeAddress sender_node_address = 1; int32 nonce = 2; @@ -214,27 +225,32 @@ message PrefixedSealedAndSignedMessage { string uid = 4; } +enum TradeProtocolVersion { + MULTISIG_2_3 = 0; +} + message InitTradeRequest { - string trade_id = 1; - NodeAddress sender_node_address = 2; - PubKeyRing pub_key_ring = 3; - int64 trade_amount = 4; - int64 trade_price = 5; - int64 trade_fee = 6; - string account_id = 7; - string payment_account_id = 8; - string payment_method_id = 9; - string uid = 10; - bytes account_age_witness_signature_of_offer_id = 11; - int64 current_date = 12; - NodeAddress maker_node_address = 13; - NodeAddress taker_node_address = 14; - NodeAddress arbitrator_node_address = 15; - string reserve_tx_hash = 16; - string reserve_tx_hex = 17; - string reserve_tx_key = 18; - string payout_address = 19; - bytes maker_signature = 20; + TradeProtocolVersion trade_protocol_version = 1; + string offer_id = 2; + int64 trade_amount = 3; + int64 trade_price = 4; + string payment_method_id = 5; + string maker_account_id = 6; + string taker_account_id = 7; + string maker_payment_account_id = 8; + string taker_payment_account_id = 9; + PubKeyRing taker_pub_key_ring = 10; + string uid = 11; + bytes account_age_witness_signature_of_offer_id = 12; + int64 current_date = 13; + NodeAddress maker_node_address = 14; + NodeAddress taker_node_address = 15; + NodeAddress arbitrator_node_address = 16; + string reserve_tx_hash = 17; + string reserve_tx_hex = 18; + string reserve_tx_key = 19; + string payout_address = 20; + string challenge = 21; } message InitMultisigRequest { @@ -244,6 +260,7 @@ message InitMultisigRequest { string prepared_multisig_hex = 4; string made_multisig_hex = 5; string exchanged_multisig_hex = 6; + string trade_fee_address = 7; } message SignContractRequest { @@ -281,6 +298,8 @@ message DepositResponse { string uid = 2; int64 current_date = 3; string error_message = 4; + int64 buyerSecurityDeposit = 5; + int64 sellerSecurityDeposit = 6; } message DepositsConfirmedMessage { @@ -610,37 +629,38 @@ message OfferPayload { bool use_market_based_price = 8; int64 amount = 9; int64 min_amount = 10; - string base_currency_code = 11; - string counter_currency_code = 12; - string payment_method_id = 13; - string maker_payment_account_id = 14; - string country_code = 15; - repeated string accepted_country_codes = 16; - string bank_id = 17; - repeated string accepted_bank_ids = 18; - string version_nr = 19; - int64 block_height_at_offer_creation = 20; - int64 maker_fee = 21; - int64 buyer_security_deposit = 22; - int64 seller_security_deposit = 23; - int64 max_trade_limit = 24; - int64 max_trade_period = 25; - bool use_auto_close = 26; - bool use_re_open_after_auto_close = 27; - int64 lower_close_price = 28; - int64 upper_close_price = 29; - bool is_private_offer = 30; - string hash_of_challenge = 31; - map<string, string> extra_data = 32; - int32 protocol_version = 33; - - NodeAddress arbitrator_signer = 1001; - bytes arbitrator_signature = 1002; - repeated string reserve_tx_key_images = 1003; + double maker_fee_pct = 11; + double taker_fee_pct = 12; + double penalty_fee_pct = 13; + double buyer_security_deposit_pct = 14; + double seller_security_deposit_pct = 15; + string base_currency_code = 16; + string counter_currency_code = 17; + string payment_method_id = 18; + string maker_payment_account_id = 19; + string country_code = 20; + repeated string accepted_country_codes = 21; + string bank_id = 22; + repeated string accepted_bank_ids = 23; + string version_nr = 24; + int64 block_height_at_offer_creation = 25; + int64 max_trade_limit = 26; + int64 max_trade_period = 27; + bool use_auto_close = 28; + bool use_re_open_after_auto_close = 29; + int64 lower_close_price = 30; + int64 upper_close_price = 31; + bool is_private_offer = 32; + string challenge_hash = 33; + map<string, string> extra_data = 34; + int32 protocol_version = 35; + NodeAddress arbitrator_signer = 36; + bytes arbitrator_signature = 37; + repeated string reserve_tx_key_images = 38; } enum OfferDirection { - OFFER_DIRECTION_ERROR = 0; + OFFER_DIRECTION_UNDEFINED = 0; BUY = 1; SELL = 2; } @@ -740,6 +760,12 @@ message DisputeResult { PEER_WAS_LATE = 12; } + enum SubtractFeeFrom { + BUYER_ONLY = 0; + SELLER_ONLY = 1; + BUYER_AND_SELLER = 2; + } + string trade_id = 1; int32 trader_id = 2; Winner winner = 3; @@ -750,11 +776,12 @@ message DisputeResult { string summary_notes = 8; ChatMessage chat_message = 9; bytes arbitrator_signature = 10; - int64 buyer_payout_amount = 11; - int64 seller_payout_amount = 12; - bytes arbitrator_pub_key = 13; - int64 close_date = 14; - bool is_loser_publisher = 15; + int64 buyer_payout_amount_before_cost = 11; + int64 seller_payout_amount_before_cost = 12; + SubtractFeeFrom subtract_fee_from = 13; + bytes arbitrator_pub_key = 14; + int64 close_date = 15; + bool is_loser_publisher = 16; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -830,9 +857,9 @@ message PaymentAccountPayload { SwishAccountPayload swish_account_payload = 14; USPostalMoneyOrderAccountPayload u_s_postal_money_order_account_payload = 15; UpholdAccountPayload uphold_account_payload = 16; - CashAppAccountPayload cash_app_account_payload = 17 [deprecated = true]; + CashAppAccountPayload cash_app_account_payload = 17; MoneyBeamAccountPayload money_beam_account_payload = 18; - VenmoAccountPayload venmo_account_payload = 19 [deprecated = true]; + VenmoAccountPayload venmo_account_payload = 19; PopmoneyAccountPayload popmoney_account_payload = 20; RevolutAccountPayload revolut_account_payload = 21; WeChatPayAccountPayload we_chat_pay_account_payload = 22; @@ -854,6 +881,7 @@ message PaymentAccountPayload { MoneseAccountPayload monese_account_payload = 38; VerseAccountPayload verse_account_payload = 39; CashAtAtmAccountPayload cash_at_atm_account_payload = 40; + PayPalAccountPayload paypal_account_payload = 41; } } @@ -945,6 +973,7 @@ message JapanBankAccountPayload { message AustraliaPayidPayload { string bank_account_name = 1; string payid = 2; + string extra_info = 3; } message SpecificBanksAccountPayload { @@ -1031,19 +1060,21 @@ message UpholdAccountPayload { string account_owner = 2; } -// Deprecated, not used anymore message CashAppAccountPayload { - string cash_tag = 1; + string email_or_mobile_nr_or_cashtag = 1; + string extra_info = 2; } message MoneyBeamAccountPayload { string account_id = 1; } -// Deprecated, not used anymore message VenmoAccountPayload { - string venmo_user_name = 1; - string holder_name = 2; + string email_or_mobile_nr_or_username = 1; +} +message PayPalAccountPayload { + string email_or_mobile_nr_or_username = 1; + string extra_info = 2; } message PopmoneyAccountPayload { @@ -1052,7 +1083,7 @@ message PopmoneyAccountPayload { } message RevolutAccountPayload { - string user_name = 1; + string username = 1; } message PerfectMoneyAccountPayload { @@ -1227,9 +1258,9 @@ message PersistableEnvelope { IgnoredMailboxMap ignored_mailbox_map = 16; RemovedPayloadsMap removed_payloads_map = 17; - XmrAddressEntryList xmr_address_entry_list = 1001; - SignedOfferList signed_offer_list = 1002; - EncryptedConnectionList encrypted_connection_list = 1003; + XmrAddressEntryList xmr_address_entry_list = 18; + SignedOfferList signed_offer_list = 19; + EncryptedConnectionList encrypted_connection_list = 20; } } @@ -1305,8 +1336,8 @@ message XmrAddressEntry { TRADE_PAYOUT = 5; } - int32 subaddress_index = 7; - string address_string = 8; + int32 subaddress_index = 7; + string address_string = 8; string offer_id = 9; Context context = 10; int64 coin_locked_in_multi_sig = 11; @@ -1337,6 +1368,7 @@ message Offer { NOT_AVAILABLE = 4; REMOVED = 5; MAKER_OFFLINE = 6; + INVALID = 7; } OfferPayload offer_payload = 1; @@ -1362,7 +1394,7 @@ message SignedOffer { message OpenOffer { enum State { PB_ERROR = 0; - SCHEDULED = 1; + PENDING = 1; AVAILABLE = 2; RESERVED = 3; CLOSED = 4; @@ -1374,24 +1406,25 @@ message OpenOffer { State state = 2; int64 trigger_price = 3; bool reserve_exact_amount = 4; - repeated string scheduled_tx_hashes = 5; - string scheduled_amount = 6; // BigInteger - string split_output_tx_hash = 7; - string reserve_tx_hash = 8; - string reserve_tx_hex = 9; - string reserve_tx_key = 10; + string split_output_tx_hash = 5; + int64 split_output_tx_fee = 6; + repeated string scheduled_tx_hashes = 7; + string scheduled_amount = 8; // BigInteger + string reserve_tx_hash = 9; + string reserve_tx_hex = 10; + string reserve_tx_key = 11; + string challenge = 12; } message Tradable { oneof message { OpenOffer open_offer = 1; - BuyerAsMakerTrade buyer_as_maker_trade = 2; - BuyerAsTakerTrade buyer_as_taker_trade = 3; - SellerAsMakerTrade seller_as_maker_trade = 4; - SellerAsTakerTrade seller_as_taker_trade = 5; - ArbitratorTrade arbitrator_trade = 6; - - SignedOffer signed_offer = 1001; + SignedOffer signed_offer = 2; + BuyerAsMakerTrade buyer_as_maker_trade = 3; + BuyerAsTakerTrade buyer_as_taker_trade = 4; + SellerAsMakerTrade seller_as_maker_trade = 5; + SellerAsTakerTrade seller_as_taker_trade = 6; + ArbitratorTrade arbitrator_trade = 7; } } @@ -1413,18 +1446,17 @@ message Trade { DEPOSIT_TXS_SEEN_IN_NETWORK = 13; DEPOSIT_TXS_CONFIRMED_IN_BLOCKCHAIN = 14; DEPOSIT_TXS_UNLOCKED_IN_BLOCKCHAIN = 15; - BUYER_CONFIRMED_IN_UI_PAYMENT_SENT = 16; + BUYER_CONFIRMED_PAYMENT_SENT = 16; BUYER_SENT_PAYMENT_SENT_MSG = 17; BUYER_SEND_FAILED_PAYMENT_SENT_MSG = 18; BUYER_STORED_IN_MAILBOX_PAYMENT_SENT_MSG = 19; BUYER_SAW_ARRIVED_PAYMENT_SENT_MSG = 20; SELLER_RECEIVED_PAYMENT_SENT_MSG = 21; - SELLER_CONFIRMED_IN_UI_PAYMENT_RECEIPT = 22; + SELLER_CONFIRMED_PAYMENT_RECEIPT = 22; SELLER_SENT_PAYMENT_RECEIVED_MSG = 23; SELLER_SEND_FAILED_PAYMENT_RECEIVED_MSG = 24; SELLER_STORED_IN_MAILBOX_PAYMENT_RECEIVED_MSG = 25; SELLER_SAW_ARRIVED_PAYMENT_RECEIVED_MSG = 26; - TRADE_COMPLETED = 27; } enum Phase { @@ -1436,7 +1468,6 @@ message Trade { DEPOSITS_UNLOCKED = 5; PAYMENT_SENT = 6; PAYMENT_RECEIVED = 7; - COMPLETED = 8; } enum PayoutState { @@ -1477,29 +1508,29 @@ message Trade { string payout_tx_hex = 4; string payout_tx_key = 5; int64 amount = 6; - int64 taker_fee = 8; - int64 total_tx_fee = 9; - int64 take_offer_date = 10; - int64 price = 11; - State state = 12; - PayoutState payout_state = 13; - DisputeState dispute_state = 14; - TradePeriodState period_state = 15; - Contract contract = 16; - string contract_as_json = 17; - bytes contract_hash = 18; - NodeAddress arbitrator_node_address = 19; - NodeAddress mediator_node_address = 20; - string error_message = 21; - string counter_currency_tx_id = 22; - repeated ChatMessage chat_message = 23; - MediationResultState mediation_result_state = 24; - int64 lock_time = 25; - int64 start_time = 26; - NodeAddress refund_agent_node_address = 27; - RefundResultState refund_result_state = 28; - string counter_currency_extra_data = 29; - string uid = 30; + int64 take_offer_date = 7; + int64 price = 8; + State state = 9; + PayoutState payout_state = 10; + DisputeState dispute_state = 11; + TradePeriodState period_state = 12; + Contract contract = 13; + string contract_as_json = 14; + bytes contract_hash = 15; + NodeAddress arbitrator_node_address = 16; + NodeAddress mediator_node_address = 17; + string error_message = 18; + string counter_currency_tx_id = 19; + repeated ChatMessage chat_message = 20; + MediationResultState mediation_result_state = 21; + int64 lock_time = 22; + int64 start_time = 23; + NodeAddress refund_agent_node_address = 24; + RefundResultState refund_result_state = 25; + string counter_currency_extra_data = 26; + string uid = 27; + bool is_completed = 28; + string challenge = 29; } message BuyerAsMakerTrade { @@ -1519,7 +1550,7 @@ message SellerAsTakerTrade { } message ArbitratorTrade { - Trade trade = 1; + Trade trade = 1; } message ProcessModel { @@ -1530,18 +1561,18 @@ message ProcessModel { bool use_savings_wallet = 5; int64 funds_needed_for_trade = 6; string payment_sent_message_state = 7; - bytes maker_signature = 8; - TradePeer maker = 9; - TradePeer taker = 10; - TradePeer arbitrator = 11; - NodeAddress temp_trade_peer_node_address = 12; - string multisig_address = 13; - PaymentSentMessage payment_sent_message = 14; - PaymentReceivedMessage payment_received_message = 15; - DisputeClosedMessage dispute_closed_message = 16; - bytes mediated_payout_tx_signature = 17; // placeholder if mediation used in future - int64 buyer_payout_amount_from_mediation = 18; - int64 seller_payout_amount_from_mediation = 19; + string payment_sent_message_state_arbitrator = 8; + bytes maker_signature = 9; + TradePeer maker = 10; + TradePeer taker = 11; + TradePeer arbitrator = 12; + NodeAddress temp_trade_peer_node_address = 13; + string multisig_address = 14; + bytes mediated_payout_tx_signature = 15; // placeholder if mediation used in future + int64 buyer_payout_amount_from_mediation = 16; + int64 seller_payout_amount_from_mediation = 17; + int64 trade_protocol_error_height = 18; + string trade_fee_address = 19; } message TradePeer { @@ -1562,20 +1593,26 @@ message TradePeer { AccountAgeWitness account_age_witness = 20; int64 current_date = 21; bytes mediated_payout_tx_signature = 22; - - string reserve_tx_hash = 1001; - string reserve_tx_hex = 1002; - string reserve_tx_key = 1003; - repeated string reserve_tx_key_images = 1004; - string prepared_multisig_hex = 1005; - string made_multisig_hex = 1006; - string exchanged_multisig_hex = 1007; - string deposit_tx_hash = 1008; - string deposit_tx_hex = 1009; - string deposit_tx_key = 1010; - int64 security_deposit = 1011; - string updated_multisig_hex = 1012; - bool deposits_confirmed_message_acked = 1013; + PaymentSentMessage payment_sent_message = 23; + PaymentReceivedMessage payment_received_message = 24; + DisputeClosedMessage dispute_closed_message = 25; + string reserve_tx_hash = 26; + string reserve_tx_hex = 27; + string reserve_tx_key = 28; + repeated string reserve_tx_key_images = 29; + string prepared_multisig_hex = 30; + string made_multisig_hex = 31; + string exchanged_multisig_hex = 32; + string updated_multisig_hex = 33; + bool deposits_confirmed_message_acked = 34; + string deposit_tx_hash = 35; + string deposit_tx_hex = 36; + string deposit_tx_key = 37; + int64 deposit_tx_fee = 38; + int64 security_deposit = 39; + string unsigned_payout_tx_hex = 40; + int64 payout_tx_fee = 41; + int64 payout_amount = 42; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1689,9 +1726,9 @@ message PreferencesPayload { string rpc_user = 43; string rpc_pw = 44; string take_offer_selected_payment_account_id = 45; - double buyer_security_deposit_as_percent = 46; + double security_deposit_as_percent = 46; int32 ignore_dust_threshold = 47; - double buyer_security_deposit_as_percent_for_crypto = 48; + double security_deposit_as_percent_for_crypto = 48; int32 block_notify_port = 49; int32 css_theme = 50; bool tac_accepted_v120 = 51; @@ -1701,11 +1738,16 @@ message PreferencesPayload { bool show_offers_matching_my_accounts = 55; bool deny_api_taker = 56; bool notify_on_pre_release = 57; - MoneroNodeSettings monero_node_settings = 58; + XmrNodeSettings xmr_node_settings = 58; int32 clear_data_after_days = 59; string buy_screen_crypto_currency_code = 60; string sell_screen_crypto_currency_code = 61; bool split_offer_output = 62; + bool use_sound_for_notifications = 63; + bool use_sound_for_notifications_initialized = 64; + string buy_screen_other_currency_code = 65; + string sell_screen_other_currency_code = 66; + bool show_private_offers = 67; } message AutoConfirmSettings { @@ -1716,10 +1758,11 @@ message AutoConfirmSettings { string currency_code = 5; } -message MoneroNodeSettings { +message XmrNodeSettings { string blockchain_path = 1; string bootstrap_url = 2; repeated string startup_flags = 3; + bool sync_blockchain = 4; } /////////////////////////////////////////////////////////////////////////////////////////// @@ -1743,6 +1786,7 @@ message UserPayload { repeated RefundAgent accepted_refund_agents = 14; RefundAgent registered_refund_agent = 15; map<string, string> cookie = 16; + int64 wallet_creation_date = 17; } message BlockChainExplorer { @@ -1839,6 +1883,10 @@ message PaymentAccountForm { PAXUM = 12; PAY_BY_MAIL = 13; CASH_AT_ATM = 14; + AUSTRALIA_PAYID = 15; + CASH_APP = 16; + PAYPAL = 17; + VENMO = 18; } FormId id = 1; repeated PaymentAccountFormField fields = 2; @@ -1903,7 +1951,9 @@ message PaymentAccountFormField { SPECIAL_INSTRUCTIONS = 54; STATE = 55; TRADE_CURRENCIES = 56; - USER_NAME = 57; + USERNAME = 57; + EMAIL_OR_MOBILE_NR_OR_USERNAME = 58; + EMAIL_OR_MOBILE_NR_OR_CASHTAG = 59; } enum Component { TEXT = 0; diff --git a/relay/src/main/java/haveno/relay/RelayMain.java b/relay/src/main/java/haveno/relay/RelayMain.java index f613ba9977..c96c3d2331 100644 --- a/relay/src/main/java/haveno/relay/RelayMain.java +++ b/relay/src/main/java/haveno/relay/RelayMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.relay; diff --git a/relay/src/main/java/haveno/relay/RelayService.java b/relay/src/main/java/haveno/relay/RelayService.java index ce66d007cf..7f4e7fba2c 100644 --- a/relay/src/main/java/haveno/relay/RelayService.java +++ b/relay/src/main/java/haveno/relay/RelayService.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.relay; diff --git a/scripts/deployment/haveno-pricenode.env b/scripts/deployment/haveno-pricenode.env new file mode 100644 index 0000000000..7c52bdd4f5 --- /dev/null +++ b/scripts/deployment/haveno-pricenode.env @@ -0,0 +1 @@ +JAVA_OPTS="-XX:+ExitOnOutOfMemoryError" \ No newline at end of file diff --git a/scripts/deployment/haveno-pricenode.service b/scripts/deployment/haveno-pricenode.service new file mode 100644 index 0000000000..aa595924e8 --- /dev/null +++ b/scripts/deployment/haveno-pricenode.service @@ -0,0 +1,22 @@ +[Unit] +Description=Haveno Price Node +After=network.target + +[Service] +SyslogIdentifier=haveno-pricenode +EnvironmentFile=/etc/default/haveno-pricenode.env +ExecStart=/home/haveno-pricenode/haveno-pricenode/haveno-pricenode 2 +ExecStop=/bin/kill -TERM ${MAINPID} +Restart=on-failure + +User=haveno-pricenode +Group=haveno-pricenode + +PrivateTmp=true +ProtectSystem=full +NoNewPrivileges=true +PrivateDevices=true +MemoryDenyWriteExecute=false + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/scripts/deployment/haveno-seednode.service b/scripts/deployment/haveno-seednode.service new file mode 100644 index 0000000000..113e746609 --- /dev/null +++ b/scripts/deployment/haveno-seednode.service @@ -0,0 +1,38 @@ +[Unit] +Description=Haveno seednode +After=network.target + +[Service] +User=haveno +Group=haveno +SyslogIdentifier=Haveno-Seednode + +ExecStart=/bin/sh /home/haveno/haveno/haveno-seednode --baseCurrencyNetwork=XMR_STAGENET\ + --useLocalhostForP2P=false\ + --useDevPrivilegeKeys=false\ +# Uncomment the following line to use external tor +# --hiddenServiceAddress=example.onion\ + --nodePort=2002\ + --appName=haveno-XMR_STAGENET_Seed_2002\ +# --logLevel=trace\ + --xmrNode=http://[::1]:38088\ + --xmrNodeUsername=admin\ + --xmrNodePassword=password + +ExecStop=/bin/kill ${MAINPID} +Restart=always + +# Hardening +PrivateTmp=true +ProtectSystem=full +NoNewPrivileges=true +PrivateDevices=true +MemoryDenyWriteExecute=false +ProtectControlGroups=true +ProtectKernelTunables=true +RestrictSUIDSGID=true +# limit memory usage to 2gb +LimitRSS=2000000000 + +[Install] +WantedBy=multi-user.target diff --git a/scripts/deployment/haveno-seednode2.service b/scripts/deployment/haveno-seednode2.service new file mode 100644 index 0000000000..d2604c1c06 --- /dev/null +++ b/scripts/deployment/haveno-seednode2.service @@ -0,0 +1,38 @@ +[Unit] +Description=Haveno seednode 2 +After=network.target + +[Service] +User=haveno +Group=haveno +SyslogIdentifier=Haveno-Seednode2 + +ExecStart=/bin/sh /home/haveno/haveno/haveno-seednode --baseCurrencyNetwork=XMR_STAGENET\ + --useLocalhostForP2P=false\ + --useDevPrivilegeKeys=false\ +# Uncomment the following line to use external tor +# --hiddenServiceAddress=example.onion\ + --nodePort=2003\ + --appName=haveno-XMR_STAGENET_Seed_2003\ +# --logLevel=trace\ + --xmrNode=http://[::1]:38088\ + --xmrNodeUsername=admin\ + --xmrNodePassword=password + +ExecStop=/bin/kill ${MAINPID} +Restart=always + +# Hardening +PrivateTmp=true +ProtectSystem=full +NoNewPrivileges=true +PrivateDevices=true +MemoryDenyWriteExecute=false +ProtectControlGroups=true +ProtectKernelTunables=true +RestrictSUIDSGID=true +# limit memory usage to 2gb +LimitRSS=2000000000 + +[Install] +WantedBy=multi-user.target diff --git a/scripts/deployment/monero-stagenet.service b/scripts/deployment/monero-stagenet.service new file mode 100644 index 0000000000..177076c5ce --- /dev/null +++ b/scripts/deployment/monero-stagenet.service @@ -0,0 +1,26 @@ +[Unit] +Description=Monero stagenet node +After=network.target + +[Service] +User=monero-stagenet +Group=monero-stagenet +Type=simple +ExecStart=/home/monero-stagenet/monerod --config-file /home/monero-stagenet/shared-stagenet.conf --non-interactive +SyslogIdentifier=stagenet-node +Restart=always + +# Hardening +PrivateTmp=true +#ProtectSystem=full +NoNewPrivileges=true +PrivateDevices=true +MemoryDenyWriteExecute=false +ProtectControlGroups=true +ProtectKernelTunables=true +RestrictSUIDSGID=true +# limit memory usage to 4gb +LimitRSS=4000000000 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/scripts/deployment/private-stagenet.conf b/scripts/deployment/private-stagenet.conf new file mode 100644 index 0000000000..5f06c80925 --- /dev/null +++ b/scripts/deployment/private-stagenet.conf @@ -0,0 +1,20 @@ +stagenet=1 +data-dir=/home/monero-stagenet/private-stagenet/ +log-file=/home/monero-stagenet/logs/ +p2p-bind-ip=0.0.0.0 +p2p-bind-port=38079 +hide-my-port=1 +no-zmq=1 + +# RPC +#rpc-bind-ip=136.244.105.131 +rpc-bind-ip=127.0.0.1 +rpc-bind-port=38088 +rpc-login=admin:password + +confirm-external-bind=1 +restricted-rpc=0 # must be unrestricted for arbitrator +no-igd=1 + +# second vps peer +add-priority-node=45.63.8.26:38080 \ No newline at end of file diff --git a/scripts/deployment/private-stagenet.service b/scripts/deployment/private-stagenet.service new file mode 100644 index 0000000000..5b9c871483 --- /dev/null +++ b/scripts/deployment/private-stagenet.service @@ -0,0 +1,26 @@ +[Unit] +Description=Private stagenet node +After=network.target + +[Service] +User=monero-stagenet +Group=monero-stagenet +Type=simple +ExecStart=/home/monero-stagenet/monerod --config-file /home/monero-stagenet/private-stagenet.conf --non-interactive +SyslogIdentifier=private-stagenet-node +Restart=always + +# Hardening +PrivateTmp=true +#ProtectSystem=full +NoNewPrivileges=true +PrivateDevices=true +MemoryDenyWriteExecute=false +ProtectControlGroups=true +ProtectKernelTunables=true +RestrictSUIDSGID=true +# limit memory usage to 4gb +LimitRSS=4000000000 + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/scripts/deployment/run-arbitrator-daemon.sh b/scripts/deployment/run-arbitrator-daemon.sh new file mode 100644 index 0000000000..229a03508a --- /dev/null +++ b/scripts/deployment/run-arbitrator-daemon.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Start arbitrator daemon on Monero's stagenet (Haveno testnet) + +runArbitrator() { + ./haveno-daemon --baseCurrencyNetwork=XMR_STAGENET \ + --useLocalhostForP2P=false \ + --useDevPrivilegeKeys=false \ + --nodePort=7777 \ + --appName=haveno-XMR_STAGENET_arbitrator \ + --xmrNode=http://127.0.0.1:38088 \ + --xmrNodeUsername=admin \ + --xmrNodePassword=password +} + +cd /home/haveno/haveno && \ +runArbitrator \ No newline at end of file diff --git a/scripts/deployment/run-arbitrator-gui.sh b/scripts/deployment/run-arbitrator-gui.sh new file mode 100644 index 0000000000..12d09d41f7 --- /dev/null +++ b/scripts/deployment/run-arbitrator-gui.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Start arbitrator GUI on Monero's stagenet (Haveno testnet) + +runArbitrator() { + ./haveno-desktop --baseCurrencyNetwork=XMR_STAGENET \ + --useLocalhostForP2P=false \ + --useDevPrivilegeKeys=false \ + --nodePort=7777 \ + --appName=haveno-XMR_STAGENET_arbitrator \ + --xmrNode=http://127.0.0.1:38088 \ + --xmrNodeUsername=admin \ + --xmrNodePassword=password +} + +cd /home/haveno/haveno && \ +runArbitrator \ No newline at end of file diff --git a/scripts/deployment/shared-stagenet.conf b/scripts/deployment/shared-stagenet.conf new file mode 100644 index 0000000000..b149949e53 --- /dev/null +++ b/scripts/deployment/shared-stagenet.conf @@ -0,0 +1,19 @@ +stagenet=1 +data-dir=/home/monero-stagenet/shared-stagenet/ +log-file=/home/monero-stagenet/logs/ +p2p-bind-ip=0.0.0.0 +p2p-bind-port=38080 +#hide-my-port=1 +no-zmq=1 + +# RPC +#rpc-bind-ip=136.244.105.131 +rpc-bind-ip=0.0.0.0 +rpc-bind-port=38081 + +confirm-external-bind=1 +restricted-rpc=1 +no-igd=1 + +# second vps peer +#add-peer=70.34.196.88:38080 \ No newline at end of file diff --git a/scripts/install_java.bat b/scripts/install_java.bat index b53b087917..28224d2d9c 100644 --- a/scripts/install_java.bat +++ b/scripts/install_java.bat @@ -25,9 +25,9 @@ cd /D "%~dp0" title Install Java -set jdk_version=11.0.2 +set jdk_version=21.0.2 set jdk_filename=openjdk-%jdk_version%_windows-x64_bin -set jdk_url=https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_windows-x64_bin.zip +set jdk_url=https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_windows-x64_bin.zip if exist "%PROGRAMFILES%\Java\openjdk\jdk-%jdk_version%" ( echo %PROGRAMFILES%\Java\openjdk\jdk-%jdk_version% already exists, skipping install diff --git a/scripts/install_java.sh b/scripts/install_java.sh index d14214b9f7..e52fb5f918 100755 --- a/scripts/install_java.sh +++ b/scripts/install_java.sh @@ -15,9 +15,9 @@ set -e unameOut="$(uname -s)" case "${unameOut}" in Linux*) - JAVA_HOME=/usr/lib/jvm/openjdk-11.0.2 - JDK_FILENAME=openjdk-11.0.2_linux-x64_bin.tar.gz - JDK_URL=https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_linux-x64_bin.tar.gz + JAVA_HOME=/usr/lib/jvm/openjdk-21.0.2 + JDK_FILENAME=openjdk-21.0.2_linux-x64_bin.tar.gz + JDK_URL=https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_linux-x64_bin.tar.gz # Determine which package manager to use depending on the distribution declare -A osInfo; @@ -52,9 +52,9 @@ case "${unameOut}" in update-alternatives --set javac $JAVA_HOME/bin/javac ;; Darwin*) - JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk/Contents/Home - JDK_FILENAME=openjdk-11.0.2_osx-x64_bin.tar.gz - JDK_URL=https://download.java.net/java/GA/jdk11/9/GPL/openjdk-11.0.2_osx-x64_bin.tar.gz + JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-21.0.2.jdk/Contents/Home + JDK_FILENAME=openjdk-21.0.2_macos-x64_bin.tar.gz + JDK_URL=https://download.java.net/java/GA/jdk21.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-21.0.2_macos-x64_bin.tar.gz if [ ! -d "$JAVA_HOME" ]; then if [[ $(command -v brew) == "" ]]; then echo "Installing Homebrew" @@ -66,10 +66,10 @@ case "${unameOut}" in brew install curl curl -L -O $JDK_URL - sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk | sudo bash + sudo mkdir /Library/Java/JavaVirtualMachines/openjdk-21.0.2.jdk | sudo bash gunzip -c $JDK_FILENAME | tar xopf - - sudo mv jdk-11.0.2.jdk/* /Library/Java/JavaVirtualMachines/openjdk-11.0.2.jdk - sudo rmdir jdk-11.0.2.jdk + sudo mv jdk-21.0.2.jdk/* /Library/Java/JavaVirtualMachines/openjdk-21.0.2.jdk + sudo rmdir jdk-21.0.2.jdk rm $JDK_FILENAME fi diff --git a/scripts/install_tails/README.md b/scripts/install_tails/README.md new file mode 100644 index 0000000000..05b6470fd8 --- /dev/null +++ b/scripts/install_tails/README.md @@ -0,0 +1,22 @@ +# Install Haveno on Tails + +After you already have a [Tails USB](https://tails.net/install/linux/index.en.html#download): + +1. Enable [persistent storage](https://tails.net/doc/persistent_storage/index.en.html). +2. Set up [administration password](https://tails.net/doc/first_steps/welcome_screen/administration_password/). +3. Activate dotfiles in persistent storage settings. +4. Execute the following command in the terminal to download and execute the installation script. + + ``` + curl -fsSLO https://github.com/haveno-dex/haveno/raw/master/scripts/install_tails/haveno-install.sh && bash haveno-install.sh <REPLACE_WITH_BINARY_ZIP_URL> <REPLACE_WITH_PGP_FINGERPRINT> + ``` + + Replace the binary zip URL and PGP fingerprint for the network you're using. For example: + + ``` + curl -fsSLO https://github.com/haveno-dex/haveno/raw/master/scripts/install_tails/haveno-install.sh && bash haveno-install.sh https://github.com/havenoexample/haveno-example/releases/latest/download/haveno-linux-deb.zip FAA24D878B8D36C90120A897CA02DAC12DAE2D0F + ``` +5. Start Haveno by finding the icon in the launcher under **Applications > Other**. + +> [!note] +> If you have already installed Haveno on Tails, we recommend moving your data directory (/home/amnesia/Persistent/Haveno-example) to the new default location (/home/amnesia/Persistent/haveno/Data/Haveno-example), to retain your history and for future support. \ No newline at end of file diff --git a/scripts/install_tails/assets/exec.sh b/scripts/install_tails/assets/exec.sh new file mode 100644 index 0000000000..ad0610a60b --- /dev/null +++ b/scripts/install_tails/assets/exec.sh @@ -0,0 +1,62 @@ +#!/bin/bash + + +# This script serves as the execution entry point for the Haveno application from a desktop menu icon, +# specifically tailored for use in the Tails OS. It is intended to be linked as the 'Exec' command +# in a .desktop file, enabling users to start Haveno directly from the desktop interface. +# +# FUNCTIONAL OVERVIEW: +# - Automatic installation and configuration of Haveno if not already set up. +# - Linking Haveno data directories to persistent storage to preserve user data across sessions. +# +# NOTE: +# This script assumes that Haveno's related utility scripts and files are correctly placed and accessible +# in the specified directories. + + +# Function to print messages in blue +echo_blue() { + if [ -t 1 ]; then + # If File descriptor 1 (stdout) is open and refers to a terminal + echo -e "\033[1;34m$1\033[0m" + else + # If stdout is not a terminal, send a desktop notification + notify-send -i "/home/amnesia/Persistent/haveno/App/utils/icon.png" "Starting Haveno" "$1" + fi +} + + +# Function to print error messages in red +echo_red() { + if [ -t 1 ]; then + # If File descriptor 1 (stdout) is open and refers to a terminal + echo -e "\033[0;31m$1\033[0m" + else + # If stdout is not a terminal, send a desktop notification + notify-send -u critical -i "error" "Staring Haveno" "$1\nExiting..." + fi +} + + +# Define file locations +persistence_dir="/home/amnesia/Persistent" +data_dir="${persistence_dir}/haveno/Data" + + +# Create data dir +mkdir -p "${data_dir}" + + +# Check if Haveno is already installed and configured +if [ ! -f "/opt/haveno/bin/Haveno" ] || [ ! -f "/etc/onion-grater.d/haveno.yml" ]; then + echo_blue "Installing Haveno and configuring system..." + pkexec "${persistence_dir}/haveno/App/utils/install.sh" + # Redirect user data to Tails Persistent Storage + ln -s "${data_dir}" /home/amnesia/.local/share/Haveno +else + echo_blue "Haveno is already installed and configured." +fi + + +echo_blue "Starting Haveno..." +/opt/haveno/bin/Haveno --torControlPort 951 --torControlCookieFile=/var/run/tor/control.authcookie --torControlUseSafeCookieAuth --userDataDir=${data_dir} --useTorForXmr=on --socks5ProxyXmrAddress=127.0.0.1:9050 diff --git a/scripts/install_tails/assets/haveno.desktop b/scripts/install_tails/assets/haveno.desktop new file mode 100644 index 0000000000..0160cfd78e --- /dev/null +++ b/scripts/install_tails/assets/haveno.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Haveno +Comment=A decentralized monero exchange network. +Exec=/home/amnesia/Persistent/haveno/App/utils/exec.sh +Icon=/home/amnesia/Persistent/haveno/App/utils/icon.png +Terminal=false +Type=Application +Categories=Other +MimeType= diff --git a/scripts/install_tails/assets/haveno.yml b/scripts/install_tails/assets/haveno.yml new file mode 100644 index 0000000000..029327c78c --- /dev/null +++ b/scripts/install_tails/assets/haveno.yml @@ -0,0 +1,56 @@ +--- +- apparmor-profiles: + - '/opt/haveno/bin/Haveno' + users: + - 'amnesia' + commands: + AUTHCHALLENGE: + - 'SAFECOOKIE .*' + SETEVENTS: + - 'CIRC ORCONN INFO NOTICE WARN ERR HS_DESC HS_DESC_CONTENT' + GETINFO: + - pattern: 'status/bootstrap-phase' + response: + - pattern: '250-status/bootstrap-phase=*' + replacement: '250-status/bootstrap-phase=NOTICE BOOTSTRAP PROGRESS=100 TAG=done SUMMARY="Done"' + - 'net/listeners/socks' + ADD_ONION: + - pattern: 'NEW:(\S+) Port=9999,(\S+)' + replacement: 'NEW:{} Port=9999,{client-address}:{}' + - pattern: '(\S+):(\S+) Port=9999,(\S+)' + replacement: '{}:{} Port=9999,{client-address}:{}' + DEL_ONION: + - '.+' + HSFETCH: + - '.+' + events: + CIRC: + suppress: true + ORCONN: + suppress: true + INFO: + suppress: true + NOTICE: + suppress: true + WARN: + suppress: true + ERR: + suppress: true + HS_DESC: + response: + - pattern: '650 HS_DESC CREATED (\S+) (\S+) (\S+) \S+ (.+)' + replacement: '650 HS_DESC CREATED {} {} {} redacted {}' + - pattern: '650 HS_DESC UPLOAD (\S+) (\S+) .*' + replacement: '650 HS_DESC UPLOAD {} {} redacted redacted' + - pattern: '650 HS_DESC UPLOADED (\S+) (\S+) .+' + replacement: '650 HS_DESC UPLOADED {} {} redacted' + - pattern: '650 HS_DESC REQUESTED (\S+) NO_AUTH' + replacement: '650 HS_DESC REQUESTED {} NO_AUTH' + - pattern: '650 HS_DESC REQUESTED (\S+) NO_AUTH \S+ \S+' + replacement: '650 HS_DESC REQUESTED {} NO_AUTH redacted redacted' + - pattern: '650 HS_DESC RECEIVED (\S+) NO_AUTH \S+ \S+' + replacement: '650 HS_DESC RECEIVED {} NO_AUTH redacted redacted' + - pattern: '.*' + replacement: '' + HS_DESC_CONTENT: + suppress: true \ No newline at end of file diff --git a/scripts/install_tails/assets/icon.png b/scripts/install_tails/assets/icon.png new file mode 100644 index 0000000000..4a50f0dd75 Binary files /dev/null and b/scripts/install_tails/assets/icon.png differ diff --git a/scripts/install_tails/assets/install.sh b/scripts/install_tails/assets/install.sh new file mode 100644 index 0000000000..d49782ac0f --- /dev/null +++ b/scripts/install_tails/assets/install.sh @@ -0,0 +1,79 @@ +#!/bin/bash + + +# This script automates the installation and configuration of Haveno on a Tails OS system, +# +# FUNCTIONAL OVERVIEW: +# - Verification of the Haveno installer's presence. +# - Installation of the Haveno application with dpkg. +# - Removal of automatically created desktop icons to clean up after installation. +# - Deployment of Tor configuration for Haveno. +# - Restart of the onion-grater service to apply new configurations. +# +# The script requires administrative privileges to perform system modifications. + + +# Function to print messages in blue +echo_blue() { + if [ -t 1 ]; then + # If File descriptor 1 (stdout) is open and refers to a terminal + echo -e "\033[1;34m$1\033[0m" + else + # If stdout is not a terminal, send a desktop notification + notify-send -i "/home/amnesia/Persistent/haveno/App/utils/icon.png" "Starting Haveno" "$1" + fi +} + + +# Function to print error messages in red +echo_red() { + if [ -t 1 ]; then + # If File descriptor 1 (stdout) is open and refers to a terminal + echo -e "\033[0;31m$1\033[0m" + else + # If stdout is not a terminal, send a desktop notification + notify-send -u critical -i "error" "Staring Haveno" "$1\nExiting..." + fi +} + + +# Define file locations +persistence_dir="/home/amnesia/Persistent" +app_dir="${persistence_dir}/haveno/App" +install_dir="${persistence_dir}/haveno/Install" +haveno_installer="${install_dir}/haveno.deb" +haveno_config_file="${app_dir}/utils/haveno.yml" + + +# Check if the Haveno installer exists +if [ ! -f "${haveno_installer}" ]; then + echo_red "Haveno installer not found at ${haveno_installer}." + exit 1 +fi + + +# Install Haveno +echo_blue "Installing Haveno..." +dpkg -i "${haveno_installer}" || { echo_red "Failed to install Haveno."; exit 1; } + + +# Remove installed desktop menu icon +rm -f /usr/share/applications/haveno-Haveno.desktop + + +# Change access rights for Tor control cookie +echo_blue "Changing access rights for Tor control cookie..." +chmod o+r /var/run/tor/control.authcookie || { echo_red "Failed to change access rights for Tor control cookie."; exit 1; } + + +# Copy haveno.yml configuration file +echo_blue "Copying Tor onion-grater configuration to /etc/onion-grater.d/..." +cp "${haveno_config_file}" /etc/onion-grater.d/haveno.yml || { echo_red "Failed to copy haveno.yml."; exit 1; } + + +# Restart onion-grater service +echo_blue "Restarting onion-grater service..." +systemctl restart onion-grater.service || { echo_red "Failed to restart onion-grater service."; exit 1; } + + +echo_blue "Haveno installation and configuration complete." diff --git a/scripts/install_tails/deprecated/README.md b/scripts/install_tails/deprecated/README.md new file mode 100644 index 0000000000..0345bd1ea4 --- /dev/null +++ b/scripts/install_tails/deprecated/README.md @@ -0,0 +1,11 @@ +# Steps to use (This has serious security concerns to tails threat model only run when you need to access haveno) + +## 1. Enable persistent storage and admin password before starting tails + +## 2. Get your haveno deb file in persistent storage (amd64 version for tails) + +## 3. Edit the path to the haveno deb file if necessary then run ```sudo ./haveno-install.sh``` +## 4. As amnesia run ```source ~/.bashrc``` +## 5. Start haveno using ```haveno-tails``` + +## You will need to run this script after each reset, but your data will be saved persistently in /home/amnesia/Persistence/Haveno \ No newline at end of file diff --git a/scripts/install_tails/deprecated/haveno-install.sh b/scripts/install_tails/deprecated/haveno-install.sh new file mode 100644 index 0000000000..247354ff87 --- /dev/null +++ b/scripts/install_tails/deprecated/haveno-install.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +############################################################################# +# Written by BrandyJson, with heavy inspiration from bisq.wiki tails script # +############################################################################# +echo "Installing dpkg from persistent, (1.07-1, if this is out of date change the deb path in the script or manually install after running" +dpkg -i "/home/amnesia/Persistent/haveno_1.0.7-1_amd64.deb" +echo -e "Allowing amnesia to read tor control port cookie, only run this script when you actually want to use haveno\n\n!!! not secure !!!\n" +chmod o+r /var/run/tor/control.authcookie +echo "Updating apparmor-profile" +echo "--- +- apparmor-profiles: + - '/opt/haveno/bin/Haveno' + users: + - 'amnesia' + commands: + AUTHCHALLENGE: + - 'SAFECOOKIE .*' + SETEVENTS: + - 'CIRC ORCONN INFO NOTICE WARN ERR HS_DESC HS_DESC_CONTENT' + GETINFO: + - pattern: 'status/bootstrap-phase' + response: + - pattern: '250-status/bootstrap-phase=*' + replacement: '250-status/bootstrap-phase=NOTICE BOOTSTRAP PROGRESS=100 TAG=done SUMMARY="Done"' + - 'net/listeners/socks' + ADD_ONION: + - pattern: 'NEW:(\S+) Port=9999,(\S+)' + replacement: 'NEW:{} Port=9999,{client-address}:{}' + - pattern: '(\S+):(\S+) Port=9999,(\S+)' + replacement: '{}:{} Port=9999,{client-address}:{}' + DEL_ONION: + - '.+' + HSFETCH: + - '.+' + events: + CIRC: + suppress: true + ORCONN: + suppress: true + INFO: + suppress: true + NOTICE: + suppress: true + WARN: + suppress: true + ERR: + suppress: true + HS_DESC: + response: + - pattern: '650 HS_DESC CREATED (\S+) (\S+) (\S+) \S+ (.+)' + replacement: '650 HS_DESC CREATED {} {} {} redacted {}' + - pattern: '650 HS_DESC UPLOAD (\S+) (\S+) .*' + replacement: '650 HS_DESC UPLOAD {} {} redacted redacted' + - pattern: '650 HS_DESC UPLOADED (\S+) (\S+) .+' + replacement: '650 HS_DESC UPLOADED {} {} redacted' + - pattern: '650 HS_DESC REQUESTED (\S+) NO_AUTH' + replacement: '650 HS_DESC REQUESTED {} NO_AUTH' + - pattern: '650 HS_DESC REQUESTED (\S+) NO_AUTH \S+ \S+' + replacement: '650 HS_DESC REQUESTED {} NO_AUTH redacted redacted' + - pattern: '650 HS_DESC RECEIVED (\S+) NO_AUTH \S+ \S+' + replacement: '650 HS_DESC RECEIVED {} NO_AUTH redacted redacted' + - pattern: '.*' + replacement: '' + HS_DESC_CONTENT: + suppress: true" > /etc/onion-grater.d/haveno.yml +echo "Adding rule to iptables to allow for monero-wallet-rpc to work" +iptables -I OUTPUT 2 -p tcp -d 127.0.0.1 -m tcp --dport 18081 -m owner --uid-owner 1855 -j ACCEPT +echo "Updating torsocks to allow for inbound connection" +sed -i 's/#AllowInbound/AllowInbound/g' /etc/tor/torsocks.conf + +echo "Restarting onion-grater service" + +systemctl restart onion-grater.service + +echo "alias haveno-tails='torsocks /opt/haveno/bin/Haveno --torControlPort 951 --torControlCookieFile=/var/run/tor/control.authcookie --torControlUseSafeCookieAuth --useTorForXmr=ON --userDataDir=/home/amnesia/Persistent/'" >> /home/amnesia/.bashrc +echo -e "Everything is set up just run\n\nsource ~/.bashrc\n\nThen you can start haveno using haveno-tails" diff --git a/scripts/install_tails/haveno-install.sh b/scripts/install_tails/haveno-install.sh new file mode 100755 index 0000000000..e9a8c37bf4 --- /dev/null +++ b/scripts/install_tails/haveno-install.sh @@ -0,0 +1,148 @@ +#!/bin/bash + + +# This script facilitates the setup and installation of the Haveno application on Tails OS. +# +# FUNCTIONAL OVERVIEW: +# - Creating necessary persistent directories and copying utility files. +# - Downloading Haveno binary, signature file, and GPG key for verification. +# - Importing and verifying the GPG key to ensure the authenticity of the download. +# - Setting up desktop icons in both local and persistent directories. + + +# Function to print messages in blue +echo_blue() { + echo -e "\033[1;34m$1\033[0m" +} + + +# Function to print error messages in red +echo_red() { + echo -e "\033[0;31m$1\033[0m" +} + + +# Define version and file locations +user_url=$1 +base_url=$(printf ${user_url} | awk -F'/' -v OFS='/' '{$NF=""}1') +expected_fingerprint=$2 +binary_filename=$(awk -F'/' '{ print $NF }' <<< "$user_url") +package_filename="haveno.deb" +signature_filename="${binary_filename}.sig" +key_filename="$(printf "$expected_fingerprint" | tr -d ' ' | sed -E 's/.*(................)/\1/' )".asc +assets_dir="/tmp/assets" +persistence_dir="/home/amnesia/Persistent" +app_dir="${persistence_dir}/haveno/App" +data_dir="${persistence_dir}/haveno/Data" +install_dir="${persistence_dir}/haveno/Install" +dotfiles_dir="/live/persistence/TailsData_unlocked/dotfiles" +persistent_desktop_dir="$dotfiles_dir/.local/share/applications" +local_desktop_dir="/home/amnesia/.local/share/applications" +wget_flags="--tries=10 --timeout=10 --waitretry=5 --retry-connrefused --show-progress" + + +# Create temp location for downloads +echo_blue "Creating temporary directory for Haveno resources ..." +mkdir -p "${assets_dir}" || { echo_red "Failed to create directory ${assets_dir}"; exit 1; } + + +# Download resources +echo_blue "Downloading resources for Haveno on Tails ..." +wget "${wget_flags}" -cqP "${assets_dir}" https://github.com/haveno-dex/haveno/raw/master/scripts/install_tails/assets/exec.sh || { echo_red "Failed to download resource (exec.sh)."; exit 1; } +wget "${wget_flags}" -cqP "${assets_dir}" https://github.com/haveno-dex/haveno/raw/master/scripts/install_tails/assets/install.sh || { echo_red "Failed to download resource (install.sh)."; exit 1; } +wget "${wget_flags}" -cqP "${assets_dir}" https://github.com/haveno-dex/haveno/raw/master/scripts/install_tails/assets/haveno.desktop || { echo_red "Failed to resource (haveno.desktop)."; exit 1; } +wget "${wget_flags}" -cqP "${assets_dir}" https://raw.githubusercontent.com/haveno-dex/haveno/master/scripts/install_tails/assets/icon.png || { echo_red "Failed to download resource (icon.png)."; exit 1; } +wget "${wget_flags}" -cqP "${assets_dir}" https://github.com/haveno-dex/haveno/raw/master/scripts/install_tails/assets/haveno.yml || { echo_red "Failed to download resource (haveno.yml)."; exit 1; } + + +# Create persistent directory +echo_blue "Creating persistent directory for Haveno ..." +mkdir -p "${app_dir}" || { echo_red "Failed to create directory ${app_dir}"; exit 1; } + + +# Copy utility files to persistent storage and make scripts executable +echo_blue "Copying haveno utility files to persistent storage ..." +rsync -av "${assets_dir}/" "${app_dir}/utils/" || { echo_red "Failed to rsync files to ${app_dir}/utils/"; exit 1; } +find "${app_dir}/utils/" -type f -name "*.sh" -exec chmod +x {} \; || { echo_red "Failed to make scripts executable"; exit 1; } + + +echo_blue "Creating desktop menu icon ..." +# Create desktop directories +mkdir -p "${local_desktop_dir}" +mkdir -p "${persistent_desktop_dir}" + + +# Copy .desktop file to persistent directory +cp "${assets_dir}/haveno.desktop" "${persistent_desktop_dir}" || { echo_red "Failed to copy .desktop file to persistent directory $persistent_desktop_dir"; exit 1; } + + +# Create a symbolic link to it in the local .desktop directory, if it doesn't exist +if [ ! -L "${local_desktop_dir}/haveno.desktop" ]; then + ln -s "${persistent_desktop_dir}/haveno.desktop" "${local_desktop_dir}/haveno.desktop" || { echo_red "Failed to create symbolic link for .desktop file"; exit 1; } +fi + + +# Download Haveno binary +echo_blue "Downloading Haveno from URL provided ..." +wget "${wget_flags}" -cq "${user_url}" || { echo_red "Failed to download Haveno binary."; exit 1; } + + +# Download Haveno signature file +echo_blue "Downloading Haveno signature ..." +wget "${wget_flags}" -cq "${base_url}""${signature_filename}" || { echo_red "Failed to download Haveno signature."; exit 1; } + + +# Download the GPG key +echo_blue "Downloading signing GPG key ..." +wget "${wget_flags}" -cqO "${key_filename}" "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x$(echo "$expected_fingerprint" | tr -d ' ')" || { echo_red "Failed to download GPG key."; exit 1; } + + +# Import the GPG key +echo_blue "Importing the GPG key ..." +gpg --import "${key_filename}" || { echo_red "Failed to import GPG key."; exit 1; } + + +# Extract imported fingerprints +imported_fingerprints=$(gpg --with-colons --fingerprint | grep -A 1 'pub' | grep 'fpr' | cut -d: -f10 | tr -d '\n') + + +# Remove spaces from the expected fingerprint for comparison +formatted_expected_fingerprint=$(echo "${expected_fingerprint}" | tr -d ' ') + + +# Check if the expected fingerprint is in the list of imported fingerprints +if [[ ! "${imported_fingerprints}" =~ "${formatted_expected_fingerprint}" ]]; then + echo_red "The imported GPG key fingerprint does not match the expected fingerprint." + exit 1 +fi + + +# Verify the downloaded binary with the signature +echo_blue "Verifying the signature of the downloaded file ..." +OUTPUT=$(gpg --digest-algo SHA256 --verify "${signature_filename}" "${binary_filename}" 2>&1) + +if ! echo "$OUTPUT" | grep -q "Good signature from"; then + echo_red "Verification failed: $OUTPUT" + exit 1; + else 7z x "${binary_filename}" && mv haveno*.deb "${package_filename}" +fi + +echo_blue "Haveno binaries have been successfully verified." + + +# Move the binary and its signature to the persistent directory +mkdir -p "${install_dir}" + + +# Delete old Haveno binaries +#rm -f "${install_dir}/"*.deb* +mv "${binary_filename}" "${package_filename}" "${key_filename}" "${signature_filename}" "${install_dir}" +echo_blue "Files moved to persistent directory ${install_dir}" + + +# Remove stale resources +rm -rf "${assets_dir}" + + +# Completed confirmation +echo_blue "Haveno installation setup completed successfully." diff --git a/seednode/docker/Dockerfile b/seednode/docker/Dockerfile index 21bfaf2712..ab4a276ebc 100644 --- a/seednode/docker/Dockerfile +++ b/seednode/docker/Dockerfile @@ -1,7 +1,7 @@ # docker run -it -p 9050 -p 2002 --restart-policy unless-stopped --name haveno-seednode haveno-seednode # TODO: image very heavy, but it's hard to significantly reduce the size without bins -FROM openjdk:11 +FROM openjdk:21-jdk-bullseye RUN set -ex && \ apt update && \ diff --git a/seednode/haveno-seednode.service b/seednode/haveno-seednode.service index 7551c54fea..448a36e1a8 100644 --- a/seednode/haveno-seednode.service +++ b/seednode/haveno-seednode.service @@ -11,10 +11,13 @@ SyslogIdentifier=Haveno-Seednode ExecStart=/bin/sh $PATH/haveno-seednode --baseCurrencyNetwork=XMR_STAGENET\ --useLocalhostForP2P=false\ --useDevPrivilegeKeys=false\ +# Uncomment the following line to use external tor +# --hiddenServiceAddress=example.onion\ --nodePort=2002\ - --appName=haveno-XMR_STAGENET_Seed_2002 + --appName=haveno-XMR_STAGENET_Seed_2002\ + --xmrNode=http://[::1]:38088 -ExecStop=/bin/kill ${MAINPID} +ExecStop=/bin/kill ${MAINPID} ; sleep 5 Restart=always # Hardening diff --git a/seednode/haveno.env b/seednode/haveno.env index 81184268a2..9b7ff903e6 100644 --- a/seednode/haveno.env +++ b/seednode/haveno.env @@ -1,11 +1,11 @@ # configuration for haveno service # install in /etc/default/haveno.env -# java home, set to openjdk 10 -JAVA_HOME=/usr/lib/jvm/openjdk-10.0.2 +# java home, set to latest openjdk 21 from os repository +JAVA_HOME=/usr/lib/jvm/openjdk-21 # java memory and remote management options -JAVA_OPTS="-Xms4096M -Xmx4096M" +JAVA_OPTS="-Xms4096M -Xmx4096M -XX:+ExitOnOutOfMemoryError" # use external tor (change to -1 for internal tor binary) HAVENO_EXTERNAL_TOR_PORT=9051 @@ -28,7 +28,7 @@ BITCOIN_RPC_BLOCKNOTIFY_PORT=5120 HAVENO_HOME=__HAVENO_HOME__ HAVENO_APP_NAME=haveno-seednode HAVENO_ENTRYPOINT=haveno-seednode -HAVENO_BASE_CURRENCY=btc_mainnet +HAVENO_BASE_CURRENCY=xmr_mainnet # haveno node settings HAVENO_NODE_PORT=8000 diff --git a/seednode/install_seednode_debian.sh b/seednode/install_seednode_debian.sh index dafc9c5af0..83043a1779 100755 --- a/seednode/install_seednode_debian.sh +++ b/seednode/install_seednode_debian.sh @@ -7,22 +7,21 @@ echo "[*] Haveno Seednode installation script" ROOT_USER=root ROOT_GROUP=root -ROOT_PKG="build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 git vim screen ufw" +ROOT_PKG="build-essential libtool autotools-dev automake pkg-config bsdmainutils python3 git vim screen ufw openjdk-21-jdk" ROOT_HOME=/root SYSTEMD_SERVICE_HOME=/etc/systemd/system SYSTEMD_ENV_HOME=/etc/default -HAVENO_REPO_URL=https://github.com/bisq-network/bisq +HAVENO_REPO_URL=https://github.com/haveno-dex/haveno HAVENO_REPO_NAME=haveno HAVENO_REPO_TAG=master -HAVENO_LATEST_RELEASE=$(curl -s https://api.github.com/repos/bisq-network/bisq/releases/latest|grep tag_name|head -1|cut -d '"' -f4) +HAVENO_LATEST_RELEASE=$(curl -s https://api.github.com/repos/haveno-dex/haveno/releases/latest|grep tag_name|head -1|cut -d '"' -f4) HAVENO_HOME=/haveno HAVENO_USER=haveno -# by default, this script will build and setup bitcoin fullnode -# if you want to use an existing bitcoin fullnode, see next section -BITCOIN_INSTALL=true +# by default, this script will not build and setup bitcoin full-node +BITCOIN_INSTALL=false BITCOIN_REPO_URL=https://github.com/bitcoin/bitcoin BITCOIN_REPO_NAME=bitcoin BITCOIN_REPO_TAG=$(curl -s https://api.github.com/repos/bitcoin/bitcoin/releases/latest|grep tag_name|head -1|cut -d '"' -f4) @@ -60,19 +59,13 @@ sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get upgrade -qq echo "[*] Installing base packages" sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${ROOT_PKG} -echo "[*] Installing Git LFS" -sudo -H -i -u "${ROOT_USER}" apt-get install git-lfs -sudo -H -i -u "${ROOT_USER}" git lfs install - echo "[*] Cloning Haveno repo" sudo -H -i -u "${ROOT_USER}" git config --global advice.detachedHead false sudo -H -i -u "${ROOT_USER}" git clone --branch "${HAVENO_REPO_TAG}" "${HAVENO_REPO_URL}" "${ROOT_HOME}/${HAVENO_REPO_NAME}" echo "[*] Installing Tor" -sudo -H -i -u "${ROOT_USER}" wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | gp -g --dearmor | tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null -sudo -H -i -u "${ROOT_USER}" echo "deb [arch=amd64 signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.o -rg/torproject.org focal main" > /etc/apt/sources.list.d/tor.list +sudo -H -i -u "${ROOT_USER}" wget -qO- https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc | sudo gpg --dearmor | sudo tee /usr/share/keyrings/tor-archive-keyring.gpg >/dev/null +echo "deb [arch=amd64 signed-by=/usr/share/keyrings/tor-archive-keyring.gpg] https://deb.torproject.org/torproject.org focal main" | sudo -H -i -u "${ROOT_USER}" tee /etc/apt/sources.list.d/tor.list sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get update -q sudo -H -i -u "${ROOT_USER}" DEBIAN_FRONTEND=noninteractive apt-get install -qq -y ${TOR_PKG} @@ -128,17 +121,14 @@ echo "[*] Moving Haveno repo" sudo -H -i -u "${ROOT_USER}" mv "${ROOT_HOME}/${HAVENO_REPO_NAME}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}" sudo -H -i -u "${ROOT_USER}" chown -R "${HAVENO_USER}:${HAVENO_GROUP}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}" -echo "[*] Installing OpenJDK 10.0.2 from Haveno repo" -sudo -H -i -u "${ROOT_USER}" "${HAVENO_HOME}/${HAVENO_REPO_NAME}/scripts/install_java.sh" - echo "[*] Installing Haveno init script" -sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno.service" "${SYSTEMD_SERVICE_HOME}/haveno.service" +sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno-seednode.service" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service" if [ "${BITCOIN_INSTALL}" = true ];then - sudo sed -i -e "s/#Requires=bitcoin.service/Requires=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno.service" - sudo sed -i -e "s/#BindsTo=bitcoin.service/BindsTo=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno.service" + sudo sed -i -e "s/#Requires=bitcoin.service/Requires=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service" + sudo sed -i -e "s/#BindsTo=bitcoin.service/BindsTo=bitcoin.service/" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service" fi -sudo sed -i -e "s/__HAVENO_REPO_NAME__/${HAVENO_REPO_NAME}/" "${SYSTEMD_SERVICE_HOME}/haveno.service" -sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${SYSTEMD_SERVICE_HOME}/haveno.service" +sudo sed -i -e "s/__HAVENO_REPO_NAME__/${HAVENO_REPO_NAME}/" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service" +sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${SYSTEMD_SERVICE_HOME}/haveno-seednode.service" echo "[*] Installing Haveno environment file with Bitcoin RPC credentials" sudo -H -i -u "${ROOT_USER}" install -c -o "${ROOT_USER}" -g "${ROOT_GROUP}" -m 644 "${HAVENO_HOME}/${HAVENO_REPO_NAME}/seednode/haveno.env" "${SYSTEMD_ENV_HOME}/haveno.env" @@ -154,16 +144,13 @@ sudo sed -i -e "s!__HAVENO_HOME__!${HAVENO_HOME}!" "${SYSTEMD_ENV_HOME}/haveno.e echo "[*] Checking out Haveno ${HAVENO_LATEST_RELEASE}" sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && git checkout ${HAVENO_LATEST_RELEASE}" -echo "[*] Performing Git LFS pull" -sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && git lfs pull" - echo "[*] Building Haveno from source" sudo -H -i -u "${HAVENO_USER}" sh -c "cd ${HAVENO_HOME}/${HAVENO_REPO_NAME} && ./gradlew build -x test < /dev/null" # redirect from /dev/null is necessary to workaround gradlew non-interactive shell hanging issue echo "[*] Updating systemd daemon configuration" sudo -H -i -u "${ROOT_USER}" systemctl daemon-reload sudo -H -i -u "${ROOT_USER}" systemctl enable tor.service -sudo -H -i -u "${ROOT_USER}" systemctl enable haveno.service +sudo -H -i -u "${ROOT_USER}" systemctl enable haveno-seednode.service if [ "${BITCOIN_INSTALL}" = true ];then sudo -H -i -u "${ROOT_USER}" systemctl enable bitcoin.service fi @@ -185,13 +172,13 @@ fi echo "[*] Adding notes to motd" sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "Haveno Seednode instructions:" >> /etc/motd' -sudo -H -i -u "${ROOT_USER}" sh -c 'echo "https://github.com/bisq-network/bisq/tree/master/seednode" >> /etc/motd' +sudo -H -i -u "${ROOT_USER}" sh -c 'echo "https://github.com/haveno-dex/haveno/tree/master/seednode" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "How to check logs for Haveno-Seednode service:" >> /etc/motd' -sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo journalctl --no-pager --unit haveno" >> /etc/motd' +sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo journalctl --no-pager --unit haveno-seednode" >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo " " >> /etc/motd' sudo -H -i -u "${ROOT_USER}" sh -c 'echo "How to restart Haveno-Seednode service:" >> /etc/motd' -sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo service haveno restart" >> /etc/motd' +sudo -H -i -u "${ROOT_USER}" sh -c 'echo "sudo service haveno-seednode restart" >> /etc/motd' echo '[*] Done!' diff --git a/seednode/src/main/java/haveno/seednode/SeedNode.java b/seednode/src/main/java/haveno/seednode/SeedNode.java index 8aa28dc309..2fb5332733 100644 --- a/seednode/src/main/java/haveno/seednode/SeedNode.java +++ b/seednode/src/main/java/haveno/seednode/SeedNode.java @@ -1,25 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.seednode; import com.google.inject.Injector; import haveno.core.app.misc.AppSetup; -import haveno.core.app.misc.AppSetupWithP2PAndDAO; +import haveno.core.app.misc.AppSetupWithP2P; import haveno.core.network.p2p.inventory.GetInventoryRequestHandler; import lombok.Setter; import lombok.extern.slf4j.Slf4j; @@ -35,7 +35,7 @@ public class SeedNode { } public void startApplication() { - appSetup = injector.getInstance(AppSetupWithP2PAndDAO.class); + appSetup = injector.getInstance(AppSetupWithP2P.class); appSetup.start(); getInventoryRequestHandler = injector.getInstance(GetInventoryRequestHandler.class); diff --git a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java index 459bb717f6..e0f5ad7c3e 100644 --- a/seednode/src/main/java/haveno/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/haveno/seednode/SeedNodeMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.seednode; @@ -41,7 +41,7 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class SeedNodeMain extends ExecutableForAppWithP2p { private static final long CHECK_CONNECTION_LOSS_SEC = 30; - private static final String VERSION = "0.0.11"; + private static final String VERSION = "1.0.14"; private SeedNode seedNode; private Timer checkConnectionLossTime; @@ -75,7 +75,7 @@ public class SeedNodeMain extends ExecutableForAppWithP2p { seedNode = new SeedNode(); UserThread.execute(this::onApplicationLaunched); } catch (Exception e) { - e.printStackTrace(); + log.error("Error launching seed node: {}\n", e.toString(), e); } }); } diff --git a/seednode/src/main/resources/logback.xml b/seednode/src/main/resources/logback.xml index 914b9d3d4b..1200e72118 100644 --- a/seednode/src/main/resources/logback.xml +++ b/seednode/src/main/resources/logback.xml @@ -1,8 +1,11 @@ <?xml version="1.0" encoding="UTF-8"?> <configuration> + + <conversionRule conversionWord="hl2" converterClass="haveno.common.app.LogHighlighter" /> + <appender name="CONSOLE_APPENDER" class="ch.qos.logback.core.ConsoleAppender"> <encoder> - <pattern>%highlight(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{15}: %msg %xEx%n)</pattern> + <pattern>%hl2(%d{MMM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{40}: %msg %xEx%n)</pattern> </encoder> </appender> diff --git a/seednode/src/test/java/haveno/seednode/GuiceSetupTest.java b/seednode/src/test/java/haveno/seednode/GuiceSetupTest.java index 3bb4dd69cf..e82a226919 100644 --- a/seednode/src/test/java/haveno/seednode/GuiceSetupTest.java +++ b/seednode/src/test/java/haveno/seednode/GuiceSetupTest.java @@ -2,7 +2,7 @@ package haveno.seednode; import com.google.inject.Guice; import haveno.common.config.Config; -import haveno.core.app.misc.AppSetupWithP2PAndDAO; +import haveno.core.app.misc.AppSetupWithP2P; import haveno.core.app.misc.ModuleForAppWithP2p; import haveno.core.locale.CurrencyUtil; import haveno.core.locale.Res; @@ -15,6 +15,6 @@ public class GuiceSetupTest { CurrencyUtil.setup(); ModuleForAppWithP2p module = new ModuleForAppWithP2p(new Config()); - Guice.createInjector(module).getInstance(AppSetupWithP2PAndDAO.class); + Guice.createInjector(module).getInstance(AppSetupWithP2P.class); } } diff --git a/seednode/torrc b/seednode/torrc index 1a9d20ee98..d6e2c55b55 100644 --- a/seednode/torrc +++ b/seednode/torrc @@ -1,18 +1,155 @@ -RunAsDaemon 1 -SOCKSPort 9050 -ControlPort 9051 -Log notice syslog +## Configuration file for Haveno Seednode +## +## To start/reload/etc this instance, run "systemctl start tor" (or reload, or..). +## This instance will run as user debian-tor; its data directory is /var/lib/tor. +## +## This file is configured via: +## /usr/share/tor/tor-service-defaults-torrc +## +## See 'man tor', for more options you can use in this file. -CookieAuthentication 0 -CookieAuthFileGroupReadable 1 -DataDirectoryGroupReadable 1 +## Tor opens a socks proxy on port 9050 by default -- even if you don't +## configure one below. Set "SocksPort 0" if you plan to run Tor only +## as a relay, and not make any local application connections yourself. +#SocksPort 9050 # Default: Bind to localhost:9050 for local connections. +# ### SocksPort flag: OnionTrafficOnly ### +## Tell the tor client to only connect to .onion addresses in response to SOCKS5 requests on this connection. +## This is equivalent to NoDNSRequest, NoIPv4Traffic, NoIPv6Traffic. +# ### SocksPort flag: ExtendedErrors ### +## Return extended error code in the SOCKS reply. So far, the possible errors are: +# X'F0' Onion Service Descriptor Can Not be Found +# X'F1' Onion Service Descriptor Is Invalid +# X'F2' Onion Service Introduction Failed +# X'F3' Onion Service Rendezvous Failed +# X'F4' Onion Service Missing Client Authorization +# X'F5' Onion Service Wrong Client Authorization +# X'F6' Onion Service Invalid Address +# X'F7' Onion Service Introduction Timed Out +SocksPort 9050 OnionTrafficOnly ExtendedErrors -SafeSocks 0 -HiddenServiceStatistics 0 +## Entry policies to allow/deny SOCKS requests based on IP address. +## First entry that matches wins. If no SocksPolicy is set, we accept +## all (and only) requests that reach a SocksPort. Untrusted users who +## can access your SocksPort may be able to learn about the connections +## you make. +SocksPolicy accept 127.0.0.1 +SocksPolicy accept6 [::1] +SocksPolicy reject * + +## Tor will reject application connections that use unsafe variants of the socks protocol +## — ones that only provide an IP address, meaning the application is doing a DNS resolve first. +## Specifically, these are socks4 and socks5 when not doing remote DNS. (Default: 0) +#SafeSocks 1 + +## Tor will make a notice-level log entry for each connection to the Socks port indicating +## whether the request used a safe socks protocol or an unsafe one (see above entry on SafeSocks). +## This helps to determine whether an application using Tor is possibly leaking DNS requests. (Default: 0) +TestSocks 1 + +## Logs go to stdout at level "notice" unless redirected by something +## else, like one of the below lines. You can have as many Log lines as +## you want. +## +## We advise using "notice" in most cases, since anything more verbose +## may provide sensitive information to an attacker who obtains the logs. +## +## Send all messages of level 'notice' or higher to /var/log/tor/notices.log +#Log notice file /var/log/tor/notices.log +## Send every possible message to /var/log/tor/debug.log +#Log debug file /var/log/tor/debug.log +## Use the system log instead of Tor's logfiles (This is default) +#Log notice syslog +## To send all messages to stderr: +#Log debug stderr + +# Try to write to disk less frequently than we would otherwise. This is useful when running on flash memory. AvoidDiskWrites 1 -#MaxClientCircuitsPending 64 -#KeepalivePeriod 2 -#CircuitBuildTimeout 5 -#NewCircuitPeriod 15 -#NumEntryGuards 8 +## TODO: This option has no effect. Bisq/Haveno is tor client &/or hidden service. 'man torrc': +## Relays and bridges only. When this option is enabled, a Tor relay writes obfuscated statistics on its +## role as hidden-service directory, introduction point, or rendezvous point to disk every 24 hours. +## If ExtraInfoStatistics is enabled, it will be published as part of the extra-info document. (Default: 1) +HiddenServiceStatistics 0 + +## NOTE: In order to use the ControlPort, the <user> must belong to the tor group. +## sudo usermod -aG debian-tor <user> +## +## The port on which Tor will listen for local connections from Tor +## controller applications, as documented in control-spec.txt. +#ControlPort 9051 +## If you enable the controlport, be sure to enable one of these +## authentication methods, to prevent attackers from accessing it. +## +## Compute the hash of a password with "tor --hash-password password". +#HashedControlPassword 16:872860B76453A77D60CA2BB8C1A7042072093276A3D701AD684053EC4C +CookieAuthentication 0 # (Default: 1) + +## MetricsPort provides an interface to the underlying Tor relay metrics. +## Exposing publicly is dangerous, set a very strict access policy. +## Retrieve the metrics with: curl http://127.0.0.1:9035/metrics +MetricsPort 127.0.0.1:9035 +MetricsPortPolicy accept 127.0.0.1 +MetricsPortPolicy accept [::1] + +############### This section is just for location-hidden services ### + +## Once you have configured a hidden service, you can look at the +## contents of the file ".../hidden_service/hostname" for the address +## to tell people. e.g.: 'sudo cat /var/lib/tor/haveno_seednode/hostname' +## +## HiddenServicePort x y:z says to redirect requests on port x to the +## address y:z. +## +## If you plan to keep your service available for a long time, you might want to make a backup copy +## of the private_key file or complete folder /var/lib/tor/hidden_service somewhere. + +#### Haveno seednode incoming anonymity connections ### +HiddenServiceDir /var/lib/tor/haveno_seednode +HiddenServicePort 2002 127.0.0.1:2002 +HiddenServicePort 2002 [::1]:2002 + +## NOTE: HiddenService options are per onion service +## https://community.torproject.org/onion-services/advanced/dos/ +## +## Rate limiting at the Introduction Points +## Intropoint protections prevents onion service DoS from becoming a DoS for the entire machine and its guard. +HiddenServiceEnableIntroDoSDefense 1 +#HiddenServiceEnableIntroDoSRatePerSec 25 # (Default: 25) +#HiddenServiceEnableIntroDoSBurstPerSec 200 # (Default: 200) + +# Number of introduction points the hidden service will have. You can’t have more than 20. +#HiddenServiceNumIntroductionPoints 3 # (Default: 3) + +## https://tpo.pages.torproject.net/onion-services/ecosystem/technology/pow/#configuring-an-onion-service-with-the-pow-protection +## Proof of Work (PoW) before establishing Rendezvous Circuits +## The lower the queue and burst rates, the higher the puzzle effort tends to be for users. +HiddenServicePoWDefensesEnabled 1 +HiddenServicePoWQueueRate 50 # (Default: 250) +HiddenServicePoWQueueBurst 250 # (Default: 2500) + +## Stream limits in the established Rendezvous Circuits +## The maximum number of simultaneous streams (connections) per rendezvous circuit. The max value allowed is 65535. (0 = unlimited) +HiddenServiceMaxStreams 25 +#HiddenServiceMaxStreamsCloseCircuit 1 + +#### Haveno seednode2 incoming anonymity connections ### +HiddenServiceDir /var/lib/tor/haveno_seednode2 +HiddenServicePort 2003 127.0.0.1:2003 +HiddenServicePort 2003 [::1]:2003 + +HiddenServiceEnableIntroDoSDefense 1 +#HiddenServiceEnableIntroDoSRatePerSec 25 # (Default: 25) +#HiddenServiceEnableIntroDoSBurstPerSec 200 # (Default: 200) +#HiddenServiceNumIntroductionPoints 3 # (Default: 3) + +HiddenServicePoWDefensesEnabled 1 +HiddenServicePoWQueueRate 50 # (Default: 250) +HiddenServicePoWQueueBurst 250 # (Default: 2500) + +HiddenServiceMaxStreams 25 +#HiddenServiceMaxStreamsCloseCircuit 1 + +##################################################################### + +LongLivedPorts 2002,2003 +## Default: 21, 22, 706, 1863, 5050, 5190, 5222, 5223, 6523, 6667, 6697, 8300 diff --git a/seednode/uninstall_seednode_debian.sh b/seednode/uninstall_seednode_debian.sh index ea9ff721f5..e78839c9e3 100755 --- a/seednode/uninstall_seednode_debian.sh +++ b/seednode/uninstall_seednode_debian.sh @@ -3,9 +3,9 @@ echo "[*] Uninstalling Bitcoin and Haveno, will delete all data!!" sleep 10 sudo rm -rf /root/haveno sudo systemctl stop bitcoin -sudo systemctl stop haveno +sudo systemctl stop haveno-seednode sudo systemctl disable bitcoin -sudo systemctl disable haveno +sudo systemctl disable haveno-seednode sudo userdel -f -r haveno sudo userdel -f -r bitcoin echo "[*] Done!" diff --git a/statsnode/src/main/java/haveno/statistics/Statistics.java b/statsnode/src/main/java/haveno/statistics/Statistics.java index 5ae5ca2493..d2d3b65c33 100644 --- a/statsnode/src/main/java/haveno/statistics/Statistics.java +++ b/statsnode/src/main/java/haveno/statistics/Statistics.java @@ -1,25 +1,25 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.statistics; import com.google.inject.Injector; import haveno.core.app.misc.AppSetup; -import haveno.core.app.misc.AppSetupWithP2PAndDAO; +import haveno.core.app.misc.AppSetupWithP2P; import haveno.core.offer.OfferBookService; import haveno.core.provider.price.PriceFeedService; import haveno.core.trade.statistics.TradeStatisticsManager; @@ -52,7 +52,7 @@ public class Statistics { priceFeedService.setCurrencyCode("USD"); p2pService.addP2PServiceListener(new BootstrapListener() { @Override - public void onUpdatedDataReceived() { + public void onDataReceived() { // we need to have tor ready log.info("onBootstrapComplete: we start requestPriceFeed"); priceFeedService.startRequestingPrices(price -> log.info("requestPriceFeed. price=" + price), @@ -62,7 +62,7 @@ public class Statistics { } }); - appSetup = injector.getInstance(AppSetupWithP2PAndDAO.class); + appSetup = injector.getInstance(AppSetupWithP2P.class); appSetup.start(); } } diff --git a/statsnode/src/main/java/haveno/statistics/StatisticsMain.java b/statsnode/src/main/java/haveno/statistics/StatisticsMain.java index 0fa19fbf90..f4587c2640 100644 --- a/statsnode/src/main/java/haveno/statistics/StatisticsMain.java +++ b/statsnode/src/main/java/haveno/statistics/StatisticsMain.java @@ -1,18 +1,18 @@ /* - * This file is part of Haveno. + * This file is part of Bisq. * - * Haveno is free software: you can redistribute it and/or modify it + * Bisq is free software: you can redistribute it and/or modify it * under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at * your option) any later version. * - * Haveno is distributed in the hope that it will be useful, but WITHOUT + * Bisq is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public * License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with Haveno. If not, see <http://www.gnu.org/licenses/>. + * along with Bisq. If not, see <http://www.gnu.org/licenses/>. */ package haveno.statistics;