diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 9a5308e22..f8cc8f9ca 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -4,7 +4,7 @@ contact_links: url: https://github.com/cake-tech/cake_wallet/discussions/new?category=feature-requests about: Suggest an idea for Cake Wallet - name: Not sure where to start? - url: https://guides.cakewallet.com + url: https://docs.cakewallet.com about: Start by reading checking out the guides! - name: Need help? url: https://cakewallet.com/#contact diff --git a/.github/workflows/automated_integration_test.yml b/.github/workflows/automated_integration_test.yml new file mode 100644 index 000000000..51bc83ce0 --- /dev/null +++ b/.github/workflows/automated_integration_test.yml @@ -0,0 +1,298 @@ +name: Automated Integration Tests + +on: + # pull_request: + # branches: [main, CW-659-Transaction-History-Automated-Tests] + workflow_dispatch: + inputs: + branch: + description: "Branch name to build" + required: true + default: "main" + +jobs: + Automated_integration_test: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + api-level: [29] + # arch: [x86, x86_64] + env: + STORE_PASS: test@cake_wallet + KEY_PASS: test@cake_wallet + PR_NUMBER: ${{ github.event.number }} + + steps: + - name: is pr + if: github.event_name == 'pull_request' + run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV + + - name: is not pr + if: github.event_name != 'pull_request' + run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV + + - name: Free Disk Space (Ubuntu) + uses: insightsengineering/disk-space-reclaimer@v1 + with: + tools-cache: true + android: false + dotnet: true + haskell: true + large-packages: true + swap-storage: true + docker-images: true + + - uses: actions/checkout@v2 + - uses: actions/setup-java@v2 + with: + distribution: "temurin" + java-version: "17" + - name: Configure placeholder git details + run: | + git config --global user.email "CI@cakewallet.com" + git config --global user.name "Cake Github Actions" + - name: Flutter action + uses: subosito/flutter-action@v1 + with: + flutter-version: "3.24.0" + channel: stable + + - name: Install package dependencies + run: | + sudo apt update + sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang + + - name: Execute Build and Setup Commands + run: | + sudo mkdir -p /opt/android + sudo chown $USER /opt/android + cd /opt/android + -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + cargo install cargo-ndk + git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }} + cd cake_wallet/scripts/android/ + ./install_ndk.sh + source ./app_env.sh cakewallet + chmod +x pubspec_gen.sh + ./app_config.sh + + - name: Cache Externals + id: cache-externals + uses: actions/cache@v3 + with: + path: | + /opt/android/cake_wallet/cw_haven/android/.cxx + /opt/android/cake_wallet/scripts/monero_c/release + key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }} + + - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} + name: Generate Externals + run: | + cd /opt/android/cake_wallet/scripts/android/ + source ./app_env.sh cakewallet + ./build_monero_all.sh + + - name: Install Flutter dependencies + run: | + cd /opt/android/cake_wallet + flutter pub get + + + - name: Install go and gomobile + run: | + # install go > 1.23: + wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz + sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz + export PATH=$PATH:/usr/local/go/bin + export PATH=$PATH:~/go/bin + go install golang.org/x/mobile/cmd/gomobile@latest + gomobile init + + - name: Build mwebd + run: | + # paths are reset after each step, so we need to set them again: + export PATH=$PATH:/usr/local/go/bin + export PATH=$PATH:~/go/bin + cd /opt/android/cake_wallet/scripts/android/ + ./build_mwebd.sh --dont-install + + - name: Generate KeyStore + run: | + cd /opt/android/cake_wallet/android/app + keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS + + - name: Generate key properties + run: | + cd /opt/android/cake_wallet + flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS + + - name: Generate localization + run: | + cd /opt/android/cake_wallet + flutter packages pub run tool/generate_localization.dart + + - name: Build generated code + run: | + cd /opt/android/cake_wallet + ./model_generator.sh + + - name: Add secrets + run: | + cd /opt/android/cake_wallet + touch lib/.secrets.g.dart + touch cw_evm/lib/.secrets.g.dart + touch cw_solana/lib/.secrets.g.dart + touch cw_core/lib/.secrets.g.dart + touch cw_nano/lib/.secrets.g.dart + touch cw_tron/lib/.secrets.g.dart + echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart + echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart + echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart + echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart + echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart + echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart + echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart + echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart + echo "const wyreApiKey = '${{ secrets.WYRE_API_KEY }}';" >> lib/.secrets.g.dart + echo "const wyreAccountId = '${{ secrets.WYRE_ACCOUNT_ID }}';" >> lib/.secrets.g.dart + echo "const moonPayApiKey = '${{ secrets.MOON_PAY_API_KEY }}';" >> lib/.secrets.g.dart + echo "const moonPaySecretKey = '${{ secrets.MOON_PAY_SECRET_KEY }}';" >> lib/.secrets.g.dart + echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart + echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart + echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart + echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart + echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart + echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart + echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart + echo "const trocadorApiKey = '${{ secrets.TROCADOR_API_KEY }}';" >> lib/.secrets.g.dart + echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart + echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart + echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart + echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart + echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart + echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart + echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart + echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart + echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart + echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart + echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart + echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart + echo "const exchangeHelperApiKey = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart + echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart + echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart + echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart + echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart + echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart + echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart + echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart + echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart + echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart + echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart + echo "const nanoNowNodesApiKey = '${{ secrets.NANO_NOW_NODES_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart + echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart + echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart + echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart + echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart + echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart + echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart + echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart + echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart + + - name: Rename app + run: | + echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties + + - name: Build + run: | + cd /opt/android/cake_wallet + flutter build apk --release --split-per-abi + + # - name: Rename apk file + # run: | + # cd /opt/android/cake_wallet/build/app/outputs/flutter-apk + # mkdir test-apk + # cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk + # cp app-x86_64-release.apk test-apk/${{env.BRANCH_NAME}}_x86.apk + + # - name: Upload Artifact + # uses: kittaakos/upload-artifact-as-is@v0 + # with: + # path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/ + + # - name: Send Test APK + # continue-on-error: true + # uses: adrey/slack-file-upload-action@1.0.5 + # with: + # token: ${{ secrets.SLACK_APP_TOKEN }} + # path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/${{env.BRANCH_NAME}}.apk + # channel: ${{ secrets.SLACK_APK_CHANNEL }} + # title: "${{ env.BRANCH_NAME }}.apk" + # filename: ${{ env.BRANCH_NAME }}.apk + # initial_comment: ${{ github.event.head_commit.message }} + + - name: 🦾 Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: 🦾 Cache gradle + uses: gradle/actions/setup-gradle@v3 + + - name: 🦾 Cache AVD + uses: actions/cache@v4 + id: avd-cache + with: + path: | + ~/.android/avd/* + ~/.android/adb* + key: avd-${{ matrix.api-level }} + + - name: 🦾 Create AVD and generate snapshot for caching + if: steps.avd-cache.outputs.cache-hit != 'true' + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + force-avd-creation: false + # arch: ${{ matrix.arch }} + emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + working-directory: /opt/android/cake_wallet + disable-animations: false + script: echo "Generated AVD snapshot for caching." + + - name: 🚀 Integration tests on Android Emulator + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ matrix.api-level }} + force-avd-creation: false + emulator-options: -no-snapshot-save -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none + disable-animations: true + working-directory: /opt/android/cake_wallet + script: | + chmod a+rx integration_test_runner.sh + ./integration_test_runner.sh diff --git a/.github/workflows/cache_dependencies.yml b/.github/workflows/cache_dependencies.yml index ce098b7f1..cb2afa396 100644 --- a/.github/workflows/cache_dependencies.yml +++ b/.github/workflows/cache_dependencies.yml @@ -34,7 +34,7 @@ jobs: - name: Flutter action uses: subosito/flutter-action@v1 with: - flutter-version: "3.19.6" + flutter-version: "3.24.4" channel: stable - name: Install package dependencies @@ -62,6 +62,7 @@ jobs: /opt/android/cake_wallet/cw_haven/android/.cxx /opt/android/cake_wallet/scripts/monero_c/release key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }} + - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} name: Generate Externals run: | @@ -73,8 +74,8 @@ jobs: id: cache-keystore uses: actions/cache@v3 with: - path: /opt/android/cake_wallet/android/app/key.jks - key: $STORE_PASS + path: /opt/android/cake_wallet/android/app + key: keystore - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }} name: Generate KeyStore diff --git a/.github/workflows/no_print_in_dart.yaml b/.github/workflows/no_print_in_dart.yaml new file mode 100644 index 000000000..8cd24edfe --- /dev/null +++ b/.github/workflows/no_print_in_dart.yaml @@ -0,0 +1,21 @@ +name: No print statements in dart files + +on: + pull_request: + branches: [main] + +jobs: + PR_test_build: + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + - name: Check for print() statements in dart code (use printV() instead) + if: github.event_name == 'pull_request' + run: | + GIT_GREP_OUT="$(git grep ' print(' | (grep .dart: || test $? = 1) | (grep -v print_verbose.dart || test $? = 1) || true)" + [[ "x$GIT_GREP_OUT" == "x" ]] && exit 0 + echo "$GIT_GREP_OUT" + echo "There are .dart files which use print() statements" + echo "Please use printV from package: cw_core/utils/print_verbose.dart" + exit 1 diff --git a/.github/workflows/pr_test_build_android.yml b/.github/workflows/pr_test_build_android.yml index 774404e3b..d98c0b77b 100644 --- a/.github/workflows/pr_test_build_android.yml +++ b/.github/workflows/pr_test_build_android.yml @@ -53,7 +53,7 @@ jobs: - name: Flutter action uses: subosito/flutter-action@v1 with: - flutter-version: "3.19.6" + flutter-version: "3.24.0" channel: stable - name: Install package dependencies @@ -61,14 +61,32 @@ jobs: sudo apt update sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang - - name: Execute Build and Setup Commands + + - name: Clone Repo run: | sudo mkdir -p /opt/android sudo chown $USER /opt/android + cd /opt/android + git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }} + +# - name: Cache Keystore +# id: cache-keystore +# uses: actions/cache@v3 +# with: +# path: /opt/android/cake_wallet/android/app +# key: keystore +# +# - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }} + - name: Generate KeyStore + run: | + cd /opt/android/cake_wallet/android/app + keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS + + - name: Execute Build and Setup Commands + run: | cd /opt/android -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh cargo install cargo-ndk - git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }} cd cake_wallet/scripts/android/ ./install_ndk.sh source ./app_env.sh cakewallet @@ -115,28 +133,15 @@ jobs: cd /opt/android/cake_wallet/scripts/android/ ./build_mwebd.sh --dont-install -# - name: Cache Keystore -# id: cache-keystore -# uses: actions/cache@v3 -# with: -# path: /opt/android/cake_wallet/android/app/key.jks -# key: $STORE_PASS -# -# - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }} - - name: Generate KeyStore - run: | - cd /opt/android/cake_wallet/android/app - keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS - - name: Generate key properties run: | cd /opt/android/cake_wallet - flutter packages pub run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS + dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS - name: Generate localization run: | cd /opt/android/cake_wallet - flutter packages pub run tool/generate_localization.dart + dart run tool/generate_localization.dart - name: Build generated code run: | @@ -183,6 +188,7 @@ jobs: echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart + echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart @@ -201,7 +207,7 @@ jobs: echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart - echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dar + echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart diff --git a/.github/workflows/pr_test_build_linux.yml b/.github/workflows/pr_test_build_linux.yml index f3ce1045d..f690e0236 100644 --- a/.github/workflows/pr_test_build_linux.yml +++ b/.github/workflows/pr_test_build_linux.yml @@ -38,7 +38,7 @@ jobs: - name: Flutter action uses: subosito/flutter-action@v1 with: - flutter-version: "3.19.6" + flutter-version: "3.24.0" channel: stable - name: Install package dependencies @@ -111,7 +111,7 @@ jobs: - name: Generate localization run: | cd /opt/android/cake_wallet - flutter packages pub run tool/generate_localization.dart + dart run tool/generate_localization.dart - name: Build generated code run: | @@ -165,6 +165,7 @@ jobs: echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart + echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart diff --git a/README.md b/README.md index 078c4437e..ea8f34624 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,17 @@ Cake Wallet includes support for several cryptocurrencies, including: * F-Droid: https://fdroid.cakelabs.com * APK: https://github.com/cake-tech/cake_wallet/releases +### APK Verification + +APK releases on GitHub, Accrescent, and F-Droid use the same key. They can easily be verified using [apksigner](https://developer.android.com/tools/apksigner#options-verify) or [AppVerifier](https://github.com/soupslurpr/AppVerifier). + +See below for Cake Wallet's SHA-256 signing certificate hash: + +``` +com.cakewallet.cake_wallet +C5:40:53:AB:0F:10:D9:54:17:62:A3:DA:76:65:AE:3D:BA:5E:7C:74:3A:B4:F1:08:A5:34:9D:62:AC:10:6E:F5 +``` + # Support We have 24/7 free support. Please contact support@cakewallet.com diff --git a/android/app/build.gradle b/android/app/build.gradle index 5005a8bab..b65c54108 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -38,11 +38,14 @@ if (appPropertiesFile.exists()) { android { compileSdkVersion 34 + buildToolsVersion "34.0.0" lintOptions { disable 'InvalidPackage' } + namespace "com.cakewallet.cake_wallet" + defaultConfig { applicationId appProperties['id'] minSdkVersion 24 @@ -80,7 +83,7 @@ android { } } - ndkVersion "25.1.8937393" + ndkVersion "27.0.12077973" } flutter { @@ -96,4 +99,4 @@ configurations { implementation.exclude module:'proto-google-common-protos' implementation.exclude module:'protolite-well-known-types' implementation.exclude module:'protobuf-javalite' -} \ No newline at end of file +} diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml index dc767a55d..f880684a6 100644 --- a/android/app/src/debug/AndroidManifest.xml +++ b/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/android/app/src/main/AndroidManifestBase.xml b/android/app/src/main/AndroidManifestBase.xml index 508560e1b..a5282d6bd 100644 --- a/android/app/src/main/AndroidManifestBase.xml +++ b/android/app/src/main/AndroidManifestBase.xml @@ -1,5 +1,4 @@ - + diff --git a/android/app/src/profile/AndroidManifest.xml b/android/app/src/profile/AndroidManifest.xml index dc767a55d..f880684a6 100644 --- a/android/app/src/profile/AndroidManifest.xml +++ b/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/android/build.gradle b/android/build.gradle index 7ddb75179..66de0bdca 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.8.21' + ext.kotlin_version = '2.0.21' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:8.7.1' classpath 'com.google.gms:google-services:4.3.8' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } diff --git a/android/gradle.properties b/android/gradle.properties index 66dd09454..d130e538a 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,4 +1,4 @@ -org.gradle.jvmargs=-Xmx3072M +org.gradle.jvmargs=-Xmx4096M android.enableR8=true android.useAndroidX=true android.enableJetifier=true diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index 733c691d3..0cc4e42b9 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip diff --git a/assets/bitcoin_electrum_server_list.yml b/assets/bitcoin_electrum_server_list.yml index 20a28cd24..83da6a0b2 100644 --- a/assets/bitcoin_electrum_server_list.yml +++ b/assets/bitcoin_electrum_server_list.yml @@ -1,6 +1,3 @@ -- - uri: electrum.cakewallet.com:50002 - useSSL: true - uri: btc-electrum.cakewallet.com:50002 useSSL: true diff --git a/assets/ethereum_server_list.yml b/assets/ethereum_server_list.yml index 125085d88..965638471 100644 --- a/assets/ethereum_server_list.yml +++ b/assets/ethereum_server_list.yml @@ -6,5 +6,7 @@ uri: rpc.flashbots.net - uri: eth-mainnet.public.blastapi.io +- + uri: eth.nownodes.io - uri: ethereum.publicnode.com \ No newline at end of file diff --git a/assets/images/discord.png b/assets/images/discord.png new file mode 100644 index 000000000..23fe37a36 Binary files /dev/null and b/assets/images/discord.png differ diff --git a/assets/images/discourse.png b/assets/images/discourse.png new file mode 100644 index 000000000..b8bab2c5d Binary files /dev/null and b/assets/images/discourse.png differ diff --git a/assets/images/seed_verified.png b/assets/images/seed_verified.png new file mode 100644 index 000000000..e03706193 Binary files /dev/null and b/assets/images/seed_verified.png differ diff --git a/assets/node_list.yml b/assets/node_list.yml index 6191129b3..49cc00a94 100644 --- a/assets/node_list.yml +++ b/assets/node_list.yml @@ -2,6 +2,7 @@ uri: xmr-node.cakewallet.com:18081 is_default: true trusted: true + useSSL: true - uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081 is_default: false diff --git a/assets/polygon_node_list.yml b/assets/polygon_node_list.yml index 34504269d..63878bc0c 100644 --- a/assets/polygon_node_list.yml +++ b/assets/polygon_node_list.yml @@ -3,4 +3,6 @@ - uri: polygon-bor.publicnode.com - - uri: polygon.llamarpc.com \ No newline at end of file + uri: polygon.llamarpc.com +- + uri: matic.nownodes.io \ No newline at end of file diff --git a/assets/solana_node_list.yml b/assets/solana_node_list.yml index e5641d3f8..c96b370a8 100644 --- a/assets/solana_node_list.yml +++ b/assets/solana_node_list.yml @@ -1,10 +1,10 @@ - uri: rpc.ankr.com - is_default: true useSSL: true - uri: api.mainnet-beta.solana.com:443 useSSL: true - uri: solana-rpc.publicnode.com:443 - useSSL: true \ No newline at end of file + useSSL: true + is_default: true \ No newline at end of file diff --git a/assets/text/Monerocom_Release_Notes.txt b/assets/text/Monerocom_Release_Notes.txt index 46f21e172..3a6706a26 100644 --- a/assets/text/Monerocom_Release_Notes.txt +++ b/assets/text/Monerocom_Release_Notes.txt @@ -1,3 +1,3 @@ -Add airgapped Monero wallet support (best used with our new offline app Cupcake) -New Buy & Sell flow -Bug fixes \ No newline at end of file +Support Monero Ledger +Bug fixes +New designs and better user experience \ No newline at end of file diff --git a/assets/text/Release_Notes.txt b/assets/text/Release_Notes.txt index 6764826a7..f7d5e4d2c 100644 --- a/assets/text/Release_Notes.txt +++ b/assets/text/Release_Notes.txt @@ -1,5 +1,5 @@ -Add Litecoin Ledger support -Add airgapped Monero wallet support (best used with our new offline app Cupcake) -MWEB fixes and enhancements -New Buy & Sell flow -Bug fixes \ No newline at end of file +Support Monero Ledger +Prepare for Haven removal +Improve Ethereum and Polygon sending process +Bug fixes +New designs and better user experience \ No newline at end of file diff --git a/assets/tron_node_list.yml b/assets/tron_node_list.yml index f9fd91179..1e34de712 100644 --- a/assets/tron_node_list.yml +++ b/assets/tron_node_list.yml @@ -4,9 +4,8 @@ useSSL: true - uri: api.trongrid.io - is_default: false + is_default: true useSSL: true - uri: trx.nownodes.io - is_default: true useSSL: true \ No newline at end of file diff --git a/build-guide-linux.md b/build-guide-linux.md index 55264fbfa..99c2ed0c8 100644 --- a/build-guide-linux.md +++ b/build-guide-linux.md @@ -120,7 +120,7 @@ Install Flutter package dependencies with this command: Your CakeWallet binary will be built with some specific keys for iterate with 3rd party services. You may generate these secret keys placeholders with the following command: -`$ flutter packages pub run tool/generate_new_secrets.dart` +`$ dart run tool/generate_new_secrets.dart` We will generate mobx models for the project. @@ -128,7 +128,7 @@ We will generate mobx models for the project. Then we need to generate localization files. -`$ flutter packages pub run tool/generate_localization.dart` +`$ dart run tool/generate_localization.dart` ### 5. Build! diff --git a/configure_cake_wallet.sh b/configure_cake_wallet.sh index 90ce1c446..a083ec7ff 100755 --- a/configure_cake_wallet.sh +++ b/configure_cake_wallet.sh @@ -1,5 +1,5 @@ #!/bin/bash - +set -x -e IOS="ios" ANDROID="android" MACOS="macos" @@ -36,6 +36,6 @@ fi source ./app_env.sh cakewallet ./app_config.sh cd ../.. && flutter pub get -flutter packages pub run tool/generate_localization.dart -./model_generator.sh +dart run tool/generate_localization.dart +#./model_generator.sh #cd macos && pod install diff --git a/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart b/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart index a02c51c69..c8715b239 100644 --- a/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_hardware_wallet_service.dart @@ -6,6 +6,7 @@ import 'package:cw_bitcoin/utils.dart'; import 'package:cw_core/hardware/hardware_account_data.dart'; import 'package:ledger_bitcoin/ledger_bitcoin.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; +import 'package:cw_core/utils/print_verbose.dart'; class BitcoinHardwareWalletService { BitcoinHardwareWalletService(this.ledgerConnection); diff --git a/cw_bitcoin/lib/bitcoin_wallet_service.dart b/cw_bitcoin/lib/bitcoin_wallet_service.dart index 06f2082e4..7ee1534bf 100644 --- a/cw_bitcoin/lib/bitcoin_wallet_service.dart +++ b/cw_bitcoin/lib/bitcoin_wallet_service.dart @@ -106,6 +106,15 @@ class BitcoinWalletService extends WalletService< final walletInfo = walletInfoSource.values .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!; await walletInfoSource.delete(walletInfo.key); + + final unspentCoinsToDelete = unspentCoinsInfoSource.values.where( + (unspentCoin) => unspentCoin.walletId == walletInfo.id).toList(); + + final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList(); + + if (keysToDelete.isNotEmpty) { + await unspentCoinsInfoSource.deleteAll(keysToDelete); + } } @override diff --git a/cw_bitcoin/lib/electrum.dart b/cw_bitcoin/lib/electrum.dart index df8e14119..4fc4c1ad8 100644 --- a/cw_bitcoin/lib/electrum.dart +++ b/cw_bitcoin/lib/electrum.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/foundation.dart'; import 'package:rxdart/rxdart.dart'; @@ -117,17 +118,17 @@ class ElectrumClient { _parseResponse(message); } } catch (e) { - print("socket.listen: $e"); + printV("socket.listen: $e"); } }, onError: (Object error) { final errorMsg = error.toString(); - print(errorMsg); + printV(errorMsg); unterminatedString = ''; socket = null; }, onDone: () { - print("SOCKET CLOSED!!!!!"); + printV("SOCKET CLOSED!!!!!"); unterminatedString = ''; try { if (host == socket?.address.host || socket == null) { @@ -136,7 +137,7 @@ class ElectrumClient { socket = null; } } catch (e) { - print("onDone: $e"); + printV("onDone: $e"); } }, cancelOnError: true, @@ -181,7 +182,7 @@ class ElectrumClient { unterminatedString = ''; } } catch (e) { - print("parse $e"); + printV("parse $e"); } } @@ -234,21 +235,21 @@ class ElectrumClient { return []; }); - Future>> getListUnspent(String scriptHash) => - call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]) - .then((dynamic result) { - if (result is List) { - return result.map((dynamic val) { - if (val is Map) { - return val; - } + Future>> getListUnspent(String scriptHash) async { + final result = await call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]); - return {}; - }).toList(); + if (result is List) { + return result.map((dynamic val) { + if (val is Map) { + return val; } - return []; - }); + return {}; + }).toList(); + } + + return []; + } Future>> getMempool(String scriptHash) => call(method: 'blockchain.scripthash.get_mempool', params: [scriptHash]) @@ -403,7 +404,7 @@ class ElectrumClient { } on RequestFailedTimeoutException catch (_) { return null; } catch (e) { - print("getCurrentBlockChainTip: ${e.toString()}"); + printV("getCurrentBlockChainTip: ${e.toString()}"); return null; } } @@ -434,7 +435,7 @@ class ElectrumClient { return subscription; } catch (e) { - print("subscribe $e"); + printV("subscribe $e"); return null; } } @@ -473,7 +474,7 @@ class ElectrumClient { return completer.future; } catch (e) { - print("callWithTimeout $e"); + printV("callWithTimeout $e"); rethrow; } } diff --git a/cw_bitcoin/lib/electrum_transaction_history.dart b/cw_bitcoin/lib/electrum_transaction_history.dart index b688f097b..d096d0e7b 100644 --- a/cw_bitcoin/lib/electrum_transaction_history.dart +++ b/cw_bitcoin/lib/electrum_transaction_history.dart @@ -5,6 +5,7 @@ import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/utils/file.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/transaction_history.dart'; @@ -30,7 +31,10 @@ abstract class ElectrumTransactionHistoryBase String _password; int _height; - Future init() async => await _load(); + Future init() async { + clear(); + await _load(); + } @override void addOne(ElectrumTransactionInfo transaction) => transactions[transaction.id] = transaction; @@ -51,7 +55,7 @@ abstract class ElectrumTransactionHistoryBase final data = json.encode({'height': _height, 'transactions': txjson}); await encryptionFileUtils.write(path: path, password: _password, data: data); } catch (e) { - print('Error while save bitcoin transaction history: ${e.toString()}'); + printV('Error while save bitcoin transaction history: ${e.toString()}'); } } @@ -88,7 +92,7 @@ abstract class ElectrumTransactionHistoryBase _height = content['height'] as int; } catch (e) { - print(e); + printV(e); } } diff --git a/cw_bitcoin/lib/electrum_wallet.dart b/cw_bitcoin/lib/electrum_wallet.dart index b27270626..13df353b4 100644 --- a/cw_bitcoin/lib/electrum_wallet.dart +++ b/cw_bitcoin/lib/electrum_wallet.dart @@ -4,6 +4,8 @@ import 'dart:io'; import 'dart:isolate'; import 'package:bitcoin_base/bitcoin_base.dart'; +import 'package:cw_bitcoin/litecoin_wallet_addresses.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_bitcoin/bitcoin_wallet.dart'; import 'package:cw_bitcoin/litecoin_wallet.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -304,6 +306,7 @@ abstract class ElectrumWalletBase Future init() async { await walletAddresses.init(); await transactionHistory.init(); + await cleanUpDuplicateUnspentCoins(); await save(); _autoSaveTimer = @@ -479,8 +482,8 @@ abstract class ElectrumWalletBase syncStatus = SyncedSyncStatus(); } } catch (e, stacktrace) { - print(stacktrace); - print("startSync $e"); + printV(stacktrace); + printV("startSync $e"); syncStatus = FailedSyncStatus(); } } @@ -500,10 +503,11 @@ abstract class ElectrumWalletBase @action Future updateFeeRates() async { - if (await checkIfMempoolAPIIsEnabled()) { + if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) { try { - final response = - await http.get(Uri.parse("http://mempool.cakewallet.com:8999/api/v1/fees/recommended")); + final response = await http + .get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended")) + .timeout(Duration(seconds: 5)); final result = json.decode(response.body) as Map; final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0; @@ -518,7 +522,7 @@ abstract class ElectrumWalletBase _feeRates = [slowFee, mediumFee, fastFee]; return; } catch (e) { - print(e); + printV(e); } } @@ -609,8 +613,8 @@ abstract class ElectrumWalletBase } } } catch (e, stacktrace) { - print(stacktrace); - print("connectToNode $e"); + printV(stacktrace); + printV("connectToNode $e"); syncStatus = FailedSyncStatus(); } } @@ -1118,6 +1122,7 @@ abstract class ElectrumWalletBase )..addListener((transaction) async { transactionHistory.addOne(transaction); await updateBalance(); + await updateAllUnspents(); }); } @@ -1210,6 +1215,7 @@ abstract class ElectrumWalletBase .removeWhere((utxo) => estimatedTx.utxos.any((e) => e.utxo.txHash == utxo.hash)); await updateBalance(); + await updateAllUnspents(); }); } catch (e) { throw e; @@ -1365,7 +1371,7 @@ abstract class ElectrumWalletBase } @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { try { await _receiveStream?.cancel(); await electrumClient.close(); @@ -1402,9 +1408,11 @@ abstract class ElectrumWalletBase unspentCoins = updatedUnspentCoins; - if (unspentCoinsInfo.length != updatedUnspentCoins.length) { + final currentWalletUnspentCoins = + unspentCoinsInfo.values.where((element) => element.walletId == id); + + if (currentWalletUnspentCoins.length != updatedUnspentCoins.length) { unspentCoins.forEach((coin) => addCoinInfo(coin)); - return; } await updateCoins(unspentCoins); @@ -1430,6 +1438,7 @@ abstract class ElectrumWalletBase coin.isFrozen = coinInfo.isFrozen; coin.isSending = coinInfo.isSending; coin.note = coinInfo.note; + if (coin.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord) coin.bitcoinAddressRecord.balance += coinInfo.value; } else { @@ -1467,47 +1476,70 @@ abstract class ElectrumWalletBase @action Future addCoinInfo(BitcoinUnspent coin) async { - final newInfo = UnspentCoinsInfo( - walletId: id, - hash: coin.hash, - isFrozen: coin.isFrozen, - isSending: coin.isSending, - noteRaw: coin.note, - address: coin.bitcoinAddressRecord.address, - value: coin.value, - vout: coin.vout, - isChange: coin.isChange, - isSilentPayment: coin is BitcoinSilentPaymentsUnspent, - ); + // Check if the coin is already in the unspentCoinsInfo for the wallet + final existingCoinInfo = unspentCoinsInfo.values + .firstWhereOrNull((element) => element.walletId == walletInfo.id && element == coin); - await unspentCoinsInfo.add(newInfo); + if (existingCoinInfo == null) { + final newInfo = UnspentCoinsInfo( + walletId: id, + hash: coin.hash, + isFrozen: coin.isFrozen, + isSending: coin.isSending, + noteRaw: coin.note, + address: coin.bitcoinAddressRecord.address, + value: coin.value, + vout: coin.vout, + isChange: coin.isChange, + isSilentPayment: coin is BitcoinSilentPaymentsUnspent, + ); + + await unspentCoinsInfo.add(newInfo); + } } Future _refreshUnspentCoinsInfo() async { try { - final List keys = []; + final List keys = []; final currentWalletUnspentCoins = - unspentCoinsInfo.values.where((element) => element.walletId.contains(id)); + unspentCoinsInfo.values.where((record) => record.walletId == id); - if (currentWalletUnspentCoins.isNotEmpty) { - currentWalletUnspentCoins.forEach((element) { - final existUnspentCoins = unspentCoins - .where((coin) => element.hash.contains(coin.hash) && element.vout == coin.vout); + for (final element in currentWalletUnspentCoins) { + if (RegexUtils.addressTypeFromStr(element.address, network) is MwebAddress) continue; - if (existUnspentCoins.isEmpty) { - keys.add(element.key); - } - }); + final existUnspentCoins = unspentCoins.where((coin) => element == coin); + + if (existUnspentCoins.isEmpty) { + keys.add(element.key); + } } if (keys.isNotEmpty) { await unspentCoinsInfo.deleteAll(keys); } } catch (e) { - print("refreshUnspentCoinsInfo $e"); + printV("refreshUnspentCoinsInfo $e"); } } + Future cleanUpDuplicateUnspentCoins() async { + final currentWalletUnspentCoins = + unspentCoinsInfo.values.where((element) => element.walletId == id); + final Map uniqueUnspentCoins = {}; + final List duplicateKeys = []; + + for (final unspentCoin in currentWalletUnspentCoins) { + final key = '${unspentCoin.hash}:${unspentCoin.vout}'; + if (!uniqueUnspentCoins.containsKey(key)) { + uniqueUnspentCoins[key] = unspentCoin; + } else { + duplicateKeys.add(unspentCoin.key); + } + } + + if (duplicateKeys.isNotEmpty) await unspentCoinsInfo.deleteAll(duplicateKeys); + } + int transactionVSize(String transactionHex) => BtcTransaction.fromRaw(transactionHex).getVSize(); Future canReplaceByFee(ElectrumTransactionInfo tx) async { @@ -1525,14 +1557,22 @@ abstract class ElectrumWalletBase final bundle = await getTransactionExpanded(hash: txId); final outputs = bundle.originalTransaction.outputs; - final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden); + final ownAddresses = walletAddresses.allAddresses.map((addr) => addr.address).toSet(); - // look for a change address in the outputs - final changeOutput = outputs.firstWhereOrNull((output) => changeAddresses.any( - (element) => element.address == addressFromOutputScript(output.scriptPubKey, network))); + final receiverAmount = outputs + .where((output) => + !ownAddresses.contains(addressFromOutputScript(output.scriptPubKey, network))) + .fold(0, (sum, output) => sum + output.amount.toInt()); - var allInputsAmount = 0; + if (receiverAmount == 0) { + throw Exception("Receiver output not found."); + } + final availableInputs = unspentCoins.where((utxo) => utxo.isSending && !utxo.isFrozen).toList(); + int totalBalance = availableInputs.fold( + 0, (previousValue, element) => previousValue + element.value.toInt()); + + int allInputsAmount = 0; for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) { final input = bundle.originalTransaction.inputs[i]; final inputTransaction = bundle.ins[i]; @@ -1543,12 +1583,10 @@ abstract class ElectrumWalletBase int totalOutAmount = bundle.originalTransaction.outputs .fold(0, (previousValue, element) => previousValue + element.amount.toInt()); - var currentFee = allInputsAmount - totalOutAmount; int remainingFee = (newFee - currentFee > 0) ? newFee - currentFee : newFee; - - return changeOutput != null && changeOutput.amount.toInt() - remainingFee >= 0; + return totalBalance - receiverAmount - remainingFee >= _dustAmount; } Future replaceByFee(String hash, int newFee) async { @@ -1556,12 +1594,13 @@ abstract class ElectrumWalletBase final bundle = await getTransactionExpanded(hash: hash); final utxos = []; + final outputs = []; List privateKeys = []; var allInputsAmount = 0; String? memo; - // Add inputs + // Add original inputs for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) { final input = bundle.originalTransaction.inputs[i]; final inputTransaction = bundle.ins[i]; @@ -1572,7 +1611,6 @@ abstract class ElectrumWalletBase final addressRecord = walletAddresses.allAddresses.firstWhere((element) => element.address == address); - final btcAddress = RegexUtils.addressTypeFromStr(addressRecord.address, network); final privkey = generateECPrivate( hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd, @@ -1595,10 +1633,8 @@ abstract class ElectrumWalletBase ); } - // Create a list of available outputs - final outputs = []; + // Add original outputs for (final out in bundle.originalTransaction.outputs) { - // Check if the script contains OP_RETURN final script = out.scriptPubKey.script; if (script.contains('OP_RETURN') && memo == null) { final index = script.indexOf('OP_RETURN'); @@ -1628,17 +1664,95 @@ abstract class ElectrumWalletBase throw Exception("New fee must be higher than the current fee."); } - // Deduct Remaining Fee from Main Outputs + // Deduct fee from change outputs first, if possible if (remainingFee > 0) { + final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden); for (int i = outputs.length - 1; i >= 0; i--) { - int outputAmount = outputs[i].value.toInt(); + final output = outputs[i]; + final isChange = changeAddresses + .any((element) => element.address == output.address.toAddress(network)); + + if (isChange) { + int outputAmount = output.value.toInt(); + if (outputAmount > _dustAmount) { + int deduction = (outputAmount - _dustAmount >= remainingFee) + ? remainingFee + : outputAmount - _dustAmount; + outputs[i] = BitcoinOutput( + address: output.address, value: BigInt.from(outputAmount - deduction)); + remainingFee -= deduction; + + if (remainingFee <= 0) break; + } + } + } + } + + // If still not enough, add UTXOs until the fee is covered + if (remainingFee > 0) { + final unusedUtxos = unspentCoins + .where((utxo) => utxo.isSending && !utxo.isFrozen && utxo.confirmations! > 0) + .toList(); + + for (final utxo in unusedUtxos) { + final address = RegexUtils.addressTypeFromStr(utxo.address, network); + final privkey = generateECPrivate( + hd: utxo.bitcoinAddressRecord.isHidden + ? walletAddresses.sideHd + : walletAddresses.mainHd, + index: utxo.bitcoinAddressRecord.index, + network: network, + ); + privateKeys.add(privkey); + + utxos.add(UtxoWithAddress( + utxo: BitcoinUtxo( + txHash: utxo.hash, + value: BigInt.from(utxo.value), + vout: utxo.vout, + scriptType: _getScriptType(address)), + ownerDetails: + UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: address), + )); + + allInputsAmount += utxo.value; + remainingFee -= utxo.value; + + if (remainingFee < 0) { + final changeOutput = outputs.firstWhereOrNull((output) => walletAddresses.allAddresses + .any((addr) => addr.address == output.address.toAddress(network))); + if (changeOutput != null) { + final newValue = changeOutput.value.toInt() + (-remainingFee); + outputs[outputs.indexOf(changeOutput)] = + BitcoinOutput(address: changeOutput.address, value: BigInt.from(newValue)); + } else { + final changeAddress = await walletAddresses.getChangeAddress(); + outputs.add(BitcoinOutput( + address: RegexUtils.addressTypeFromStr(changeAddress.address, network), + value: BigInt.from(-remainingFee))); + } + + remainingFee = 0; + break; + } + + if (remainingFee <= 0) break; + } + } + + // Deduct from the receiver's output if remaining fee is still greater than 0 + if (remainingFee > 0) { + for (int i = 0; i < outputs.length; i++) { + final output = outputs[i]; + int outputAmount = output.value.toInt(); if (outputAmount > _dustAmount) { int deduction = (outputAmount - _dustAmount >= remainingFee) ? remainingFee : outputAmount - _dustAmount; + outputs[i] = BitcoinOutput( - address: outputs[i].address, value: BigInt.from(outputAmount - deduction)); + address: output.address, value: BigInt.from(outputAmount - deduction)); remainingFee -= deduction; if (remainingFee <= 0) break; @@ -1677,7 +1791,6 @@ abstract class ElectrumWalletBase final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) { final key = privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey); - if (key == null) { throw Exception("Cannot find private key"); } @@ -1708,6 +1821,7 @@ abstract class ElectrumWalletBase }); transactionHistory.addOne(transaction); await updateBalance(); + await updateAllUnspents(); }); } catch (e) { throw e; @@ -1729,7 +1843,7 @@ abstract class ElectrumWalletBase try { final blockHash = await http.get( Uri.parse( - "http://mempool.cakewallet.com:8999/api/v1/block-height/$height", + "https://mempool.cakewallet.com/api/v1/block-height/$height", ), ); @@ -1738,7 +1852,7 @@ abstract class ElectrumWalletBase jsonDecode(blockHash.body) != null) { final blockResponse = await http.get( Uri.parse( - "http://mempool.cakewallet.com:8999/api/v1/block/${blockHash.body}", + "https://mempool.cakewallet.com/api/v1/block/${blockHash.body}", ), ); if (blockResponse.statusCode == 200 && @@ -1849,7 +1963,7 @@ abstract class ElectrumWalletBase return historiesWithDetails; } catch (e) { - print("fetchTransactions $e"); + printV("fetchTransactions $e"); return {}; } } @@ -1973,7 +2087,7 @@ abstract class ElectrumWalletBase } Future updateTransactions() async { - print("updateTransactions() called!"); + printV("updateTransactions() called!"); try { if (_isTransactionUpdating) { return; @@ -2005,8 +2119,8 @@ abstract class ElectrumWalletBase walletAddresses.updateReceiveAddresses(); _isTransactionUpdating = false; } catch (e, stacktrace) { - print(stacktrace); - print(e); + printV(stacktrace); + printV(e); _isTransactionUpdating = false; } } @@ -2024,13 +2138,13 @@ abstract class ElectrumWalletBase try { await _scripthashesUpdateSubject[sh]?.close(); } catch (e) { - print("failed to close: $e"); + printV("failed to close: $e"); } } try { _scripthashesUpdateSubject[sh] = await electrumClient.scripthashUpdate(sh); } catch (e) { - print("failed scripthashUpdate: $e"); + printV("failed scripthashUpdate: $e"); } _scripthashesUpdateSubject[sh]?.listen((event) async { try { @@ -2040,7 +2154,7 @@ abstract class ElectrumWalletBase await _fetchAddressHistory(address, await getCurrentChainTip()); } catch (e, s) { - print("sub error: $e"); + printV("sub error: $e"); _onError?.call(FlutterErrorDetails( exception: e, stack: s, @@ -2048,7 +2162,7 @@ abstract class ElectrumWalletBase )); } }, onError: (e, s) { - print("sub_listen error: $e $s"); + printV("sub_listen error: $e $s"); }); })); } @@ -2100,7 +2214,7 @@ abstract class ElectrumWalletBase if (balances.isNotEmpty && balances.first['confirmed'] == null) { // if we got null balance responses from the server, set our connection status to lost and return our last known balance: - print("got null balance responses from the server, setting connection status to lost"); + printV("got null balance responses from the server, setting connection status to lost"); syncStatus = LostConnectionSyncStatus(); return balance[currency] ?? ElectrumBalance(confirmed: 0, unconfirmed: 0, frozen: 0); } @@ -2127,7 +2241,7 @@ abstract class ElectrumWalletBase } Future updateBalance() async { - print("updateBalance() called!"); + printV("updateBalance() called!"); balance[currency] = await fetchBalances(); await save(); } @@ -2267,7 +2381,7 @@ abstract class ElectrumWalletBase } void _syncStatusReaction(SyncStatus syncStatus) async { - print("SYNC_STATUS_CHANGE: ${syncStatus}"); + printV("SYNC_STATUS_CHANGE: ${syncStatus}"); if (syncStatus is SyncingSyncStatus) { return; } diff --git a/cw_bitcoin/lib/electrum_wallet_addresses.dart b/cw_bitcoin/lib/electrum_wallet_addresses.dart index c29579436..6774a5036 100644 --- a/cw_bitcoin/lib/electrum_wallet_addresses.dart +++ b/cw_bitcoin/lib/electrum_wallet_addresses.dart @@ -3,6 +3,8 @@ import 'dart:io' show Platform; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart'; +import 'package:cw_bitcoin/electrum_wallet.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; @@ -193,7 +195,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { receiveAddresses.remove(addressRecord); receiveAddresses.insert(0, addressRecord); } catch (e) { - print("ElectrumWalletAddressBase: set address ($addr): $e"); + printV("ElectrumWalletAddressBase: set address ($addr): $e"); } } @@ -483,7 +485,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store { await saveAddressesInBox(); } catch (e) { - print("updateAddresses $e"); + printV("updateAddresses $e"); } } diff --git a/cw_bitcoin/lib/litecoin_wallet.dart b/cw_bitcoin/lib/litecoin_wallet.dart index ac74b02f0..44d1fa47a 100644 --- a/cw_bitcoin/lib/litecoin_wallet.dart +++ b/cw_bitcoin/lib/litecoin_wallet.dart @@ -9,6 +9,7 @@ import 'package:crypto/crypto.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_core/cake_hive.dart'; import 'package:cw_core/mweb_utxo.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/node.dart'; import 'package:cw_mweb/mwebd.pbgrpc.dart'; import 'package:fixnum/fixnum.dart'; @@ -283,7 +284,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } Future waitForMwebAddresses() async { - print("waitForMwebAddresses() called!"); + printV("waitForMwebAddresses() called!"); // ensure that we have the full 1000 mweb addresses generated before continuing: // should no longer be needed, but leaving here just in case await (walletAddresses as LitecoinWalletAddresses).ensureMwebAddressUpToIndexExists(1020); @@ -302,8 +303,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { @action @override Future startSync() async { - print("startSync() called!"); - print("STARTING SYNC - MWEB ENABLED: $mwebEnabled"); + printV("startSync() called!"); + printV("STARTING SYNC - MWEB ENABLED: $mwebEnabled"); if (!mwebEnabled) { try { // in case we're switching from a litecoin wallet that had mweb enabled @@ -317,33 +318,33 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { return; } - print("STARTING SYNC - MWEB ENABLED: $mwebEnabled"); + printV("STARTING SYNC - MWEB ENABLED: $mwebEnabled"); _syncTimer?.cancel(); try { mwebSyncStatus = SyncronizingSyncStatus(); try { await subscribeForUpdates(); } catch (e) { - print("failed to subcribe for updates: $e"); + printV("failed to subcribe for updates: $e"); } updateFeeRates(); _feeRatesTimer?.cancel(); _feeRatesTimer = Timer.periodic(const Duration(minutes: 1), (timer) async => await updateFeeRates()); - print("START SYNC FUNCS"); + printV("START SYNC FUNCS"); await waitForMwebAddresses(); await processMwebUtxos(); await updateTransactions(); await updateUnspent(); await updateBalance(); - print("DONE SYNC FUNCS"); - } catch (e, s) { - print("mweb sync failed: $e $s"); - mwebSyncStatus = FailedSyncStatus(error: "mweb sync failed: $e"); + } catch (e) { + printV("failed to start mweb sync: $e"); + syncStatus = FailedSyncStatus(); return; } + _syncTimer?.cancel(); _syncTimer = Timer.periodic(const Duration(milliseconds: 3000), (timer) async { if (mwebSyncStatus is FailedSyncStatus) { _syncTimer?.cancel(); @@ -401,7 +402,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { for (var coin in tx.unspents!) { final utxo = mwebUtxosBox.get(coin.address); if (utxo != null) { - print("deleting utxo ${coin.address} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + printV("deleting utxo ${coin.address} @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); await mwebUtxosBox.delete(coin.address); } } @@ -428,7 +429,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { return; } } catch (e) { - print("error syncing: $e"); + printV("error syncing: $e"); mwebSyncStatus = FailedSyncStatus(error: e.toString()); } }); @@ -437,12 +438,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { @action @override Future stopSync() async { - print("stopSync() called!"); + printV("stopSync() called!"); _syncTimer?.cancel(); _utxoStream?.cancel(); _feeRatesTimer?.cancel(); await CwMweb.stop(); await super.stopSync(); + printV("stopped syncing!"); } Future initMwebUtxosBox() async { @@ -514,7 +516,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } Future handleIncoming(MwebUtxo utxo) async { - print("handleIncoming() called!"); + printV("handleIncoming() called!"); final status = await CwMweb.status(StatusRequest()); var date = DateTime.now(); var confirmations = 0; @@ -559,7 +561,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { final addressRecord = walletAddresses.allAddresses .firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address); if (addressRecord == null) { - print("we don't have this address in the wallet! ${utxo.address}"); + printV("we don't have this address in the wallet! ${utxo.address}"); return; } @@ -580,13 +582,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } Future processMwebUtxos() async { - print("processMwebUtxos() called!"); + printV("processMwebUtxos() called!"); if (!mwebEnabled) { return; } int restoreHeight = walletInfo.restoreHeight; - print("SCANNING FROM HEIGHT: $restoreHeight"); + printV("SCANNING FROM HEIGHT: $restoreHeight"); final req = UtxosRequest(scanSecret: scanSecret, fromHeight: restoreHeight); // process new utxos as they come in: @@ -621,7 +623,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { // but do update the utxo height if it's somehow different: final existingUtxo = mwebUtxosBox.get(utxo.outputId); if (existingUtxo!.height != utxo.height) { - print( + printV( "updating utxo height for $utxo.outputId: ${existingUtxo.height} -> ${utxo.height}"); existingUtxo.height = utxo.height; await mwebUtxosBox.put(utxo.outputId, existingUtxo); @@ -644,7 +646,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { await handleIncoming(utxo); }, onError: (error) { - print("error in utxo stream: $error"); + printV("error in utxo stream: $error"); mwebSyncStatus = FailedSyncStatus(error: error.toString()); }, cancelOnError: true, @@ -652,7 +654,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } Future deleteSpentUtxos() async { - print("deleteSpentUtxos() called!"); + printV("deleteSpentUtxos() called!"); final chainHeight = await electrumClient.getCurrentBlockChainTip(); final status = await CwMweb.status(StatusRequest()); if (chainHeight == null || status.blockHeaderHeight != chainHeight) return; @@ -676,7 +678,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } Future checkMwebUtxosSpent() async { - print("checkMwebUtxosSpent() called!"); + printV("checkMwebUtxosSpent() called!"); if (!mwebEnabled) { return; } @@ -757,6 +759,13 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { if (!mwebEnabled) return false; if (!tx.isPending) return false; + final isMwebTx = (tx.inputAddresses?.any((addr) => addr.contains("mweb")) ?? false) || + (tx.outputAddresses?.any((addr) => addr.contains("mweb")) ?? false); + + if (!isMwebTx) { + return false; + } + final outputId = [], target = {}; final isHash = RegExp(r'^[a-f0-9]{64}$').hasMatch; final spendingOutputIds = tx.inputAddresses?.where(isHash) ?? []; @@ -791,7 +800,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } Future updateUnspent() async { - print("updateUnspent() called!"); + printV("updateUnspent() called!"); await checkMwebUtxosSpent(); await updateAllUnspents(); } @@ -822,7 +831,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { .firstWhereOrNull((addressRecord) => addressRecord.address == utxo.address); if (addressRecord == null) { - print("utxo contains an address that is not in the wallet: ${utxo.address}"); + printV("utxo contains an address that is not in the wallet: ${utxo.address}"); return; } final unspent = BitcoinUnspent( @@ -863,7 +872,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { mwebUtxosBox.values.forEach((utxo) { bool isConfirmed = utxo.height > 0; - print( + printV( "utxo: ${isConfirmed ? "confirmed" : "unconfirmed"} ${utxo.spent ? "spent" : "unspent"} ${utxo.outputId} ${utxo.height} ${utxo.value}"); if (isConfirmed) { @@ -1001,7 +1010,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { final sum1 = _sumOutputAmounts(outputs.map((e) => e.toOutput).toList()) + fee; final sum2 = utxos.sumOfUtxosValue(); if (sum1 != sum2) { - print("@@@@@ WE HAD TO ADJUST THE FEE! @@@@@@@@"); + printV("@@@@@ WE HAD TO ADJUST THE FEE! @@@@@@@@"); final diff = sum2 - sum1; // add the difference to the fee (abs value): fee += diff.abs(); @@ -1166,7 +1175,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { addressRecord.balance -= utxo.value.toInt(); }); transaction.inputAddresses?.addAll(addresses); - print("isPegIn: $isPegIn, isPegOut: $isPegOut"); + printV("isPegIn: $isPegIn, isPegOut: $isPegOut"); transaction.additionalInfo["isPegIn"] = isPegIn; transaction.additionalInfo["isPegOut"] = isPegOut; transactionHistory.addOne(transaction); @@ -1174,10 +1183,10 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { await updateBalance(); }); } catch (e, s) { - print(e); - print(s); + printV(e); + printV(s); if (e.toString().contains("commit failed")) { - print(e); + printV(e); throw Exception("Transaction commit failed (no peers responded), please try again."); } rethrow; @@ -1190,7 +1199,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store { } @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _utxoStream?.cancel(); _feeRatesTimer?.cancel(); _syncTimer?.cancel(); diff --git a/cw_bitcoin/lib/litecoin_wallet_addresses.dart b/cw_bitcoin/lib/litecoin_wallet_addresses.dart index 062c590ba..afe3c75b8 100644 --- a/cw_bitcoin/lib/litecoin_wallet_addresses.dart +++ b/cw_bitcoin/lib/litecoin_wallet_addresses.dart @@ -9,6 +9,7 @@ import 'package:cw_bitcoin/bitcoin_unspent.dart'; import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_bitcoin/utils.dart'; import 'package:cw_bitcoin/electrum_wallet_addresses.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_mweb/cw_mweb.dart'; import 'package:flutter/foundation.dart'; @@ -35,7 +36,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with for (int i = 0; i < mwebAddresses.length; i++) { mwebAddrs.add(mwebAddresses[i].address); } - print("initialized with ${mwebAddrs.length} mweb addresses"); + printV("initialized with ${mwebAddrs.length} mweb addresses"); } final Bip32Slip10Secp256k1? mwebHd; @@ -73,25 +74,25 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with } while (generating) { - print("generating....."); + printV("generating....."); // this function was called multiple times in multiple places: await Future.delayed(const Duration(milliseconds: 100)); } - print("Generating MWEB addresses up to index $index"); + printV("Generating MWEB addresses up to index $index"); generating = true; try { while (mwebAddrs.length <= (index + 1)) { final addresses = await CwMweb.addresses(scan, spend, mwebAddrs.length, mwebAddrs.length + 50); - print("generated up to index ${mwebAddrs.length}"); + printV("generated up to index ${mwebAddrs.length}"); // sleep for a bit to avoid making the main thread unresponsive: await Future.delayed(Duration(milliseconds: 200)); mwebAddrs.addAll(addresses!); } } catch (_) {} generating = false; - print("Done generating MWEB addresses len: ${mwebAddrs.length}"); + printV("Done generating MWEB addresses len: ${mwebAddrs.length}"); // ensure mweb addresses are up to date: // This is the Case if the Litecoin Wallet is a hardware Wallet @@ -109,7 +110,7 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with )) .toList(); addMwebAddresses(addressRecords); - print("set ${addressRecords.length} mweb addresses"); + printV("set ${addressRecords.length} mweb addresses"); } } diff --git a/cw_bitcoin/lib/litecoin_wallet_service.dart b/cw_bitcoin/lib/litecoin_wallet_service.dart index d519f4d0a..89ae384d4 100644 --- a/cw_bitcoin/lib/litecoin_wallet_service.dart +++ b/cw_bitcoin/lib/litecoin_wallet_service.dart @@ -126,6 +126,15 @@ class LitecoinWalletService extends WalletService< mwebdLogs.deleteSync(); } } + + final unspentCoinsToDelete = unspentCoinsInfoSource.values.where( + (unspentCoin) => unspentCoin.walletId == walletInfo.id).toList(); + + final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList(); + + if (keysToDelete.isNotEmpty) { + await unspentCoinsInfoSource.deleteAll(keysToDelete); + } } @override diff --git a/cw_bitcoin/lib/psbt_transaction_builder.dart b/cw_bitcoin/lib/psbt_transaction_builder.dart index 81efb792e..8cb979730 100644 --- a/cw_bitcoin/lib/psbt_transaction_builder.dart +++ b/cw_bitcoin/lib/psbt_transaction_builder.dart @@ -2,6 +2,7 @@ import 'dart:typed_data'; import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:convert/convert.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:ledger_bitcoin/psbt.dart'; class PSBTTransactionBuild { @@ -16,6 +17,10 @@ class PSBTTransactionBuild { for (var i = 0; i < inputs.length; i++) { final input = inputs[i]; + printV(input.utxo.isP2tr()); + printV(input.utxo.isSegwit()); + printV(input.utxo.isP2shSegwit()); + psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList())); psbt.setInputOutputIndex(i, input.utxo.vout); psbt.setInputSequence(i, enableRBF ? 0x1 : 0xffffffff); diff --git a/cw_bitcoin/pubspec.lock b/cw_bitcoin/pubspec.lock index c8a83f90c..c65f056bb 100644 --- a/cw_bitcoin/pubspec.lock +++ b/cw_bitcoin/pubspec.lock @@ -29,10 +29,10 @@ packages: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" asn1lib: dependency: transitive description: @@ -145,10 +145,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: "direct dev" description: @@ -161,10 +161,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.4.13" build_runner_core: dependency: transitive description: @@ -250,18 +250,18 @@ packages: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cryptography: dependency: "direct main" description: @@ -360,10 +360,10 @@ packages: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -431,10 +431,10 @@ packages: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" grpc: dependency: "direct main" description: @@ -503,10 +503,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -535,26 +535,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" ledger_bitcoin: dependency: "direct main" description: @@ -577,7 +577,7 @@ packages: description: path: "packages/ledger-litecoin" ref: HEAD - resolved-ref: "07cd61ef76a2a017b6d5ef233396740163265457" + resolved-ref: "3dee36713e6ebec9dceb59b9ccae7f243a53ea9e" url: "https://github.com/cake-tech/ledger-flutter-plus-plugins" source: git version: "0.0.2" @@ -593,10 +593,10 @@ packages: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" matcher: dependency: transitive description: @@ -609,26 +609,26 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "2.0.0" mobx: dependency: "direct main" description: @@ -681,10 +681,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.12" path_provider_foundation: dependency: transitive description: @@ -729,10 +729,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -809,18 +809,18 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" + sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.3" shared_preferences_foundation: dependency: transitive description: @@ -849,10 +849,10 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: "59dc807b94d29d52ddbb1b3c0d3b9d0a67fc535a64e62a5542c8db0513fcb6c2" + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: @@ -873,10 +873,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -967,10 +967,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timing: dependency: transitive description: @@ -991,10 +991,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" universal_ble: dependency: transitive description: @@ -1031,10 +1031,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.4" watcher: dependency: "direct overridden" description: @@ -1047,18 +1047,26 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "3.0.1" xdg_directories: dependency: transitive description: @@ -1092,5 +1100,5 @@ packages: source: hosted version: "2.2.1" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/cw_bitcoin/pubspec.yaml b/cw_bitcoin/pubspec.yaml index bff6104ac..522199c82 100644 --- a/cw_bitcoin/pubspec.yaml +++ b/cw_bitcoin/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: http: ^1.1.0 mobx: ^2.0.7+4 flutter_mobx: ^2.0.6+1 - intl: ^0.18.0 + intl: ^0.19.0 shared_preferences: ^2.0.15 cw_core: path: ../cw_core diff --git a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart index d14dc582d..931893ef8 100644 --- a/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart +++ b/cw_bitcoin_cash/lib/src/bitcoin_cash_wallet_service.dart @@ -85,6 +85,15 @@ class BitcoinCashWalletService extends WalletService< final walletInfo = walletInfoSource.values .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!; await walletInfoSource.delete(walletInfo.key); + + final unspentCoinsToDelete = unspentCoinsInfoSource.values.where( + (unspentCoin) => unspentCoin.walletId == walletInfo.id).toList(); + + final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList(); + + if (keysToDelete.isNotEmpty) { + await unspentCoinsInfoSource.deleteAll(keysToDelete); + } } @override diff --git a/cw_core/lib/battery_optimization_native.dart b/cw_core/lib/battery_optimization_native.dart index edd04d3f4..8e476ea6a 100644 --- a/cw_core/lib/battery_optimization_native.dart +++ b/cw_core/lib/battery_optimization_native.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/services.dart'; const MethodChannel _channel = MethodChannel('com.cake_wallet/native_utils'); @@ -6,17 +7,17 @@ Future requestDisableBatteryOptimization() async { try { await _channel.invokeMethod('disableBatteryOptimization'); } on PlatformException catch (e) { - print("Failed to disable battery optimization: '${e.message}'."); + printV("Failed to disable battery optimization: '${e.message}'."); } } Future isBatteryOptimizationDisabled() async { try { final bool isDisabled = await _channel.invokeMethod('isBatteryOptimizationDisabled') as bool; - print('It\'s actually disabled? $isDisabled'); + printV('It\'s actually disabled? $isDisabled'); return isDisabled; } on PlatformException catch (e) { - print("Failed to check battery optimization status: '${e.message}'."); + printV("Failed to check battery optimization status: '${e.message}'."); return false; } } diff --git a/cw_core/lib/get_height_by_date.dart b/cw_core/lib/get_height_by_date.dart index 2b0b77a89..aee12b423 100644 --- a/cw_core/lib/get_height_by_date.dart +++ b/cw_core/lib/get_height_by_date.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:intl/intl.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; @@ -152,7 +153,7 @@ int getMoneroHeigthByDate({required DateTime date}) { height = startHeight + daysHeight - heightPerDay; } } catch (e) { - print(e.toString()); + printV(e.toString()); } return height; @@ -270,7 +271,7 @@ const bitcoinDates = { Future getBitcoinHeightByDateAPI({required DateTime date}) async { final response = await http.get( Uri.parse( - "http://mempool.cakewallet.com:8999/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}", + "https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}", ), ); diff --git a/cw_core/lib/hardware/device_connection_type.dart b/cw_core/lib/hardware/device_connection_type.dart index 466d58e2a..76a501af1 100644 --- a/cw_core/lib/hardware/device_connection_type.dart +++ b/cw_core/lib/hardware/device_connection_type.dart @@ -7,7 +7,7 @@ enum DeviceConnectionType { static List supportedConnectionTypes(WalletType walletType, [bool isIOS = false]) { switch (walletType) { - // case WalletType.monero: + case WalletType.monero: case WalletType.bitcoin: case WalletType.litecoin: case WalletType.ethereum: diff --git a/cw_core/lib/hive_type_ids.dart b/cw_core/lib/hive_type_ids.dart index 6432c484b..0899ac665 100644 --- a/cw_core/lib/hive_type_ids.dart +++ b/cw_core/lib/hive_type_ids.dart @@ -18,4 +18,5 @@ const SPL_TOKEN_TYPE_ID = 16; const DERIVATION_INFO_TYPE_ID = 17; const TRON_TOKEN_TYPE_ID = 18; const HARDWARE_WALLET_TYPE_TYPE_ID = 19; -const MWEB_UTXO_TYPE_ID = 20; \ No newline at end of file +const MWEB_UTXO_TYPE_ID = 20; +const HAVEN_SEED_STORE_TYPE_ID = 21; \ No newline at end of file diff --git a/cw_core/lib/monero_balance.dart b/cw_core/lib/monero_balance.dart index 98a7f134a..9a63c407e 100644 --- a/cw_core/lib/monero_balance.dart +++ b/cw_core/lib/monero_balance.dart @@ -3,8 +3,8 @@ import 'package:cw_core/monero_amount_format.dart'; class MoneroBalance extends Balance { MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0}) - : formattedFullBalance = moneroAmountToString(amount: fullBalance), - formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance), + : formattedFullBalance = moneroAmountToString(amount: frozenBalance + fullBalance), + formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance), formattedLockedBalance = moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance), super(unlockedBalance, fullBalance); diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index 1094b6402..18d2ffc44 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -203,9 +203,30 @@ class Node extends HiveObject with Keyable { headers: {'Content-Type': 'application/json'}, body: json.encode(body), ); - client.close(); + if (( + response.body.contains("400 Bad Request") // Some other generic error + || response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare + || response.headers["location"] != null // Generic reverse proxy + || response.body.contains("301 Moved Permanently") // Poorly configured generic reverse proxy + ) && !(useSSL??false) + ) { + + final oldUseSSL = useSSL; + useSSL = true; + try { + final ret = await requestMoneroNode(); + if (ret == true) { + await save(); + return ret; + } + useSSL = oldUseSSL; + } catch (e) { + useSSL = oldUseSSL; + } + } + final resBody = json.decode(response.body) as Map; return !(resBody['result']['offline'] as bool); } catch (_) { diff --git a/cw_core/lib/unspent_coins_info.dart b/cw_core/lib/unspent_coins_info.dart index ed09e17e0..a60feb634 100644 --- a/cw_core/lib/unspent_coins_info.dart +++ b/cw_core/lib/unspent_coins_info.dart @@ -1,10 +1,11 @@ import 'package:cw_core/hive_type_ids.dart'; +import 'package:cw_core/unspent_comparable_mixin.dart'; import 'package:hive/hive.dart'; part 'unspent_coins_info.g.dart'; @HiveType(typeId: UnspentCoinsInfo.typeId) -class UnspentCoinsInfo extends HiveObject { +class UnspentCoinsInfo extends HiveObject with UnspentComparable { UnspentCoinsInfo({ required this.walletId, required this.hash, diff --git a/cw_core/lib/unspent_comparable_mixin.dart b/cw_core/lib/unspent_comparable_mixin.dart new file mode 100644 index 000000000..ee0c05496 --- /dev/null +++ b/cw_core/lib/unspent_comparable_mixin.dart @@ -0,0 +1,27 @@ +mixin UnspentComparable { + String get address; + + String get hash; + + int get value; + + int get vout; + + String? get keyImage; + + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is UnspentComparable && + other.hash == hash && + other.address == address && + other.value == value && + other.vout == vout && + other.keyImage == keyImage; + } + + @override + int get hashCode { + return Object.hash(address, hash, value, vout, keyImage); + } +} diff --git a/cw_core/lib/unspent_transaction_output.dart b/cw_core/lib/unspent_transaction_output.dart index d225493e9..da71f6983 100644 --- a/cw_core/lib/unspent_transaction_output.dart +++ b/cw_core/lib/unspent_transaction_output.dart @@ -1,4 +1,6 @@ -class Unspent { +import 'package:cw_core/unspent_comparable_mixin.dart'; + +class Unspent with UnspentComparable { Unspent(this.address, this.hash, this.value, this.vout, this.keyImage) : isSending = true, isFrozen = false, diff --git a/cw_core/lib/utils/print_verbose.dart b/cw_core/lib/utils/print_verbose.dart new file mode 100644 index 000000000..a5c3337e5 --- /dev/null +++ b/cw_core/lib/utils/print_verbose.dart @@ -0,0 +1,84 @@ +void printV(dynamic content) { + CustomTrace programInfo = CustomTrace(StackTrace.current); + print("${programInfo.fileName}#${programInfo.lineNumber}:${programInfo.columnNumber} ${programInfo.callerFunctionName}: $content"); +} + +// https://stackoverflow.com/a/59386101 + +class CustomTrace { + final StackTrace _trace; + + String? fileName; + String? functionName; + String? callerFunctionName; + int? lineNumber; + int? columnNumber; + + CustomTrace(this._trace) { + try { + _parseTrace(); + } catch (e) { + print("Unable to parse trace (printV): $e"); + } + } + + String _getFunctionNameFromFrame(String frame) { + /* Just giving another nickname to the frame */ + var currentTrace = frame; + /* To get rid off the #number thing, get the index of the first whitespace */ + var indexOfWhiteSpace = currentTrace.indexOf(' '); + + /* Create a substring from the first whitespace index till the end of the string */ + var subStr = currentTrace.substring(indexOfWhiteSpace); + + /* Grab the function name using reg expr */ + var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9_]')); + + /* Create a new substring from the function name index till the end of string */ + subStr = subStr.substring(indexOfFunction); + + indexOfWhiteSpace = subStr.indexOf(RegExp(r'[ .]')); + + /* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */ + subStr = subStr.substring(0, indexOfWhiteSpace); + + return subStr; + } + + void _parseTrace() { + /* The trace comes with multiple lines of strings, (each line is also known as a frame), so split the trace's string by lines to get all the frames */ + var frames = this._trace.toString().split("\n"); + + /* The first frame is the current function */ + this.functionName = _getFunctionNameFromFrame(frames[0]); + + /* The second frame is the caller function */ + this.callerFunctionName = _getFunctionNameFromFrame(frames[1]); + + /* The first frame has all the information we need */ + var traceString = frames[1]; + + /* Search through the string and find the index of the file name by looking for the '.dart' regex */ + var indexOfFileName = traceString.indexOf(RegExp(r'[/A-Za-z_]+.dart'), 1); // 1 to offest and not print the printV function name + + var fileInfo = traceString.substring(indexOfFileName); + + var listOfInfos = fileInfo.split(":"); + + /* Splitting fileInfo by the character ":" separates the file name, the line number and the column counter nicely. + Example: main.dart:5:12 + To get the file name, we split with ":" and get the first index + To get the line number, we would have to get the second index + To get the column number, we would have to get the third index + */ + try { + this.fileName = listOfInfos[0]; + this.lineNumber = int.tryParse(listOfInfos[1]); + var columnStr = listOfInfos[2]; + columnStr = columnStr.replaceFirst(")", ""); + this.columnNumber = int.tryParse(columnStr); + } catch (e) { + + } + } +} diff --git a/cw_core/lib/wallet_addresses.dart b/cw_core/lib/wallet_addresses.dart index 714d229d9..b0da0e7a1 100644 --- a/cw_core/lib/wallet_addresses.dart +++ b/cw_core/lib/wallet_addresses.dart @@ -1,4 +1,5 @@ import 'package:cw_core/address_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_type.dart'; @@ -71,7 +72,7 @@ abstract class WalletAddresses { await walletInfo.save(); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/cw_core/lib/wallet_base.dart b/cw_core/lib/wallet_base.dart index 112a20852..16c794a25 100644 --- a/cw_core/lib/wallet_base.dart +++ b/cw_core/lib/wallet_base.dart @@ -83,7 +83,7 @@ abstract class WalletBase rescan({required int height}); - Future close({required bool shouldCleanup}); + Future close({bool shouldCleanup = false}); Future changePassword(String password); diff --git a/cw_core/lib/window_size.dart b/cw_core/lib/window_size.dart index a0f192f66..dffbfab99 100644 --- a/cw_core/lib/window_size.dart +++ b/cw_core/lib/window_size.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/services.dart'; const MethodChannel _channel = MethodChannel('com.cake_wallet/native_utils'); @@ -14,9 +15,9 @@ Future setDefaultMinimumWindowSize() async { ) as bool; if (!result) { - print("Failed to set minimum window size."); + printV("Failed to set minimum window size."); } } on PlatformException catch (e) { - print("Failed to set minimum window size: '${e.message}'."); + printV("Failed to set minimum window size: '${e.message}'."); } } diff --git a/cw_core/pubspec.lock b/cw_core/pubspec.lock index c2bdda5f1..c12839a19 100644 --- a/cw_core/pubspec.lock +++ b/cw_core/pubspec.lock @@ -5,34 +5,39 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: eb376e9acf6938204f90eb3b1f00b578640d3188b4c8a8ec054f9f479af8d051 + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "64.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "69f54f967773f6c26c7dcb13e93d7ccee8b17a641689da39e878d5cf13b06893" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 url: "https://pub.dev" source: hosted - version: "6.2.0" + version: "6.7.0" args: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.6.0" asn1lib: dependency: transitive description: name: asn1lib - sha256: "21afe4333076c02877d14f4a89df111e658a6d466cbfc802eb705eb91bd5adfd" + sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.5.5" async: dependency: transitive description: @@ -69,10 +74,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: "direct dev" description: @@ -85,18 +90,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "581bacf68f89ec8792f5e5a0b2c4decd1c948e97ce659dc783688c8a88fbec21" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.8" + version: "2.4.13" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: c9e32d21dd6626b5c163d48b037ce906bbe428bc23ab77bcd77bb21e593b6185 + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.2.11" + version: "7.3.2" built_collection: dependency: transitive description: @@ -109,10 +114,10 @@ packages: dependency: transitive description: name: built_value - sha256: c9aabae0718ec394e5bc3c7272e6bb0dc0b32201a08fe185ec1d8401d3e39309 + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.8.1" + version: "8.9.2" cake_backup: dependency: "direct main" description: @@ -166,42 +171,42 @@ packages: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cryptography: dependency: transitive description: name: cryptography - sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35 + sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" cupertino_icons: dependency: transitive description: name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "1.0.8" dart_style: dependency: transitive description: name: dart_style - sha256: "40ae61a5d43feea6d24bd22c0537a6629db858963b99b4bc1c3db80676f32368" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.7" encrypt: dependency: "direct main" description: @@ -222,26 +227,26 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" file: dependency: "direct main" description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -251,10 +256,10 @@ packages: dependency: "direct main" description: name: flutter_mobx - sha256: "4a5d062ff85ed3759f4aac6410ff0ffae32e324b2e71ca722ae1b37b32e865f4" + sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e" url: "https://pub.dev" source: hosted - version: "2.2.0+2" + version: "2.2.1+1" flutter_test: dependency: "direct dev" description: flutter @@ -264,10 +269,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -280,10 +285,10 @@ packages: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" hive: dependency: transitive description: @@ -304,10 +309,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -328,10 +333,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -352,42 +357,50 @@ packages: dependency: transitive description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" logging: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" matcher: dependency: transitive description: @@ -400,42 +413,42 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" mobx: dependency: "direct main" description: name: mobx - sha256: "74ee54012dc7c1b3276eaa960a600a7418ef5f9997565deb8fca1fd88fb36b78" + sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e" url: "https://pub.dev" source: hosted - version: "2.3.0+1" + version: "2.3.3+2" mobx_codegen: dependency: "direct dev" description: name: mobx_codegen - sha256: b26c7f9c20b38f0ea572c1ed3f29d8e027cb265538bbd1aed3ec198642cfca42 + sha256: "8e0d8653a0c720ad933cd8358f6f89f740ce89203657c13f25bea772ef1fff7c" url: "https://pub.dev" source: hosted - version: "2.6.0+1" + version: "2.6.1" nested: dependency: transitive description: @@ -464,26 +477,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: b27217933eeeba8ff24845c34003b003b2b22151de3c908d0e679e8fe1aa078b + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "477184d672607c0a3bf68fbbf601805f92ef79c82b64b4d6eb318cbca4c48668" + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.12" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -504,18 +517,18 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -528,10 +541,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "43ac87de6e10afabc85c445745a7b799e04de84cebaa4fd7bf55a5e1e9604d29" + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" url: "https://pub.dev" source: hosted - version: "3.7.4" + version: "3.9.1" pool: dependency: transitive description: @@ -544,10 +557,10 @@ packages: dependency: transitive description: name: provider - sha256: "9a96a0a19b594dbc5bf0f1f27d2bc67d5f95957359b461cd9feb44ed6ae75096" + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "6.1.2" pub_semver: dependency: transitive description: @@ -560,10 +573,10 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" shelf: dependency: transitive description: @@ -576,10 +589,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -589,10 +602,10 @@ packages: dependency: "direct main" description: name: socks5_proxy - sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a" + sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.6" source_gen: dependency: transitive description: @@ -661,10 +674,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timing: dependency: transitive description: @@ -685,10 +698,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" unorm_dart: dependency: "direct main" description: @@ -709,10 +722,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.4" watcher: dependency: "direct overridden" description: @@ -721,30 +734,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.4.0" - win32: - dependency: transitive - description: - name: win32 - sha256: "350a11abd2d1d97e0cc7a28a81b781c08002aa2864d9e3f192ca0ffa18b06ed3" - url: "https://pub.dev" - source: hosted - version: "5.0.9" + version: "3.0.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" yaml: dependency: transitive description: @@ -754,5 +775,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0-0 <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/cw_core/pubspec.yaml b/cw_core/pubspec.yaml index 6e32c2ba1..19eda51e0 100644 --- a/cw_core/pubspec.yaml +++ b/cw_core/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: path_provider: ^2.0.11 mobx: ^2.0.7+4 flutter_mobx: ^2.0.6+1 - intl: ^0.18.0 + intl: ^0.19.0 encrypt: ^5.0.1 cake_backup: git: diff --git a/cw_evm/lib/evm_chain_client.dart b/cw_evm/lib/evm_chain_client.dart index 1935df2af..7dad39f7a 100644 --- a/cw_evm/lib/evm_chain_client.dart +++ b/cw_evm/lib/evm_chain_client.dart @@ -36,7 +36,18 @@ abstract class EVMChainClient { bool connect(Node node) { try { - _client = Web3Client(node.uri.toString(), httpClient); + Uri? rpcUri; + bool isModifiedNodeUri = false; + + if (node.uriRaw == 'eth.nownodes.io' || node.uriRaw == 'matic.nownodes.io') { + isModifiedNodeUri = true; + String nowNodeApiKey = secrets.nowNodesApiKey; + + rpcUri = Uri.https(node.uriRaw, '/$nowNodeApiKey'); + } + + _client = + Web3Client(isModifiedNodeUri ? rpcUri!.toString() : node.uri.toString(), httpClient); return true; } catch (e) { @@ -83,23 +94,20 @@ abstract class EVMChainClient { } } - Future getEstimatedGas({ - String? contractAddress, + Future getEstimatedGasUnitsForTransaction({ required EthereumAddress toAddress, required EthereumAddress senderAddress, required EtherAmount value, + String? contractAddress, EtherAmount? gasPrice, - // EtherAmount? maxFeePerGas, - // EtherAmount? maxPriorityFeePerGas, + EtherAmount? maxFeePerGas, }) async { try { if (contractAddress == null) { final estimatedGas = await _client!.estimateGas( sender: senderAddress, - gasPrice: gasPrice, to: toAddress, value: value, - // maxPriorityFeePerGas: maxPriorityFeePerGas, // maxFeePerGas: maxFeePerGas, ); @@ -133,7 +141,9 @@ abstract class EVMChainClient { required Credentials privateKey, required String toAddress, required BigInt amount, - required BigInt gas, + required BigInt gasFee, + required int estimatedGasUnits, + required int maxFeePerGas, required EVMChainTransactionPriority priority, required CryptoCurrency currency, required int exponent, @@ -152,6 +162,8 @@ abstract class EVMChainClient { maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip), amount: isNativeToken ? EtherAmount.inWei(amount) : EtherAmount.zero(), data: data != null ? hexToBytes(data) : null, + maxGas: estimatedGasUnits, + maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas), ); Uint8List signedTransaction; @@ -180,7 +192,7 @@ abstract class EVMChainClient { return PendingEVMChainTransaction( signedTransaction: signedTransaction, amount: amount.toString(), - fee: gas, + fee: gasFee, sendTransaction: _sendTransaction, exponent: exponent, ); @@ -191,7 +203,10 @@ abstract class EVMChainClient { required EthereumAddress to, required EtherAmount amount, EtherAmount? maxPriorityFeePerGas, + EtherAmount? gasPrice, + EtherAmount? maxFeePerGas, Uint8List? data, + int? maxGas, }) { return Transaction( from: from, @@ -199,6 +214,9 @@ abstract class EVMChainClient { maxPriorityFeePerGas: maxPriorityFeePerGas, value: amount, data: data, + maxGas: maxGas, + gasPrice: gasPrice, + maxFeePerGas: maxFeePerGas, ); } diff --git a/cw_evm/lib/evm_chain_transaction_history.dart b/cw_evm/lib/evm_chain_transaction_history.dart index c4d91783f..7c46ebecc 100644 --- a/cw_evm/lib/evm_chain_transaction_history.dart +++ b/cw_evm/lib/evm_chain_transaction_history.dart @@ -34,7 +34,10 @@ abstract class EVMChainTransactionHistoryBase //! Common methods across all child classes - Future init() async => await _load(); + Future init() async { + clear(); + await _load(); + } @override Future save() async { diff --git a/cw_evm/lib/evm_chain_wallet.dart b/cw_evm/lib/evm_chain_wallet.dart index cfaf39d98..dca16539c 100644 --- a/cw_evm/lib/evm_chain_wallet.dart +++ b/cw_evm/lib/evm_chain_wallet.dart @@ -14,6 +14,7 @@ import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/sync_status.dart'; import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; @@ -200,7 +201,7 @@ abstract class EVMChainWalletBase } else { // MaxFeePerGas with gasPrice; maxFeePerGas = gasPrice; - debugPrint('MaxFeePerGas with gasPrice: $maxFeePerGas'); + printV('MaxFeePerGas with gasPrice: $maxFeePerGas'); } final totalGasFee = estimatedGasUnits * maxFeePerGas; @@ -220,7 +221,7 @@ abstract class EVMChainWalletBase /// - The exact amount the user wants to send, /// - The addressHex for the receiving wallet, /// - A contract address which would be essential in determining if to calcualate the estimate for ERC20 or native ETH - Future calculateActualEstimatedFeeForCreateTransaction({ + Future calculateActualEstimatedFeeForCreateTransaction({ required amount, required String? contractAddress, required String receivingAddressHex, @@ -239,22 +240,27 @@ abstract class EVMChainWalletBase maxFeePerGas = gasPrice; } - final estimatedGas = await _client.getEstimatedGas( + final estimatedGas = await _client.getEstimatedGasUnitsForTransaction( contractAddress: contractAddress, senderAddress: _evmChainPrivateKey.address, value: EtherAmount.fromBigInt(EtherUnit.wei, amount!), gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice), toAddress: EthereumAddress.fromHex(receivingAddressHex), - // maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas), - // maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip), + maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas), ); final totalGasFee = estimatedGas * maxFeePerGas; - return totalGasFee; + + return GasParamsHandler( + estimatedGasUnits: estimatedGas, + estimatedGasFee: totalGasFee, + maxFeePerGas: maxFeePerGas, + gasPrice: gasPrice, + ); } - return 0; + return GasParamsHandler.zero(); } catch (e) { - return 0; + return GasParamsHandler.zero(); } } @@ -264,7 +270,7 @@ abstract class EVMChainWalletBase } @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _client.stop(); _transactionsUpdateTimer?.cancel(); _updateFeesTimer?.cancel(); @@ -317,7 +323,7 @@ abstract class EVMChainWalletBase gasPrice = await _client.getGasUnitPrice(); - estimatedGasUnits = await _client.getEstimatedGas( + estimatedGasUnits = await _client.getEstimatedGasUnitsForTransaction( senderAddress: _evmChainPrivateKey.address, toAddress: _evmChainPrivateKey.address, gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice), @@ -348,6 +354,8 @@ abstract class EVMChainWalletBase int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18; num amountToEVMChainMultiplier = pow(10, exponent); String? contractAddress; + int estimatedGasUnitsForTransaction = 0; + int maxFeePerGasForTransaction = 0; String toAddress = _credentials.outputs.first.isParsedAddress ? _credentials.outputs.first.extractedAddress! : _credentials.outputs.first.address; @@ -366,14 +374,16 @@ abstract class EVMChainWalletBase outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0))); totalAmount = BigInt.from(totalOriginalAmount * amountToEVMChainMultiplier); - final estimateFees = await calculateActualEstimatedFeeForCreateTransaction( + final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction( amount: totalAmount, receivingAddressHex: toAddress, priority: _credentials.priority!, contractAddress: contractAddress, ); - estimatedFeesForTransaction = BigInt.from(estimateFees); + estimatedFeesForTransaction = BigInt.from(gasFeesModel.estimatedGasFee); + estimatedGasUnitsForTransaction = gasFeesModel.estimatedGasUnits; + maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas; if (erc20Balance.balance < totalAmount) { throw EVMChainTransactionCreationException(transactionCurrency); @@ -391,14 +401,16 @@ abstract class EVMChainWalletBase totalAmount = erc20Balance.balance; } - final estimateFees = await calculateActualEstimatedFeeForCreateTransaction( + final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction( amount: totalAmount, receivingAddressHex: toAddress, priority: _credentials.priority!, contractAddress: contractAddress, ); - estimatedFeesForTransaction = BigInt.from(estimateFees); + estimatedFeesForTransaction = BigInt.from(gasFeesModel.estimatedGasFee); + estimatedGasUnitsForTransaction = gasFeesModel.estimatedGasUnits; + maxFeePerGasForTransaction = gasFeesModel.maxFeePerGas; if (output.sendAll && transactionCurrency is! Erc20Token) { totalAmount = (erc20Balance.balance - estimatedFeesForTransaction); @@ -419,12 +431,14 @@ abstract class EVMChainWalletBase } final pendingEVMChainTransaction = await _client.signTransaction( + estimatedGasUnits: estimatedGasUnitsForTransaction, privateKey: _evmChainPrivateKey, toAddress: toAddress, amount: totalAmount, - gas: estimatedFeesForTransaction, + gasFee: estimatedFeesForTransaction, priority: _credentials.priority!, currency: transactionCurrency, + maxFeePerGas: maxFeePerGasForTransaction, exponent: exponent, contractAddress: transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null, @@ -727,3 +741,25 @@ abstract class EVMChainWalletBase @override final String? passphrase; } + +class GasParamsHandler { + final int estimatedGasUnits; + final int estimatedGasFee; + final int maxFeePerGas; + final int gasPrice; + + GasParamsHandler( + {required this.estimatedGasUnits, + required this.estimatedGasFee, + required this.maxFeePerGas, + required this.gasPrice}); + + static GasParamsHandler zero() { + return GasParamsHandler( + estimatedGasUnits: 0, + estimatedGasFee: 0, + maxFeePerGas: 0, + gasPrice: 0, + ); + } +} diff --git a/cw_evm/lib/evm_ledger_credentials.dart b/cw_evm/lib/evm_ledger_credentials.dart index a0b7788dc..b579b9108 100644 --- a/cw_evm/lib/evm_ledger_credentials.dart +++ b/cw_evm/lib/evm_ledger_credentials.dart @@ -3,6 +3,7 @@ import 'dart:typed_data'; import 'package:cw_core/hardware/device_not_connected_exception.dart' as exception; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:ledger_ethereum/ledger_ethereum.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:web3dart/crypto.dart'; @@ -96,7 +97,7 @@ class EvmLedgerCredentials extends CredentialsWithKnownAddress { await ethereumLedgerApp!.getAndProvideERC20TokenInformation( erc20ContractAddress: erc20ContractAddress, chainId: chainId); } catch (e) { - print(e); + printV(e); rethrow; // if (e.errorCode != -28672) rethrow; } diff --git a/cw_haven/android/build.gradle b/cw_haven/android/build.gradle index d29c31d4e..8eb728a67 100644 --- a/cw_haven/android/build.gradle +++ b/cw_haven/android/build.gradle @@ -2,14 +2,14 @@ group 'com.cakewallet.cw_haven' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '2.0.21' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:8.7.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -25,8 +25,20 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 28 + compileSdkVersion 33 + if (project.android.hasProperty("namespace")) { + namespace 'com.cakewallet.cw_haven' + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = '17' + } sourceSets { main.java.srcDirs += 'src/main/kotlin' } diff --git a/cw_haven/lib/haven_account_list.dart b/cw_haven/lib/haven_account_list.dart index 9399efc27..41e3bbf57 100644 --- a/cw_haven/lib/haven_account_list.dart +++ b/cw_haven/lib/haven_account_list.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/account.dart'; import 'package:cw_core/account_list.dart'; @@ -77,7 +78,7 @@ abstract class HavenAccountListBase extends AccountList with Store { _isRefreshing = false; } catch (e) { _isRefreshing = false; - print(e); + printV(e); rethrow; } } diff --git a/cw_haven/lib/haven_subaddress_list.dart b/cw_haven/lib/haven_subaddress_list.dart index b40b3484c..8a5125a55 100644 --- a/cw_haven/lib/haven_subaddress_list.dart +++ b/cw_haven/lib/haven_subaddress_list.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_haven/api/structs/subaddress_row.dart'; import 'package:flutter/services.dart'; import 'package:mobx/mobx.dart'; @@ -79,7 +80,7 @@ abstract class HavenSubaddressListBase with Store { _isRefreshing = false; } on PlatformException catch (e) { _isRefreshing = false; - print(e); + printV(e); rethrow; } } diff --git a/cw_haven/lib/haven_wallet.dart b/cw_haven/lib/haven_wallet.dart index e2e598bbe..6c372d344 100644 --- a/cw_haven/lib/haven_wallet.dart +++ b/cw_haven/lib/haven_wallet.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_haven/haven_transaction_creation_credentials.dart'; import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_haven/haven_transaction_creation_exception.dart'; @@ -107,7 +108,7 @@ abstract class HavenWalletBase Future? updateBalance() => null; @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _listener?.stop(); _onAccountChangeReaction?.reaction.dispose(); _autoSaveTimer?.cancel(); @@ -130,7 +131,7 @@ abstract class HavenWalletBase syncStatus = ConnectedSyncStatus(); } catch (e) { syncStatus = FailedSyncStatus(); - print(e); + printV(e); } } @@ -147,7 +148,7 @@ abstract class HavenWalletBase _listener?.start(); } catch (e) { syncStatus = FailedSyncStatus(); - print(e); + printV(e); rethrow; } } @@ -324,7 +325,7 @@ abstract class HavenWalletBase await transactionHistory.save(); _isTransactionUpdating = false; } catch (e) { - print(e); + printV(e); _isTransactionUpdating = false; } } @@ -403,7 +404,7 @@ abstract class HavenWalletBase syncStatus = SyncingSyncStatus(blocksLeft, ptc); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -413,7 +414,7 @@ abstract class HavenWalletBase _askForUpdateBalance(); await Future.delayed(Duration(seconds: 1)); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/cw_haven/lib/haven_wallet_addresses.dart b/cw_haven/lib/haven_wallet_addresses.dart index c3d1ef46c..192c09ef7 100644 --- a/cw_haven/lib/haven_wallet_addresses.dart +++ b/cw_haven/lib/haven_wallet_addresses.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_addresses_with_account.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/account.dart'; @@ -60,7 +61,7 @@ abstract class HavenWalletAddressesBase extends WalletAddressesWithAccount=3.2.0-0 <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/cw_haven/pubspec.yaml b/cw_haven/pubspec.yaml index d868c986d..452fed93a 100644 --- a/cw_haven/pubspec.yaml +++ b/cw_haven/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: path_provider: ^2.0.11 mobx: ^2.0.7+4 flutter_mobx: ^2.0.6+1 - intl: ^0.18.0 + intl: ^0.19.0 cw_core: path: ../cw_core diff --git a/cw_monero/lib/api/coins_info.dart b/cw_monero/lib/api/coins_info.dart index c1b634cc6..ef7d3cfd6 100644 --- a/cw_monero/lib/api/coins_info.dart +++ b/cw_monero/lib/api/coins_info.dart @@ -12,6 +12,18 @@ int countOfCoins() => monero.Coins_count(coins!); monero.CoinsInfo getCoin(int index) => monero.Coins_coin(coins!, index); +int? getCoinByKeyImage(String keyImage) { + final count = countOfCoins(); + for (int i = 0; i < count; i++) { + final coin = getCoin(i); + final coinAddress = monero.CoinsInfo_keyImage(coin); + if (keyImage == coinAddress) { + return i; + } + } + return null; +} + void freezeCoin(int index) => monero.Coins_setFrozen(coins!, index: index); void thawCoin(int index) => monero.Coins_thaw(coins!, index: index); diff --git a/cw_monero/lib/api/transaction_history.dart b/cw_monero/lib/api/transaction_history.dart index 7748a16af..854ee01c3 100644 --- a/cw_monero/lib/api/transaction_history.dart +++ b/cw_monero/lib/api/transaction_history.dart @@ -6,6 +6,7 @@ import 'package:cw_monero/api/exceptions/creation_transaction_exception.dart'; import 'package:cw_monero/api/monero_output.dart'; import 'package:cw_monero/api/structs/pending_transaction.dart'; import 'package:cw_monero/api/wallet.dart'; +import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart'; import 'package:ffi/ffi.dart'; import 'package:monero/monero.dart' as monero; import 'package:monero/src/generated_bindings_monero.g.dart' as monero_gen; @@ -17,7 +18,7 @@ String getTxKey(String txId) { final status = monero.Wallet_status(wptr!); if (status != 0) { final error = monero.Wallet_errorString(wptr!); - return txId+"_"+error; + return ""; } return txKey; } @@ -91,12 +92,23 @@ Future createTransactionSync( List preferredInputs = const []}) async { final amt = amount == null ? 0 : monero.Wallet_amountFromString(amount); - - final address_ = address.toNativeUtf8(); - final paymentId_ = paymentId.toNativeUtf8(); - final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8(); final waddr = wptr!.address; + + // force reconnection in case the os killed the connection? + // fixes failed to get block height error. + Isolate.run(() async { + monero.Wallet_synchronized(Pointer.fromAddress(waddr)); + }); + + final address_ = address.toNativeUtf8(); + final paymentId_ = paymentId.toNativeUtf8(); + if (preferredInputs.isEmpty) { + throw MoneroTransactionCreationException("No inputs provided, transaction cannot be constructed"); + } + + final preferredInputs_ = preferredInputs.join(monero.defaultSeparatorStr).toNativeUtf8(); + final addraddr = address_.address; final paymentIdAddr = paymentId_.address; final preferredInputsAddr = preferredInputs_.address; @@ -159,8 +171,8 @@ PendingTransactionDescription createTransactionMultDestSync( final dstAddrs = outputs.map((e) => e.address).toList(); final amounts = outputs.map((e) => monero.Wallet_amountFromString(e.amount)).toList(); - // print("multDest: dstAddrs: $dstAddrs"); - // print("multDest: amounts: $amounts"); + // printV("multDest: dstAddrs: $dstAddrs"); + // printV("multDest: amounts: $amounts"); final txptr = monero.Wallet_createTransactionMultDest( wptr!, @@ -188,19 +200,35 @@ String? commitTransactionFromPointerAddress({required int address, required bool commitTransaction(transactionPointer: monero.PendingTransaction.fromAddress(address), useUR: useUR); String? commitTransaction({required monero.PendingTransaction transactionPointer, required bool useUR}) { + final transactionPointerAddress = transactionPointer.address; final txCommit = useUR - ? monero.PendingTransaction_commitUR(transactionPointer, 120) - : monero.PendingTransaction_commit(transactionPointer, filename: '', overwrite: false); + ? monero.PendingTransaction_commitUR(transactionPointer, 120) + : Isolate.run(() { + monero.PendingTransaction_commit( + Pointer.fromAddress(transactionPointerAddress), + filename: '', + overwrite: false, + ); + }); - final String? error = (() { + String? error = (() { final status = monero.PendingTransaction_status(transactionPointer.cast()); if (status == 0) { return null; } - return monero.Wallet_errorString(wptr!); + return monero.PendingTransaction_errorString(transactionPointer.cast()); })(); + if (error == null) { + error = (() { + final status = monero.Wallet_status(wptr!); + if (status == 0) { + return null; + } + return monero.Wallet_errorString(wptr!); + })(); - if (error != null) { + } + if (error != null && error != "no tx keys found for this txid") { throw CreationTransactionException(message: error); } if (useUR) { @@ -348,16 +376,7 @@ class Transaction { confirmations = monero.TransactionInfo_confirmations(txInfo), fee = monero.TransactionInfo_fee(txInfo), description = monero.TransactionInfo_description(txInfo), - key = getTxKey(txInfo); - - static String getTxKey(monero.TransactionInfo txInfo) { - final txKey = monero.Wallet_getTxKey(wptr!, txid: monero.TransactionInfo_hash(txInfo)); - final status = monero.Wallet_status(wptr!); - if (status != 0) { - return ""; - } - return txKey; - } + key = getTxKey(monero.TransactionInfo_hash(txInfo)); Transaction.dummy({ required this.displayLabel, diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index 928fd7ef1..78153a654 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -2,15 +2,17 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:isolate'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart'; +import 'package:flutter/foundation.dart'; import 'package:monero/monero.dart' as monero; import 'package:mutex/mutex.dart'; int getSyncingHeight() { // final height = monero.MONERO_cw_WalletListener_height(getWlptr()); final h2 = monero.Wallet_blockChainHeight(wptr!); - // print("height: $height / $h2"); + // printV("height: $height / $h2"); return h2; } @@ -69,9 +71,9 @@ String getSeedLegacy(String? language) { Map>> addressCache = {}; String getAddress({int accountIndex = 0, int addressIndex = 0}) { - // print("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}"); + // printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}"); while (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) { - print("adding subaddress"); + printV("adding subaddress"); monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex); } addressCache[wptr!.address] ??= {}; @@ -100,7 +102,7 @@ Future setupNodeSync( bool useSSL = false, bool isLightWallet = false, String? socksProxyAddress}) async { - print(''' + printV(''' { wptr!, daemonAddress: $address, @@ -119,16 +121,24 @@ Future setupNodeSync( daemonUsername: login ?? '', daemonPassword: password ?? ''); }); - // monero.Wallet_init3(wptr!, argv0: '', defaultLogBaseName: 'moneroc', console: true, logPath: ''); final status = monero.Wallet_status(wptr!); if (status != 0) { final error = monero.Wallet_errorString(wptr!); - print("error: $error"); + printV("error: $error"); throw SetupWalletException(message: error); } + if (kDebugMode) { + monero.Wallet_init3( + wptr!, argv0: '', + defaultLogBaseName: 'moneroc', + console: true, + logPath: '', + ); + } + return status == 0; } @@ -150,14 +160,15 @@ final storeMutex = Mutex(); int lastStorePointer = 0; int lastStoreHeight = 0; -void storeSync() async { +void storeSync({bool force = false}) async { final addr = wptr!.address; final synchronized = await Isolate.run(() { return monero.Wallet_synchronized(Pointer.fromAddress(addr)); }); if (lastStorePointer == wptr!.address && lastStoreHeight + 5000 > monero.Wallet_blockChainHeight(wptr!) && - !synchronized) { + !synchronized && + !force) { return; } lastStorePointer = wptr!.address; diff --git a/cw_monero/lib/api/wallet_manager.dart b/cw_monero/lib/api/wallet_manager.dart index 7f9dbd8fa..530d58d62 100644 --- a/cw_monero/lib/api/wallet_manager.dart +++ b/cw_monero/lib/api/wallet_manager.dart @@ -2,6 +2,7 @@ import 'dart:ffi'; import 'dart:io'; import 'dart:isolate'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/exceptions/wallet_creation_exception.dart'; import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart'; @@ -50,9 +51,9 @@ final monero.WalletManager wmPtr = Pointer.fromAddress((() { // than plugging gdb in. Especially on windows/android. monero.printStarts = false; _wmPtr ??= monero.WalletManagerFactory_getWalletManager(); - print("ptr: $_wmPtr"); + printV("ptr: $_wmPtr"); } catch (e) { - print(e); + printV(e); rethrow; } return _wmPtr!.address; @@ -81,6 +82,7 @@ void createWalletSync( wptr = newWptr; monero.Wallet_store(wptr!, path: path); openedWalletsByPath[path] = wptr!; + _lastOpenedWallet = path; // is the line below needed? // setupNodeSync(address: "node.moneroworld.com:18089"); @@ -116,6 +118,7 @@ void restoreWalletFromSeedSync( wptr = newWptr; openedWalletsByPath[path] = wptr!; + _lastOpenedWallet = path; } void restoreWalletFromKeysSync( @@ -183,6 +186,7 @@ void restoreWalletFromKeysSync( wptr = newWptr; openedWalletsByPath[path] = wptr!; + _lastOpenedWallet = path; } void restoreWalletFromSpendKeySync( @@ -220,7 +224,7 @@ void restoreWalletFromSpendKeySync( if (status != 0) { final err = monero.Wallet_errorString(newWptr); - print("err: $err"); + printV("err: $err"); throw WalletRestoreFromKeysException(message: err); } @@ -231,6 +235,7 @@ void restoreWalletFromSpendKeySync( storeSync(); openedWalletsByPath[path] = wptr!; + _lastOpenedWallet = path; } String _lastOpenedWallet = ""; @@ -260,7 +265,7 @@ Future restoreWalletFromHardwareWallet( throw WalletRestoreFromSeedException(message: error); } wptr = newWptr; - + _lastOpenedWallet = path; openedWalletsByPath[path] = wptr!; } @@ -286,8 +291,23 @@ Future loadWallet( /// 0: Software Wallet /// 1: Ledger /// 2: Trezor - final deviceType = monero.WalletManager_queryWalletDevice(wmPtr, - keysFileName: "$path.keys", password: password, kdfRounds: 1); + late final deviceType; + + if (Platform.isAndroid || Platform.isIOS) { + deviceType = monero.WalletManager_queryWalletDevice( + wmPtr, + keysFileName: "$path.keys", + password: password, + kdfRounds: 1, + ); + final status = monero.WalletManager_errorString(wmPtr); + if (status != "") { + printV("loadWallet:"+status); + throw WalletOpeningException(message: status); + } + } else { + deviceType = 0; + } if (deviceType == 1) { final dummyWPtr = wptr ?? @@ -304,15 +324,15 @@ Future loadWallet( final newWptr = Pointer.fromAddress(newWptrAddr); - _lastOpenedWallet = path; final status = monero.Wallet_status(newWptr); if (status != 0) { final err = monero.Wallet_errorString(newWptr); - print(err); + printV("loadWallet:"+err); throw WalletOpeningException(message: err); } wptr = newWptr; + _lastOpenedWallet = path; openedWalletsByPath[path] = wptr!; } } diff --git a/cw_monero/lib/ledger.dart b/cw_monero/lib/ledger.dart index c947d0944..b95c655a0 100644 --- a/cw_monero/lib/ledger.dart +++ b/cw_monero/lib/ledger.dart @@ -2,11 +2,12 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:typed_data'; +import 'package:collection/collection.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:ffi/ffi.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus_dart.dart'; import 'package:monero/monero.dart' as monero; -// import 'package:polyseed/polyseed.dart'; LedgerConnection? gLedger; @@ -28,9 +29,16 @@ void enableLedgerExchange(monero.wallet ptr, LedgerConnection connection) { ptr, emptyPointer.cast(), 0); malloc.free(emptyPointer); - // print("> ${ledgerRequest.toHexString()}"); + _logLedgerCommand(ledgerRequest, false); final response = await exchange(connection, ledgerRequest); - // print("< ${response.toHexString()}"); + _logLedgerCommand(response, true); + + if (ListEquality().equals(response, [0x55, 0x15])) { + await connection.disconnect(); + // // TODO: Show POPUP pls unlock your device + // await Future.delayed(Duration(seconds: 15)); + // response = await exchange(connection, ledgerRequest); + } final Pointer result = malloc(response.length); for (var i = 0; i < response.length; i++) { @@ -82,3 +90,59 @@ class ExchangeOperation extends LedgerRawOperation { @override Future> write(ByteDataWriter writer) async => [inputData]; } + +const _ledgerMoneroCommands = { + 0x00: "INS_NONE", + 0x02: "INS_RESET", + 0x20: "INS_GET_KEY", + 0x21: "INS_DISPLAY_ADDRESS", + 0x22: "INS_PUT_KEY", + 0x24: "INS_GET_CHACHA8_PREKEY", + 0x26: "INS_VERIFY_KEY", + 0x28: "INS_MANAGE_SEEDWORDS", + 0x30: "INS_SECRET_KEY_TO_PUBLIC_KEY", + 0x32: "INS_GEN_KEY_DERIVATION", + 0x34: "INS_DERIVATION_TO_SCALAR", + 0x36: "INS_DERIVE_PUBLIC_KEY", + 0x38: "INS_DERIVE_SECRET_KEY", + 0x3A: "INS_GEN_KEY_IMAGE", + 0x3B: "INS_DERIVE_VIEW_TAG", + 0x3C: "INS_SECRET_KEY_ADD", + 0x3E: "INS_SECRET_KEY_SUB", + 0x40: "INS_GENERATE_KEYPAIR", + 0x42: "INS_SECRET_SCAL_MUL_KEY", + 0x44: "INS_SECRET_SCAL_MUL_BASE", + 0x46: "INS_DERIVE_SUBADDRESS_PUBLIC_KEY", + 0x48: "INS_GET_SUBADDRESS", + 0x4A: "INS_GET_SUBADDRESS_SPEND_PUBLIC_KEY", + 0x4C: "INS_GET_SUBADDRESS_SECRET_KEY", + 0x70: "INS_OPEN_TX", + 0x72: "INS_SET_SIGNATURE_MODE", + 0x74: "INS_GET_ADDITIONAL_KEY", + 0x76: "INS_STEALTH", + 0x77: "INS_GEN_COMMITMENT_MASK", + 0x78: "INS_BLIND", + 0x7A: "INS_UNBLIND", + 0x7B: "INS_GEN_TXOUT_KEYS", + 0x7D: "INS_PREFIX_HASH", + 0x7C: "INS_VALIDATE", + 0x7E: "INS_MLSAG", + 0x7F: "INS_CLSAG", + 0x80: "INS_CLOSE_TX", + 0xA0: "INS_GET_TX_PROOF", + 0xC0: "INS_GET_RESPONSE" +}; + +void _logLedgerCommand(Uint8List command, [bool isResponse = true]) { + String toHexString(Uint8List data) => + data.map((e) => e.toRadixString(16).padLeft(2, '0')).join(); + + + + if (isResponse) { + printV("< ${toHexString(command)}"); + } else { + printV( + "> ${_ledgerMoneroCommands[command[1]]} ${toHexString(command.sublist(2))}"); + } +} diff --git a/cw_monero/lib/monero_account_list.dart b/cw_monero/lib/monero_account_list.dart index 29d096efd..aa23e276f 100644 --- a/cw_monero/lib/monero_account_list.dart +++ b/cw_monero/lib/monero_account_list.dart @@ -1,4 +1,5 @@ import 'package:cw_core/monero_amount_format.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/account.dart'; import 'package:cw_monero/api/account_list.dart' as account_list; @@ -74,7 +75,7 @@ abstract class MoneroAccountListBase with Store { _isRefreshing = false; } catch (e) { _isRefreshing = false; - print(e); + printV(e); rethrow; } } diff --git a/cw_monero/lib/monero_subaddress_list.dart b/cw_monero/lib/monero_subaddress_list.dart index c20b23b5e..bc6f223d7 100644 --- a/cw_monero/lib/monero_subaddress_list.dart +++ b/cw_monero/lib/monero_subaddress_list.dart @@ -1,4 +1,5 @@ import 'package:cw_core/subaddress.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_monero/api/coins_info.dart'; import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list; import 'package:cw_monero/api/wallet.dart'; @@ -87,7 +88,7 @@ abstract class MoneroSubaddressListBase with Store { _isRefreshing = false; } on PlatformException catch (e) { _isRefreshing = false; - print(e); + printV(e); rethrow; } } diff --git a/cw_monero/lib/monero_unspent.dart b/cw_monero/lib/monero_unspent.dart index 87d8f0b39..8a104edf4 100644 --- a/cw_monero/lib/monero_unspent.dart +++ b/cw_monero/lib/monero_unspent.dart @@ -1,10 +1,33 @@ import 'package:cw_core/unspent_transaction_output.dart'; +import 'package:cw_core/utils/print_verbose.dart'; +import 'package:cw_monero/api/coins_info.dart'; +import 'package:monero/monero.dart' as monero; class MoneroUnspent extends Unspent { MoneroUnspent( String address, String hash, String keyImage, int value, bool isFrozen, this.isUnlocked) : super(address, hash, value, 0, keyImage) { - this.isFrozen = isFrozen; + } + + @override + set isFrozen(bool freeze) { + printV("set isFrozen: $freeze ($keyImage): $freeze"); + final coinId = getCoinByKeyImage(keyImage!); + if (coinId == null) throw Exception("Unable to find a coin for address $address"); + if (freeze) { + freezeCoin(coinId); + } else { + thawCoin(coinId); + } + } + + @override + bool get isFrozen { + printV("get isFrozen"); + final coinId = getCoinByKeyImage(keyImage!); + if (coinId == null) throw Exception("Unable to find a coin for address $address"); + final coin = getCoin(coinId); + return monero.CoinsInfo_frozen(coin); } final bool isUnlocked; diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index 04d530b07..098d4ac3d 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -17,6 +17,7 @@ import 'package:cw_core/pending_transaction.dart'; import 'package:cw_core/sync_status.dart'; import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/unspent_coins_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_monero/api/account_list.dart'; @@ -167,7 +168,7 @@ abstract class MoneroWalletBase Future? updateBalance() => null; @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _listener?.stop(); _onAccountChangeReaction?.reaction.dispose(); _onTxHistoryChangeReaction?.reaction.dispose(); @@ -191,7 +192,7 @@ abstract class MoneroWalletBase syncStatus = ConnectedSyncStatus(); } catch (e) { syncStatus = FailedSyncStatus(); - print(e); + printV(e); } } @@ -222,7 +223,7 @@ abstract class MoneroWalletBase _listener?.start(); } catch (e) { syncStatus = FailedSyncStatus(); - print(e); + printV(e); rethrow; } } @@ -306,9 +307,8 @@ abstract class MoneroWalletBase throw MoneroTransactionCreationException('You do not have enough XMR to send this amount.'); } - if (!spendAllCoins && (allInputsAmount < totalAmount + estimatedFee)) { - throw MoneroTransactionNoInputsException(inputs.length); - } + if (inputs.isEmpty) MoneroTransactionCreationException( + 'No inputs selected'); final moneroOutputs = outputs.map((output) { final outputAddress = output.isParsedAddress ? output.extractedAddress : output.address; @@ -328,29 +328,29 @@ abstract class MoneroWalletBase final amount = output.sendAll ? null : output.cryptoAmount!.replaceAll(',', '.'); final formattedAmount = output.sendAll ? null : output.formattedCryptoAmount; - if ((formattedAmount != null && unlockedBalance < formattedAmount) || - (formattedAmount == null && unlockedBalance <= 0)) { - final formattedBalance = moneroAmountToString(amount: unlockedBalance); + // if ((formattedAmount != null && unlockedBalance < formattedAmount) || + // (formattedAmount == null && unlockedBalance <= 0)) { + // final formattedBalance = moneroAmountToString(amount: unlockedBalance); + // + // throw MoneroTransactionCreationException( + // 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); + // } - throw MoneroTransactionCreationException( - 'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.'); - } - - final estimatedFee = calculateEstimatedFee(_credentials.priority, formattedAmount); - if (!spendAllCoins && - ((formattedAmount != null && allInputsAmount < (formattedAmount + estimatedFee)) || - formattedAmount == null)) { - throw MoneroTransactionNoInputsException(inputs.length); - } - - pendingTransactionDescription = await transaction_history.createTransaction( - address: address!, - amount: amount, - priorityRaw: _credentials.priority.serialize(), - accountIndex: walletAddresses.account!.id, - preferredInputs: inputs); + final estimatedFee = + calculateEstimatedFee(_credentials.priority, formattedAmount); + if (inputs.isEmpty) MoneroTransactionCreationException( + 'No inputs selected'); + pendingTransactionDescription = + await transaction_history.createTransaction( + address: address!, + amount: amount, + priorityRaw: _credentials.priority.serialize(), + accountIndex: walletAddresses.account!.id, + preferredInputs: inputs); } + // final status = monero.PendingTransaction_status(pendingTransactionDescription); + return PendingMoneroTransaction(pendingTransactionDescription); } @@ -391,8 +391,8 @@ abstract class MoneroWalletBase try { await backupWalletFiles(name); } catch (e) { - print("¯\\_(ツ)_/¯"); - print(e); + printV("¯\\_(ツ)_/¯"); + printV(e); } } @@ -401,7 +401,7 @@ abstract class MoneroWalletBase final currentWalletDirPath = await pathForWalletDir(name: name, type: type); if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) { // NOTE: this is realistically only required on windows. - print("closing wallet"); + printV("closing wallet"); final wmaddr = wmPtr.address; final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address; await Isolate.run(() { @@ -409,7 +409,7 @@ abstract class MoneroWalletBase Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true); }); openedWalletsByPath.remove("$currentWalletDirPath/$name"); - print("wallet closed"); + printV("wallet closed"); } try { // -- rename the waller folder -- @@ -498,7 +498,7 @@ abstract class MoneroWalletBase for (var i = 0; i < coinCount; i++) { final coin = getCoin(i); final coinSpent = monero.CoinsInfo_spent(coin); - if (coinSpent == false) { + if (coinSpent == false && monero.CoinsInfo_subaddrAccount(coin) == walletAddresses.account!.id) { final unspent = MoneroUnspent( monero.CoinsInfo_address(coin), monero.CoinsInfo_hash(coin), @@ -542,7 +542,7 @@ abstract class MoneroWalletBase await _refreshUnspentCoinsInfo(); _askForUpdateBalance(); } catch (e, s) { - print(e.toString()); + printV(e.toString()); onError?.call(FlutterErrorDetails( exception: e, stack: s, @@ -589,7 +589,7 @@ abstract class MoneroWalletBase await unspentCoinsInfo.deleteAll(keys); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -621,7 +621,7 @@ abstract class MoneroWalletBase await transactionHistory.save(); _isTransactionUpdating = false; } catch (e) { - print(e); + printV(e); _isTransactionUpdating = false; } } @@ -708,9 +708,9 @@ abstract class MoneroWalletBase void _askForUpdateBalance() { final unlockedBalance = _getUnlockedBalance(); - final fullBalance = _getFullBalance(); + final fullBalance = monero_wallet.getFullBalance( + accountIndex: walletAddresses.account!.id); final frozenBalance = _getFrozenBalance(); - if (balance[currency]!.fullBalance != fullBalance || balance[currency]!.unlockedBalance != unlockedBalance || balance[currency]!.frozenBalance != frozenBalance) { @@ -730,10 +730,10 @@ abstract class MoneroWalletBase var frozenBalance = 0; for (var coin in unspentCoinsInfo.values.where((element) => - element.walletId == id && element.accountIndex == walletAddresses.account!.id)) { - if (coin.isFrozen) frozenBalance += coin.value; + element.walletId == id && + element.accountIndex == walletAddresses.account!.id)) { + if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value; } - return frozenBalance; } @@ -763,7 +763,7 @@ abstract class MoneroWalletBase syncStatus = SyncingSyncStatus(blocksLeft, ptc); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -773,7 +773,7 @@ abstract class MoneroWalletBase _askForUpdateBalance(); await Future.delayed(Duration(seconds: 1)); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/cw_monero/lib/monero_wallet_addresses.dart b/cw_monero/lib/monero_wallet_addresses.dart index ae78132d3..14b8a2b9b 100644 --- a/cw_monero/lib/monero_wallet_addresses.dart +++ b/cw_monero/lib/monero_wallet_addresses.dart @@ -1,6 +1,7 @@ import 'package:cw_core/account.dart'; import 'package:cw_core/address_info.dart'; import 'package:cw_core/subaddress.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list; @@ -96,7 +97,7 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store { await saveAddressesInBox(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/cw_monero/lib/monero_wallet_service.dart b/cw_monero/lib/monero_wallet_service.dart index 6f49640be..18171a568 100644 --- a/cw_monero/lib/monero_wallet_service.dart +++ b/cw_monero/lib/monero_wallet_service.dart @@ -1,23 +1,26 @@ import 'dart:ffi'; import 'dart:io'; + +import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/unspent_coins_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; -import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_monero/api/account_list.dart'; import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager; import 'package:cw_monero/api/wallet_manager.dart'; import 'package:cw_monero/ledger.dart'; import 'package:cw_monero/monero_wallet.dart'; +import 'package:collection/collection.dart'; import 'package:hive/hive.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; -import 'package:polyseed/polyseed.dart'; import 'package:monero/monero.dart' as monero; +import 'package:polyseed/polyseed.dart'; class MoneroNewWalletCredentials extends WalletCredentials { MoneroNewWalletCredentials( @@ -110,7 +113,7 @@ class MoneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('MoneroWalletsManager Error: ${e.toString()}'); + printV('MoneroWalletsManager Error: ${e.toString()}'); rethrow; } } @@ -122,7 +125,7 @@ class MoneroWalletService extends WalletService< return monero_wallet_manager.isWalletExist(path: path); } catch (e) { // TODO: Implement Exception for wallet list service. - print('MoneroWalletsManager Error: $e'); + printV('MoneroWalletsManager Error: $e'); rethrow; } } @@ -132,14 +135,12 @@ class MoneroWalletService extends WalletService< try { final path = await pathForWallet(name: name, type: getType()); - if (walletFilesExist(path)) { - await repairOldAndroidWallet(name); - } + if (walletFilesExist(path)) await repairOldAndroidWallet(name); await monero_wallet_manager .openWalletAsync({'path': path, 'password': password}); - final walletInfo = walletInfoSource.values.firstWhere( - (info) => info.id == WalletBase.idFor(name, getType())); + final walletInfo = walletInfoSource.values + .firstWhere((info) => info.id == WalletBase.idFor(name, getType())); final wallet = MoneroWallet( walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource, @@ -168,7 +169,7 @@ class MoneroWalletService extends WalletService< } await restoreOrResetWalletFiles(name); - return openWallet(name, password, retryOnFailure: false); + return await openWallet(name, password, retryOnFailure: false); } } @@ -177,7 +178,7 @@ class MoneroWalletService extends WalletService< final path = await pathForWalletDir(name: wallet, type: getType()); if (openedWalletsByPath["$path/$wallet"] != null) { // NOTE: this is realistically only required on windows. - print("closing wallet"); + printV("closing wallet"); final wmaddr = wmPtr.address; final waddr = openedWalletsByPath["$path/$wallet"]!.address; // await Isolate.run(() { @@ -185,7 +186,7 @@ class MoneroWalletService extends WalletService< Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false); // }); openedWalletsByPath.remove("$path/$wallet"); - print("wallet closed"); + printV("wallet closed"); } final file = Directory(path); @@ -203,7 +204,7 @@ class MoneroWalletService extends WalletService< @override Future rename(String currentName, String password, String newName) async { final currentWalletInfo = walletInfoSource.values.firstWhere( - (info) => info.id == WalletBase.idFor(currentName, getType())); + (info) => info.id == WalletBase.idFor(currentName, getType())); final currentWallet = MoneroWallet( walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource, @@ -241,7 +242,7 @@ class MoneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('MoneroWalletsManager Error: $e'); + printV('MoneroWalletsManager Error: $e'); rethrow; } } @@ -254,14 +255,14 @@ class MoneroWalletService extends WalletService< final password = credentials.password; final height = credentials.height; - if (wptr == null ) monero_wallet_manager.createWalletPointer(); + if (wptr == null) monero_wallet_manager.createWalletPointer(); enableLedgerExchange(wptr!, credentials.ledgerConnection); await monero_wallet_manager.restoreWalletFromHardwareWallet( - path: path, - password: password!, - restoreHeight: height!, - deviceName: 'Ledger'); + path: path, + password: password!, + restoreHeight: height!, + deviceName: 'Ledger'); final wallet = MoneroWallet( walletInfo: credentials.walletInfo!, @@ -272,13 +273,14 @@ class MoneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('MoneroWalletsManager Error: $e'); + printV('MoneroWalletsManager Error: $e'); rethrow; } } @override - Future restoreFromSeed(MoneroRestoreWalletFromSeedCredentials credentials, + Future restoreFromSeed( + MoneroRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async { // Restore from Polyseed if (Polyseed.isValidSeed(credentials.mnemonic)) { @@ -301,7 +303,7 @@ class MoneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('MoneroWalletsManager Error: $e'); + printV('MoneroWalletsManager Error: $e'); rethrow; } } @@ -312,13 +314,14 @@ class MoneroWalletService extends WalletService< final path = await pathForWallet(name: credentials.name, type: getType()); final polyseedCoin = PolyseedCoin.POLYSEED_MONERO; final lang = PolyseedLang.getByPhrase(credentials.mnemonic); - final polyseed = Polyseed.decode(credentials.mnemonic, lang, polyseedCoin); + final polyseed = + Polyseed.decode(credentials.mnemonic, lang, polyseedCoin); return _restoreFromPolyseed( path, credentials.password!, polyseed, credentials.walletInfo!, lang); } catch (e) { // TODO: Implement Exception for wallet list service. - print('MoneroWalletsManager Error: $e'); + printV('MoneroWalletsManager Error: $e'); rethrow; } } @@ -354,24 +357,18 @@ class MoneroWalletService extends WalletService< Future repairOldAndroidWallet(String name) async { try { - if (!Platform.isAndroid) { - return; - } + if (!Platform.isAndroid) return; final oldAndroidWalletDirPath = await outdatedAndroidPathForWalletDir(name: name); final dir = Directory(oldAndroidWalletDirPath); - if (!dir.existsSync()) { - return; - } + if (!dir.existsSync()) return; final newWalletDirPath = await pathForWalletDir(name: name, type: getType()); dir.listSync().forEach((f) { final file = File(f.path); - final name = f.path - .split('/') - .last; + final name = f.path.split('/').last; final newPath = newWalletDirPath + '/$name'; final newFile = File(newPath); @@ -381,7 +378,7 @@ class MoneroWalletService extends WalletService< newFile.writeAsBytesSync(file.readAsBytesSync()); }); } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -390,9 +387,7 @@ class MoneroWalletService extends WalletService< try { final path = await pathForWallet(name: name, type: getType()); - if (walletFilesExist(path)) { - await repairOldAndroidWallet(name); - } + if (walletFilesExist(path)) await repairOldAndroidWallet(name); await monero_wallet_manager.openWalletAsync({'path': path, 'password': password}); final walletInfo = walletInfoSource.values @@ -411,8 +406,10 @@ class MoneroWalletService extends WalletService< @override bool requireHardwareWalletConnection(String name) { - final walletInfo = walletInfoSource.values - .firstWhere((info) => info.id == WalletBase.idFor(name, getType())); - return walletInfo.isHardwareWallet; + return walletInfoSource.values + .firstWhereOrNull( + (info) => info.id == WalletBase.idFor(name, getType())) + ?.isHardwareWallet ?? + false; } } diff --git a/cw_monero/lib/pending_monero_transaction.dart b/cw_monero/lib/pending_monero_transaction.dart index eb714eeb3..1c01a60dc 100644 --- a/cw_monero/lib/pending_monero_transaction.dart +++ b/cw_monero/lib/pending_monero_transaction.dart @@ -6,6 +6,7 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/amount_converter.dart'; import 'package:cw_core/pending_transaction.dart'; +import 'package:cw_monero/api/wallet.dart'; class DoubleSpendException implements Exception { DoubleSpendException(); @@ -53,6 +54,7 @@ class PendingMoneroTransaction with PendingTransaction { rethrow; } + storeSync(force: true); } @override diff --git a/cw_monero/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux b/cw_monero/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux new file mode 120000 index 000000000..17553f81e --- /dev/null +++ b/cw_monero/linux/flutter/ephemeral/.plugin_symlinks/path_provider_linux @@ -0,0 +1 @@ +/Users/omarhatem/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/ \ No newline at end of file diff --git a/cw_monero/pubspec.lock b/cw_monero/pubspec.lock index 31d44ac63..24be1c0dd 100644 --- a/cw_monero/pubspec.lock +++ b/cw_monero/pubspec.lock @@ -21,10 +21,10 @@ packages: dependency: transitive description: name: args - sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" asn1lib: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: "direct dev" description: @@ -93,10 +93,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.4.13" build_runner_core: dependency: transitive description: @@ -174,18 +174,18 @@ packages: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cryptography: dependency: transitive description: @@ -253,18 +253,18 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -311,10 +311,10 @@ packages: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" hashlib: dependency: transitive description: @@ -375,10 +375,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -407,26 +407,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" ledger_flutter_plus: dependency: "direct main" description: @@ -447,10 +447,10 @@ packages: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" matcher: dependency: transitive description: @@ -463,26 +463,26 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a" + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.6" + version: "2.0.0" mobx: dependency: "direct main" description: @@ -503,8 +503,8 @@ packages: dependency: "direct main" description: path: "impls/monero.dart" - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 - resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 + ref: af5277f96073917185864d3596e82b67bee54e78 + resolved-ref: af5277f96073917185864d3596e82b67bee54e78 url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" @@ -552,10 +552,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.12" path_provider_foundation: dependency: transitive description: @@ -600,10 +600,10 @@ packages: dependency: transitive description: name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.5" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -680,10 +680,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -765,10 +765,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timing: dependency: transitive description: @@ -789,10 +789,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" universal_ble: dependency: transitive description: @@ -829,10 +829,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.4" watcher: dependency: "direct overridden" description: @@ -845,18 +845,26 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "3.0.1" xdg_directories: dependency: transitive description: @@ -882,5 +890,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.19.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/cw_monero/pubspec.yaml b/cw_monero/pubspec.yaml index 71cbfa243..61caf93da 100644 --- a/cw_monero/pubspec.yaml +++ b/cw_monero/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: path_provider: ^2.0.11 mobx: ^2.0.7+4 flutter_mobx: ^2.0.6+1 - intl: ^0.18.0 + intl: ^0.19.0 encrypt: ^5.0.1 polyseed: ^0.0.6 cw_core: @@ -25,7 +25,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 + ref: af5277f96073917185864d3596e82b67bee54e78 # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash path: impls/monero.dart mutex: ^3.1.0 diff --git a/cw_mweb/android/build.gradle b/cw_mweb/android/build.gradle index 7e67b98ad..0d17a47ec 100644 --- a/cw_mweb/android/build.gradle +++ b/cw_mweb/android/build.gradle @@ -2,14 +2,14 @@ group 'com.cakewallet.mweb' version '1.0-SNAPSHOT' buildscript { - ext.kotlin_version = '1.7.10' + ext.kotlin_version = '2.0.21' repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:8.7.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -33,15 +33,19 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 31 + compileSdkVersion 33 + + if (project.android.hasProperty("namespace")) { + namespace 'com.cakewallet.mweb' + } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' } sourceSets { diff --git a/cw_mweb/android/settings.gradle b/cw_mweb/android/settings.gradle index 88fbd66fb..4a0c212c0 100644 --- a/cw_mweb/android/settings.gradle +++ b/cw_mweb/android/settings.gradle @@ -1 +1,3 @@ rootProject.name = 'cw_mweb' +id "com.android.application" version "8.3.2" apply false +id "org.jetbrains.kotlin.android" version "2.0.20" apply false diff --git a/cw_mweb/lib/cw_mweb.dart b/cw_mweb/lib/cw_mweb.dart index 75cc0bcca..594197018 100644 --- a/cw_mweb/lib/cw_mweb.dart +++ b/cw_mweb/lib/cw_mweb.dart @@ -4,6 +4,7 @@ import 'dart:developer'; import 'dart:io'; import 'dart:typed_data'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:grpc/grpc.dart'; import 'package:path_provider/path_provider.dart'; import 'cw_mweb_platform_interface.dart'; @@ -39,18 +40,18 @@ class CwMweb { final fileStream = file.openRead(lastLength, currentLength); final newLines = await fileStream.transform(utf8.decoder).join(); lastLength = currentLength; - log(newLines); + printV(newLines); } } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log('The mwebd debug log probably is not initialized yet.'); + printV('The mwebd debug log probably is not initialized yet.'); } }); } static Future _initializeClient() async { - print("_initializeClient() called!"); + printV("_initializeClient() called!"); final appDir = await getApplicationSupportDirectory(); const ltcNodeUri = "ltc-electrum.cakewallet.com:9333"; @@ -61,14 +62,14 @@ class CwMweb { if (_port == null || _port == 0) { throw Exception("Failed to start server"); } - log("Attempting to connect to server on port: $_port"); + printV("Attempting to connect to server on port: $_port"); // wait for the server to finish starting up before we try to connect to it: await Future.delayed(const Duration(seconds: 8)); _clientChannel = ClientChannel('127.0.0.1', port: _port!, channelShutdownHandler: () { _rpcClient = null; - log("Channel is shutting down!"); + printV("Channel is shutting down!"); }, options: const ChannelOptions( credentials: ChannelCredentials.insecure(), @@ -90,14 +91,14 @@ class CwMweb { } return _rpcClient!; } on GrpcError catch (e) { - log("Attempt $i failed: $e"); - log('Caught grpc error: ${e.message}'); + printV("Attempt $i failed: $e"); + printV('Caught grpc error: ${e.message}'); _rpcClient = null; // necessary if the database isn't open: await stop(); await Future.delayed(const Duration(seconds: 3)); } catch (e) { - log("Attempt $i failed: $e"); + printV("Attempt $i failed: $e"); _rpcClient = null; await stop(); await Future.delayed(const Duration(seconds: 3)); @@ -111,9 +112,9 @@ class CwMweb { await CwMwebPlatform.instance.stop(); await cleanup(); } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log("Error stopping server: $e"); + printV("Error stopping server: $e"); } } @@ -123,9 +124,9 @@ class CwMweb { ?.split(',') .first; } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log("Error getting address: $e"); + printV("Error getting address: $e"); } return null; } @@ -159,9 +160,9 @@ class CwMweb { _rpcClient = await stub(); return await _rpcClient!.spent(request, options: CallOptions(timeout: TIMEOUT_DURATION)); } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log("Error getting spent: $e"); + printV("Error getting spent: $e"); } return SpentResponse(); } @@ -172,9 +173,9 @@ class CwMweb { _rpcClient = await stub(); return await _rpcClient!.status(request, options: CallOptions(timeout: TIMEOUT_DURATION)); } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log("Error getting status: $e"); + printV("Error getting status: $e"); } return StatusResponse(); } @@ -185,9 +186,9 @@ class CwMweb { _rpcClient = await stub(); return await _rpcClient!.create(request, options: CallOptions(timeout: TIMEOUT_DURATION)); } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log("Error getting create: $e"); + printV("Error getting create: $e"); } return CreateResponse(); } @@ -201,9 +202,9 @@ class CwMweb { log("got utxo stream"); return resp; } on GrpcError catch (e) { - log('Caught grpc error: ${e.message}'); + printV('Caught grpc error: ${e.message}'); } catch (e) { - log("Error getting utxos: $e"); + printV("Error getting utxos: $e"); } return null; } @@ -217,7 +218,7 @@ class CwMweb { log('Caught grpc error: ${e.message}'); throw "error from broadcast mweb: $e"; } catch (e) { - log("Error getting create: $e"); + printV("Error getting utxos: $e"); rethrow; } } diff --git a/cw_mweb/pubspec.yaml b/cw_mweb/pubspec.yaml index cfe43c70b..2b71264ee 100644 --- a/cw_mweb/pubspec.yaml +++ b/cw_mweb/pubspec.yaml @@ -13,6 +13,8 @@ dependencies: grpc: ^3.2.4 path_provider: ^2.1.2 plugin_platform_interface: ^2.0.2 + cw_core: + path: ../cw_core dev_dependencies: flutter_test: diff --git a/cw_nano/lib/nano_client.dart b/cw_nano/lib/nano_client.dart index 7f8e1d0a9..8b62273da 100644 --- a/cw_nano/lib/nano_client.dart +++ b/cw_nano/lib/nano_client.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:cw_core/nano_account_info_response.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_nano/nano_block_info_response.dart'; import 'package:cw_core/n2_node.dart'; import 'package:cw_nano/nano_balance.dart'; @@ -106,7 +107,7 @@ class NanoClient { final data = await jsonDecode(response.body); return AccountInfoResponse.fromJson(data as Map); } catch (e) { - print("error while getting account info $e"); + printV("error while getting account info $e"); return null; } } @@ -127,7 +128,7 @@ class NanoClient { final data = await jsonDecode(response.body); return BlockContentsResponse.fromJson(data["contents"] as Map); } catch (e) { - print("error while getting block info $e"); + printV("error while getting block info $e"); return null; } } @@ -508,7 +509,7 @@ class NanoClient { .map((transaction) => NanoTransactionModel.fromJson(transaction)) .toList(); } catch (e) { - print(e); + printV(e); return []; } } diff --git a/cw_nano/lib/nano_transaction_history.dart b/cw_nano/lib/nano_transaction_history.dart index 44d64f7d4..2b551ffa6 100644 --- a/cw_nano/lib/nano_transaction_history.dart +++ b/cw_nano/lib/nano_transaction_history.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:core'; import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/encryption_file_utils.dart'; import 'package:mobx/mobx.dart'; @@ -27,7 +28,10 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase init() async => await _load(); + Future init() async { + clear(); + await _load(); + } @override Future save() async { @@ -37,7 +41,7 @@ abstract class NanoTransactionHistoryBase extends TransactionHistoryBase changePassword(String password) => throw UnimplementedError("changePassword"); @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _client.stop(); _receiveTimer?.cancel(); } @@ -170,12 +171,12 @@ abstract class NanoWalletBase await _updateRep(); await _receiveAll(); } catch (e) { - print(e); + printV(e); } syncStatus = ConnectedSyncStatus(); } catch (e) { - print(e); + printV(e); syncStatus = FailedSyncStatus(); } } @@ -367,7 +368,7 @@ abstract class NanoWalletBase syncStatus = SyncedSyncStatus(); } catch (e) { - print(e); + printV(e); syncStatus = FailedSyncStatus(); rethrow; } @@ -444,7 +445,7 @@ abstract class NanoWalletBase try { balance[currency] = await _client.getBalance(_publicAddress!); } catch (e) { - print("Failed to get balance $e"); + printV("Failed to get balance $e"); // if we don't have a balance, we should at least create one, since it's a late binding // otherwise, it's better to just leave it as whatever it was before: if (balance[currency] == null) { diff --git a/cw_nano/lib/nano_wallet_addresses.dart b/cw_nano/lib/nano_wallet_addresses.dart index e8eae7737..f1ff14a85 100644 --- a/cw_nano/lib/nano_wallet_addresses.dart +++ b/cw_nano/lib/nano_wallet_addresses.dart @@ -1,4 +1,5 @@ import 'package:cw_core/cake_hive.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/nano_account.dart'; @@ -47,7 +48,7 @@ abstract class NanoWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = ''; await saveAddressesInBox(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } } diff --git a/cw_nano/pubspec.lock b/cw_nano/pubspec.lock index dd955e344..f426d96dc 100644 --- a/cw_nano/pubspec.lock +++ b/cw_nano/pubspec.lock @@ -21,18 +21,18 @@ packages: dependency: transitive description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.6.0" asn1lib: dependency: transitive description: name: asn1lib - sha256: "58082b3f0dca697204dbab0ef9ff208bfaea7767ea771076af9a343488428dda" + sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70" url: "https://pub.dev" source: hosted - version: "1.5.3" + version: "1.5.5" async: dependency: transitive description: @@ -77,10 +77,10 @@ packages: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" build_config: dependency: transitive description: @@ -93,10 +93,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.1" + version: "4.0.2" build_resolvers: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.4.13" build_runner_core: dependency: "direct overridden" description: @@ -190,18 +190,18 @@ packages: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" crypto: dependency: transitive description: name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.6" cryptography: dependency: transitive description: @@ -245,18 +245,18 @@ packages: dependency: "direct main" description: name: ed25519_hd_key - sha256: c5c9f11a03f5789bf9dcd9ae88d641571c802640851f1cacdb13123f171b3a26 + sha256: "31e191ec97492873067e46dc9cc0c7d55170559c83a478400feffa0627acaccf" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" encrypt: dependency: transitive description: name: encrypt - sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb" + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.0.3" fake_async: dependency: transitive description: @@ -269,26 +269,26 @@ packages: dependency: transitive description: name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" fixnum_nanodart: dependency: transitive description: @@ -306,10 +306,10 @@ packages: dependency: transitive description: name: flutter_mobx - sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e" + sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e" url: "https://pub.dev" source: hosted - version: "2.0.6+5" + version: "2.2.1+1" flutter_test: dependency: "direct dev" description: flutter @@ -324,10 +324,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -340,10 +340,10 @@ packages: dependency: transitive description: name: graphs - sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" hex: dependency: "direct main" description: @@ -372,10 +372,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -396,10 +396,10 @@ packages: dependency: transitive description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -420,34 +420,34 @@ packages: dependency: transitive description: name: json_annotation - sha256: b10a7b2ff83d83c777edba3c6a0f97045ddadd56c944e1a23a3fdf43a1bf4467 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.1" + version: "4.9.0" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" libcrypto: dependency: "direct main" description: @@ -460,10 +460,10 @@ packages: dependency: transitive description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" matcher: dependency: transitive description: @@ -476,26 +476,26 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" mobx: dependency: "direct main" description: @@ -529,6 +529,14 @@ packages: url: "https://github.com/perishllc/nanoutil.git" source: git version: "1.0.3" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -549,26 +557,26 @@ packages: dependency: transitive description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.12" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -581,34 +589,34 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" pinenacl: dependency: transitive description: name: pinenacl - sha256: "3a5503637587d635647c93ea9a8fecf48a420cc7deebe6f1fc85c2a5637ab327" + sha256: "57e907beaacbc3c024a098910b6240758e899674de07d6949a67b52fd984cbdf" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -621,10 +629,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.9.1" pool: dependency: transitive description: @@ -633,6 +641,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: @@ -645,50 +661,50 @@ packages: dependency: transitive description: name: pubspec_parse - sha256: c63b2876e58e194e4b0828fcb080ad0e06d051cb607a6be51a9e084f47cb9367 + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.3" + version: "1.3.0" rational: dependency: transitive description: name: rational - sha256: ba58e9e18df9abde280e8b10051e4bce85091e41e8e7e411b6cde2e738d357cf + sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.3.2" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.3" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "671e7a931f55a08aa45be2a13fe7247f2a41237897df434b30d2012388191833" + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.5.3" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shared_preferences_platform_interface: dependency: transitive description: @@ -701,18 +717,18 @@ packages: dependency: transitive description: name: shared_preferences_web - sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.4.2" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.1" shelf: dependency: transitive description: @@ -725,10 +741,10 @@ packages: dependency: transitive description: name: shelf_web_socket - sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -738,10 +754,10 @@ packages: dependency: transitive description: name: socks5_proxy - sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a" + sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.6" source_gen: dependency: transitive description: @@ -810,10 +826,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timing: dependency: transitive description: @@ -834,10 +850,10 @@ packages: dependency: transitive description: name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.2" + version: "1.4.0" unorm_dart: dependency: transitive description: @@ -858,10 +874,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.4" watcher: dependency: "direct overridden" description: @@ -870,30 +886,38 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.4.0" - win32: - dependency: transitive - description: - name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" - url: "https://pub.dev" - source: hosted - version: "5.5.0" + version: "3.0.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" yaml: dependency: transitive description: @@ -903,5 +927,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.3.0 <4.0.0" - flutter: ">=3.16.6" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/cw_polygon/lib/polygon_client.dart b/cw_polygon/lib/polygon_client.dart index d55ee2269..cb8331977 100644 --- a/cw_polygon/lib/polygon_client.dart +++ b/cw_polygon/lib/polygon_client.dart @@ -14,11 +14,19 @@ class PolygonClient extends EVMChainClient { required EtherAmount amount, EtherAmount? maxPriorityFeePerGas, Uint8List? data, + int? maxGas, + EtherAmount? gasPrice, + EtherAmount? maxFeePerGas, }) { return Transaction( from: from, to: to, value: amount, + // data: data, + maxGas: maxGas, + // gasPrice: gasPrice, + // maxFeePerGas: maxFeePerGas, + // maxPriorityFeePerGas: maxPriorityFeePerGas, ); } diff --git a/cw_shared_external/android/build.gradle b/cw_shared_external/android/build.gradle index 64b550364..8d2b1b13d 100644 --- a/cw_shared_external/android/build.gradle +++ b/cw_shared_external/android/build.gradle @@ -25,7 +25,20 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdkVersion 30 + compileSdkVersion 33 + + if (project.android.hasProperty("namespace")) { + namespace 'com.cakewallet.cw_shared_external' + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + + kotlinOptions { + jvmTarget = '17' + } sourceSets { main.java.srcDirs += 'src/main/kotlin' diff --git a/cw_solana/lib/solana_client.dart b/cw_solana/lib/solana_client.dart index 23e88fe5e..95376c563 100644 --- a/cw_solana/lib/solana_client.dart +++ b/cw_solana/lib/solana_client.dart @@ -1,11 +1,13 @@ import 'dart:async'; import 'dart:convert'; -import 'dart:math'; +import 'dart:math' as math; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/node.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_solana/pending_solana_transaction.dart'; import 'package:cw_solana/solana_balance.dart'; +import 'package:cw_solana/solana_exceptions.dart'; import 'package:cw_solana/solana_transaction_model.dart'; import 'package:http/http.dart' as http; import 'package:solana/dto.dart'; @@ -179,7 +181,7 @@ class SolanaWalletClient { bool isOutgoingTx = transfer.source == publicKey.toBase58(); double amount = (double.tryParse(transfer.amount) ?? 0.0) / - pow(10, splTokenDecimal ?? 9); + math.pow(10, splTokenDecimal ?? 9); transactions.add( SolanaTransactionModel( @@ -275,6 +277,7 @@ class SolanaWalletClient { required String destinationAddress, required Ed25519HDKeyPair ownerKeypair, required bool isSendAll, + required double solBalance, String? tokenMint, List references = const [], }) async { @@ -289,6 +292,7 @@ class SolanaWalletClient { ownerKeypair: ownerKeypair, commitment: commitment, isSendAll: isSendAll, + solBalance: solBalance, ); return pendingNativeTokenTransaction; } else { @@ -300,6 +304,7 @@ class SolanaWalletClient { destinationAddress: destinationAddress, ownerKeypair: ownerKeypair, commitment: commitment, + solBalance: solBalance, ); return pendingSPLTokenTransaction; } @@ -352,6 +357,23 @@ class SolanaWalletClient { return fee; } + Future hasSufficientFundsLeftForRent({ + required double inputAmount, + required double solBalance, + required double fee, + }) async { + final rent = + await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed); + + final rentInSol = (rent / lamportsPerSol).toDouble(); + + final remnant = solBalance - (inputAmount + fee); + + if (remnant > rentInSol) return true; + + return false; + } + Future _signNativeTokenTransaction({ required String tokenTitle, required int tokenDecimals, @@ -360,6 +382,7 @@ class SolanaWalletClient { required Ed25519HDKeyPair ownerKeypair, required Commitment commitment, required bool isSendAll, + required double solBalance, }) async { // Convert SOL to lamport int lamports = (inputAmount * lamportsPerSol).toInt(); @@ -377,6 +400,16 @@ class SolanaWalletClient { commitment, ); + bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent( + inputAmount: inputAmount, + fee: fee, + solBalance: solBalance, + ); + + if (!hasSufficientFundsLeft) { + throw SolanaSignNativeTokenTransactionRentException(); + } + SignedTx signedTx; if (isSendAll) { final feeInLamports = (fee * lamportsPerSol).toInt(); @@ -424,6 +457,7 @@ class SolanaWalletClient { required String destinationAddress, required Ed25519HDKeyPair ownerKeypair, required Commitment commitment, + required double solBalance, }) async { final destinationOwner = Ed25519HDPublicKey.fromBase58(destinationAddress); final mint = Ed25519HDPublicKey.fromBase58(tokenMint); @@ -446,7 +480,7 @@ class SolanaWalletClient { // Throw an appropriate exception if the sender has no associated // token account if (associatedSenderAccount == null) { - throw NoAssociatedTokenAccountException(ownerKeypair.address, mint.toBase58()); + throw SolanaNoAssociatedTokenAccountException(ownerKeypair.address, mint.toBase58()); } try { @@ -456,11 +490,11 @@ class SolanaWalletClient { funder: ownerKeypair, ); } catch (e) { - throw Exception('Insufficient SOL balance to complete this transaction: ${e.toString()}'); + throw SolanaCreateAssociatedTokenAccountException(e.toString()); } // Input by the user - final amount = (inputAmount * pow(10, tokenDecimals)).toInt(); + final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt(); final instruction = TokenInstruction.transfer( source: Ed25519HDPublicKey.fromBase58(associatedSenderAccount.pubkey), @@ -482,6 +516,16 @@ class SolanaWalletClient { commitment, ); + bool hasSufficientFundsLeft = await hasSufficientFundsLeftForRent( + inputAmount: inputAmount, + fee: fee, + solBalance: solBalance, + ); + + if (!hasSufficientFundsLeft) { + throw SolanaSignSPLTokenTransactionRentException(); + } + final signedTx = await _signTransactionInternal( message: message, signers: signers, @@ -529,7 +573,7 @@ class SolanaWalletClient { return signature; } catch (e) { - print('Error while sending transaction: ${e.toString()}'); + printV('Error while sending transaction: ${e.toString()}'); throw Exception(e); } } @@ -546,7 +590,7 @@ class SolanaWalletClient { return null; } } catch (e) { - print('Error occurred while fetching token image: \n${e.toString()}'); + printV('Error occurred while fetching token image: \n${e.toString()}'); return null; } } diff --git a/cw_solana/lib/solana_exceptions.dart b/cw_solana/lib/solana_exceptions.dart index 7409b0500..888c95068 100644 --- a/cw_solana/lib/solana_exceptions.dart +++ b/cw_solana/lib/solana_exceptions.dart @@ -19,3 +19,20 @@ class SolanaTransactionWrongBalanceException implements Exception { @override String toString() => exceptionMessage; } + +class SolanaSignNativeTokenTransactionRentException implements Exception {} + +class SolanaCreateAssociatedTokenAccountException implements Exception { + final String exceptionMessage; + + SolanaCreateAssociatedTokenAccountException(this.exceptionMessage); +} + +class SolanaSignSPLTokenTransactionRentException implements Exception {} + +class SolanaNoAssociatedTokenAccountException implements Exception { + const SolanaNoAssociatedTokenAccountException(this.account, this.mint); + + final String account; + final String mint; +} diff --git a/cw_solana/lib/solana_transaction_history.dart b/cw_solana/lib/solana_transaction_history.dart index 77f93b9ee..62b9db8f7 100644 --- a/cw_solana/lib/solana_transaction_history.dart +++ b/cw_solana/lib/solana_transaction_history.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:core'; import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_solana/solana_transaction_info.dart'; import 'package:mobx/mobx.dart'; @@ -25,7 +26,10 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase init() async => await _load(); + Future init() async { + clear(); + await _load(); + } @override Future save() async { @@ -36,8 +40,8 @@ abstract class SolanaTransactionHistoryBase extends TransactionHistoryBase changePassword(String password) => throw UnimplementedError("changePassword"); @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _client.stop(); _transactionsUpdateTimer?.cancel(); } @@ -227,6 +228,8 @@ abstract class SolanaWalletBase final walletBalanceForCurrency = balance[transactionCurrency]!.balance; + final solBalance = balance[CryptoCurrency.sol]!.balance; + double totalAmount = 0.0; bool isSendAll = false; @@ -278,6 +281,7 @@ abstract class SolanaWalletBase ? solCredentials.outputs.first.extractedAddress! : solCredentials.outputs.first.address, isSendAll: isSendAll, + solBalance: solBalance, ); return pendingSolanaTransaction; @@ -454,7 +458,7 @@ abstract class SolanaWalletBase SolanaBalance(0.0); balance[token] = tokenBalance; } catch (e) { - print('Error fetching spl token (${token.symbol}) balance ${e.toString()}'); + printV('Error fetching spl token (${token.symbol}) balance ${e.toString()}'); } } else { balance.remove(token); diff --git a/cw_solana/lib/solana_wallet_addresses.dart b/cw_solana/lib/solana_wallet_addresses.dart index 19eb91fa1..7e9bd9008 100644 --- a/cw_solana/lib/solana_wallet_addresses.dart +++ b/cw_solana/lib/solana_wallet_addresses.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:mobx/mobx.dart'; @@ -30,7 +31,7 @@ abstract class SolanaWalletAddressesBase extends WalletAddresses with Store { addressesMap[address] = ''; await saveAddressesInBox(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } } diff --git a/cw_tron/lib/tron_transaction_history.dart b/cw_tron/lib/tron_transaction_history.dart index 9d226c09c..c940c7708 100644 --- a/cw_tron/lib/tron_transaction_history.dart +++ b/cw_tron/lib/tron_transaction_history.dart @@ -25,7 +25,10 @@ abstract class TronTransactionHistoryBase extends TransactionHistoryBase init() async => await _load(); + Future init() async { + clear(); + await _load(); + } @override Future save() async { diff --git a/cw_tron/lib/tron_wallet.dart b/cw_tron/lib/tron_wallet.dart index 3cd8bfc99..cfa80f0d3 100644 --- a/cw_tron/lib/tron_wallet.dart +++ b/cw_tron/lib/tron_wallet.dart @@ -217,7 +217,7 @@ abstract class TronWalletBase Future changePassword(String password) => throw UnimplementedError("changePassword"); @override - Future close({required bool shouldCleanup}) async => _transactionsUpdateTimer?.cancel(); + Future close({bool shouldCleanup = false}) async => _transactionsUpdateTimer?.cancel(); @action @override diff --git a/cw_wownero/lib/api/transaction_history.dart b/cw_wownero/lib/api/transaction_history.dart index 6b0923e83..3cebdd811 100644 --- a/cw_wownero/lib/api/transaction_history.dart +++ b/cw_wownero/lib/api/transaction_history.dart @@ -6,13 +6,16 @@ import 'package:cw_wownero/api/exceptions/creation_transaction_exception.dart'; import 'package:cw_wownero/api/wallet.dart'; import 'package:cw_wownero/api/wownero_output.dart'; import 'package:cw_wownero/api/structs/pending_transaction.dart'; +import 'package:cw_wownero/exceptions/wownero_transaction_creation_exception.dart'; import 'package:ffi/ffi.dart'; import 'package:monero/wownero.dart' as wownero; import 'package:monero/src/generated_bindings_wownero.g.dart' as wownero_gen; String getTxKey(String txId) { - return wownero.Wallet_getTxKey(wptr!, txid: txId); + final ret = wownero.Wallet_getTxKey(wptr!, txid: txId); + wownero.Wallet_status(wptr!); + return ret; } wownero.TransactionHistory? txhistory; @@ -86,7 +89,10 @@ Future createTransactionSync( final amt = amount == null ? 0 : wownero.Wallet_amountFromString(amount); final address_ = address.toNativeUtf8(); - final paymentId_ = paymentId.toNativeUtf8(); + final paymentId_ = paymentId.toNativeUtf8(); + if (preferredInputs.isEmpty) { + throw WowneroTransactionCreationException("No inputs provided, transaction cannot be constructed"); + } final preferredInputs_ = preferredInputs.join(wownero.defaultSeparatorStr).toNativeUtf8(); final waddr = wptr!.address; @@ -175,13 +181,23 @@ void commitTransaction({required wownero.PendingTransaction transactionPointer}) final txCommit = wownero.PendingTransaction_commit(transactionPointer, filename: '', overwrite: false); - final String? error = (() { + String? error = (() { final status = wownero.PendingTransaction_status(transactionPointer.cast()); if (status == 0) { return null; } - return wownero.Wallet_errorString(wptr!); + return wownero.PendingTransaction_errorString(transactionPointer.cast()); })(); + if (error == null) { + error = (() { + final status = wownero.Wallet_status(wptr!); + if (status == 0) { + return null; + } + return wownero.Wallet_errorString(wptr!); + })(); + + } if (error != null) { throw CreationTransactionException(message: error); diff --git a/cw_wownero/lib/api/wallet.dart b/cw_wownero/lib/api/wallet.dart index baf9c8960..21dcd04c7 100644 --- a/cw_wownero/lib/api/wallet.dart +++ b/cw_wownero/lib/api/wallet.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:ffi'; import 'dart:isolate'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_wownero/api/account_list.dart'; import 'package:cw_wownero/api/exceptions/setup_wallet_exception.dart'; import 'package:monero/wownero.dart' as wownero; @@ -10,7 +11,7 @@ import 'package:mutex/mutex.dart'; int getSyncingHeight() { // final height = wownero.WOWNERO_cw_WalletListener_height(getWlptr()); final h2 = wownero.Wallet_blockChainHeight(wptr!); - // print("height: $height / $h2"); + // printV("height: $height / $h2"); return h2; } @@ -71,7 +72,7 @@ Map>> addressCache = {}; String getAddress({int accountIndex = 0, int addressIndex = 1}) { while (wownero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) { - print("adding subaddress"); + printV("adding subaddress"); wownero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex); } addressCache[wptr!.address] ??= {}; @@ -100,7 +101,7 @@ Future setupNodeSync( bool useSSL = false, bool isLightWallet = false, String? socksProxyAddress}) async { - print(''' + printV(''' { wptr!, daemonAddress: $address, @@ -125,7 +126,7 @@ Future setupNodeSync( if (status != 0) { final error = wownero.Wallet_errorString(wptr!); - print("error: $error"); + printV("error: $error"); throw SetupWalletException(message: error); } diff --git a/cw_wownero/lib/api/wallet_manager.dart b/cw_wownero/lib/api/wallet_manager.dart index ed6d86823..6681652db 100644 --- a/cw_wownero/lib/api/wallet_manager.dart +++ b/cw_wownero/lib/api/wallet_manager.dart @@ -2,6 +2,7 @@ import 'dart:ffi'; import 'dart:io'; import 'dart:isolate'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_wownero/api/account_list.dart'; import 'package:cw_wownero/api/exceptions/wallet_creation_exception.dart'; import 'package:cw_wownero/api/exceptions/wallet_opening_exception.dart'; @@ -53,9 +54,9 @@ final wownero.WalletManager wmPtr = Pointer.fromAddress((() { // than plugging gdb in. Especially on windows/android. wownero.printStarts = false; _wmPtr ??= wownero.WalletManagerFactory_getWalletManager(); - print("ptr: $_wmPtr"); + printV("ptr: $_wmPtr"); } catch (e) { - print(e); + printV(e); rethrow; } return _wmPtr!.address; @@ -230,7 +231,7 @@ void restoreWalletFromSpendKeySync( if (status != 0) { final err = wownero.Wallet_errorString(newWptr); - print("err: $err"); + printV("err: $err"); throw WalletRestoreFromKeysException(message: err); } @@ -299,7 +300,7 @@ void loadWallet( final status = wownero.Wallet_status(newWptr); if (status != 0) { final err = wownero.Wallet_errorString(newWptr); - print(err); + printV(err); throw WalletOpeningException(message: err); } wptr = newWptr; diff --git a/cw_wownero/lib/mywownero.dart b/cw_wownero/lib/mywownero.dart index d50e48b64..afbb9b375 100644 --- a/cw_wownero/lib/mywownero.dart +++ b/cw_wownero/lib/mywownero.dart @@ -1,3 +1,5 @@ +import 'package:cw_core/utils/print_verbose.dart'; + const prefixLength = 3; String swapEndianBytes(String original) { @@ -37,14 +39,14 @@ String mnemonicDecode(String seed) { .indexOf(wlist[i + 2].substring(0, prefixLength)); if (w1 == -1 || w2 == -1 || w3 == -1) { - print("invalid word in mnemonic"); + printV("invalid word in mnemonic"); return ''; } final x = w1 + n * (((n - w1) + w2) % n) + n * n * (((n - w2) + w3) % n); if (x % n != w1) { - print("Something went wrong when decoding your private key, please try again"); + printV("Something went wrong when decoding your private key, please try again"); return ''; } diff --git a/cw_wownero/lib/wownero_account_list.dart b/cw_wownero/lib/wownero_account_list.dart index 6d408ba8f..cf1554b7a 100644 --- a/cw_wownero/lib/wownero_account_list.dart +++ b/cw_wownero/lib/wownero_account_list.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wownero_amount_format.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/account.dart'; @@ -74,7 +75,7 @@ abstract class WowneroAccountListBase with Store { _isRefreshing = false; } catch (e) { _isRefreshing = false; - print(e); + printV(e); rethrow; } } diff --git a/cw_wownero/lib/wownero_subaddress_list.dart b/cw_wownero/lib/wownero_subaddress_list.dart index 2ef4f2045..876e4bfcf 100644 --- a/cw_wownero/lib/wownero_subaddress_list.dart +++ b/cw_wownero/lib/wownero_subaddress_list.dart @@ -1,4 +1,5 @@ import 'package:cw_core/subaddress.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_wownero/api/coins_info.dart'; import 'package:cw_wownero/api/subaddress_list.dart' as subaddress_list; import 'package:cw_wownero/api/wallet.dart'; @@ -95,7 +96,7 @@ abstract class WowneroSubaddressListBase with Store { _isRefreshing = false; } on PlatformException catch (e) { _isRefreshing = false; - print(e); + printV(e); rethrow; } } diff --git a/cw_wownero/lib/wownero_wallet.dart b/cw_wownero/lib/wownero_wallet.dart index 5927d6434..c4c79af11 100644 --- a/cw_wownero/lib/wownero_wallet.dart +++ b/cw_wownero/lib/wownero_wallet.dart @@ -15,6 +15,7 @@ import 'package:cw_core/sync_status.dart'; import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coins_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wownero_amount_format.dart'; @@ -161,7 +162,7 @@ abstract class WowneroWalletBase Future? updateBalance() => null; @override - Future close({required bool shouldCleanup}) async { + Future close({bool shouldCleanup = false}) async { _listener?.stop(); _onAccountChangeReaction?.reaction.dispose(); _onTxHistoryChangeReaction?.reaction.dispose(); @@ -185,7 +186,7 @@ abstract class WowneroWalletBase syncStatus = ConnectedSyncStatus(); } catch (e) { syncStatus = FailedSyncStatus(); - print(e); + printV(e); } } @@ -216,7 +217,7 @@ abstract class WowneroWalletBase _listener?.start(); } catch (e) { syncStatus = FailedSyncStatus(); - print(e); + printV(e); rethrow; } } @@ -349,8 +350,8 @@ abstract class WowneroWalletBase try { await backupWalletFiles(name); } catch (e) { - print("¯\\_(ツ)_/¯"); - print(e); + printV("¯\\_(ツ)_/¯"); + printV(e); } } @@ -359,7 +360,7 @@ abstract class WowneroWalletBase final currentWalletDirPath = await pathForWalletDir(name: name, type: type); if (openedWalletsByPath["$currentWalletDirPath/$name"] != null) { // NOTE: this is realistically only required on windows. - print("closing wallet"); + printV("closing wallet"); final wmaddr = wmPtr.address; final waddr = openedWalletsByPath["$currentWalletDirPath/$name"]!.address; await Isolate.run(() { @@ -367,7 +368,7 @@ abstract class WowneroWalletBase Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), true); }); openedWalletsByPath.remove("$currentWalletDirPath/$name"); - print("wallet closed"); + printV("wallet closed"); } try { // -- rename the waller folder -- @@ -499,7 +500,7 @@ abstract class WowneroWalletBase await _refreshUnspentCoinsInfo(); _askForUpdateBalance(); } catch (e, s) { - print(e.toString()); + printV(e.toString()); onError?.call(FlutterErrorDetails( exception: e, stack: s, @@ -546,7 +547,7 @@ abstract class WowneroWalletBase await unspentCoinsInfo.deleteAll(keys); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -577,7 +578,7 @@ abstract class WowneroWalletBase await transactionHistory.save(); _isTransactionUpdating = false; } catch (e) { - print(e); + printV(e); _isTransactionUpdating = false; } } @@ -717,7 +718,7 @@ abstract class WowneroWalletBase syncStatus = SyncingSyncStatus(blocksLeft, ptc); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -727,7 +728,7 @@ abstract class WowneroWalletBase _askForUpdateBalance(); await Future.delayed(Duration(seconds: 1)); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/cw_wownero/lib/wownero_wallet_addresses.dart b/cw_wownero/lib/wownero_wallet_addresses.dart index eed81eb45..0b2ade073 100644 --- a/cw_wownero/lib/wownero_wallet_addresses.dart +++ b/cw_wownero/lib/wownero_wallet_addresses.dart @@ -1,6 +1,7 @@ import 'package:cw_core/account.dart'; import 'package:cw_core/address_info.dart'; import 'package:cw_core/subaddress.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_addresses.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_wownero/api/transaction_history.dart'; @@ -94,7 +95,7 @@ abstract class WowneroWalletAddressesBase extends WalletAddresses with Store { await saveAddressesInBox(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/cw_wownero/lib/wownero_wallet_service.dart b/cw_wownero/lib/wownero_wallet_service.dart index 6f0fafc88..1cd462cd9 100644 --- a/cw_wownero/lib/wownero_wallet_service.dart +++ b/cw_wownero/lib/wownero_wallet_service.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/unspent_coins_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; @@ -99,7 +100,7 @@ class WowneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('WowneroWalletsManager Error: ${e.toString()}'); + printV('WowneroWalletsManager Error: ${e.toString()}'); rethrow; } } @@ -111,7 +112,7 @@ class WowneroWalletService extends WalletService< return wownero_wallet_manager.isWalletExist(path: path); } catch (e) { // TODO: Implement Exception for wallet list service. - print('WowneroWalletsManager Error: $e'); + printV('WowneroWalletsManager Error: $e'); rethrow; } } @@ -182,7 +183,7 @@ class WowneroWalletService extends WalletService< final path = await pathForWalletDir(name: wallet, type: getType()); if (openedWalletsByPath["$path/$wallet"] != null) { // NOTE: this is realistically only required on windows. - print("closing wallet"); + printV("closing wallet"); final wmaddr = wmPtr.address; final waddr = openedWalletsByPath["$path/$wallet"]!.address; // await Isolate.run(() { @@ -190,7 +191,7 @@ class WowneroWalletService extends WalletService< Pointer.fromAddress(wmaddr), Pointer.fromAddress(waddr), false); // }); openedWalletsByPath.remove("$path/$wallet"); - print("wallet closed"); + printV("wallet closed"); } final file = Directory(path); @@ -241,7 +242,7 @@ class WowneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('WowneroWalletsManager Error: $e'); + printV('WowneroWalletsManager Error: $e'); rethrow; } } @@ -274,7 +275,7 @@ class WowneroWalletService extends WalletService< return wallet; } catch (e) { // TODO: Implement Exception for wallet list service. - print('WowneroWalletsManager Error: $e'); + printV('WowneroWalletsManager Error: $e'); rethrow; } } @@ -291,7 +292,7 @@ class WowneroWalletService extends WalletService< path, credentials.password!, polyseed, credentials.walletInfo!, lang); } catch (e) { // TODO: Implement Exception for wallet list service. - print('WowneroWalletsManager Error: $e'); + printV('WowneroWalletsManager Error: $e'); rethrow; } } @@ -348,7 +349,7 @@ class WowneroWalletService extends WalletService< newFile.writeAsBytesSync(file.readAsBytesSync()); }); } catch (e) { - print(e.toString()); + printV(e.toString()); } } } diff --git a/cw_wownero/pubspec.lock b/cw_wownero/pubspec.lock index a861c6bac..1e16fa089 100644 --- a/cw_wownero/pubspec.lock +++ b/cw_wownero/pubspec.lock @@ -21,18 +21,18 @@ packages: dependency: transitive description: name: args - sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.6.0" asn1lib: dependency: transitive description: name: asn1lib - sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039 + sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.5" async: dependency: transitive description: @@ -53,10 +53,10 @@ packages: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" build_config: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: build_daemon - sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.2" build_resolvers: dependency: "direct dev" description: @@ -85,18 +85,18 @@ packages: dependency: "direct dev" description: name: build_runner - sha256: "3ac61a79bfb6f6cc11f693591063a7f19a7af628dc52f141743edac5c16e8c22" + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.4.9" + version: "2.4.13" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292" + sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" url: "https://pub.dev" source: hosted - version: "7.2.7" + version: "7.2.10" built_collection: dependency: transitive description: @@ -109,10 +109,10 @@ packages: dependency: transitive description: name: built_value - sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725" + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.4.3" + version: "8.9.2" cake_backup: dependency: transitive description: @@ -134,10 +134,10 @@ packages: dependency: transitive description: name: checked_yaml - sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311" + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.0.3" clock: dependency: transitive description: @@ -150,10 +150,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.10.0" collection: dependency: transitive description: @@ -166,26 +166,26 @@ packages: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" cryptography: dependency: transitive description: name: cryptography - sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35 + sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05 url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.7.0" cupertino_icons: dependency: transitive description: @@ -213,10 +213,10 @@ packages: dependency: "direct main" description: name: encrypt - sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb" + sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.0.3" fake_async: dependency: transitive description: @@ -229,26 +229,26 @@ packages: dependency: "direct main" description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter @@ -258,10 +258,10 @@ packages: dependency: "direct main" description: name: flutter_mobx - sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e" + sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e" url: "https://pub.dev" source: hosted - version: "2.0.6+5" + version: "2.2.1+1" flutter_test: dependency: "direct dev" description: flutter @@ -271,10 +271,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: @@ -287,26 +287,26 @@ packages: dependency: transitive description: name: graphs - sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.2" hashlib: dependency: transitive description: name: hashlib - sha256: d41795742c10947930630118c6836608deeb9047cd05aee32d2baeb697afd66a + sha256: f572f2abce09fc7aee53f15927052b9732ea1053e540af8cae211111ee0b99b1 url: "https://pub.dev" source: hosted - version: "1.19.2" + version: "1.21.0" hashlib_codecs: dependency: transitive description: name: hashlib_codecs - sha256: "2b570061f5a4b378425be28a576c1e11783450355ad4345a19f606ff3d96db0f" + sha256: "8cea9ccafcfeaa7324d2ae52c61c69f7ff71f4237507a018caab31b9e416e3b1" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" hive: dependency: transitive description: @@ -327,10 +327,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -351,10 +351,10 @@ packages: dependency: "direct main" description: name: intl - sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf url: "https://pub.dev" source: hosted - version: "0.18.1" + version: "0.19.0" io: dependency: transitive description: @@ -375,42 +375,42 @@ packages: dependency: transitive description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.9.0" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" url: "https://pub.dev" source: hosted - version: "10.0.0" + version: "10.0.5" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.5" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "3.0.1" logging: dependency: transitive description: name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.3.0" matcher: dependency: transitive description: @@ -423,48 +423,48 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.11.1" meta: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.15.0" mime: dependency: transitive description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" mobx: dependency: "direct main" description: name: mobx - sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a + sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e" url: "https://pub.dev" source: hosted - version: "2.1.3+1" + version: "2.3.3+2" mobx_codegen: dependency: "direct dev" description: name: mobx_codegen - sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181" + sha256: d4beb9cea4b7b014321235f8fdc7c2193ee0fe1d1198e9da7403f8bc85c4407c url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.0" monero: dependency: "direct main" description: path: "impls/monero.dart" - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 - resolved-ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 + ref: af5277f96073917185864d3596e82b67bee54e78 + resolved-ref: af5277f96073917185864d3596e82b67bee54e78 url: "https://github.com/mrcyjanek/monero_c" source: git version: "0.0.0" @@ -476,6 +476,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -496,26 +504,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.4" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72 + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.12" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.0" path_provider_linux: dependency: transitive description: @@ -528,26 +536,26 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: @@ -560,10 +568,10 @@ packages: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.9.1" polyseed: dependency: "direct main" description: @@ -580,38 +588,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a" + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" shelf: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611" url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.0" sky_engine: dependency: transitive description: flutter @@ -621,10 +637,10 @@ packages: dependency: transitive description: name: socks5_proxy - sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a" + sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.6" source_gen: dependency: transitive description: @@ -693,10 +709,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.6.1" + version: "0.7.2" timing: dependency: transitive description: @@ -717,10 +733,10 @@ packages: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" unorm_dart: dependency: transitive description: @@ -741,10 +757,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "14.2.4" watcher: dependency: "direct overridden" description: @@ -753,38 +769,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.3.0" - win32: - dependency: transitive - description: - name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 - url: "https://pub.dev" - source: hosted - version: "3.1.3" + version: "3.0.1" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" yaml: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=3.2.0-0 <4.0.0" - flutter: ">=3.7.0" + dart: ">=3.5.0 <4.0.0" + flutter: ">=3.24.0" diff --git a/cw_wownero/pubspec.yaml b/cw_wownero/pubspec.yaml index 28ece82ef..a92f530f6 100644 --- a/cw_wownero/pubspec.yaml +++ b/cw_wownero/pubspec.yaml @@ -17,7 +17,7 @@ dependencies: path_provider: ^2.0.11 mobx: ^2.0.7+4 flutter_mobx: ^2.0.6+1 - intl: ^0.18.0 + intl: ^0.19.0 encrypt: ^5.0.1 polyseed: ^0.0.6 cw_core: @@ -25,7 +25,7 @@ dependencies: monero: git: url: https://github.com/mrcyjanek/monero_c - ref: d72c15f4339791a7bbdf17e9d827b7b56ca144e4 + ref: af5277f96073917185864d3596e82b67bee54e78 # ref: 6eb571ea498ed7b854934785f00fabfd0dadf75b # monero_c hash path: impls/monero.dart mutex: ^3.1.0 diff --git a/how_to_add_new_wallet_type.md b/how_to_add_new_wallet_type.md index d71e181e0..74350e5d8 100644 --- a/how_to_add_new_wallet_type.md +++ b/how_to_add_new_wallet_type.md @@ -23,7 +23,7 @@ - Add the code to run the code generation needed for the files in the `cw_walletx` package to the `model_generator.sh` script - cd cw_walletx && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. + cd cw_walletx && flutter pub get && dart run build_runner build --delete-conflicting-outputs && cd .. - Add the relevant dev_dependencies for generating the files also - build_runner @@ -78,9 +78,9 @@ A `Proxy` class is used to communicate with the specific wallet package we have. ./app_config.sh - cd cw_walletx && flutter pub get && flutter packages pub run build_runner build + cd cw_walletx && flutter pub get && dart run build_runner build - flutter packages pub run build_runner build --delete-conflicting-outputs + dart run build_runner build --delete-conflicting-outputs Moving forward, our interactions with the cw_walletx package would be through the proxy class and its methods. @@ -191,9 +191,9 @@ You can add as many node entries as desired. - Run the following commands after to generate modified files in cw_core and lib - cd cw_core && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd .. + cd cw_core && flutter pub get && dart run build_runner build --delete-conflicting-outputs && cd .. - flutter packages pub run build_runner build --delete-conflicting-outputs + dart run build_runner build --delete-conflicting-outputs - Lastly, before we run the app to test what we’ve done so far, - Go to `lib/src/dashboard/widgets/menu_widget.dart` and add an icon for walletX to be used within the app. diff --git a/howto-build-android.md b/howto-build-android.md index 57d29f459..5afecfba3 100644 --- a/howto-build-android.md +++ b/howto-build-android.md @@ -8,7 +8,7 @@ The following are the system requirements to build Cake Wallet for your Android Ubuntu >= 20.04 Android SDK 29 or higher (better to have the latest one 33) Android NDK 17c -Flutter 3.19.x +Flutter 3.24.4 ``` ### 1. Installing Package Dependencies @@ -51,7 +51,7 @@ You may download and install the latest version of Android Studio [here](https:/ ### 3. Installing Flutter -Install Flutter with version `3.19.x`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually). +Install Flutter with version `3.24.4`. For this please check section [Install Flutter manually](https://docs.flutter.dev/get-started/install/linux#install-flutter-manually). ### 4. Installing rustup @@ -66,7 +66,7 @@ Verify that the Android toolchain, Flutter, and Android Studio have been correct The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding. ``` Doctor summary (to see all details, run flutter doctor -v): -[✓] Flutter (Channel stable, 3.19.x, on Linux, locale en_US.UTF-8) +[✓] Flutter (Channel stable, 3.24.4, on Linux, locale en_US.UTF-8) [✓] Android toolchain - develop for Android devices (Android SDK version 29 or higher) [✓] Android Studio (version 4.0 or higher) ``` @@ -126,17 +126,17 @@ Install Flutter package dependencies with this command: Your Cake Wallet binary will be built with cryptographic salts, which are used for secure encryption of your data. You may generate these secret salts with the following command: -`$ flutter packages pub run tool/generate_new_secrets.dart` +`$ dart run tool/generate_new_secrets.dart` Next, we must generate key properties based on the secure keystore you generated for Android (in step 5). **MODIFY THE FOLLOWING COMMAND** with the "store password" and "key password" you assigned when creating your keystore (in step 5). -`$ flutter packages pub run tool/generate_android_key_properties.dart keyAlias=key storeFile=$HOME/key.jks storePassword= keyPassword=` +`$ dart run tool/generate_android_key_properties.dart keyAlias=key storeFile=$HOME/key.jks storePassword= keyPassword=` **REMINDER:** The *above* command will **not** succeed unless you replaced the `storePassword` and `keyPassword` variables with the correct passwords for your keystore. Then we need to generate localization files. -`$ flutter packages pub run tool/generate_localization.dart` +`$ dart run tool/generate_localization.dart` Finally build mobx models for the app: diff --git a/howto-build-ios.md b/howto-build-ios.md index 544d4359e..753e17e93 100644 --- a/howto-build-ios.md +++ b/howto-build-ios.md @@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your iOS devi ``` macOS >= 14.0 Xcode 15.3 -Flutter 3.19.x +Flutter 3.24.4 ``` ### 1. Installing Package Dependencies @@ -26,7 +26,7 @@ You may download and install the latest version of [Xcode](https://developer.app ### 3. Installing Flutter -Need to install flutter with version `3.19.x`. For this please check section [Install Flutter](https://docs.flutter.dev/get-started/install/macos/mobile-ios?tab=download). +Need to install flutter with version `3.24.4`. For this please check section [Install Flutter](https://docs.flutter.dev/get-started/install/macos/mobile-ios?tab=download). ### 4. Installing rustup @@ -41,7 +41,7 @@ Verify that the Flutter and Xcode have been correctly installed on your system w The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding. ``` Doctor summary (to see all details, run flutter doctor -v): -[✓] Flutter (Channel stable, 3.19.x, on macOS 14.x.x) +[✓] Flutter (Channel stable, 3.24.4, on macOS 14.x.x) [✓] Xcode - develop for iOS and macOS (Xcode 15.3) ``` @@ -82,7 +82,7 @@ Install Flutter package dependencies with this command: Your Cake Wallet binary will be built with cryptographic salts, which are used for secure encryption of your data. You may generate these secret salts with the following command: -`$ flutter packages pub run tool/generate_new_secrets.dart` +`$ dart run tool/generate_new_secrets.dart` Then we need to generate localization files and mobx models. diff --git a/howto-build-macos.md b/howto-build-macos.md index 2e535e5be..a497e1ffa 100644 --- a/howto-build-macos.md +++ b/howto-build-macos.md @@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your macOS de ``` macOS >= 14.0 Xcode 15.3 -Flutter 3.19.x +Flutter 3.24.4 ``` ### 1. Installing Package Dependencies @@ -28,7 +28,7 @@ You may download and install the latest version of [Xcode](https://developer.app ### 3. Installing Flutter -Need to install flutter with version `3.19.x`. For this please check section [Install Flutter](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download). +Need to install flutter with version `3.24.4`. For this please check section [Install Flutter](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download). ### 4. Installing rustup @@ -43,7 +43,7 @@ Verify that Flutter and Xcode have been correctly installed on your system with The output of this command will appear like this, indicating successful installations. If there are problems with your installation, they **must** be corrected before proceeding. ``` Doctor summary (to see all details, run flutter doctor -v): -[✓] Flutter (Channel stable, 3.19.x, on macOS 14.x.x) +[✓] Flutter (Channel stable, 3.24.4, on macOS 14.x.x) [✓] Xcode - develop for iOS and macOS (Xcode 15.3) ``` @@ -93,7 +93,7 @@ Install Flutter package dependencies with this command: Your Cake Wallet binary will be built with cryptographic salts, which are used for secure encryption of your data. You may generate these secret salts with the following command: -`$ flutter packages pub run tool/generate_new_secrets.dart` +`$ dart run tool/generate_new_secrets.dart` Then we need to generate localization files and mobx models. diff --git a/howto-build-windows.md b/howto-build-windows.md index 504f8f785..3ebecaa61 100644 --- a/howto-build-windows.md +++ b/howto-build-windows.md @@ -6,12 +6,12 @@ The following are the system requirements to build CakeWallet for your Windows P ``` Windows 10 or later (64-bit), x86-64 based -Flutter 3.19.x +Flutter 3.24.4 ``` ### 1. Installing Flutter -Install Flutter with version `3.19.x`. Follow the Flutter [installation guide](https://docs.flutter.dev/get-started/install/windows). +Install Flutter with version `3.24.4`. Follow the Flutter [installation guide](https://docs.flutter.dev/get-started/install/windows). ### 2. Install Development Tools diff --git a/integration_test/components/common_test_constants.dart b/integration_test/components/common_test_constants.dart index 302d52189..6ace69b45 100644 --- a/integration_test/components/common_test_constants.dart +++ b/integration_test/components/common_test_constants.dart @@ -4,10 +4,10 @@ import 'package:cw_core/wallet_type.dart'; class CommonTestConstants { static final pin = [0, 8, 0, 1]; static final String sendTestAmount = '0.00008'; - static final String exchangeTestAmount = '8'; + static final String exchangeTestAmount = '0.01'; static final WalletType testWalletType = WalletType.solana; static final String testWalletName = 'Integrated Testing Wallet'; - static final CryptoCurrency testReceiveCurrency = CryptoCurrency.sol; - static final CryptoCurrency testDepositCurrency = CryptoCurrency.usdtSol; + static final CryptoCurrency testReceiveCurrency = CryptoCurrency.usdtSol; + static final CryptoCurrency testDepositCurrency = CryptoCurrency.sol; static final String testWalletAddress = '5v9gTW1yWPffhnbNKuvtL2frevAf4HpBMw8oYnfqUjhm'; } diff --git a/integration_test/components/common_test_flows.dart b/integration_test/components/common_test_flows.dart index 82f714da0..8350b5859 100644 --- a/integration_test/components/common_test_flows.dart +++ b/integration_test/components/common_test_flows.dart @@ -7,6 +7,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:cake_wallet/main.dart' as app; +import '../robots/create_pin_welcome_page_robot.dart'; import '../robots/dashboard_page_robot.dart'; import '../robots/disclaimer_page_robot.dart'; import '../robots/new_wallet_page_robot.dart'; @@ -37,6 +38,7 @@ class CommonTestFlows { _walletListPageRobot = WalletListPageRobot(_tester), _newWalletTypePageRobot = NewWalletTypePageRobot(_tester), _restoreOptionsPageRobot = RestoreOptionsPageRobot(_tester), + _createPinWelcomePageRobot = CreatePinWelcomePageRobot(_tester), _restoreFromSeedOrKeysPageRobot = RestoreFromSeedOrKeysPageRobot(_tester), _walletGroupDescriptionPageRobot = WalletGroupDescriptionPageRobot(_tester); @@ -53,6 +55,7 @@ class CommonTestFlows { final WalletListPageRobot _walletListPageRobot; final NewWalletTypePageRobot _newWalletTypePageRobot; final RestoreOptionsPageRobot _restoreOptionsPageRobot; + final CreatePinWelcomePageRobot _createPinWelcomePageRobot; final RestoreFromSeedOrKeysPageRobot _restoreFromSeedOrKeysPageRobot; final WalletGroupDescriptionPageRobot _walletGroupDescriptionPageRobot; @@ -190,10 +193,12 @@ class CommonTestFlows { WalletType walletTypeToCreate, List pin, ) async { - await _welcomePageRobot.navigateToCreateNewWalletPage(); + await _createPinWelcomePageRobot.tapSetAPinButton(); await setupPinCodeForWallet(pin); + await _welcomePageRobot.navigateToCreateNewWalletPage(); + await _selectWalletTypeForWallet(walletTypeToCreate); } @@ -201,12 +206,14 @@ class CommonTestFlows { WalletType walletTypeToRestore, List pin, ) async { + await _createPinWelcomePageRobot.tapSetAPinButton(); + + await setupPinCodeForWallet(pin); + await _welcomePageRobot.navigateToRestoreWalletPage(); await _restoreOptionsPageRobot.navigateToRestoreFromSeedsOrKeysPage(); - await setupPinCodeForWallet(pin); - await _selectWalletTypeForWallet(walletTypeToRestore); } diff --git a/integration_test/robots/create_pin_welcome_page_robot.dart b/integration_test/robots/create_pin_welcome_page_robot.dart new file mode 100644 index 000000000..ca136cb38 --- /dev/null +++ b/integration_test/robots/create_pin_welcome_page_robot.dart @@ -0,0 +1,53 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/welcome/create_pin_welcome_page.dart'; +import 'package:cake_wallet/wallet_type_utils.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import '../components/common_test_cases.dart'; + +class CreatePinWelcomePageRobot { + CreatePinWelcomePageRobot(this.tester) : commonTestCases = CommonTestCases(tester); + + final WidgetTester tester; + late CommonTestCases commonTestCases; + + Future isCreatePinWelcomePage() async { + await commonTestCases.isSpecificPage(); + } + + void hasTitle() { + String title; + if (isMoneroOnly) { + title = S.current.monero_com; + } + + if (isHaven) { + title = S.current.haven_app; + } + + title = S.current.cake_wallet; + + commonTestCases.hasText(title); + } + + void hasDescription() { + String description; + if (isMoneroOnly) { + description = S.current.monero_com_wallet_text; + } + + if (isHaven) { + description = S.current.haven_app_wallet_text; + } + + description = S.current.new_first_wallet_text; + + commonTestCases.hasText(description); + } + + Future tapSetAPinButton() async { + await commonTestCases.tapItemByKey('create_pin_welcome_page_create_a_pin_button_key'); + + await commonTestCases.defaultSleepTime(); + } +} diff --git a/integration_test/robots/exchange_page_robot.dart b/integration_test/robots/exchange_page_robot.dart index e01b2df9c..a3378e293 100644 --- a/integration_test/robots/exchange_page_robot.dart +++ b/integration_test/robots/exchange_page_robot.dart @@ -123,10 +123,8 @@ class ExchangePageRobot { return; } - await commonTestCases.dragUntilVisible( - 'picker_items_index_${depositCurrency.name}_button_key', - 'picker_scrollbar_key', - ); + await commonTestCases.enterText(depositCurrency.name, 'search_bar_widget_key'); + await commonTestCases.defaultSleepTime(); await commonTestCases.tapItemByKey('picker_items_index_${depositCurrency.name}_button_key'); @@ -149,10 +147,8 @@ class ExchangePageRobot { return; } - await commonTestCases.dragUntilVisible( - 'picker_items_index_${receiveCurrency.name}_button_key', - 'picker_scrollbar_key', - ); + await commonTestCases.enterText(receiveCurrency.name, 'search_bar_widget_key'); + await commonTestCases.defaultSleepTime(); await commonTestCases.tapItemByKey('picker_items_index_${receiveCurrency.name}_button_key'); @@ -318,7 +314,7 @@ class ExchangePageRobot { Future handleErrors(String initialAmount) async { await tester.pumpAndSettle(); - + await _handleMinLimitError(initialAmount); await _handleMaxLimitError(initialAmount); diff --git a/integration_test/robots/send_page_robot.dart b/integration_test/robots/send_page_robot.dart index 20cef948d..f8e1a49ad 100644 --- a/integration_test/robots/send_page_robot.dart +++ b/integration_test/robots/send_page_robot.dart @@ -84,13 +84,11 @@ class SendPageRobot { return; } - await commonTestCases.dragUntilVisible( - 'picker_items_index_${receiveCurrency.name}_button_key', - 'picker_scrollbar_key', - ); + await commonTestCases.enterText(receiveCurrency.title, 'search_bar_widget_key'); + await commonTestCases.defaultSleepTime(); - await commonTestCases.tapItemByKey('picker_items_index_${receiveCurrency.name}_button_key'); + await commonTestCases.tapItemByKey('picker_items_index_${receiveCurrency.fullName}_button_key'); } Future enterReceiveAddress(String receiveAddress) async { @@ -210,6 +208,7 @@ class SendPageRobot { _handleAuthPage(); } } + await tester.pump(); } Future handleSendResult() async { @@ -366,4 +365,4 @@ class SendPageRobot { Future _onIgnoreButtonOnSentDialogPressed() async { await commonTestCases.tapItemByKey('send_page_sent_dialog_ignore_button_key'); } -} \ No newline at end of file +} diff --git a/integration_test/robots/wallet_keys_robot.dart b/integration_test/robots/wallet_keys_robot.dart index f6aeb3a66..189929737 100644 --- a/integration_test/robots/wallet_keys_robot.dart +++ b/integration_test/robots/wallet_keys_robot.dart @@ -42,11 +42,11 @@ class WalletKeysAndSeedPageRobot { bool hasPrivateKey = appStore.wallet!.privateKey != null; if (walletType == WalletType.monero) { - final moneroWallet = appStore.wallet as MoneroWallet; + final moneroWallet = appStore.wallet as MoneroWalletBase; final lang = PolyseedLang.getByPhrase(moneroWallet.seed); final legacySeed = moneroWallet.seedLegacy(lang.nameEnglish); - _confirmMoneroWalletCredentials( + await _confirmMoneroWalletCredentials( appStore, walletName, moneroWallet.seed, @@ -59,7 +59,7 @@ class WalletKeysAndSeedPageRobot { final lang = PolyseedLang.getByPhrase(wowneroWallet.seed); final legacySeed = wowneroWallet.seedLegacy(lang.nameEnglish); - _confirmMoneroWalletCredentials( + await _confirmMoneroWalletCredentials( appStore, walletName, wowneroWallet.seed, @@ -105,12 +105,12 @@ class WalletKeysAndSeedPageRobot { await commonTestCases.defaultSleepTime(seconds: 5); } - void _confirmMoneroWalletCredentials( + Future _confirmMoneroWalletCredentials( AppStore appStore, String walletName, String seed, String legacySeed, - ) { + ) async { final keys = appStore.wallet!.keys as MoneroWalletKeys; final hasPublicSpendKey = commonTestCases.isKeyPresent( @@ -145,10 +145,18 @@ class WalletKeysAndSeedPageRobot { tester.printToConsole('$walletName wallet has private view key properly displayed'); } if (hasSeeds) { + await commonTestCases.dragUntilVisible( + '${walletName}_wallet_seed_item_key', + 'wallet_keys_page_credentials_list_view_key', + ); commonTestCases.hasText(seed); tester.printToConsole('$walletName wallet has seeds properly displayed'); } if (hasSeedLegacy) { + await commonTestCases.dragUntilVisible( + '${walletName}_wallet_seed_legacy_item_key', + 'wallet_keys_page_credentials_list_view_key', + ); commonTestCases.hasText(legacySeed); tester.printToConsole('$walletName wallet has legacy seeds properly displayed'); } diff --git a/integration_test/test_suites/confirm_seeds_flow_test.dart b/integration_test/test_suites/confirm_seeds_flow_test.dart index bf6fd5a5f..2d11a2cc4 100644 --- a/integration_test/test_suites/confirm_seeds_flow_test.dart +++ b/integration_test/test_suites/confirm_seeds_flow_test.dart @@ -101,7 +101,7 @@ Future _confirmSeedsFlowForWalletType( walletKeysAndSeedPageRobot.hasTitle(); walletKeysAndSeedPageRobot.hasShareWarning(); - walletKeysAndSeedPageRobot.confirmWalletCredentials(walletType); + await walletKeysAndSeedPageRobot.confirmWalletCredentials(walletType); await walletKeysAndSeedPageRobot.backToDashboard(); } diff --git a/integration_test_runner.sh b/integration_test_runner.sh new file mode 100755 index 000000000..34c9227c0 --- /dev/null +++ b/integration_test_runner.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +declare -a targets +declare -a passed_tests +declare -a failed_tests + +# Collect all Dart test files in the integration_test directory +while IFS= read -r -d $'\0' file; do + targets+=("$file") +done < <(find integration_test/test_suites -name "*.dart" -type f -print0) + +# Run each test and collect results +for target in "${targets[@]}" +do + echo "Running test: $target" + if flutter drive \ + --driver=test_driver/integration_test.dart \ + --target="$target"; then + echo "✅ Test passed: $target" + passed_tests+=("$target") + else + echo "❌ Test failed: $target" + failed_tests+=("$target") + fi +done + +# Provide a summary of test results +echo -e "\n===== Test Summary =====" +if [ ${#passed_tests[@]} -gt 0 ]; then + echo "✅ Passed Tests:" + for test in "${passed_tests[@]}"; do + echo " - $test" + done +fi + +if [ ${#failed_tests[@]} -gt 0 ]; then + echo -e "\n❌ Failed Tests:" + for test in "${failed_tests[@]}"; do + echo " - $test" + done + # Exit with a non-zero status to indicate failure + exit 1 +else + echo -e "\n🎉 All tests passed successfully!" +fi diff --git a/ios/Podfile.lock b/ios/Podfile.lock index abcac01fb..8046ba307 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -2,7 +2,7 @@ PODS: - connectivity_plus (0.0.1): - Flutter - ReachabilitySwift - - CryptoSwift (1.8.2) + - CryptoSwift (1.8.3) - cw_haven (0.0.1): - cw_haven/Boost (= 0.0.1) - cw_haven/Haven (= 0.0.1) @@ -81,10 +81,10 @@ PODS: - flutter_inappwebview_ios (0.0.1): - Flutter - flutter_inappwebview_ios/Core (= 0.0.1) - - OrderedSet (~> 5.0) + - OrderedSet (~> 6.0.3) - flutter_inappwebview_ios/Core (0.0.1): - Flutter - - OrderedSet (~> 5.0) + - OrderedSet (~> 6.0.3) - flutter_local_authentication (1.2.0): - Flutter - flutter_mailer (0.0.1): @@ -94,11 +94,11 @@ PODS: - fluttertoast (0.0.2): - Flutter - Toast - - in_app_review (0.2.0): + - in_app_review (2.0.0): - Flutter - integration_test (0.0.1): - Flutter - - OrderedSet (5.0.0) + - OrderedSet (6.0.3) - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -106,7 +106,7 @@ PODS: - FlutterMacOS - permission_handler_apple (9.1.1): - Flutter - - ReachabilitySwift (5.2.3) + - ReachabilitySwift (5.2.4) - SDWebImage (5.19.7): - SDWebImage/Core (= 5.19.7) - SDWebImage/Core (5.19.7) @@ -238,33 +238,33 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d - CryptoSwift: c63a805d8bb5e5538e88af4e44bb537776af11ea + CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483 cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a cw_mweb: 87af74f9659fed0c1a2cbfb44413f1070e79e3ae cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 - devicelocale: b22617f40038496deffba44747101255cee005b0 + devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926 DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_inappwebview_ios: 97215cf7d4677db55df76782dbd2930c5e1c1ea0 + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - fluttertoast: 48c57db1b71b0ce9e6bba9f31c940ff4b001293c - in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d - integration_test: 13825b8a9334a850581300559b8839134b124670 - OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c - package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c + in_app_review: a31b5257259646ea78e0e35fc914979b0031d011 + integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 + package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 - ReachabilitySwift: 7f151ff156cea1481a8411701195ac6a984f4979 + ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3 sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986 - share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad + share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 diff --git a/ios/Runner/AppDelegate.swift b/ios/Runner/AppDelegate.swift index 675d7244a..e595d2a0c 100644 --- a/ios/Runner/AppDelegate.swift +++ b/ios/Runner/AppDelegate.swift @@ -2,7 +2,7 @@ import UIKit import Flutter import workmanager -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, diff --git a/ios/ZanoWallet.framework/ZanoWallet b/ios/ZanoWallet.framework/ZanoWallet new file mode 100644 index 000000000..701878274 Binary files /dev/null and b/ios/ZanoWallet.framework/ZanoWallet differ diff --git a/ios/zano_libwallet2_api_c.dylib b/ios/zano_libwallet2_api_c.dylib new file mode 120000 index 000000000..ed324a208 --- /dev/null +++ b/ios/zano_libwallet2_api_c.dylib @@ -0,0 +1 @@ +../scripts/monero_c/release/zano/host-apple-ios_libwallet2_api_c.dylib \ No newline at end of file diff --git a/lib/anypay/anypay_api.dart b/lib/anypay/anypay_api.dart index 8af3be08c..0b81d24c2 100644 --- a/lib/anypay/anypay_api.dart +++ b/lib/anypay/anypay_api.dart @@ -56,7 +56,7 @@ class AnyPayApi { final response = await post(url, headers: headers, body: utf8.encode(json.encode(body))); if (response.statusCode != 200) { - ExceptionHandler.onError(FlutterErrorDetails(exception: response)); + await ExceptionHandler.onError(FlutterErrorDetails(exception: response)); throw Exception('Unexpected response http code: ${response.statusCode}'); } diff --git a/lib/bitcoin/cw_bitcoin.dart b/lib/bitcoin/cw_bitcoin.dart index 7ff525789..5e5ee5bce 100644 --- a/lib/bitcoin/cw_bitcoin.dart +++ b/lib/bitcoin/cw_bitcoin.dart @@ -404,8 +404,8 @@ class CWBitcoin extends Bitcoin { list.add(dInfoCopy); } catch (e, s) { - print("derivationInfoError: $e"); - print("derivationInfoStack: $s"); + printV("derivationInfoError: $e"); + printV("derivationInfoStack: $s"); } } } @@ -498,7 +498,7 @@ class CWBitcoin extends Bitcoin { try { return hardwareWalletService.getAvailableAccounts(index: index, limit: limit); } catch (err) { - print(err); + printV(err); throw err; } } @@ -510,7 +510,7 @@ class CWBitcoin extends Bitcoin { try { return hardwareWalletService.getAvailableAccounts(index: index, limit: limit); } catch (err) { - print(err); + printV(err); throw err; } } diff --git a/lib/buy/dfx/dfx_buy_provider.dart b/lib/buy/dfx/dfx_buy_provider.dart index c1ed762b1..c11a0d771 100644 --- a/lib/buy/dfx/dfx_buy_provider.dart +++ b/lib/buy/dfx/dfx_buy_provider.dart @@ -12,6 +12,7 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -136,7 +137,7 @@ class DFXBuyProvider extends BuyProvider { return {}; } } catch (e) { - print('DFX Error fetching fiat currencies: $e'); + printV('DFX Error fetching fiat currencies: $e'); return {}; } } @@ -266,19 +267,19 @@ class DFXBuyProvider extends BuyProvider { quote.setCryptoCurrency = cryptoCurrency; return [quote]; } else { - print('DFX: Unexpected data type: ${responseData.runtimeType}'); + printV('DFX: Unexpected data type: ${responseData.runtimeType}'); return null; } } else { if (responseData is Map && responseData.containsKey('message')) { - print('DFX Error: ${responseData['message']}'); + printV('DFX Error: ${responseData['message']}'); } else { - print('DFX Failed to fetch buy quote: ${response.statusCode}'); + printV('DFX Failed to fetch buy quote: ${response.statusCode}'); } return null; } } catch (e) { - print('DFX Error fetching buy quote: $e'); + printV('DFX Error fetching buy quote: $e'); return null; } } diff --git a/lib/buy/meld/meld_buy_provider.dart b/lib/buy/meld/meld_buy_provider.dart index 1ac3931d1..a9759aab8 100644 --- a/lib/buy/meld/meld_buy_provider.dart +++ b/lib/buy/meld/meld_buy_provider.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:flutter/material.dart'; import 'dart:developer'; @@ -75,11 +76,11 @@ class MeldBuyProvider extends BuyProvider { data.map((e) => PaymentMethod.fromMeldJson(e as Map)).toList(); return paymentMethods; } else { - print('Meld: Failed to fetch payment types'); + printV('Meld: Failed to fetch payment types'); return List.empty(); } } catch (e) { - print('Meld: Failed to fetch payment types: $e'); + printV('Meld: Failed to fetch payment types: $e'); return List.empty(); } } @@ -132,7 +133,7 @@ class MeldBuyProvider extends BuyProvider { return null; } } catch (e) { - print('Error fetching buy quote: $e'); + printV('Error fetching buy quote: $e'); return null; } } diff --git a/lib/buy/moonpay/moonpay_provider.dart b/lib/buy/moonpay/moonpay_provider.dart index b93c0f02d..5794e0794 100644 --- a/lib/buy/moonpay/moonpay_provider.dart +++ b/lib/buy/moonpay/moonpay_provider.dart @@ -18,6 +18,7 @@ import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -113,11 +114,11 @@ class MoonPayProvider extends BuyProvider { if (response.statusCode == 200) { return jsonDecode(response.body) as Map; } else { - print('MoonPay does not support fiat: $fiatCurrency'); + printV('MoonPay does not support fiat: $fiatCurrency'); return {}; } } catch (e) { - print('MoonPay Error fetching fiat currencies: $e'); + printV('MoonPay Error fetching fiat currencies: $e'); return {}; } } @@ -204,11 +205,11 @@ class MoonPayProvider extends BuyProvider { return [quote]; } else { - print('Moon Pay: Error fetching buy quote: '); + printV('Moon Pay: Error fetching buy quote: '); return null; } } catch (e) { - print('Moon Pay: Error fetching buy quote: $e'); + printV('Moon Pay: Error fetching buy quote: $e'); return null; } } diff --git a/lib/buy/onramper/onramper_buy_provider.dart b/lib/buy/onramper/onramper_buy_provider.dart index dade41d43..f229cb833 100644 --- a/lib/buy/onramper/onramper_buy_provider.dart +++ b/lib/buy/onramper/onramper_buy_provider.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; @@ -67,11 +68,11 @@ class OnRamperBuyProvider extends BuyProvider { .map((item) => PaymentMethod.fromOnramperJson(item as Map)) .toList(); } else { - print('Failed to fetch available payment types'); + printV('Failed to fetch available payment types'); return []; } } catch (e) { - print('Failed to fetch available payment types: $e'); + printV('Failed to fetch available payment types: $e'); return []; } } @@ -98,11 +99,11 @@ class OnRamperBuyProvider extends BuyProvider { return result; } else { - print('Failed to fetch onramp metadata'); + printV('Failed to fetch onramp metadata'); return {}; } } catch (e) { - print('Error occurred: $e'); + printV('Error occurred: $e'); return {}; } } @@ -178,11 +179,11 @@ class OnRamperBuyProvider extends BuyProvider { return validQuotes; } else { - print('Onramper: Failed to fetch rate'); + printV('Onramper: Failed to fetch rate'); return null; } } catch (e) { - print('Onramper: Failed to fetch rate $e'); + printV('Onramper: Failed to fetch rate $e'); return null; } } @@ -248,11 +249,18 @@ class OnRamperBuyProvider extends BuyProvider { String _tagToNetwork(String tag) { switch (tag) { case 'OMNI': + case 'BSC': return tag; case 'POL': return 'POLYGON'; - default: - return CryptoCurrency.fromString(tag).fullName ?? tag; + case 'ZEC': + return 'ZCASH'; + default: + try { + return CryptoCurrency.fromString(tag).fullName!; + } catch (_) { + return tag; + } } } diff --git a/lib/buy/robinhood/robinhood_buy_provider.dart b/lib/buy/robinhood/robinhood_buy_provider.dart index e8de5a59c..271b9c090 100644 --- a/lib/buy/robinhood/robinhood_buy_provider.dart +++ b/lib/buy/robinhood/robinhood_buy_provider.dart @@ -13,6 +13,7 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -145,7 +146,7 @@ class RobinhoodBuyProvider extends BuyProvider { if (paymentType != null && paymentType != PaymentType.all) { paymentMethod = normalizePaymentMethod(paymentType); - if (paymentMethod == null) paymentMethod = paymentType.name; + if (paymentMethod == null) return null; } final action = isBuyAction ? 'buy' : 'sell'; @@ -176,7 +177,7 @@ class RobinhoodBuyProvider extends BuyProvider { if (responseData.containsKey('message')) { log('Robinhood Error: ${responseData['message']}'); } else { - print('Robinhood Failed to fetch $action quote: ${response.statusCode}'); + printV('Robinhood Failed to fetch $action quote: ${response.statusCode}'); } return null; } @@ -185,6 +186,7 @@ class RobinhoodBuyProvider extends BuyProvider { return null; } + // Supported payment methods: // ● buying_power // ● crypto_balance // ● debit_card diff --git a/lib/cake_pay/cake_pay_api.dart b/lib/cake_pay/cake_pay_api.dart index 1f91b338d..f9aa2f0f1 100644 --- a/lib/cake_pay/cake_pay_api.dart +++ b/lib/cake_pay/cake_pay_api.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:cake_wallet/cake_pay/cake_pay_order.dart'; import 'package:cake_wallet/cake_pay/cake_pay_user_credentials.dart'; import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cake_wallet/entities/country.dart'; import 'package:http/http.dart' as http; @@ -92,6 +93,9 @@ class CakePayApi { required int quantity, required String userEmail, required String token, + required bool confirmsNoVpn, + required bool confirmsVoidedRefund, + required bool confirmsTermsAgreed, }) async { final uri = Uri.https(baseCakePayUri, createOrderPath); final headers = { @@ -105,7 +109,10 @@ class CakePayApi { 'quantity': quantity, 'user_email': userEmail, 'token': token, - 'send_email': true + 'send_email': true, + 'confirms_no_vpn': confirmsNoVpn, + 'confirms_voided_refund': confirmsVoidedRefund, + 'confirms_terms_agreed': confirmsTermsAgreed, }; try { @@ -140,7 +147,7 @@ class CakePayApi { final response = await http.get(uri, headers: headers); - print('Response: ${response.statusCode}'); + printV('Response: ${response.statusCode}'); if (response.statusCode != 200) { throw Exception('Unexpected http status: ${response.statusCode}'); @@ -167,19 +174,17 @@ class CakePayApi { throw Exception('Unexpected http status: ${response.statusCode}'); } } catch (e) { - print('Caught exception: $e'); + printV('Caught exception: $e'); } } /// Get Countries - Future> getCountries( - {required String CSRFToken, required String authorization}) async { + Future> getCountries({required String apiKey}) async { final uri = Uri.https(baseCakePayUri, countriesPath); final headers = { 'accept': 'application/json', - 'authorization': authorization, - 'X-CSRFToken': CSRFToken, + 'Authorization': 'Api-Key $apiKey', }; final response = await http.get(uri, headers: headers); @@ -198,8 +203,7 @@ class CakePayApi { /// Get Vendors Future> getVendors({ - required String CSRFToken, - required String authorization, + required String apiKey, int? page, String? country, String? countryCode, @@ -226,14 +230,14 @@ class CakePayApi { var headers = { 'accept': 'application/json; charset=UTF-8', - 'authorization': authorization, - 'X-CSRFToken': CSRFToken, + 'Authorization': 'Api-Key $apiKey', }; var response = await http.get(uri, headers: headers); if (response.statusCode != 200) { - throw Exception(response.body); + throw Exception( + 'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}'); } final bodyJson = json.decode(response.body); diff --git a/lib/cake_pay/cake_pay_service.dart b/lib/cake_pay/cake_pay_service.dart index cf2ec254c..768588775 100644 --- a/lib/cake_pay/cake_pay_service.dart +++ b/lib/cake_pay/cake_pay_service.dart @@ -25,7 +25,7 @@ class CakePayService { /// Get Available Countries Future> getCountries() async => - await cakePayApi.getCountries(CSRFToken: CSRFToken, authorization: authorization); + await cakePayApi.getCountries(apiKey: cakePayApiKey); /// Get Vendors Future> getVendors({ @@ -40,8 +40,7 @@ class CakePayService { bool? custom, }) async { final result = await cakePayApi.getVendors( - CSRFToken: CSRFToken, - authorization: authorization, + apiKey: cakePayApiKey, page: page, country: country, countryCode: countryCode, @@ -91,17 +90,27 @@ class CakePayService { } /// Purchase Gift Card - Future createOrder( - {required int cardId, required String price, required int quantity}) async { + Future createOrder({ + required int cardId, + required String price, + required int quantity, + required bool confirmsNoVpn, + required bool confirmsVoidedRefund, + required bool confirmsTermsAgreed, + }) async { final userEmail = (await secureStorage.read(key: cakePayEmailStorageKey))!; final token = (await secureStorage.read(key: cakePayUserTokenKey))!; return await cakePayApi.createOrder( - apiKey: cakePayApiKey, - cardId: cardId, - price: price, - quantity: quantity, - token: token, - userEmail: userEmail); + apiKey: cakePayApiKey, + cardId: cardId, + price: price, + quantity: quantity, + token: token, + userEmail: userEmail, + confirmsNoVpn: confirmsNoVpn, + confirmsVoidedRefund: confirmsVoidedRefund, + confirmsTermsAgreed: confirmsTermsAgreed, + ); } ///Simulate Purchase Gift Card diff --git a/lib/core/address_validator.dart b/lib/core/address_validator.dart index 9ca8a41ad..dbb6f9541 100644 --- a/lib/core/address_validator.dart +++ b/lib/core/address_validator.dart @@ -80,7 +80,7 @@ class AddressValidator extends TextValidator { case CryptoCurrency.shib: pattern = '0x[0-9a-zA-Z]+'; case CryptoCurrency.xrp: - pattern = '[0-9a-zA-Z]{34}|X[0-9a-zA-Z]{46}'; + pattern = '[0-9a-zA-Z]{34}|[0-9a-zA-Z]{33}|X[0-9a-zA-Z]{46}'; case CryptoCurrency.xhv: pattern = 'hvx|hvi|hvs[0-9a-zA-Z]+'; case CryptoCurrency.xag: @@ -106,9 +106,8 @@ class AddressValidator extends TextValidator { case CryptoCurrency.wow: pattern = '[0-9a-zA-Z]+'; case CryptoCurrency.bch: - pattern = '^(bitcoincash:)?(q|p)[0-9a-zA-Z]{41,42}'; - case CryptoCurrency.bnb: - pattern = '[0-9a-zA-Z]+'; + pattern = '(?:bitcoincash:)?(q|p)[0-9a-zA-Z]{41}' + '|[13][a-km-zA-HJ-NP-Z1-9]{25,34}'; case CryptoCurrency.hbar: pattern = '[0-9a-zA-Z.]+'; case CryptoCurrency.zaddr: @@ -134,7 +133,7 @@ class AddressValidator extends TextValidator { case CryptoCurrency.btcln: pattern = '(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)'; default: - pattern = '[0-9a-zA-Z]+'; + return ''; } return '$BEFORE_REGEX($pattern)$AFTER_REGEX'; @@ -203,7 +202,7 @@ class AddressValidator extends TextValidator { case CryptoCurrency.avaxc: return [42]; case CryptoCurrency.bch: - return [42, 43, 44, 54, 55]; + return [42, 54, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35]; case CryptoCurrency.bnb: return [42]; case CryptoCurrency.nano: @@ -282,10 +281,14 @@ class AddressValidator extends TextValidator { switch (type) { case CryptoCurrency.xmr: - case CryptoCurrency.wow: pattern = '(4[0-9a-zA-Z]{94})' '|(8[0-9a-zA-Z]{94})' '|([0-9a-zA-Z]{106})'; + case CryptoCurrency.wow: + pattern = '(W[0-9a-zA-Z]{94})' + '|(W[0-9a-zA-Z]{94})' + '|(W[0-9a-zA-Z]{96})' + '|([0-9a-zA-Z]{106})'; case CryptoCurrency.btc: pattern = '${P2pkhAddress.regex.pattern}|${P2shAddress.regex.pattern}|${P2wpkhAddress.regex.pattern}|${P2trAddress.regex.pattern}|${P2wshAddress.regex.pattern}|${SilentPaymentAddress.regex.pattern}'; diff --git a/lib/core/auth_service.dart b/lib/core/auth_service.dart index 791701395..378c52ec0 100644 --- a/lib/core/auth_service.dart +++ b/lib/core/auth_service.dart @@ -4,6 +4,7 @@ import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/core/totp_request_details.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:mobx/mobx.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -51,7 +52,7 @@ class AuthService with Store { try { password = await secureStorage.read(key: key) ?? ''; } catch (e) { - print(e); + printV(e); } return walletName.isNotEmpty && password.isNotEmpty; diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index 992ed6288..f101ed7e1 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -7,6 +7,7 @@ import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/themes/theme_list.dart'; import 'package:cw_core/root_dir.dart'; import 'package:cake_wallet/utils/device_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/foundation.dart'; import 'package:hive/hive.dart'; @@ -110,11 +111,11 @@ class BackupService { for (var ignore in ignoreFiles) { final filename = entity.absolute.path; if (filename.endsWith(ignore) && !filename.contains("wallets/")) { - print("ignoring backup file: $filename"); + printV("ignoring backup file: $filename"); return; } } - print("restoring: $filename"); + printV("restoring: $filename"); if (entity.statSync().type == FileSystemEntityType.directory) { zipEncoder.addDirectory(Directory(entity.path)); } else { @@ -175,11 +176,11 @@ class BackupService { final filename = file.name; for (var ignore in ignoreFiles) { if (filename.endsWith(ignore) && !filename.contains("wallets/")) { - print("ignoring backup file: $filename"); + printV("ignoring backup file: $filename"); continue outer; } } - print("restoring: $filename"); + printV("restoring: $filename"); if (file.isFile) { final content = file.content as List; File('${appDir.path}/' + filename) @@ -193,7 +194,7 @@ class BackupService { await _verifyWallets(); await _importKeychainDumpV2(password); await _importPreferencesDump(); - await _importTransactionDescriptionDump(); + await _importTransactionDescriptionDump(); // HiveError: Box has already been closed } Future _verifyWallets() async { @@ -230,17 +231,15 @@ class BackupService { json.decode(transactionDescriptionFile.readAsStringSync()) as Map; final descriptionsMap = jsonData.map((key, value) => MapEntry(key, TransactionDescription.fromJson(value as Map))); - - if (!_transactionDescriptionBox.isOpen) { - final transactionDescriptionsBoxKey = await getEncryptionKey(secureStorage: secureStorageShared, forKey: TransactionDescription.boxKey); - final transactionDescriptionBox = await CakeHive.openBox( + var box = _transactionDescriptionBox; + if (!box.isOpen) { + final transactionDescriptionsBoxKey = + await getEncryptionKey(secureStorage: _secureStorage, forKey: TransactionDescription.boxKey); + box = await CakeHive.openBox( TransactionDescription.boxName, - encryptionKey: transactionDescriptionsBoxKey, - ); - await transactionDescriptionBox.putAll(descriptionsMap); - return; - } - await _transactionDescriptionBox.putAll(descriptionsMap); + encryptionKey: transactionDescriptionsBoxKey); + } + await box.putAll(descriptionsMap); } Future _importPreferencesDump() async { diff --git a/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart b/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart index efbf9df74..d7fe53c73 100644 --- a/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart +++ b/lib/core/wallet_connect/chain_service/solana/solana_chain_service.dart @@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_w import 'package:cake_wallet/core/wallet_connect/models/connection_model.dart'; import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_widget.dart'; import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:solana/base58.dart'; import 'package:solana/solana.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; @@ -127,7 +128,7 @@ class SolanaChainServiceImpl implements ChainService { commitment: Commitment.confirmed, ); - print(signature); + printV(signature); bottomSheetService.queueBottomSheet( isModalDismissible: true, @@ -165,7 +166,7 @@ class SolanaChainServiceImpl implements ChainService { try { sign = await ownerKeyPair?.sign(base58decode(solanaSignMessage.message)); } catch (e) { - print(e); + printV(e); } if (sign == null) { diff --git a/lib/core/wallet_connect/web3wallet_service.dart b/lib/core/wallet_connect/web3wallet_service.dart index ba4785643..ad892a594 100644 --- a/lib/core/wallet_connect/web3wallet_service.dart +++ b/lib/core/wallet_connect/web3wallet_service.dart @@ -17,6 +17,7 @@ import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_reques import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart'; import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart'; import 'package:cake_wallet/store/app_store.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:eth_sig_util/eth_sig_util.dart'; import 'package:flutter/material.dart'; @@ -260,7 +261,7 @@ abstract class Web3WalletServiceBase with Store { @action void _refreshPairings() { - print('Refreshing pairings'); + printV('Refreshing pairings'); pairings.clear(); final allPairings = _web3Wallet.pairings.getAll(); @@ -397,10 +398,10 @@ abstract class Web3WalletServiceBase with Store { // Get all pairing topics attached to this key final pairingTopicsForWallet = getPairingTopicsForWallet(key); - print(pairingTopicsForWallet); + printV(pairingTopicsForWallet); bool isPairingTopicAlreadySaved = pairingTopicsForWallet.contains(pairingTopic); - print('Is Pairing Topic Saved: $isPairingTopicAlreadySaved'); + printV('Is Pairing Topic Saved: $isPairingTopicAlreadySaved'); if (!isPairingTopicAlreadySaved) { // Update the list with the most recent pairing topic diff --git a/lib/core/wallet_loading_service.dart b/lib/core/wallet_loading_service.dart index 10e438e0c..6b1553443 100644 --- a/lib/core/wallet_loading_service.dart +++ b/lib/core/wallet_loading_service.dart @@ -2,15 +2,23 @@ import 'dart:async'; import 'package:cake_wallet/core/generate_wallet_password.dart'; import 'package:cake_wallet/core/key_service.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/reactions/on_authentication_state_change.dart'; +import 'package:cake_wallet/src/screens/auth/auth_page.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/utils/exception_handler.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cw_core/cake_hive.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:shared_preferences/shared_preferences.dart'; class WalletLoadingService { @@ -58,24 +66,25 @@ class WalletLoadingService { return wallet; } catch (error, stack) { - ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); + await ExceptionHandler.resetLastPopupDate(); + await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); // try fetching the seeds of the corrupted wallet to show it to the user String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):"; try { corruptedWalletsSeeds += await _getCorruptedWalletSeeds(name, type); } catch (e) { - corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; + corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; } // try opening another wallet that is not corrupted to give user access to the app final walletInfoSource = await CakeHive.openBox(WalletInfo.boxName); - + WalletBase? wallet; for (var walletInfo in walletInfoSource.values) { try { final walletService = walletServiceFactory.call(walletInfo.type); - final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name)); - final wallet = await walletService.openWallet(walletInfo.name, walletPassword); + final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name); + wallet = await walletService.openWallet(walletInfo.name, walletPassword); if (walletInfo.type == WalletType.monero) { await updateMoneroWalletPassword(wallet); @@ -88,10 +97,8 @@ class WalletLoadingService { // if found a wallet that is not corrupted, then still display the seeds of the corrupted ones authenticatedErrorStreamController.add(corruptedWalletsSeeds); - - return wallet; } catch (e) { - print(e); + printV(e); // save seeds and show corrupted wallets' seeds to the user try { final seeds = await _getCorruptedWalletSeeds(walletInfo.name, walletInfo.type); @@ -99,16 +106,56 @@ class WalletLoadingService { corruptedWalletsSeeds += seeds; } } catch (e) { - corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; + corruptedWalletsSeeds += "\nFailed to fetch $name seeds: $e"; } } } // if all user's wallets are corrupted throw exception - throw error.toString() + "\n\n" + corruptedWalletsSeeds; + final msg = error.toString() + "\n" + corruptedWalletsSeeds; + if (navigatorKey.currentContext != null) { + await showPopUp( + context: navigatorKey.currentContext!, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: "Corrupted seeds", + alertContent: S.of(context).corrupted_seed_notice, + leftButtonText: S.of(context).cancel, + rightButtonText: S.of(context).show_seed, + actionLeftButton: () => Navigator.of(context).pop(), + actionRightButton: () => showSeedsPopup(context, msg), + ); + }); + } else { + throw msg; + } + if (wallet == null) { + throw Exception("Wallet is null"); + } + return wallet; } } + Future showSeedsPopup(BuildContext context, String message) async { + Navigator.of(context).pop(); + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: "Corrupted seeds", + alertContent: message, + leftButtonText: S.of(context).copy, + rightButtonText: S.of(context).ok, + actionLeftButton: () async { + await Clipboard.setData(ClipboardData(text: message)); + }, + actionRightButton: () async { + Navigator.of(context).pop(); + }, + ); + }); + } + Future updateMoneroWalletPassword(WalletBase wallet) async { final key = PreferencesKey.moneroWalletUpdateV1Key(wallet.name); var isPasswordUpdated = sharedPreferences.getBool(key) ?? false; diff --git a/lib/di.dart b/lib/di.dart index 61e33c242..f7c115ae0 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -39,9 +39,12 @@ import 'package:cake_wallet/entities/wallet_manager.dart'; import 'package:cake_wallet/src/screens/buy/buy_sell_options_page.dart'; import 'package:cake_wallet/src/screens/buy/payment_method_options_page.dart'; import 'package:cake_wallet/src/screens/receive/address_list_page.dart'; +import 'package:cake_wallet/src/screens/seed/seed_verification/seed_verification_page.dart'; +import 'package:cake_wallet/src/screens/send/transaction_success_info_page.dart'; import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart'; import 'package:cake_wallet/src/screens/settings/mweb_logs_page.dart'; import 'package:cake_wallet/src/screens/settings/mweb_node_page.dart'; +import 'package:cake_wallet/src/screens/welcome/welcome_page.dart'; import 'package:cake_wallet/view_model/link_view_model.dart'; import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; @@ -568,7 +571,7 @@ Future setup({ totpAuthPageState.changeProcessText('Loading the wallet'); if (loginError != null) { - totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}'); + totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim()); } ReactionDisposer? _reaction; @@ -597,7 +600,7 @@ Future setup({ authPageState.changeProcessText('Loading the wallet'); if (loginError != null) { - authPageState.changeProcessText('ERROR: ${loginError.toString()}'); + authPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim()); loginError = null; } @@ -617,7 +620,7 @@ Future setup({ } if (loginError != null) { - authPageState.changeProcessText('ERROR: ${loginError.toString()}'); + authPageState.changeProcessText('ERROR: ${loginError.toString()}'.trim()); timer.cancel(); } }); @@ -740,6 +743,7 @@ Future setup({ _transactionDescriptionBox, getIt.get().wallet!.isHardwareWallet ? getIt.get() : null, coinTypeToSpendFrom: coinTypeToSpendFrom ?? UnspentCoinType.any, + getIt.get(param1: coinTypeToSpendFrom), ), ); @@ -1100,6 +1104,8 @@ Future setup({ (onSuccessfulPinSetup, _) => SetupPinCodePage(getIt.get(), onSuccessfulPinSetup: onSuccessfulPinSetup)); + getIt.registerFactory(() => WelcomePage()); + getIt.registerFactory(() => RescanViewModel(getIt.get().wallet!)); getIt.registerFactory(() => RescanPage(getIt.get())); @@ -1169,6 +1175,9 @@ Future setup({ getIt.registerFactoryParam( (seedPhraseLength, _) => PreSeedPage(seedPhraseLength)); + getIt.registerFactoryParam( + (content, _) => TransactionSuccessPage(content: content)); + getIt.registerFactoryParam((trade, _) => TradeDetailsViewModel( tradeForDetails: trade, @@ -1407,5 +1416,7 @@ Future setup({ getIt.registerFactory(() => SignViewModel(getIt.get().wallet!)); + getIt.registerFactory(() => SeedVerificationPage(getIt.get())); + _isSetupFinished = true; } diff --git a/lib/entities/background_tasks.dart b/lib/entities/background_tasks.dart index 5f822131f..b0ddfd925 100644 --- a/lib/entities/background_tasks.dart +++ b/lib/entities/background_tasks.dart @@ -3,9 +3,7 @@ import 'dart:io'; import 'dart:ui'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; -import 'package:cake_wallet/core/sync_status_title.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; @@ -14,6 +12,7 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cw_bitcoin/electrum_wallet.dart'; import 'package:cw_core/sync_status.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/widgets.dart'; @@ -110,7 +109,7 @@ void setWalletNotification(FlutterLocalNotificationsPlugin flutterLocalNotificat @pragma('vm:entry-point') Future onStart(ServiceInstance service) async { - print("BACKGROUND SERVICE STARTED"); + printV("BACKGROUND SERVICE STARTED"); bool bgSyncStarted = false; Timer? _syncTimer; Timer? _stuckSyncTimer; @@ -123,13 +122,13 @@ Future onStart(ServiceInstance service) async { FlutterLocalNotificationsPlugin(); service.on('stopService').listen((event) async { - print("STOPPING BACKGROUND SERVICE"); + printV("STOPPING BACKGROUND SERVICE"); _syncTimer?.cancel(); await service.stopSelf(); }); service.on('status').listen((event) async { - print(event); + printV(event); }); service.on('setForeground').listen((event) async { @@ -150,7 +149,7 @@ Future onStart(ServiceInstance service) async { bgSyncStarted = true; await Future.delayed(const Duration(seconds: DELAY_SECONDS_BEFORE_SYNC_START)); - print("STARTING SYNC FROM BG"); + printV("STARTING SYNC FROM BG"); setNotificationStarting(flutterLocalNotificationsPlugin); try { @@ -159,7 +158,7 @@ Future onStart(ServiceInstance service) async { // these errors still show up in logs which doesn't really make sense to me } - print("INITIALIZED APP CONFIGS"); + printV("INITIALIZED APP CONFIGS"); // final currentWallet = getIt.get().wallet; // // don't start syncing immediately: @@ -200,7 +199,7 @@ Future onStart(ServiceInstance service) async { } } catch (e) { // couldn't connect to mwebd (most likely) - print("error syncing litecoin wallet: $e"); + printV("error syncing litecoin wallet: $e"); } } @@ -218,7 +217,7 @@ Future onStart(ServiceInstance service) async { bool nodeSupportsSP = await (wallet as ElectrumWallet).getNodeSupportsSilentPayments(); if (!nodeSupportsSP) { - print("Configured node does not support silent payments, skipping wallet"); + printV("Configured node does not support silent payments, skipping wallet"); setWalletNotification( flutterLocalNotificationsPlugin, title: initialNotificationTitle, @@ -233,11 +232,11 @@ Future onStart(ServiceInstance service) async { syncingWallets.add(wallet); } catch (e) { - print("error syncing bitcoin wallet_$i: $e"); + printV("error syncing bitcoin wallet_$i: $e"); } } - print("STARTING SYNC TIMER"); + printV("STARTING SYNC TIMER"); _syncTimer?.cancel(); _syncTimer = Timer.periodic(const Duration(milliseconds: 2000), (timer) async { for (int i = 0; i < syncingWallets.length; i++) { @@ -247,7 +246,7 @@ Future onStart(ServiceInstance service) async { final progressPercent = (progress * 100).toStringAsPrecision(5) + "%"; if (progress > 0.999) { - print("WALLET $i SYNCED"); + printV("WALLET $i SYNCED"); wallet.stopSync(); // pop the first wallet from the list standbyWallets.add(syncingWallets.removeAt(i)); @@ -261,11 +260,11 @@ Future onStart(ServiceInstance service) async { if (shouldSync) { if (syncStatus is NotConnectedSyncStatus) { - print("${wallet.name} NOT CONNECTED"); + printV("${wallet.name} NOT CONNECTED"); final node = settingsStore.getCurrentNode(wallet.type); await wallet.connectToNode(node: node); wallet.startSync(); - print("STARTED SYNC"); + printV("STARTED SYNC"); // wait a few seconds before checking progress // await Future.delayed(const Duration(seconds: 10)); } @@ -366,7 +365,7 @@ Future onStart(ServiceInstance service) async { // } // // if the progress is the same over the last 100 seconds, restart the sync: // if (lastFewProgresses.every((p) => p == lastFewProgresses.first)) { - // print("mweb syncing is stuck, restarting..."); + // printV("mweb syncing is stuck, restarting..."); // syncStatus = LostConnectionSyncStatus(); // await stopSync(); // } @@ -417,12 +416,12 @@ Future initializeService(FlutterBackgroundService bgService, bool useNotif try { bool isServiceRunning = await bgService.isRunning(); if (isServiceRunning) { - print("Service is ALREADY running!"); + printV("Service is ALREADY running!"); return; } } catch (_) {} - print("INITIALIZING SERVICE"); + printV("INITIALIZING SERVICE"); await bgService.configure( androidConfiguration: AndroidConfiguration( @@ -469,7 +468,7 @@ class BackgroundTasks { } void registerBackgroundService() async { - print("REGISTER BACKGROUND SERVICE"); + printV("REGISTER BACKGROUND SERVICE"); try { final settingsStore = getIt.get(); final walletListViewModel = getIt.get(); @@ -514,8 +513,8 @@ class BackgroundTasks { await initializeService(bgService, useNotifications); } catch (error, stackTrace) { - print(error); - print(stackTrace); + printV(error); + printV(stackTrace); } } } diff --git a/lib/entities/biometric_auth.dart b/lib/entities/biometric_auth.dart index 353cd0492..ca9205f2a 100644 --- a/lib/entities/biometric_auth.dart +++ b/lib/entities/biometric_auth.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/services.dart'; import 'package:flutter_local_authentication/flutter_local_authentication.dart'; @@ -9,7 +10,7 @@ class BiometricAuth { final authenticated = await _flutterLocalAuthenticationPlugin.authenticate(); return authenticated; } catch (e) { - print(e); + printV(e); } return false; } @@ -20,7 +21,7 @@ class BiometricAuth { canAuthenticate = await _flutterLocalAuthenticationPlugin.canAuthenticate(); await _flutterLocalAuthenticationPlugin.setTouchIDAuthenticationAllowableReuseDuration(0); } catch (error) { - print("Exception checking support. $error"); + printV("Exception checking support. $error"); canAuthenticate = false; } diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index f873314c0..64370503f 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -4,9 +4,12 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/fiat_api_mode.dart'; +import 'package:cake_wallet/entities/haven_seed_store.dart'; +import 'package:cake_wallet/haven/haven.dart'; import 'package:cw_core/pathForWallet.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cw_core/root_dir.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:hive/hive.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; @@ -37,8 +40,8 @@ const polygonDefaultNodeUri = 'polygon-bor.publicnode.com'; const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002'; const nanoDefaultNodeUri = 'nano.nownodes.io'; const nanoDefaultPowNodeUri = 'rpc.nano.to'; -const solanaDefaultNodeUri = 'rpc.ankr.com'; -const tronDefaultNodeUri = 'trx.nownodes.io'; +const solanaDefaultNodeUri = 'solana-rpc.publicnode.com:443'; +const tronDefaultNodeUri = 'api.trongrid.io'; const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002'; const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568'; const moneroWorldNodeUri = '.moneroworld.com'; @@ -51,7 +54,8 @@ Future defaultSettingsMigration( required Box powNodes, required Box walletInfoSource, required Box tradeSource, - required Box contactSource}) async { + required Box contactSource, + required Box havenSeedStore}) async { if (Platform.isIOS) { await ios_migrate_v1(walletInfoSource, tradeSource, contactSource); } @@ -260,11 +264,72 @@ Future defaultSettingsMigration( updateBtcElectrumNodeToUseSSL(nodes, sharedPreferences); break; case 43: - _updateCakeXmrNode(nodes); + await _updateCakeXmrNode(nodes); _deselectExchangeProvider(sharedPreferences, "THORChain"); _deselectExchangeProvider(sharedPreferences, "SimpleSwap"); break; + case 44: + await _updateCakeXmrNode(nodes); + await _changeDefaultNode( + nodes: nodes, + sharedPreferences: sharedPreferences, + type: WalletType.bitcoin, + newDefaultUri: newCakeWalletBitcoinUri, + currentNodePreferenceKey: PreferencesKey.currentBitcoinElectrumSererIdKey, + useSSL: true, + oldUri: ['cakewallet.com'], + ); + _changeDefaultNode( + nodes: nodes, + sharedPreferences: sharedPreferences, + type: WalletType.tron, + newDefaultUri: tronDefaultNodeUri, + currentNodePreferenceKey: PreferencesKey.currentTronNodeIdKey, + useSSL: true, + oldUri: [ + 'tron-rpc.publicnode.com:443', + 'api.trongrid.io', + ], + ); + break; + case 45: + await _backupHavenSeeds(havenSeedStore); + updateWalletTypeNodesWithNewNode( + newNodeUri: 'matic.nownodes.io', + sharedPreferences: sharedPreferences, + nodes: nodes, + type: WalletType.polygon, + useSSL: true, + ); + updateWalletTypeNodesWithNewNode( + newNodeUri: 'eth.nownodes.io', + sharedPreferences: sharedPreferences, + nodes: nodes, + type: WalletType.ethereum, + useSSL: true, + ); + _changeDefaultNode( + nodes: nodes, + sharedPreferences: sharedPreferences, + type: WalletType.tron, + newDefaultUri: tronDefaultNodeUri, + currentNodePreferenceKey: PreferencesKey.currentTronNodeIdKey, + useSSL: true, + oldUri: [ + 'tron-rpc.publicnode.com:443', + 'trx.nownodes.io', + ], + ); + _changeDefaultNode( + nodes: nodes, + sharedPreferences: sharedPreferences, + type: WalletType.solana, + newDefaultUri: solanaDefaultNodeUri, + currentNodePreferenceKey: PreferencesKey.currentSolanaNodeIdKey, + useSSL: true, + oldUri: ['rpc.ankr.com'], + ); default: break; } @@ -272,24 +337,89 @@ Future defaultSettingsMigration( await sharedPreferences.setInt( PreferencesKey.currentDefaultSettingsMigrationVersion, version); } catch (e) { - print('Migration error: ${e.toString()}'); + printV('Migration error: ${e.toString()}'); } }); await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version); } -void _updateCakeXmrNode(Box nodes) { +Future _backupHavenSeeds(Box havenSeedStore) async { + final future = haven?.backupHavenSeeds(havenSeedStore); + if (future != null) { + await future; + } + return; +} + +/// generic function for changing any wallet default node +/// instead of making a new function for each change +Future _changeDefaultNode({ + required Box nodes, + required SharedPreferences sharedPreferences, + required WalletType type, + required String newDefaultUri, + required String currentNodePreferenceKey, + required bool useSSL, + required List oldUri, // leave empty if you want to force replace the node regardless of the user's current node +}) async { + final currentNodeId = sharedPreferences.getInt(currentNodePreferenceKey); + final currentNode = nodes.values.firstWhere((node) => node.key == currentNodeId); + final shouldReplace = oldUri.any((e) => currentNode.uriRaw.contains(e)); + + if (shouldReplace) { + var newNodeId = + nodes.values.firstWhereOrNull((element) => element.uriRaw == newDefaultUri)?.key; + + // new node doesn't exist, then add it + if (newNodeId == null) { + final newNode = Node( + uri: newDefaultUri, + type: type, + useSSL: useSSL, + ); + + await nodes.add(newNode); + newNodeId = newNode.key; + } + + await sharedPreferences.setInt(currentNodePreferenceKey, newNodeId as int); + } +} + +/// Generic function for adding a new Node for a Wallet Type. +Future updateWalletTypeNodesWithNewNode({ + required SharedPreferences sharedPreferences, + required Box nodes, + required WalletType type, + required String newNodeUri, + required bool useSSL, +}) async { + // If it already exists in the box of nodes, no need to add it annymore. + if (nodes.values.any((node) => node.uriRaw == newNodeUri)) return; + + await nodes.add( + Node( + uri: newNodeUri, + type: type, + useSSL: useSSL, + ), + ); +} + +Future _updateCakeXmrNode(Box nodes) async { final node = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletMoneroUri); - if (node != null && !node.trusted) { + if (node != null) { node.trusted = true; - node.save(); + node.useSSL = true; + await node.save(); } } void updateBtcElectrumNodeToUseSSL(Box nodes, SharedPreferences sharedPreferences) { - final btcElectrumNode = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri); + final btcElectrumNode = + nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri); if (btcElectrumNode != null) { btcElectrumNode.useSSL = true; @@ -538,7 +668,6 @@ Node? getBitcoinCashDefaultElectrumServer({required Box nodes}) { } Node getMoneroDefaultNode({required Box nodes}) { - final timeZone = DateTime.now().timeZoneOffset.inHours; var nodeUri = newCakeWalletMoneroUri; try { @@ -654,7 +783,7 @@ Future insecureStorageMigration({ await secureStorage.write( key: SecureKey.lastAuthTimeMilliseconds, value: lastAuthTimeMilliseconds.toString()); } catch (e) { - print("Error migrating shared preferences to secure storage!: $e"); + printV("Error migrating shared preferences to secure storage!: $e"); // this actually shouldn't be that big of a problem since we don't delete the old keys in this update // and we read and write to the new locations when loading storage, the migration is just for extra safety } @@ -810,7 +939,7 @@ Future addAddressesForMoneroWallets(Box walletInfoSource) asyn info.address = addressText; await info.save(); } catch (e) { - print(e.toString()); + printV(e.toString()); } }); } @@ -858,7 +987,8 @@ Future changeDefaultMoneroNode( } }); - final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero, trusted: true); + final newCakeWalletNode = + Node(uri: newCakeWalletMoneroUri, type: WalletType.monero, trusted: true); await nodeSource.add(newCakeWalletNode); @@ -897,7 +1027,7 @@ Future updateBtcNanoWalletInfos(Box walletsInfoSource) async { Future changeDefaultNanoNode( Box nodeSource, SharedPreferences sharedPreferences) async { const oldNanoNodeUriPattern = 'rpc.nano.to'; - final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); + final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey); final currentNanoNode = nodeSource.values.firstWhere((node) => node.key == currentNanoNodeId); final newCakeWalletNode = Node( @@ -909,7 +1039,8 @@ Future changeDefaultNanoNode( await nodeSource.add(newCakeWalletNode); if (currentNanoNode.uri.toString().contains(oldNanoNodeUriPattern)) { - await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, newCakeWalletNode.key as int); + await sharedPreferences.setInt( + PreferencesKey.currentNanoNodeIdKey, newCakeWalletNode.key as int); } } @@ -924,7 +1055,7 @@ Future changeDefaultBitcoinNode( currentBitcoinNode.uri.toString().contains(cakeWalletBitcoinNodeUriPattern); final newCakeWalletBitcoinNode = - Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: false); + Node(uri: newCakeWalletBitcoinUri, type: WalletType.bitcoin, useSSL: true); if (!nodeSource.values.any((element) => element.uriRaw == newCakeWalletBitcoinUri)) { await nodeSource.add(newCakeWalletBitcoinNode); diff --git a/lib/entities/ens_record.dart b/lib/entities/ens_record.dart index b2ce51806..e07d0731f 100644 --- a/lib/entities/ens_record.dart +++ b/lib/entities/ens_record.dart @@ -1,5 +1,6 @@ import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/polygon/polygon.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:ens_dart/ens_dart.dart'; @@ -45,7 +46,7 @@ class EnsRecord { final addr = await ens.withName(name).getAddress(); return addr.hex; } catch (e) { - print(e); + printV(e); return ""; } } diff --git a/lib/entities/evm_transaction_error_fees_handler.dart b/lib/entities/evm_transaction_error_fees_handler.dart new file mode 100644 index 000000000..63f6e164d --- /dev/null +++ b/lib/entities/evm_transaction_error_fees_handler.dart @@ -0,0 +1,81 @@ +class EVMTransactionErrorFeesHandler { + EVMTransactionErrorFeesHandler({ + this.balanceWei, + this.balanceEth, + this.balanceUsd, + this.txCostWei, + this.txCostEth, + this.txCostUsd, + this.overshotWei, + this.overshotEth, + this.overshotUsd, + this.error, + }); + + String? balanceWei; + String? balanceEth; + String? balanceUsd; + + String? txCostWei; + String? txCostEth; + String? txCostUsd; + + String? overshotWei; + String? overshotEth; + String? overshotUsd; + + String? error; + + factory EVMTransactionErrorFeesHandler.parseEthereumFeesErrorMessage( + String errorMessage, + double assetPriceUsd, + ) { + // Define Regular Expressions to extract the numerical values + RegExp balanceRegExp = RegExp(r'balance (\d+)'); + RegExp txCostRegExp = RegExp(r'tx cost (\d+)'); + RegExp overshotRegExp = RegExp(r'overshot (\d+)'); + + // Match the patterns in the error message + Match? balanceMatch = balanceRegExp.firstMatch(errorMessage); + Match? txCostMatch = txCostRegExp.firstMatch(errorMessage); + Match? overshotMatch = overshotRegExp.firstMatch(errorMessage); + + // Check if all required values are found + if (balanceMatch != null && txCostMatch != null && overshotMatch != null) { + // Extract the numerical strings + String balanceStr = balanceMatch.group(1)!; + String txCostStr = txCostMatch.group(1)!; + String overshotStr = overshotMatch.group(1)!; + + // Parse the numerical strings to BigInt + BigInt balanceWei = BigInt.parse(balanceStr); + BigInt txCostWei = BigInt.parse(txCostStr); + BigInt overshotWei = BigInt.parse(overshotStr); + + // Convert wei to ETH (1 ETH = 1e18 wei) + double balanceEth = balanceWei.toDouble() / 1e18; + double txCostEth = txCostWei.toDouble() / 1e18; + double overshotEth = overshotWei.toDouble() / 1e18; + + // Calculate the USD values + double balanceUsd = balanceEth * assetPriceUsd; + double txCostUsd = txCostEth * assetPriceUsd; + double overshotUsd = overshotEth * assetPriceUsd; + + return EVMTransactionErrorFeesHandler( + balanceWei: balanceWei.toString(), + balanceEth: balanceEth.toString().substring(0, 12), + balanceUsd: balanceUsd.toString().substring(0, 4), + txCostWei: txCostWei.toString(), + txCostEth: txCostEth.toString().substring(0, 12), + txCostUsd: txCostUsd.toString().substring(0, 4), + overshotWei: overshotWei.toString(), + overshotEth: overshotEth.toString().substring(0, 12), + overshotUsd: overshotUsd.toString().substring(0, 4), + ); + } else { + // If any value is missing, return an error message + return EVMTransactionErrorFeesHandler(error: 'Could not parse the error message.'); + } + } +} diff --git a/lib/entities/fs_migration.dart b/lib/entities/fs_migration.dart index ba3541561..a7604f4f1 100644 --- a/lib/entities/fs_migration.dart +++ b/lib/entities/fs_migration.dart @@ -2,6 +2,7 @@ import 'dart:io'; import 'dart:convert'; import 'package:cake_wallet/core/secure_storage.dart'; import 'package:collection/collection.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:hive/hive.dart'; import 'package:path_provider/path_provider.dart'; @@ -171,7 +172,7 @@ Future ios_migrate_wallet_passwords() async { await keyService.saveWalletPassword(walletName: name, password: password!); } } catch (e) { - print(e.toString()); + printV(e.toString()); } }); @@ -326,7 +327,7 @@ Future ios_migrate_wallet_info(Box walletsInfoSource) async { return walletInfo; } } catch (e) { - print(e.toString()); + printV(e.toString()); return null; } }) @@ -336,7 +337,7 @@ Future ios_migrate_wallet_info(Box walletsInfoSource) async { await walletsInfoSource.addAll(infoRecords); await prefs.setBool('ios_migration_wallet_info_completed', true); } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -403,7 +404,7 @@ Future ios_migrate_trades_list(Box tradeSource) async { await tradeSource.addAll(trades); await prefs.setBool('ios_migration_trade_list_completed', true); } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -437,6 +438,6 @@ Future ios_migrate_address_book(Box contactSource) async { await contactSource.addAll(contacts); await prefs.setBool('ios_migration_address_book_completed', true); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/lib/entities/haven_seed_store.dart b/lib/entities/haven_seed_store.dart new file mode 100644 index 000000000..f899799d8 --- /dev/null +++ b/lib/entities/haven_seed_store.dart @@ -0,0 +1,19 @@ +import 'package:cw_core/hive_type_ids.dart'; +import 'package:hive/hive.dart'; + +part 'haven_seed_store.g.dart'; + +@HiveType(typeId: HavenSeedStore.typeId) +class HavenSeedStore extends HiveObject { + HavenSeedStore({required this.id, this.seed}); + + static const typeId = HAVEN_SEED_STORE_TYPE_ID; + static const boxName = 'HavenSeedStore'; + static const boxKey = 'havenSeedStoreKey'; + + @HiveField(0, defaultValue: '') + String id; + + @HiveField(2) + String? seed; +} diff --git a/lib/entities/main_actions.dart b/lib/entities/main_actions.dart index 94be0d2b7..29c161c5f 100644 --- a/lib/entities/main_actions.dart +++ b/lib/entities/main_actions.dart @@ -1,7 +1,5 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; import 'package:flutter/material.dart'; @@ -68,7 +66,7 @@ class MainActions { static MainActions tradeAction = MainActions._( - name: (context) => '${S.of(context).buy} / ${S.of(context).sell}', + name: (context) => '${S.of(context).buy}/${S.of(context).sell}', image: 'assets/images/buy_sell.png', isEnabled: (viewModel) => viewModel.isEnabledTradeAction, canShow: (viewModel) => viewModel.hasTradeAction, diff --git a/lib/entities/openalias_record.dart b/lib/entities/openalias_record.dart index 6d8b759f5..b2af2e53d 100644 --- a/lib/entities/openalias_record.dart +++ b/lib/entities/openalias_record.dart @@ -1,4 +1,5 @@ import 'package:basic_utils/basic_utils.dart'; +import 'package:cw_core/utils/print_verbose.dart'; class OpenaliasRecord { OpenaliasRecord({ @@ -27,7 +28,7 @@ class OpenaliasRecord { return txtRecord; } catch (e) { - print("${e.toString()}"); + printV("${e.toString()}"); return null; } } diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index 11ba4724c..54fa4e75a 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/nostr/nostr_api.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/twitter/twitter_api.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/entities/fio_address_provider.dart'; @@ -26,23 +27,80 @@ class AddressResolver { final SettingsStore settingsStore; static const unstoppableDomains = [ - 'crypto', - 'zil', - 'x', - 'wallet', - 'bitcoin', - '888', - 'nft', - 'dao', - 'blockchain', - 'polygon', - 'klever', - 'hi', - 'kresus', - 'anime', - 'manga', - 'binanceus', - 'xmr', + "888", + "altimist", + "anime", + "austin", + "bald", + "benji", + "bet", + "binanceus", + "bitcoin", + "bitget", + "blockchain", + "ca", + "chomp", + "clay", + "co", + "com", + "crypto", + "dao", + "dfz", + "digital", + "dream", + "eth", + "ethermail", + "farms", + "fun", + "go", + "group", + "hi", + "host", + "info", + "io", + "klever", + "kresus", + "kryptic", + "lfg", + "life", + "live", + "ltd", + "manga", + "metropolis", + "moon", + "mumu", + "net", + "nft", + "online", + "org", + "pog", + "polygon", + "press", + "pro", + "propykeys", + "pudgy", + "pw", + "raiin", + "secret", + "site", + "smobler", + "space", + "stepn", + "store", + "tball", + "tech", + "ubu", + "uno", + "unstoppable", + "wallet", + "website", + "wifi", + "witg", + "wrkx", + "x", + "xmr", + "xyz", + "zil", ]; static String? extractAddressByType({required String raw, required CryptoCurrency type}) { @@ -226,7 +284,7 @@ class AddressResolver { } } } catch (e) { - print(e.toString()); + printV(e.toString()); } return ParsedAddress(addresses: [text]); diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index be2ceb869..71d285221 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -92,6 +92,7 @@ class PreferencesKey { static const donationLinkWalletName = 'donation_link_wallet_name'; static const lastSeenAppVersion = 'last_seen_app_version'; static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard'; + static const showAddressBookPopupEnabled = 'show_address_book_popup_enabled'; static const isNewInstall = 'is_new_install'; static const serviceStatusShaKey = 'service_status_sha_key'; static const walletConnectPairingTopicsList = 'wallet_connect_pairing_topics_list'; diff --git a/lib/entities/qr_scanner.dart b/lib/entities/qr_scanner.dart index 2e2637566..311bc498a 100644 --- a/lib/entities/qr_scanner.dart +++ b/lib/entities/qr_scanner.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:fast_scanner/fast_scanner.dart'; import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; @@ -61,7 +62,7 @@ class _BarcodeScannerSimpleState extends State { ); }, ); - print(e); + printV(e); } } diff --git a/lib/entities/unstoppable_domain_address.dart b/lib/entities/unstoppable_domain_address.dart index 6966fdd75..a047c85d9 100644 --- a/lib/entities/unstoppable_domain_address.dart +++ b/lib/entities/unstoppable_domain_address.dart @@ -1,5 +1,6 @@ import 'dart:convert'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:http/http.dart' as http; Future fetchUnstoppableDomainAddress(String domain, String ticker) async { @@ -20,7 +21,7 @@ Future fetchUnstoppableDomainAddress(String domain, String ticker) async return records[key] as String? ?? ''; } catch (e) { - print('Unstoppable domain error: ${e.toString()}'); + printV('Unstoppable domain error: ${e.toString()}'); address = ''; } diff --git a/lib/ethereum/cw_ethereum.dart b/lib/ethereum/cw_ethereum.dart index 7a06a1679..413cafc30 100644 --- a/lib/ethereum/cw_ethereum.dart +++ b/lib/ethereum/cw_ethereum.dart @@ -205,7 +205,7 @@ class CWEthereum extends Ethereum { try { return await hardwareWalletService.getAvailableAccounts(index: index, limit: limit); } catch (err) { - print(err); + printV(err); throw err; } } diff --git a/lib/exchange/provider/changenow_exchange_provider.dart b/lib/exchange/provider/changenow_exchange_provider.dart index 255767fa1..79f8d70d4 100644 --- a/lib/exchange/provider/changenow_exchange_provider.dart +++ b/lib/exchange/provider/changenow_exchange_provider.dart @@ -15,6 +15,7 @@ import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/distribution_info.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:http/http.dart'; class ChangeNowExchangeProvider extends ExchangeProvider { @@ -127,7 +128,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider { return isReverse ? (amount / fromAmount) : (toAmount / amount); } catch (e) { - print(e.toString()); + printV(e.toString()); return 0.0; } } diff --git a/lib/exchange/provider/exolix_exchange_provider.dart b/lib/exchange/provider/exolix_exchange_provider.dart index 5eeb6f9cf..ee5a46bbc 100644 --- a/lib/exchange/provider/exolix_exchange_provider.dart +++ b/lib/exchange/provider/exolix_exchange_provider.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:http/http.dart'; class ExolixExchangeProvider extends ExchangeProvider { @@ -59,15 +60,17 @@ class ExolixExchangeProvider extends ExchangeProvider { Future checkIsAvailable() async => true; @override - Future fetchLimits( - {required CryptoCurrency from, - required CryptoCurrency to, - required bool isFixedRateMode}) async { + Future fetchLimits({ + required CryptoCurrency from, + required CryptoCurrency to, + required bool isFixedRateMode, + }) async { final params = { 'rateType': _getRateType(isFixedRateMode), 'amount': '1', 'apiToken': apiKey, }; + if (isFixedRateMode) { params['coinFrom'] = _normalizeCurrency(to); params['coinTo'] = _normalizeCurrency(from); @@ -79,14 +82,30 @@ class ExolixExchangeProvider extends ExchangeProvider { params['networkFrom'] = _networkFor(from); params['networkTo'] = _networkFor(to); } - final uri = Uri.https(apiBaseUrl, ratePath, params); - final response = await get(uri); - if (response.statusCode != 200) - throw Exception('Unexpected http status: ${response.statusCode}'); + // Maximum of 2 attempts to fetch limits + for (int i = 0; i < 2; i++) { + final uri = Uri.https(apiBaseUrl, ratePath, params); + final response = await get(uri); - final responseJSON = json.decode(response.body) as Map; - return Limits(min: responseJSON['minAmount'] as double?); + if (response.statusCode == 200) { + final responseJSON = json.decode(response.body) as Map; + final minAmount = responseJSON['minAmount']; + final maxAmount = responseJSON['maxAmount']; + return Limits(min: _toDouble(minAmount), max: _toDouble(maxAmount)); + } else if (response.statusCode == 422) { + final errorResponse = json.decode(response.body) as Map; + if (errorResponse.containsKey('minAmount')) { + params['amount'] = errorResponse['minAmount'].toString(); + continue; + } + throw Exception('Error 422: ${errorResponse['message'] ?? 'Unknown error'}'); + } else { + throw Exception('Unexpected HTTP status: ${response.statusCode}'); + } + } + + throw Exception('Failed to fetch limits after retrying.'); } @override @@ -124,7 +143,7 @@ class ExolixExchangeProvider extends ExchangeProvider { return responseJSON['rate'] as double; } catch (e) { - print(e.toString()); + printV(e.toString()); return 0.0; } } @@ -278,4 +297,15 @@ class ExolixExchangeProvider extends ExchangeProvider { String _normalizeAddress(String address) => address.startsWith('bitcoincash:') ? address.replaceFirst('bitcoincash:', '') : address; + + static double? _toDouble(dynamic value) { + if (value is int) { + return value.toDouble(); + } else if (value is double) { + return value; + } else if (value is String) { + return double.tryParse(value); + } + return null; + } } diff --git a/lib/exchange/provider/letsexchange_exchange_provider.dart b/lib/exchange/provider/letsexchange_exchange_provider.dart index 1d4da55cb..95520d5f0 100644 --- a/lib/exchange/provider/letsexchange_exchange_provider.dart +++ b/lib/exchange/provider/letsexchange_exchange_provider.dart @@ -97,6 +97,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider { final amountToGet = double.tryParse(responseJSON['amount'] as String) ?? 0.0; + if (amountToGet == 0.0) return 0.0; + return isFixedRateMode ? amount / amountToGet : amountToGet / amount; } catch (e) { log(e.toString()); @@ -166,6 +168,7 @@ class LetsExchangeExchangeProvider extends ExchangeProvider { final status = responseJSON['status'] as String; final createdAtString = responseJSON['created_at'] as String; final expiredAtTimestamp = responseJSON['expired_at'] as int; + final extraId = responseJSON['deposit_extra_id'] as String?; final createdAt = DateTime.parse(createdAtString); final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000); @@ -197,6 +200,7 @@ class LetsExchangeExchangeProvider extends ExchangeProvider { state: TradeState.deserialize(raw: status), createdAt: createdAt, expiredAt: expiredAt, + extraId: extraId, ); } catch (e) { log(e.toString()); @@ -229,6 +233,7 @@ class LetsExchangeExchangeProvider extends ExchangeProvider { final status = responseJSON['status'] as String; final createdAtString = responseJSON['created_at'] as String; final expiredAtTimestamp = responseJSON['expired_at'] as int; + final extraId = responseJSON['deposit_extra_id'] as String?; final createdAt = DateTime.parse(createdAtString); final expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtTimestamp * 1000); @@ -247,6 +252,7 @@ class LetsExchangeExchangeProvider extends ExchangeProvider { createdAt: createdAt, expiredAt: expiredAt, isRefund: status == 'refund', + extraId: extraId, ); } diff --git a/lib/exchange/provider/quantex_exchange_provider.dart b/lib/exchange/provider/quantex_exchange_provider.dart index a4d8bafe5..ee3473360 100644 --- a/lib/exchange/provider/quantex_exchange_provider.dart +++ b/lib/exchange/provider/quantex_exchange_provider.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:http/http.dart'; class QuantexExchangeProvider extends ExchangeProvider { @@ -86,7 +87,7 @@ class QuantexExchangeProvider extends ExchangeProvider { // coin not found: return Limits(min: 0, max: 0); } catch (e) { - print(e.toString()); + printV(e.toString()); return Limits(min: 0, max: 0); } } @@ -121,7 +122,7 @@ class QuantexExchangeProvider extends ExchangeProvider { double rate = double.parse(data['price'].toString()); return rate; } catch (e) { - print("error fetching rate: ${e.toString()}"); + printV("error fetching rate: ${e.toString()}"); return 0.0; } } @@ -178,7 +179,7 @@ class QuantexExchangeProvider extends ExchangeProvider { isSendAll: isSendAll, ); } catch (e) { - print("error creating trade: ${e.toString()}"); + printV("error creating trade: ${e.toString()}"); throw TradeNotCreatedException(description, description: e.toString()); } } @@ -225,7 +226,7 @@ class QuantexExchangeProvider extends ExchangeProvider { state: state, ); } catch (e) { - print("error getting trade: ${e.toString()}"); + printV("error getting trade: ${e.toString()}"); throw TradeNotFoundException( id, provider: description, diff --git a/lib/exchange/provider/sideshift_exchange_provider.dart b/lib/exchange/provider/sideshift_exchange_provider.dart index f53d778ec..7373d5f2d 100644 --- a/lib/exchange/provider/sideshift_exchange_provider.dart +++ b/lib/exchange/provider/sideshift_exchange_provider.dart @@ -203,6 +203,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { final inputAddress = responseJSON['depositAddress'] as String; final settleAddress = responseJSON['settleAddress'] as String; final depositAmount = responseJSON['depositAmount'] as String?; + final depositMemo = responseJSON['depositMemo'] as String?; return Trade( id: id, @@ -217,6 +218,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { payoutAddress: settleAddress, createdAt: DateTime.now(), isSendAll: isSendAll, + extraId: depositMemo ); } @@ -251,6 +253,7 @@ class SideShiftExchangeProvider extends ExchangeProvider { final isVariable = (responseJSON['type'] as String) == 'variable'; final expiredAtRaw = responseJSON['expiresAt'] as String; final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal(); + final depositMemo = responseJSON['depositMemo'] as String?; return Trade( id: id, @@ -261,7 +264,8 @@ class SideShiftExchangeProvider extends ExchangeProvider { amount: expectedSendAmount ?? '', state: TradeState.deserialize(raw: status ?? 'created'), expiredAt: expiredAt, - payoutAddress: settleAddress); + payoutAddress: settleAddress, + extraId: depositMemo); } Future _createQuote(TradeRequest request) async { diff --git a/lib/exchange/provider/stealth_ex_exchange_provider.dart b/lib/exchange/provider/stealth_ex_exchange_provider.dart index 123f759ef..53c40ee62 100644 --- a/lib/exchange/provider/stealth_ex_exchange_provider.dart +++ b/lib/exchange/provider/stealth_ex_exchange_provider.dart @@ -154,6 +154,7 @@ class StealthExExchangeProvider extends ExchangeProvider { final receiveAmount = toDouble(withdrawal['amount']); final status = responseJSON['status'] as String; final createdAtString = responseJSON['created_at'] as String; + final extraId = deposit['extra_id'] as String?; final createdAt = DateTime.parse(createdAtString); final expiredAt = validUntil != null @@ -188,6 +189,7 @@ class StealthExExchangeProvider extends ExchangeProvider { state: TradeState.deserialize(raw: status), createdAt: createdAt, expiredAt: expiredAt, + extraId: extraId, ); } catch (e) { log(e.toString()); @@ -220,6 +222,7 @@ class StealthExExchangeProvider extends ExchangeProvider { final status = responseJSON['status'] as String; final createdAtString = responseJSON['created_at'] as String; final createdAt = DateTime.parse(createdAtString); + final extraId = deposit['extra_id'] as String?; return Trade( id: respId, @@ -234,6 +237,7 @@ class StealthExExchangeProvider extends ExchangeProvider { state: TradeState.deserialize(raw: status), createdAt: createdAt, isRefund: status == 'refunded', + extraId: extraId, ); } diff --git a/lib/exchange/provider/thorchain_exchange.provider.dart b/lib/exchange/provider/thorchain_exchange.provider.dart index 99b9dcf9f..aa7ab2d27 100644 --- a/lib/exchange/provider/thorchain_exchange.provider.dart +++ b/lib/exchange/provider/thorchain_exchange.provider.dart @@ -8,6 +8,7 @@ import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; @@ -86,7 +87,7 @@ class ThorChainExchangeProvider extends ExchangeProvider { return _thorChainAmountToDouble(expectedAmountOut) / amount; } catch (e) { - print(e.toString()); + printV(e.toString()); return 0.0; } } diff --git a/lib/exchange/provider/trocador_exchange_provider.dart b/lib/exchange/provider/trocador_exchange_provider.dart index 5529d824a..151ded371 100644 --- a/lib/exchange/provider/trocador_exchange_provider.dart +++ b/lib/exchange/provider/trocador_exchange_provider.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:http/http.dart'; class TrocadorExchangeProvider extends ExchangeProvider { @@ -148,7 +149,7 @@ class TrocadorExchangeProvider extends ExchangeProvider { return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount); } catch (e) { - print(e.toString()); + printV(e.toString()); return 0.0; } } @@ -170,7 +171,8 @@ class TrocadorExchangeProvider extends ExchangeProvider { if (!isFixedRateMode) 'amount_from': request.fromAmount, if (isFixedRateMode) 'amount_to': request.toAmount, 'address': request.toAddress, - 'refund': request.refundAddress + 'refund': request.refundAddress, + 'refund_memo' : '0', }; if (isFixedRateMode) { @@ -261,6 +263,7 @@ class TrocadorExchangeProvider extends ExchangeProvider { final password = responseJSON['password'] as String; final providerId = responseJSON['id_provider'] as String; final providerName = responseJSON['provider'] as String; + final addressProviderMemo = responseJSON['address_provider_memo'] as String?; return Trade( id: id, @@ -276,6 +279,7 @@ class TrocadorExchangeProvider extends ExchangeProvider { password: password, providerId: providerId, providerName: providerName, + extraId: addressProviderMemo, ); }); } diff --git a/lib/exchange/trade.dart b/lib/exchange/trade.dart index a0c08aac7..c5738cfd9 100644 --- a/lib/exchange/trade.dart +++ b/lib/exchange/trade.dart @@ -143,6 +143,7 @@ class Trade extends HiveObject { isRefund: map['isRefund'] as bool?, isSendAll: map['isSendAll'] as bool?, router: map['router'] as String?, + extraId: map['extra_id'] as String?, ); } @@ -162,6 +163,7 @@ class Trade extends HiveObject { 'isRefund': isRefund, 'isSendAll': isSendAll, 'router': router, + 'extra_id': extraId, }; } diff --git a/lib/haven/cw_haven.dart b/lib/haven/cw_haven.dart index 57c4e49c3..c54e47eb4 100644 --- a/lib/haven/cw_haven.dart +++ b/lib/haven/cw_haven.dart @@ -307,6 +307,23 @@ class CWHaven extends Haven { return havenTransactionInfo.accountIndex; } + @override + Future backupHavenSeeds(Box havenSeedStore) async { + final walletInfoSource = await CakeHive.openBox(WalletInfo.boxName); + final wallets = walletInfoSource.values + .where((element) => element.type == WalletType.haven); + for (var w in wallets) { + final walletService = HavenWalletService(walletInfoSource); + final flutterSecureStorage = secureStorageShared; + final keyService = KeyService(flutterSecureStorage); + final password = await keyService.getWalletPassword(walletName: w.name); + final wallet = await walletService.openWallet(w.name, password); + await havenSeedStore.add(HavenSeedStore(id: wallet.id, seed: wallet.seed)); + wallet.close(); + } + await havenSeedStore.flush(); + } + @override WalletService createHavenWalletService(Box walletInfoSource) { return HavenWalletService(walletInfoSource); diff --git a/lib/locales/hausa_intl.dart b/lib/locales/hausa_intl.dart index 6cf757b60..99e47d7da 100644 --- a/lib/locales/hausa_intl.dart +++ b/lib/locales/hausa_intl.dart @@ -795,6 +795,14 @@ class HaMaterialLocalizations extends GlobalMaterialLocalizations { @override // TODO: implement shareButtonLabel String get shareButtonLabel => "shareButtonLabel"; + + @override + // TODO: implement clearButtonTooltip + String get clearButtonTooltip => "clearButtonTooltip"; + + @override + // TODO: implement selectedDateLabel + String get selectedDateLabel => "selectedDateLabel"; } /// Cupertino Support diff --git a/lib/locales/yoruba_intl.dart b/lib/locales/yoruba_intl.dart index 3c720b80e..bb2385274 100644 --- a/lib/locales/yoruba_intl.dart +++ b/lib/locales/yoruba_intl.dart @@ -794,6 +794,14 @@ class YoMaterialLocalizations extends GlobalMaterialLocalizations { @override // TODO: implement shareButtonLabel String get shareButtonLabel => "shareButtonLabel"; + + @override + // TODO: implement clearButtonTooltip + String get clearButtonTooltip => "clearButtonTooltip"; + + @override + // TODO: implement selectedDateLabel + String get selectedDateLabel => "selectedDateLabel"; } /// Cupertino Support diff --git a/lib/main.dart b/lib/main.dart index 317b5cc10..a8068ef11 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/entities/contact.dart'; import 'package:cake_wallet/entities/default_settings_migration.dart'; import 'package:cake_wallet/entities/get_encryption_key.dart'; import 'package:cake_wallet/core/secure_storage.dart'; +import 'package:cake_wallet/entities/haven_seed_store.dart'; import 'package:cake_wallet/entities/language_service.dart'; import 'package:cake_wallet/entities/template.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; @@ -16,7 +17,6 @@ import 'package:cake_wallet/exchange/exchange_template.dart'; import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/locales/locale.dart'; -import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/reactions/bootstrap.dart'; import 'package:cake_wallet/router.dart' as Router; import 'package:cake_wallet/routes.dart'; @@ -90,7 +90,7 @@ Future runAppWithZone({Key? topLevelKey}) async { ); } - ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace)); + await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace)); }); } @@ -165,6 +165,10 @@ Future initializeAppConfigs({bool loadWallet = true}) async { CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter()); } + if (!CakeHive.isAdapterRegistered(HavenSeedStore.typeId)) { + CakeHive.registerAdapter(HavenSeedStoreAdapter()); + } + if (!CakeHive.isAdapterRegistered(MwebUtxo.typeId)) { CakeHive.registerAdapter(MwebUtxoAdapter()); } @@ -189,6 +193,12 @@ Future initializeAppConfigs({bool loadWallet = true}) async { final anonpayInvoiceInfo = await CakeHive.openBox(AnonpayInvoiceInfo.boxName); final unspentCoinsInfoSource = await CakeHive.openBox(UnspentCoinsInfo.boxName); + final havenSeedStoreBoxKey = + await getEncryptionKey(secureStorage: secureStorage, forKey: HavenSeedStore.boxKey); + final havenSeedStore = await CakeHive.openBox( + HavenSeedStore.boxName, + encryptionKey: havenSeedStoreBoxKey); + await initialSetup( loadWallet: loadWallet, sharedPreferences: await SharedPreferences.getInstance(), @@ -205,7 +215,8 @@ Future initializeAppConfigs({bool loadWallet = true}) async { transactionDescriptions: transactionDescriptions, secureStorage: secureStorage, anonpayInvoiceInfo: anonpayInvoiceInfo, - initialMigrationVersion: 43, + havenSeedStore: havenSeedStore, + initialMigrationVersion: 45, ); } @@ -224,8 +235,9 @@ Future initialSetup( required SecureStorage secureStorage, required Box anonpayInvoiceInfo, required Box unspentCoinsInfoSource, + required Box havenSeedStore, required bool loadWallet, - int initialMigrationVersion = 15}) async { + int initialMigrationVersion = 15, }) async { LanguageService.loadLocaleList(); await defaultSettingsMigration( secureStorage: secureStorage, @@ -235,7 +247,8 @@ Future initialSetup( contactSource: contactSource, tradeSource: tradesSource, nodes: nodes, - powNodes: powNodes); + powNodes: powNodes, + havenSeedStore: havenSeedStore); await setup( walletInfoSource: walletInfoSource, nodeSource: nodes, diff --git a/lib/mastodon/mastodon_api.dart b/lib/mastodon/mastodon_api.dart index 8326ce05d..a2fdc97bd 100644 --- a/lib/mastodon/mastodon_api.dart +++ b/lib/mastodon/mastodon_api.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:http/http.dart' as http; import 'package:cake_wallet/mastodon/mastodon_user.dart'; @@ -27,7 +28,7 @@ class MastodonAPI { return MastodonUser.fromJson(responseJSON); } catch (e) { - print('Error in lookupUserByUserName: $e'); + printV('Error in lookupUserByUserName: $e'); return null; } } @@ -56,7 +57,7 @@ class MastodonAPI { return responseJSON.map((json) => PinnedPost.fromJson(json as Map)).toList(); } catch (e) { - print('Error in getPinnedPosts: $e'); + printV('Error in getPinnedPosts: $e'); throw e; } } diff --git a/lib/nano/cw_nano.dart b/lib/nano/cw_nano.dart index 9e47edc04..9a2243d00 100644 --- a/lib/nano/cw_nano.dart +++ b/lib/nano/cw_nano.dart @@ -249,7 +249,7 @@ class CWNanoUtil extends NanoUtil { try { mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey); } catch (e) { - print("not a valid 'nano' seed key"); + printV("not a valid 'nano' seed key"); } } if (derivationType == DerivationType.bip39) { @@ -306,7 +306,7 @@ class CWNanoUtil extends NanoUtil { try { mnemonic = NanoDerivations.standardSeedToMnemonic(seedKey!); } catch (e) { - print("not a valid 'nano' seed key"); + printV("not a valid 'nano' seed key"); } } diff --git a/lib/nostr/nostr_api.dart b/lib/nostr/nostr_api.dart index 7c0eea5ef..be59f0eba 100644 --- a/lib/nostr/nostr_api.dart +++ b/lib/nostr/nostr_api.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/nostr/nostr_user.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:nostr_tools/nostr_tools.dart'; @@ -83,7 +84,7 @@ class NostrProfileHandler { relay.close(); return null; } catch (e) { - print('[!] Error with relay $relayUrl: $e'); + printV('[!] Error with relay $relayUrl: $e'); return null; } } @@ -115,7 +116,7 @@ class NostrProfileHandler { var uri = Uri.parse(relayUrl); return uri.host; } catch (e) { - print('Error parsing URL: $e'); + printV('Error parsing URL: $e'); return ''; } } diff --git a/lib/polygon/cw_polygon.dart b/lib/polygon/cw_polygon.dart index 74b4026eb..7c447406d 100644 --- a/lib/polygon/cw_polygon.dart +++ b/lib/polygon/cw_polygon.dart @@ -204,7 +204,7 @@ class CWPolygon extends Polygon { try { return await hardwareWalletService.getAvailableAccounts(index: index, limit: limit); } catch (err) { - print(err); + printV(err); throw err; } } diff --git a/lib/reactions/check_connection.dart b/lib/reactions/check_connection.dart index 570b96864..d60037543 100644 --- a/lib/reactions/check_connection.dart +++ b/lib/reactions/check_connection.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:connectivity_plus/connectivity_plus.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/sync_status.dart'; import 'package:cw_core/wallet_type.dart'; @@ -36,7 +37,7 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore } } } catch (e) { - print(e.toString()); + printV(e.toString()); } }); } diff --git a/lib/reactions/fiat_rate_update.dart b/lib/reactions/fiat_rate_update.dart index e46ef4b64..62710c515 100644 --- a/lib/reactions/fiat_rate_update.dart +++ b/lib/reactions/fiat_rate_update.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/tron/tron.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/erc20_token.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; @@ -71,7 +72,7 @@ Future startFiatRateUpdate( } } } catch (e) { - print(e); + printV(e); } }; diff --git a/lib/reactions/on_authentication_state_change.dart b/lib/reactions/on_authentication_state_change.dart index b411c5a15..c05f6fb0d 100644 --- a/lib/reactions/on_authentication_state_change.dart +++ b/lib/reactions/on_authentication_state_change.dart @@ -43,14 +43,17 @@ void startAuthenticationStateChange( if (!requireHardwareWalletConnection()) await loadCurrentWallet(); } catch (error, stack) { loginError = error; - ExceptionHandler.onError( + await ExceptionHandler.resetLastPopupDate(); + await ExceptionHandler.onError( FlutterErrorDetails(exception: error, stack: stack)); } return; } - if (state == AuthenticationState.allowed) { - if (requireHardwareWalletConnection()) { + if ([AuthenticationState.allowed, AuthenticationState.allowedCreate] + .contains(state)) { + if (state == AuthenticationState.allowed && + requireHardwareWalletConnection()) { await navigatorKey.currentState!.pushNamedAndRemoveUntil( Routes.connectDevices, (route) => false, @@ -58,14 +61,14 @@ void startAuthenticationStateChange( walletType: WalletType.monero, onConnectDevice: (context, ledgerVM) async { monero!.setGlobalLedgerConnection(ledgerVM.connection); - showPopUp( - context: context, - builder: (BuildContext context) => AlertWithOneAction( - alertTitle: S.of(context).proceed_on_device, - alertContent: S.of(context).proceed_on_device_description, - buttonText: S.of(context).cancel, - buttonAction: () => Navigator.of(context).pop()), - ); + showPopUp( + context: context, + builder: (BuildContext context) => AlertWithOneAction( + alertTitle: S.of(context).proceed_on_device, + alertContent: S.of(context).proceed_on_device_description, + buttonText: S.of(context).cancel, + buttonAction: () => Navigator.of(context).pop()), + ); await loadCurrentWallet(); getIt.get().resetCurrentSheet(); await navigatorKey.currentState! @@ -81,7 +84,7 @@ void startAuthenticationStateChange( .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); } if (!(await authenticatedErrorStreamController.stream.isEmpty)) { - ExceptionHandler.showError( + await ExceptionHandler.showError( (await authenticatedErrorStreamController.stream.first).toString()); authenticatedErrorStreamController.stream.drain(); } diff --git a/lib/reactions/on_current_node_change.dart b/lib/reactions/on_current_node_change.dart index 59a1e4897..730fba674 100644 --- a/lib/reactions/on_current_node_change.dart +++ b/lib/reactions/on_current_node_change.dart @@ -1,3 +1,4 @@ +import 'package:cw_core/utils/print_verbose.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/node.dart'; import 'package:cake_wallet/store/app_store.dart'; @@ -10,14 +11,14 @@ void startOnCurrentNodeChangeReaction(AppStore appStore) { try { await appStore.wallet!.connectToNode(node: change.newValue!); } catch (e) { - print(e.toString()); + printV(e.toString()); } }); appStore.settingsStore.powNodes.observe((change) async { try { await appStore.wallet!.connectToPowNode(node: change.newValue!); } catch (e) { - print(e.toString()); + printV(e.toString()); } }); } diff --git a/lib/reactions/on_current_wallet_change.dart b/lib/reactions/on_current_wallet_change.dart index d7e6f90c0..3840b042e 100644 --- a/lib/reactions/on_current_wallet_change.dart +++ b/lib/reactions/on_current_wallet_change.dart @@ -9,6 +9,7 @@ import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/transaction_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/reactions/check_connection.dart'; import 'package:cake_wallet/reactions/on_wallet_sync_status_change.dart'; @@ -46,7 +47,7 @@ void startCurrentWalletChangeReaction( // appStore.wallet.walletInfo.yatLastUsedAddress = address; // await appStore.wallet.walletInfo.save(); //} catch (e) { - // print(e.toString()); + // printV(e.toString()); //} //}); @@ -63,6 +64,8 @@ void startCurrentWalletChangeReaction( startWalletSyncStatusChangeReaction(wallet, fiatConversionStore); startCheckConnectionReaction(wallet, settingsStore); + await Future.delayed(Duration.zero); + if (wallet.type == WalletType.monero || wallet.type == WalletType.wownero || wallet.type == WalletType.bitcoin || @@ -89,7 +92,7 @@ void startCurrentWalletChangeReaction( } } } catch (e) { - print(e.toString()); + printV(e.toString()); } }); @@ -136,7 +139,7 @@ void startCurrentWalletChangeReaction( } } } catch (e) { - print(e.toString()); + printV(e.toString()); } }); } diff --git a/lib/reactions/on_wallet_sync_status_change.dart b/lib/reactions/on_wallet_sync_status_change.dart index df63e4dd8..072602e5f 100644 --- a/lib/reactions/on_wallet_sync_status_change.dart +++ b/lib/reactions/on_wallet_sync_status_change.dart @@ -1,5 +1,6 @@ import 'package:cake_wallet/entities/update_haven_rate.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/transaction_history.dart'; @@ -31,7 +32,7 @@ void startWalletSyncStatusChangeReaction( await WakelockPlus.disable(); } } catch (e) { - // print(e.toString()); + printV(e.toString()); } }); } diff --git a/lib/router.dart b/lib/router.dart index 1382da28f..315c17178 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -66,9 +66,11 @@ import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart'; import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart'; import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart'; import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart'; +import 'package:cake_wallet/src/screens/seed/seed_verification/seed_verification_page.dart'; import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart'; import 'package:cake_wallet/src/screens/send/send_page.dart'; import 'package:cake_wallet/src/screens/send/send_template_page.dart'; +import 'package:cake_wallet/src/screens/send/transaction_success_info_page.dart'; import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart'; import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart'; import 'package:cake_wallet/src/screens/settings/display_settings_page.dart'; @@ -105,7 +107,8 @@ import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart'; import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart'; import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart'; import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart'; -import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart'; +import 'package:cake_wallet/src/screens/welcome/create_pin_welcome_page.dart'; +import 'package:cake_wallet/src/screens/welcome/welcome_page.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; @@ -142,36 +145,33 @@ Route createRoute(RouteSettings settings) { switch (settings.name) { case Routes.welcome: - return MaterialPageRoute(builder: (_) => createWelcomePage()); + return MaterialPageRoute(builder: (_) => CreatePinWelcomePage()); - case Routes.newWalletFromWelcome: + case Routes.welcomeWallet: if (SettingsStoreBase.walletPasswordDirectInput) { - if (availableWalletTypes.length == 1) { - return createRoute( - RouteSettings( - name: Routes.newWallet, - arguments: NewWalletArguments(type: availableWalletTypes.first), - ), - ); - } else { - return createRoute(RouteSettings(name: Routes.newWalletType)); - } + return createRoute(RouteSettings(name: Routes.welcomePage)); } - return CupertinoPageRoute( builder: (_) => getIt.get(param1: (PinCodeState context, dynamic _) { - if (availableWalletTypes.length == 1) { - Navigator.of(context.context).pushNamed( - Routes.newWallet, - arguments: NewWalletArguments(type: availableWalletTypes.first), - ); - } else { - Navigator.of(context.context).pushNamed(Routes.newWalletType); - } + Navigator.of(context.context).pushNamed(Routes.welcomePage); }), fullscreenDialog: true); + case Routes.welcomePage: + return CupertinoPageRoute(builder: (_) => getIt.get()); + + case Routes.newWalletFromWelcome: + if (isSingleCoin) { + return createRoute( + RouteSettings( + name: Routes.newWallet, + arguments: NewWalletArguments(type: availableWalletTypes.first) + ), + ); + } + return createRoute(RouteSettings(name: Routes.newWalletType)); + case Routes.newWalletType: return CupertinoPageRoute( builder: (_) => getIt.get( @@ -251,24 +251,10 @@ Route createRoute(RouteSettings settings) { builder: (_) => getIt.get(param1: isNewInstall)); case Routes.restoreWalletFromSeedKeys: - final isNewInstall = settings.arguments as bool; - - if (isNewInstall) { + if (isSingleCoin) { return CupertinoPageRoute( - builder: (_) => getIt.get( - param1: (PinCodeState context, dynamic _) { - if (isSingleCoin) { - return Navigator.of(context.context) - .pushNamed(Routes.restoreWallet, arguments: availableWalletTypes.first); - } - - return Navigator.pushNamed(context.context, Routes.restoreWalletType); - }), - fullscreenDialog: true); - } else if (isSingleCoin) { - return MaterialPageRoute( builder: (_) => getIt.get(param1: availableWalletTypes.first)); - } else { + } return CupertinoPageRoute( builder: (_) => getIt.get( param1: NewWalletTypeArguments( @@ -279,21 +265,8 @@ Route createRoute(RouteSettings settings) { ), ), ); - } case Routes.restoreWalletFromHardwareWallet: - final isNewInstall = settings.arguments as bool; - - if (isNewInstall) { - return CupertinoPageRoute( - builder: (_) => getIt.get( - param1: (PinCodeState context, dynamic _) => - Navigator.of(context.context) - .pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: false), - ), - fullscreenDialog: true, - ); - } if (isSingleCoin) { return MaterialPageRoute( builder: (_) => ConnectDevicePage( @@ -305,7 +278,7 @@ Route createRoute(RouteSettings settings) { ), getIt.get(), )); - } else { + } return CupertinoPageRoute( builder: (_) => getIt.get( param1: NewWalletTypeArguments( @@ -323,7 +296,6 @@ Route createRoute(RouteSettings settings) { ), ), ); - } case Routes.restoreWalletTypeFromQR: return CupertinoPageRoute( @@ -615,6 +587,10 @@ Route createRoute(RouteSettings settings) { return MaterialPageRoute( builder: (_) => getIt.get(param1: settings.arguments as int)); + case Routes.transactionSuccessPage: + return MaterialPageRoute( + builder: (_) => getIt.get(param1: settings.arguments as String)); + case Routes.backup: return CupertinoPageRoute( fullscreenDialog: true, builder: (_) => getIt.get()); @@ -824,6 +800,12 @@ Route createRoute(RouteSettings settings) { ), ); + case Routes.walletSeedVerificationPage: + return MaterialPageRoute( + fullscreenDialog: true, + builder: (_) => getIt.get(), + ); + default: return MaterialPageRoute( builder: (_) => Scaffold( diff --git a/lib/routes.dart b/lib/routes.dart index 0b8beb0ea..517efca29 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -1,5 +1,7 @@ class Routes { static const welcome = '/welcome'; + static const welcomeWallet = '/welcome_create_restore_wallet'; + static const welcomePage = '/welcome_page'; static const newWallet = '/new_wallet'; static const setupPin = '/setup_pin_code'; static const newWalletFromWelcome = '/new_wallet_from_welcome'; @@ -51,6 +53,7 @@ class Routes { static const restoreWalletType = '/restore_wallet_type'; static const restoreWallet = '/restore_wallet'; static const preSeedPage = '/pre_seed_page'; + static const transactionSuccessPage = '/transaction_success_info_page'; static const backup = '/backup'; static const editBackupPassword = '/edit_backup_passowrd'; static const restoreFromBackup = '/restore_from_backup'; @@ -113,4 +116,5 @@ class Routes { static const urqrAnimatedPage = '/urqr/animated_page'; static const walletGroupsDisplayPage = '/wallet_groups_display_page'; static const walletGroupDescription = '/wallet_group_description'; + static const walletSeedVerificationPage = '/wallet_seed_verification_page'; } diff --git a/lib/src/screens/auth/auth_page.dart b/lib/src/screens/auth/auth_page.dart index d14a12527..e2bc1f075 100644 --- a/lib/src/screens/auth/auth_page.dart +++ b/lib/src/screens/auth/auth_page.dart @@ -1,5 +1,6 @@ import 'package:another_flushbar/flushbar.dart'; import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:mobx/mobx.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; @@ -9,6 +10,8 @@ import 'package:cake_wallet/view_model/auth_view_model.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code.dart'; import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart'; import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:flutter/services.dart'; typedef OnAuthenticationFinished = void Function(bool, AuthPageState); @@ -66,7 +69,6 @@ class AuthPagePinCodeStateImpl extends AuthPageState { dismissFlushBar(_authBar); showBar( context, S.of(context).failed_authentication(state.error)); - widget.onAuthenticationFinished(false, this); }); } @@ -77,12 +79,12 @@ class AuthPagePinCodeStateImpl extends AuthPageState { dismissFlushBar(_authBar); showBar( context, S.of(context).failed_authentication(state.error)); - widget.onAuthenticationFinished(false, this); }); } }); + if (widget.authViewModel.isBiometricalAuthenticationAllowed) { WidgetsBinding.instance.addPostFrameCallback((_) async { await Future.delayed(Duration(milliseconds: 100)); @@ -93,6 +95,23 @@ class AuthPagePinCodeStateImpl extends AuthPageState { super.initState(); } + Future _showSeedsPopup(BuildContext context, String message) async { + await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithTwoActions( + alertTitle: "Corrupted seeds", + alertContent: message, + leftButtonText: S.of(context).copy, + rightButtonText: S.of(context).ok, + actionLeftButton: () async { + await Clipboard.setData(ClipboardData(text: message)); + }, + actionRightButton: () => Navigator.of(context).pop(), + ); + }); + } + @override void dispose() { _reaction?.reaction.dispose(); diff --git a/lib/src/screens/backup/backup_page.dart b/lib/src/screens/backup/backup_page.dart index d17702724..b8065cf36 100644 --- a/lib/src/screens/backup/backup_page.dart +++ b/lib/src/screens/backup/backup_page.dart @@ -154,7 +154,7 @@ class BackupPage extends BasePage { File returnedFile = File(outputFile!); await returnedFile.writeAsBytes(backup.content); } catch (exception, stackTrace) { - ExceptionHandler.onError(FlutterErrorDetails( + await ExceptionHandler.onError(FlutterErrorDetails( exception: exception, stack: stackTrace, library: "Export Backup", diff --git a/lib/src/screens/buy/buy_sell_page.dart b/lib/src/screens/buy/buy_sell_page.dart index d2f16fe3c..945559bb6 100644 --- a/lib/src/screens/buy/buy_sell_page.dart +++ b/lib/src/screens/buy/buy_sell_page.dart @@ -170,8 +170,9 @@ class BuySellPage extends BasePage { }, color: Theme.of(context).primaryColor, textColor: Colors.white, - isDisabled: false, - isLoading: !buySellViewModel.isReadyToTrade)), + isDisabled: buySellViewModel.isBuySellQuotFailed, + isLoading: !buySellViewModel.isReadyToTrade && + !buySellViewModel.isBuySellQuotFailed)), ]), )), )); diff --git a/lib/src/screens/buy/buy_webview_page.dart b/lib/src/screens/buy/buy_webview_page.dart index ad6970861..5bca7a2ed 100644 --- a/lib/src/screens/buy/buy_webview_page.dart +++ b/lib/src/screens/buy/buy_webview_page.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/store/dashboard/orders_store.dart'; import 'package:cake_wallet/view_model/buy/buy_view_model.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; @@ -103,7 +104,7 @@ class BuyWebViewPageBodyState extends State { } } catch (e) { _isSaving = false; - print(e); + printV(e); } }); } diff --git a/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart index 6e1af1c32..bd1840974 100644 --- a/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart +++ b/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:auto_size_text/auto_size_text.dart'; import 'package:cake_wallet/cake_pay/cake_pay_card.dart'; import 'package:cake_wallet/cake_pay/cake_pay_payment_credantials.dart'; @@ -7,6 +9,7 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/cake_pay/widgets/image_placeholder.dart'; import 'package:cake_wallet/src/screens/cake_pay/widgets/link_extractor.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/number_text_fild_widget.dart'; @@ -17,6 +20,7 @@ import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart'; import 'package:flutter/material.dart'; @@ -226,7 +230,9 @@ class CakePayBuyCardPage extends BasePage { return Padding( padding: EdgeInsets.only(bottom: 12), child: PrimaryButton( - onPressed: () => navigateToCakePayBuyCardDetailPage(context, card), + onPressed: () => isIOSUnavailable(card) + ? alertIOSAvailability(context, card) + : navigateToCakePayBuyCardDetailPage(context, card), text: S.of(context).buy_now, isDisabled: !cakePayBuyCardViewModel.isEnablePurchase, color: Theme.of(context).primaryColor, @@ -241,6 +247,62 @@ class CakePayBuyCardPage extends BasePage { ); } + bool isWordInCardsName(CakePayCard card, String word) { + return card.name.toLowerCase().contains(word.toLowerCase()); + } + + bool isIOSUnavailable(CakePayCard card) { + if (!Platform.isIOS && !Platform.isMacOS) { + return false; + } + + final isDigitalGameStores = isWordInCardsName(card, 'playstation') || + isWordInCardsName(card, 'xbox') || + isWordInCardsName(card, 'steam') || + isWordInCardsName(card, 'meta quest') || + isWordInCardsName(card, 'kigso') || + isWordInCardsName(card, 'game world') || + isWordInCardsName(card, 'google') || + isWordInCardsName(card, 'nintendo'); + final isGCodes = isWordInCardsName(card, 'gcodes'); + final isApple = isWordInCardsName(card, 'itunes') || isWordInCardsName(card, 'apple'); + final isTidal = isWordInCardsName(card, 'tidal'); + final isVPNServices = isWordInCardsName(card, 'nordvpn') || + isWordInCardsName(card, 'expressvpn') || + isWordInCardsName(card, 'surfshark') || + isWordInCardsName(card, 'proton'); + final isStreamingServices = isWordInCardsName(card, 'netflix') || + isWordInCardsName(card, 'spotify') || + isWordInCardsName(card, 'hulu') || + isWordInCardsName(card, 'hbo') || + isWordInCardsName(card, 'soundcloud') || + isWordInCardsName(card, 'twitch'); + final isDatingServices = isWordInCardsName(card, 'tinder'); + + return isDigitalGameStores || + isGCodes || + isApple || + isTidal || + isVPNServices || + isStreamingServices || + isDatingServices; + } + + Future alertIOSAvailability(BuildContext context, CakePayCard card) async { + return await showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: S.of(context).cakepay_ios_not_available, + buttonText: S.of(context).ok, + buttonAction: () { + // _walletHardwareRestoreVM.error = null; + Navigator.of(context).pop(); + }); + }); + } + Future navigateToCakePayBuyCardDetailPage(BuildContext context, CakePayCard card) async { final userName = await cakePayService.getUserEmail(); final paymentCredential = PaymentCredential( diff --git a/lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart index 31eaa23ff..450fa5281 100644 --- a/lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart +++ b/lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart @@ -94,6 +94,10 @@ class CakePayCardsPage extends BasePage { _cardsListViewModel.resetLoadingNextPageState(); _cardsListViewModel.getVendors(); } + + _cardsListViewModel.settingsStore.selectedCakePayCountry = + _cardsListViewModel.selectedCountry; + } }); }); @@ -112,7 +116,7 @@ class CakePayCardsPage extends BasePage { }, child: Container( width: 32, - padding: EdgeInsets.all(8), + padding: EdgeInsets.only(top: 7, bottom: 7), decoration: BoxDecoration( color: Theme.of(context).extension()!.syncedBackgroundColor, border: Border.all( @@ -121,7 +125,7 @@ class CakePayCardsPage extends BasePage { borderRadius: BorderRadius.circular(10), ), child: Image.asset( - 'assets/images/filter.png', + 'assets/images/filter_icon.png', color: Theme.of(context).extension()!.iconColor, ))), ); @@ -137,14 +141,14 @@ class CakePayCardsPage extends BasePage { } }, child: Container( - padding: EdgeInsets.symmetric(horizontal: 6), + padding: EdgeInsets.symmetric(horizontal: 8), decoration: BoxDecoration( color: Theme.of(context).extension()!.syncedBackgroundColor, border: Border.all(color: Colors.transparent), borderRadius: BorderRadius.circular(10), ), child: Container( - margin: EdgeInsets.symmetric(vertical: 2), + margin: EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Image.asset( @@ -359,13 +363,10 @@ class _SearchWidget extends StatelessWidget { @override Widget build(BuildContext context) { final searchIcon = ExcludeSemantics( - child: Padding( - padding: EdgeInsets.all(8), - child: Image.asset( - 'assets/images/mini_search_icon.png', + child: Icon( Icons.search, color: Theme.of(context).extension()!.iconColor, + //size: 24 ), - ), ); return TextField( @@ -375,8 +376,8 @@ class _SearchWidget extends StatelessWidget { decoration: InputDecoration( filled: true, contentPadding: EdgeInsets.only( - top: 10, - left: 10, + top: 8, + left: 8, ), fillColor: Theme.of(context).extension()!.syncedBackgroundColor, hintText: S.of(context).search, diff --git a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart index 9357df2c3..fc3679104 100644 --- a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart +++ b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart @@ -10,8 +10,10 @@ import 'package:cake_wallet/src/screens/cake_pay/widgets/text_icon_button.dart'; import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/themes/extensions/picker_theme.dart'; import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; @@ -23,6 +25,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; +import 'package:url_launcher/url_launcher.dart'; class CakePayBuyCardDetailPage extends BasePage { CakePayBuyCardDetailPage(this.cakePayPurchaseViewModel); @@ -207,8 +210,10 @@ class CakePayBuyCardDetailPage extends BasePage { padding: EdgeInsets.only(bottom: 12), child: Observer(builder: (_) { return LoadingPrimaryButton( - isLoading: cakePayPurchaseViewModel.sendViewModel.state is IsExecutingState, - onPressed: () => purchaseCard(context), + isDisabled: cakePayPurchaseViewModel.isPurchasing, + isLoading: cakePayPurchaseViewModel.isPurchasing || + cakePayPurchaseViewModel.sendViewModel.state is IsExecutingState, + onPressed: () => confirmPurchaseFirst(context), text: S.of(context).purchase_gift_card, color: Theme.of(context).primaryColor, textColor: Colors.white, @@ -253,6 +258,48 @@ class CakePayBuyCardDetailPage extends BasePage { }); } + Future _showconfirmPurchaseFirstAlert(BuildContext context) async { + if (!cakePayPurchaseViewModel.confirmsNoVpn || + !cakePayPurchaseViewModel.confirmsVoidedRefund || + !cakePayPurchaseViewModel.confirmsTermsAgreed) { + await showPopUp( + context: context, + builder: (BuildContext context) => ThreeCheckboxAlert( + alertTitle: S.of(context).cakepay_confirm_purchase, + leftButtonText: S.of(context).cancel, + rightButtonText: S.of(context).confirm, + actionLeftButton: () { + cakePayPurchaseViewModel.isPurchasing = false; + Navigator.of(context).pop(); + }, + actionRightButton: (confirmsNoVpn, confirmsVoidedRefund, confirmsTermsAgreed) { + cakePayPurchaseViewModel.confirmsNoVpn = confirmsNoVpn; + cakePayPurchaseViewModel.confirmsVoidedRefund = confirmsVoidedRefund; + cakePayPurchaseViewModel.confirmsTermsAgreed = confirmsTermsAgreed; + + Navigator.of(context).pop(); + }, + ), + ); + } + + if (cakePayPurchaseViewModel.confirmsNoVpn && + cakePayPurchaseViewModel.confirmsVoidedRefund && + cakePayPurchaseViewModel.confirmsTermsAgreed) { + await purchaseCard(context); + } + } + + Future confirmPurchaseFirst(BuildContext context) async { + bool isLogged = await cakePayPurchaseViewModel.cakePayService.isLogged(); + if (!isLogged) { + Navigator.of(context).pushNamed(Routes.cakePayWelcomePage); + } else { + cakePayPurchaseViewModel.isPurchasing = true; + await _showconfirmPurchaseFirstAlert(context); + } + } + Future purchaseCard(BuildContext context) async { bool isLogged = await cakePayPurchaseViewModel.cakePayService.isLogged(); if (!isLogged) { @@ -263,7 +310,9 @@ class CakePayBuyCardDetailPage extends BasePage { } catch (_) { await cakePayPurchaseViewModel.cakePayService.logout(); } - } + + } + cakePayPurchaseViewModel.isPurchasing = false; } void _showHowToUseCard( @@ -428,3 +477,201 @@ class CakePayBuyCardDetailPage extends BasePage { } } } + +class ThreeCheckboxAlert extends BaseAlertDialog { + ThreeCheckboxAlert({ + required this.alertTitle, + required this.leftButtonText, + required this.rightButtonText, + required this.actionLeftButton, + required this.actionRightButton, + this.alertBarrierDismissible = true, + Key? key, + }); + + final String alertTitle; + final String leftButtonText; + final String rightButtonText; + final VoidCallback actionLeftButton; + final Function(bool, bool, bool) actionRightButton; + final bool alertBarrierDismissible; + + bool checkbox1 = false; + void toggleCheckbox1() => checkbox1 = !checkbox1; + bool checkbox2 = false; + void toggleCheckbox2() => checkbox2 = !checkbox2; + bool checkbox3 = false; + void toggleCheckbox3() => checkbox3 = !checkbox3; + + bool showValidationMessage = true; + + @override + String get titleText => alertTitle; + + @override + bool get isDividerExists => true; + + @override + String get leftActionButtonText => leftButtonText; + + @override + String get rightActionButtonText => rightButtonText; + + @override + VoidCallback get actionLeft => actionLeftButton; + + @override + VoidCallback get actionRight => () { + actionRightButton(checkbox1, checkbox2, checkbox3); + }; + + @override + bool get barrierDismissible => alertBarrierDismissible; + + @override + Widget content(BuildContext context) { + return ThreeCheckboxAlertContent( + checkbox1: checkbox1, + toggleCheckbox1: toggleCheckbox1, + checkbox2: checkbox2, + toggleCheckbox2: toggleCheckbox2, + checkbox3: checkbox3, + toggleCheckbox3: toggleCheckbox3, + ); + } +} + +class ThreeCheckboxAlertContent extends StatefulWidget { + ThreeCheckboxAlertContent({ + required this.checkbox1, + required this.toggleCheckbox1, + required this.checkbox2, + required this.toggleCheckbox2, + required this.checkbox3, + required this.toggleCheckbox3, + Key? key, + }) : super(key: key); + + bool checkbox1; + void Function() toggleCheckbox1; + bool checkbox2; + void Function() toggleCheckbox2; + bool checkbox3; + void Function() toggleCheckbox3; + + @override + _ThreeCheckboxAlertContentState createState() => _ThreeCheckboxAlertContentState( + checkbox1: checkbox1, + toggleCheckbox1: toggleCheckbox1, + checkbox2: checkbox2, + toggleCheckbox2: toggleCheckbox2, + checkbox3: checkbox3, + toggleCheckbox3: toggleCheckbox3, + ); + + static _ThreeCheckboxAlertContentState? of(BuildContext context) { + return context.findAncestorStateOfType<_ThreeCheckboxAlertContentState>(); + } +} + +class _ThreeCheckboxAlertContentState extends State { + _ThreeCheckboxAlertContentState({ + required this.checkbox1, + required this.toggleCheckbox1, + required this.checkbox2, + required this.toggleCheckbox2, + required this.checkbox3, + required this.toggleCheckbox3, + }); + + bool checkbox1; + void Function() toggleCheckbox1; + bool checkbox2; + void Function() toggleCheckbox2; + bool checkbox3; + void Function() toggleCheckbox3; + + bool showValidationMessage = true; + + bool get areAllCheckboxesChecked => checkbox1 && checkbox2 && checkbox3; + + @override + Widget build(BuildContext context) { + return Form( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + StandardCheckbox( + value: checkbox1, + caption: S.of(context).cakepay_confirm_no_vpn, + onChanged: (bool? value) { + setState(() { + checkbox1 = value ?? false; + toggleCheckbox1(); + showValidationMessage = !areAllCheckboxesChecked; + }); + }, + ), + StandardCheckbox( + value: checkbox2, + caption: S.of(context).cakepay_confirm_voided_refund, + onChanged: (bool? value) { + setState(() { + checkbox2 = value ?? false; + toggleCheckbox2(); + showValidationMessage = !areAllCheckboxesChecked; + }); + }, + ), + StandardCheckbox( + value: checkbox3, + caption: S.of(context).cakepay_confirm_terms_agreed, + onChanged: (bool? value) { + setState(() { + checkbox3 = value ?? false; + toggleCheckbox3(); + showValidationMessage = !areAllCheckboxesChecked; + }); + }, + ), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: () => launchUrl( + Uri.parse("https://cakepay.com/cakepay-web-terms.txt"), + mode: LaunchMode.externalApplication, + ), + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + S.of(context).settings_terms_and_conditions, + style: TextStyle( + fontSize: 16, + fontFamily: 'Lato', + fontWeight: FontWeight.w400, + color: Theme.of(context).primaryColor, + decoration: TextDecoration.none, + height: 1, + ), + softWrap: true, + ), + ), + ), + if (showValidationMessage) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + 'Please confirm all checkboxes', + style: TextStyle( + color: Colors.red, + fontSize: 14, + fontFamily: 'Lato', + fontWeight: FontWeight.w400, + decoration: TextDecoration.none, + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/connect_device/connect_device_page.dart b/lib/src/screens/connect_device/connect_device_page.dart index c2cc40229..5e52b887c 100644 --- a/lib/src/screens/connect_device/connect_device_page.dart +++ b/lib/src/screens/connect_device/connect_device_page.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; @@ -21,11 +22,13 @@ class ConnectDevicePageParams { final WalletType walletType; final OnConnectDevice onConnectDevice; final bool allowChangeWallet; + final bool isReconnect; ConnectDevicePageParams({ required this.walletType, required this.onConnectDevice, this.allowChangeWallet = false, + this.isReconnect = false, }); } @@ -33,19 +36,33 @@ class ConnectDevicePage extends BasePage { final WalletType walletType; final OnConnectDevice onConnectDevice; final bool allowChangeWallet; + final bool isReconnect; final LedgerViewModel ledgerVM; ConnectDevicePage(ConnectDevicePageParams params, this.ledgerVM) : walletType = params.walletType, onConnectDevice = params.onConnectDevice, - allowChangeWallet = params.allowChangeWallet; + allowChangeWallet = params.allowChangeWallet, + isReconnect = params.isReconnect; @override - String get title => S.current.restore_title_from_hardware_wallet; + String get title => isReconnect + ? S.current.reconnect_your_hardware_wallet + : S.current.restore_title_from_hardware_wallet; @override - Widget body(BuildContext context) => ConnectDevicePageBody( - walletType, onConnectDevice, allowChangeWallet, ledgerVM); + Widget? leading(BuildContext context) => + !isReconnect ? super.leading(context) : null; + + @override + Widget body(BuildContext context) => PopScope( + canPop: !isReconnect, + child: ConnectDevicePageBody( + walletType, + onConnectDevice, + allowChangeWallet, + ledgerVM, + )); } class ConnectDevicePageBody extends StatefulWidget { @@ -74,6 +91,9 @@ class ConnectDevicePageBodyState extends State { late Timer? _bleStateTimer = null; late StreamSubscription? _bleRefresh = null; + bool longWait = false; + Timer? _longWaitTimer; + @override void initState() { super.initState(); @@ -88,6 +108,11 @@ class ConnectDevicePageBodyState extends State { _usbRefreshTimer = Timer.periodic(Duration(seconds: 1), (_) => _refreshUsbDevices()); } + + _longWaitTimer = Timer(Duration(seconds: 10), () { + if (widget.ledgerVM.bleIsEnabled && bleDevices.isEmpty) + setState(() => longWait = true); + }); }); } @@ -97,6 +122,9 @@ class ConnectDevicePageBodyState extends State { _bleStateTimer?.cancel(); _usbRefreshTimer?.cancel(); _bleRefresh?.cancel(); + _longWaitTimer?.cancel(); + + widget.ledgerVM.stopScanning(); super.dispose(); } @@ -117,17 +145,19 @@ class ConnectDevicePageBodyState extends State { Future _refreshBleDevices() async { try { if (widget.ledgerVM.bleIsEnabled) { - _bleRefresh = widget.ledgerVM - .scanForBleDevices() - .listen((device) => setState(() => bleDevices.add(device))) - ..onError((e) { - throw e.toString(); - }); + _bleRefresh = + widget.ledgerVM.scanForBleDevices().listen((device) => setState(() { + bleDevices.add(device); + if (longWait) longWait = false; + })) + ..onError((e) { + throw e.toString(); + }); _bleRefreshTimer?.cancel(); _bleRefreshTimer = null; } } catch (e) { - print(e); + printV(e); } } @@ -174,15 +204,22 @@ class ConnectDevicePageBodyState extends State { textAlign: TextAlign.center, ), ), - // DeviceTile( - // onPressed: () => Navigator.of(context).push( - // MaterialPageRoute( - // builder: (BuildContext context) => DebugDevicePage(), - // ), - // ), - // title: "Debug Ledger", - // leading: imageLedger, - // ), + Offstage( + offstage: !longWait, + child: Padding( + padding: EdgeInsets.only(left: 20, right: 20, bottom: 20), + child: Text( + S.of(context).if_you_dont_see_your_device, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context) + .extension()! + .titleColor), + textAlign: TextAlign.center, + ), + ), + ), Observer( builder: (_) => Offstage( offstage: widget.ledgerVM.bleIsEnabled, @@ -201,7 +238,6 @@ class ConnectDevicePageBodyState extends State { ), ), ), - if (bleDevices.length > 0) ...[ Padding( padding: EdgeInsets.only(left: 20, right: 20, bottom: 20), @@ -243,7 +279,9 @@ class ConnectDevicePageBodyState extends State { style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, - color: Theme.of(context).extension()!.titleColor, + color: Theme.of(context) + .extension()! + .titleColor, ), ), ), @@ -265,8 +303,12 @@ class ConnectDevicePageBodyState extends State { if (widget.allowChangeWallet) ...[ PrimaryButton( text: S.of(context).wallets, - color: Theme.of(context).extension()!.createNewWalletButtonBackgroundColor, - textColor: Theme.of(context).extension()!.restoreWalletButtonTextColor, + color: Theme.of(context) + .extension()! + .createNewWalletButtonBackgroundColor, + textColor: Theme.of(context) + .extension()! + .restoreWalletButtonTextColor, onPressed: _onChangeWallet, ) ], diff --git a/lib/src/screens/connect_device/debug_device_page.dart b/lib/src/screens/connect_device/debug_device_page.dart index bed9d59a7..d5af9f2f6 100644 --- a/lib/src/screens/connect_device/debug_device_page.dart +++ b/lib/src/screens/connect_device/debug_device_page.dart @@ -223,10 +223,10 @@ // setState(() => status = "Sending..."); // final acc = await func(); // setState(() => status = "$method: $acc"); -// print("$method: $acc"); +// printV("$method: $acc"); // } on LedgerException catch (ex) { // setState(() => status = "${ex.errorCode.toRadixString(16)} ${ex.message}"); -// print("${ex.errorCode.toRadixString(16)} ${ex.message}"); +// printV("${ex.errorCode.toRadixString(16)} ${ex.message}"); // } // }, // color: Theme.of(context).primaryColor, diff --git a/lib/src/screens/contact/contact_list_page.dart b/lib/src/screens/contact/contact_list_page.dart index 166288135..50b4ae7c0 100644 --- a/lib/src/screens/contact/contact_list_page.dart +++ b/lib/src/screens/contact/contact_list_page.dart @@ -322,6 +322,7 @@ class _ContactListBodyState extends State { ? widget.contactListViewModel.contacts : widget.contactListViewModel.contactsToShow; return Scaffold( + backgroundColor: Theme.of(context).colorScheme.background, body: Container( child: FilteredList( list: contacts, diff --git a/lib/src/screens/dashboard/dashboard_page.dart b/lib/src/screens/dashboard/dashboard_page.dart index 9c012d518..8c236404d 100644 --- a/lib/src/screens/dashboard/dashboard_page.dart +++ b/lib/src/screens/dashboard/dashboard_page.dart @@ -285,38 +285,40 @@ class _DashboardPageView extends BasePage { .syncedBackgroundColor, ), child: Container( - padding: EdgeInsets.only(left: 24, right: 32), + padding: EdgeInsets.symmetric(horizontal: 10), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: MainActions.all .where((element) => element.canShow?.call(dashboardViewModel) ?? true) .map( - (action) => Semantics( - button: true, - enabled: (action.isEnabled?.call(dashboardViewModel) ?? true), - child: ActionButton( - key: ValueKey( - 'dashboard_page_${action.name(context)}_action_button_key'), - image: Image.asset( - action.image, - height: 24, - width: 24, - color: action.isEnabled?.call(dashboardViewModel) ?? true - ? Theme.of(context) - .extension()! - .mainActionsIconColor + (action) => Expanded( + child: Semantics( + button: true, + enabled: (action.isEnabled?.call(dashboardViewModel) ?? true), + child: ActionButton( + key: ValueKey( + 'dashboard_page_${action.name(context)}_action_button_key'), + image: Image.asset( + action.image, + height: 24, + width: 24, + color: action.isEnabled?.call(dashboardViewModel) ?? true + ? Theme.of(context) + .extension()! + .mainActionsIconColor + : Theme.of(context) + .extension()! + .labelTextColor, + ), + title: action.name(context), + onClick: () async => + await action.onTap(context, dashboardViewModel), + textColor: action.isEnabled?.call(dashboardViewModel) ?? true + ? null : Theme.of(context) .extension()! .labelTextColor, ), - title: action.name(context), - onClick: () async => - await action.onTap(context, dashboardViewModel), - textColor: action.isEnabled?.call(dashboardViewModel) ?? true - ? null - : Theme.of(context) - .extension()! - .labelTextColor, ), ), ) diff --git a/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart b/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart index 0fb629685..e5f38010d 100644 --- a/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart +++ b/lib/src/screens/dashboard/desktop_widgets/desktop_wallet_selection_dropdown.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.da import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/themes/extensions/menu_theme.dart'; +import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; diff --git a/lib/src/screens/dashboard/pages/balance_page.dart b/lib/src/screens/dashboard/pages/balance_page.dart index b16a7b090..a71a6288b 100644 --- a/lib/src/screens/dashboard/pages/balance_page.dart +++ b/lib/src/screens/dashboard/pages/balance_page.dart @@ -118,12 +118,7 @@ class CryptoBalanceWidget extends StatelessWidget { @override Widget build(BuildContext context) { - return GestureDetector( - onLongPress: () => dashboardViewModel.balanceViewModel.isReversing = - !dashboardViewModel.balanceViewModel.isReversing, - onLongPressUp: () => dashboardViewModel.balanceViewModel.isReversing = - !dashboardViewModel.balanceViewModel.isReversing, - child: SingleChildScrollView( + return SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ @@ -325,7 +320,7 @@ class CryptoBalanceWidget extends StatelessWidget { behavior: HitTestBehavior.opaque, onTap: () => launchUrl( Uri.parse( - "https://guides.cakewallet.com/docs/cryptos/bitcoin/#silent-payments"), + "https://docs.cakewallet.com/cryptos/bitcoin#silent-payments"), mode: LaunchMode.externalApplication, ), child: Row( @@ -389,7 +384,7 @@ class CryptoBalanceWidget extends StatelessWidget { behavior: HitTestBehavior.opaque, onTap: () => launchUrl( Uri.parse( - "https://guides.cakewallet.com/docs/cryptos/litecoin/#mweb"), + "https://docs.cakewallet.com/cryptos/litecoin/#mweb"), mode: LaunchMode.externalApplication, ), child: Text( @@ -459,7 +454,6 @@ class CryptoBalanceWidget extends StatelessWidget { }), ], ), - ), ); } @@ -597,44 +591,47 @@ class BalanceRowWidget extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( + GestureDetector( + onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(), + child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: hasAdditionalBalance - ? () => _showBalanceDescription( - context, S.of(context).available_balance_description) - : null, - child: Column( + Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Row( - children: [ - Semantics( - hint: 'Double tap to see more information', - container: true, - child: Text('${availableBalanceLabel}', - style: TextStyle( - fontSize: 12, - fontFamily: 'Lato', - fontWeight: FontWeight.w400, - color: Theme.of(context) - .extension()! - .labelTextColor, - height: 1)), + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: hasAdditionalBalance + ? () => _showBalanceDescription( + context, S.of(context).available_balance_description) + : null, + child: Row( + children: [ + Semantics( + hint: 'Double tap to see more information', + container: true, + child: Text('${availableBalanceLabel}', + style: TextStyle( + fontSize: 12, + fontFamily: 'Lato', + fontWeight: FontWeight.w400, + color: Theme.of(context) + .extension()! + .labelTextColor, + height: 1)), + ), + if (hasAdditionalBalance) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 4), + child: Icon(Icons.help_outline, + size: 16, + color: Theme.of(context) + .extension()! + .labelTextColor), + ), + ], ), - if (hasAdditionalBalance) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 4), - child: Icon(Icons.help_outline, - size: 16, - color: Theme.of(context) - .extension()! - .labelTextColor), - ), - ], ), SizedBox(height: 6), AutoSizeText(availableBalance, @@ -667,9 +664,10 @@ class BalanceRowWidget extends StatelessWidget { fontWeight: FontWeight.w500, color: Theme.of(context).extension()!.textColor, height: 1)), + ], ), - ), + SizedBox( width: min(MediaQuery.of(context).size.width * 0.2, 100), child: Center( @@ -712,6 +710,7 @@ class BalanceRowWidget extends StatelessWidget { ), ], ), + ), if (frozenBalance.isNotEmpty) GestureDetector( behavior: HitTestBehavior.opaque, @@ -778,7 +777,9 @@ class BalanceRowWidget extends StatelessWidget { ), ), if (hasAdditionalBalance) - Column( + GestureDetector( + onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(), + child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox(height: 24), @@ -821,12 +822,13 @@ class BalanceRowWidget extends StatelessWidget { ), ], ), + ), ], ), ), ), if (hasSecondAdditionalBalance || hasSecondAvailableBalance) ...[ - SizedBox(height: 16), + SizedBox(height: 10), Container( margin: const EdgeInsets.only(left: 16, right: 16), decoration: BoxDecoration( @@ -881,7 +883,9 @@ class BalanceRowWidget extends StatelessWidget { ], ), if (hasSecondAvailableBalance) - Row( + GestureDetector( + onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(), + child: Row( children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -890,7 +894,7 @@ class BalanceRowWidget extends StatelessWidget { behavior: HitTestBehavior.opaque, onTap: () => launchUrl( Uri.parse( - "https://guides.cakewallet.com/docs/cryptos/litecoin/#mweb"), + "https://docs.cakewallet.com/cryptos/litecoin.html#mweb"), mode: LaunchMode.externalApplication, ), child: Row( @@ -953,6 +957,7 @@ class BalanceRowWidget extends StatelessWidget { ), ], ), + ), ], ), ), diff --git a/lib/src/screens/dashboard/pages/cake_features_page.dart b/lib/src/screens/dashboard/pages/cake_features_page.dart index 37bc3a55f..bd96fd534 100644 --- a/lib/src/screens/dashboard/pages/cake_features_page.dart +++ b/lib/src/screens/dashboard/pages/cake_features_page.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; @@ -5,96 +7,93 @@ import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart'; import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:flutter_svg/flutter_svg.dart'; class CakeFeaturesPage extends StatelessWidget { CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel}); final DashboardViewModel dashboardViewModel; final CakeFeaturesViewModel cakeFeaturesViewModel; - final _scrollController = ScrollController(); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: RawScrollbar( - thumbColor: Colors.white.withOpacity(0.15), - radius: Radius.circular(20), - thumbVisibility: true, - thickness: 2, - controller: _scrollController, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 10.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SizedBox(height: 50), - Text( - 'Cake ${S.of(context).features}', - style: TextStyle( - fontSize: 24, - fontWeight: FontWeight.w500, - color: Theme.of(context).extension()!.pageTitleTextColor, - ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 50), + Text( + 'Cake ${S.of(context).features}', + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.pageTitleTextColor, ), - Expanded( - child: ListView( - controller: _scrollController, - children: [ - SizedBox(height: 20), - DashBoardRoundedCardWidget( - onTap: () => _navigatorToGiftCardsPage(context), - title: 'Cake Pay', - subTitle: S.of(context).cake_pay_subtitle, - image: Image.asset( - 'assets/images/cards.png', - height: 100, - width: 115, - fit: BoxFit.cover, - ), + ), + Expanded( + child: ListView( + children: [ + SizedBox(height: 20), + DashBoardRoundedCardWidget( + onTap: () { + if (Platform.isMacOS) { + _launchUrl("buy.cakepay.com"); + } else { + _navigatorToGiftCardsPage(context); + } + }, + title: 'Cake Pay', + subTitle: S.of(context).cake_pay_subtitle, + image: Image.asset( + 'assets/images/cards.png', + height: 100, + width: 115, + fit: BoxFit.cover, ), - SizedBox(height: 10), - DashBoardRoundedCardWidget( - onTap: () => _launchUrl("cake.nano-gpt.com"), - title: "NanoGPT", - subTitle: S.of(context).nanogpt_subtitle, - image: Image.asset( - 'assets/images/nanogpt.png', - height: 80, - width: 80, - fit: BoxFit.cover, - ), + ), + SizedBox(height: 10), + DashBoardRoundedCardWidget( + onTap: () => _launchUrl("cake.nano-gpt.com"), + title: "NanoGPT", + subTitle: S.of(context).nanogpt_subtitle, + image: Image.asset( + 'assets/images/nanogpt.png', + height: 80, + width: 80, + fit: BoxFit.cover, ), - SizedBox(height: 10), - Observer( - builder: (context) { - if (!dashboardViewModel.hasSignMessages) { - return const SizedBox(); - } - return DashBoardRoundedCardWidget( - onTap: () => Navigator.of(context).pushNamed(Routes.signPage), - title: S.current.sign_verify_message, - subTitle: S.current.sign_verify_message_sub, - icon: Icon( - Icons.speaker_notes_rounded, - color: - Theme.of(context).extension()!.pageTitleTextColor, - size: 75, - ), - ); - }, - ), - ], - ), + ), + SizedBox(height: 10), + Observer( + builder: (context) { + if (!dashboardViewModel.hasSignMessages) { + return const SizedBox(); + } + return DashBoardRoundedCardWidget( + onTap: () => Navigator.of(context).pushNamed(Routes.signPage), + title: S.current.sign_verify_message, + subTitle: S.current.sign_verify_message_sub, + icon: Icon( + Icons.speaker_notes_rounded, + color: + Theme.of(context).extension()!.pageTitleTextColor, + size: 75, + ), + ); + }, + ), + ], ), - ], - ), + ), + ], ), ), ); @@ -107,7 +106,7 @@ class CakeFeaturesPage extends StatelessWidget { mode: LaunchMode.externalApplication, ); } catch (e) { - print(e); + printV(e); } } diff --git a/lib/src/screens/dashboard/pages/transactions_page.dart b/lib/src/screens/dashboard/pages/transactions_page.dart index 0db9ac35b..9472110ea 100644 --- a/lib/src/screens/dashboard/pages/transactions_page.dart +++ b/lib/src/screens/dashboard/pages/transactions_page.dart @@ -53,7 +53,7 @@ class TransactionsPage extends StatelessWidget { onTap: () { try { final uri = Uri.parse( - "https://guides.cakewallet.com/docs/FAQ/why_are_my_funds_not_appearing/"); + "https://docs.cakewallet.com/faq/funds-not-appearing"); launchUrl(uri, mode: LaunchMode.externalApplication); } catch (_) {} }, diff --git a/lib/src/screens/dashboard/widgets/action_button.dart b/lib/src/screens/dashboard/widgets/action_button.dart index 49ebab3cd..21f056c0c 100644 --- a/lib/src/screens/dashboard/widgets/action_button.dart +++ b/lib/src/screens/dashboard/widgets/action_button.dart @@ -50,6 +50,7 @@ class ActionButton extends StatelessWidget { fontSize: 10, color: textColor ?? Theme.of(context).extension()!.cardTextColor), + textAlign: TextAlign.center, ) ], ), diff --git a/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart b/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart index 21133a438..aca3231ec 100644 --- a/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart +++ b/lib/src/screens/dashboard/widgets/sync_indicator_icon.dart @@ -8,7 +8,7 @@ class SyncIndicatorIcon extends StatelessWidget { {this.boolMode = true, this.isSynced = false, this.value = waiting, - this.size = 4.0}); + this.size = 6.0}); final bool boolMode; final bool isSynced; diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index 387904df0..e63a01f61 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -347,7 +347,7 @@ class _WalletNameFormState extends State { key: ValueKey('new_wallet_page_confirm_button_key'), onPressed: _confirmForm, text: S.of(context).seed_language_next, - color: Colors.green, + color: Theme.of(context).primaryColor, textColor: Colors.white, isLoading: _walletNewVM.state is IsExecutingState, isDisabled: _walletNewVM.name.isEmpty, diff --git a/lib/src/screens/new_wallet/widgets/select_button.dart b/lib/src/screens/new_wallet/widgets/select_button.dart index 87015b89e..6cca53cf5 100644 --- a/lib/src/screens/new_wallet/widgets/select_button.dart +++ b/lib/src/screens/new_wallet/widgets/select_button.dart @@ -40,7 +40,7 @@ class SelectButton extends StatelessWidget { @override Widget build(BuildContext context) { - final backgroundColor = color ?? (isSelected ? Colors.green : Theme.of(context).cardColor); + final backgroundColor = color ?? (isSelected ? Theme.of(context).primaryColor : Theme.of(context).cardColor); final effectiveTextColor = textColor ?? (isSelected ? Theme.of(context).extension()!.restoreWalletButtonTextColor diff --git a/lib/src/screens/receive/widgets/header_tile.dart b/lib/src/screens/receive/widgets/header_tile.dart index dc48db89d..68148bbee 100644 --- a/lib/src/screens/receive/widgets/header_tile.dart +++ b/lib/src/screens/receive/widgets/header_tile.dart @@ -31,7 +31,7 @@ class _HeaderTileState extends State { @override Widget build(BuildContext context) { - final searchIcon = Image.asset("assets/images/search_icon.png", + final searchIcon = Icon( Icons.search, color: Theme.of(context).extension()!.iconsColor); return Container( diff --git a/lib/src/screens/restore/restore_options_page.dart b/lib/src/screens/restore/restore_options_page.dart index d1d419d60..2e9e04acd 100644 --- a/lib/src/screens/restore/restore_options_page.dart +++ b/lib/src/screens/restore/restore_options_page.dart @@ -56,9 +56,8 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { } if (isMoneroOnly) { - // return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS) - // .isNotEmpty; - return false; + return DeviceConnectionType.supportedConnectionTypes(WalletType.monero, Platform.isIOS) + .isNotEmpty; } return true; @@ -85,9 +84,7 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { key: ValueKey('restore_options_from_seeds_or_keys_button_key'), onPressed: () => Navigator.pushNamed( context, - Routes.restoreWalletFromSeedKeys, - arguments: widget.isNewInstall, - ), + Routes.restoreWalletFromSeedKeys), image: imageSeedKeys, title: S.of(context).restore_title_from_seed_keys, description: S.of(context).restore_description_from_seed_keys, @@ -109,8 +106,7 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { child: OptionTile( key: ValueKey('restore_options_from_hardware_wallet_button_key'), onPressed: () => Navigator.pushNamed( - context, Routes.restoreWalletFromHardwareWallet, - arguments: widget.isNewInstall), + context, Routes.restoreWalletFromHardwareWallet), image: imageLedger, title: S.of(context).restore_title_from_hardware_wallet, description: S.of(context).restore_description_from_hardware_wallet, @@ -158,15 +154,6 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { await PermissionHandler.checkPermission(Permission.camera, context); if (!isCameraPermissionGranted) return; - bool isPinSet = false; - if (widget.isNewInstall) { - await Navigator.pushNamed(context, Routes.setupPin, - arguments: (PinCodeState setupPinContext, String _) { - setupPinContext.close(); - isPinSet = true; - }); - } - if (!widget.isNewInstall || isPinSet) { try { if (isRestoring) { return; @@ -188,5 +175,4 @@ class _RestoreOptionsBodyState extends State<_RestoreOptionsBody> { _onWalletCreateFailure(context, e.toString()); } } - } } diff --git a/lib/src/screens/root/root.dart b/lib/src/screens/root/root.dart index 9fd427a93..9e984f133 100644 --- a/lib/src/screens/root/root.dart +++ b/lib/src/screens/root/root.dart @@ -8,6 +8,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/view_model/link_view_model.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; @@ -99,7 +100,7 @@ class RootState extends State with WidgetsBindingObserver { handleDeepLinking(await getInitialUri()); } catch (e) { - print(e); + printV(e); } } diff --git a/lib/src/screens/seed/pre_seed_page.dart b/lib/src/screens/seed/pre_seed_page.dart index 475f45fca..91a47fda5 100644 --- a/lib/src/screens/seed/pre_seed_page.dart +++ b/lib/src/screens/seed/pre_seed_page.dart @@ -25,5 +25,5 @@ class PreSeedPage extends InfoPage { @override void Function(BuildContext) get onPressed => - (BuildContext context) => Navigator.of(context).popAndPushNamed(Routes.seed, arguments: true); + (BuildContext context) => Navigator.of(context).pushNamed(Routes.seed, arguments: true); } diff --git a/lib/src/screens/seed/seed_verification/seed_verification_page.dart b/lib/src/screens/seed/seed_verification/seed_verification_page.dart new file mode 100644 index 000000000..755cb2aae --- /dev/null +++ b/lib/src/screens/seed/seed_verification/seed_verification_page.dart @@ -0,0 +1,35 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/seed/seed_verification/seed_verification_step_view.dart'; +import 'package:cake_wallet/src/screens/seed/seed_verification/seed_verification_success_view.dart'; +import 'package:cake_wallet/view_model/wallet_seed_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; + +class SeedVerificationPage extends BasePage { + final WalletSeedViewModel walletSeedViewModel; + + SeedVerificationPage(this.walletSeedViewModel); + + @override + String? get title => S.current.verify_seed; + + @override + Widget body(BuildContext context) { + return Observer( + builder: (context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: walletSeedViewModel.isVerificationComplete + ? SeedVerificationSuccessView( + imageColor: titleColor(context), + ) + : SeedVerificationStepView( + walletSeedViewModel: walletSeedViewModel, + questionTextColor: titleColor(context), + ), + ); + }, + ); + } +} diff --git a/lib/src/screens/seed/seed_verification/seed_verification_step_view.dart b/lib/src/screens/seed/seed_verification/seed_verification_step_view.dart new file mode 100644 index 000000000..c7b4b31e6 --- /dev/null +++ b/lib/src/screens/seed/seed_verification/seed_verification_step_view.dart @@ -0,0 +1,135 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/utils/show_bar.dart'; +import 'package:cake_wallet/view_model/wallet_seed_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; + +class SeedVerificationStepView extends StatelessWidget { + const SeedVerificationStepView({ + required this.walletSeedViewModel, + required this.questionTextColor, + super.key, + }); + + final WalletSeedViewModel walletSeedViewModel; + final Color questionTextColor; + + @override + Widget build(BuildContext context) { + return Observer( + builder: (context) { + return Padding( + padding: EdgeInsets.symmetric(horizontal: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 48), + Align( + alignment: Alignment.center, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${S.current.seed_position_question_one} ', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: questionTextColor, + ), + ), + TextSpan( + text: '${getOrdinal(walletSeedViewModel.currentWordIndex + 1)} ', + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w800, + color: questionTextColor, + ), + ), + TextSpan( + text: S.current.seed_position_question_two, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: questionTextColor, + ), + ), + ], + ), + textAlign: TextAlign.center, + ), + ), + const SizedBox(height: 24), + Align( + alignment: Alignment.center, + child: Wrap( + spacing: 8, + runSpacing: 8, + alignment: WrapAlignment.center, + children: walletSeedViewModel.currentOptions.map( + (option) { + return GestureDetector( + onTap: () async { + final isCorrectWord = walletSeedViewModel.isChosenWordCorrect(option); + final isSecondWrongEntry = walletSeedViewModel.wrongEntries == 2; + if (!isCorrectWord) { + await showBar( + context, + isSecondWrongEntry + ? S.current.incorrect_seed_option_back + : S.current.incorrect_seed_option, + ); + + if (isSecondWrongEntry) { + Navigator.pop(context); + } + } + }, + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + color: Theme.of(context).cardColor, + ), + child: Text( + option, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w800, + color: Theme.of(context).extension()!.buttonTextColor, + ), + ), + ), + ); + }, + ).toList(), + ), + ), + ], + ), + ); + }, + ); + } + + String getOrdinal(int number) { + // Handle special cases for 11th, 12th, 13th + final lastTwoDigits = number % 100; + if (lastTwoDigits >= 11 && lastTwoDigits <= 13) { + return '${number}th'; + } + + // Check the last digit for st, nd, rd, or default th + final lastDigit = number % 10; + switch (lastDigit) { + case 1: + return '${number}st'; + case 2: + return '${number}nd'; + case 3: + return '${number}rd'; + default: + return '${number}th'; + } + } +} diff --git a/lib/src/screens/seed/seed_verification/seed_verification_success_view.dart b/lib/src/screens/seed/seed_verification/seed_verification_success_view.dart new file mode 100644 index 000000000..7d73e7a9c --- /dev/null +++ b/lib/src/screens/seed/seed_verification/seed_verification_success_view.dart @@ -0,0 +1,74 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:flutter/material.dart'; + +class SeedVerificationSuccessView extends StatelessWidget { + const SeedVerificationSuccessView({required this.imageColor, super.key}); + + final Color imageColor; + + @override + Widget build(BuildContext context) { + final image = Image.asset('assets/images/seed_verified.png', color: imageColor); + + return Center( + child: Column( + children: [ + ConstrainedBox( + constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3), + child: AspectRatio( + aspectRatio: 1.8, + child: image, + ), + ), + SizedBox(height: 16), + Text( + S.current.seed_verified, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.titleColor, + ), + ), + SizedBox(height: 48), + RichText( + text: TextSpan( + children: [ + TextSpan( + text: '${S.current.seed_verified_subtext} ', + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Theme.of(context).extension()!.secondaryTextColor, + ), + ), + TextSpan( + text: S.current.seed_display_path, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: Theme.of(context).extension()!.secondaryTextColor, + ), + ), + ], + ), + textAlign: TextAlign.center, + ), + Spacer(), + PrimaryButton( + key: ValueKey('wallet_seed_page_open_wallet_button_key'), + onPressed: () { + Navigator.of(context).popUntil((route) => route.isFirst); + }, + text: S.current.open_wallet, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + ), + SizedBox(height: 16), + ], + ), + ); + } +} diff --git a/lib/src/screens/seed/wallet_seed_page.dart b/lib/src/screens/seed/wallet_seed_page.dart index 10160839c..11dffdeac 100644 --- a/lib/src/screens/seed/wallet_seed_page.dart +++ b/lib/src/screens/seed/wallet_seed_page.dart @@ -1,6 +1,6 @@ -import 'package:cake_wallet/palette.dart'; +import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/themes/extensions/pin_code_theme.dart'; +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/utils/clipboard_util.dart'; @@ -15,7 +15,8 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/view_model/wallet_seed_view_model.dart'; -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; + +import '../../../themes/extensions/send_page_theme.dart'; class WalletSeedPage extends BasePage { WalletSeedPage(this.walletSeedViewModel, {required this.isNewWalletCreated}); @@ -29,62 +30,34 @@ class WalletSeedPage extends BasePage { final bool isNewWalletCreated; final WalletSeedViewModel walletSeedViewModel; - @override - void onClose(BuildContext context) async { - if (isNewWalletCreated) { - final confirmed = await showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithTwoActions( - alertDialogKey: ValueKey('wallet_seed_page_seed_alert_dialog_key'), - alertRightActionButtonKey: - ValueKey('wallet_seed_page_seed_alert_confirm_button_key'), - alertLeftActionButtonKey: ValueKey('wallet_seed_page_seed_alert_back_button_key'), - alertTitle: S.of(context).seed_alert_title, - alertContent: S.of(context).seed_alert_content, - leftButtonText: S.of(context).seed_alert_back, - rightButtonText: S.of(context).seed_alert_yes, - actionLeftButton: () => Navigator.of(context).pop(false), - actionRightButton: () => Navigator.of(context).pop(true), - ); - }, - ) ?? - false; - - if (confirmed) { - Navigator.of(context).popUntil((route) => route.isFirst); - } - - return; - } - - Navigator.of(context).pop(); - } - - @override - Widget? leading(BuildContext context) => isNewWalletCreated ? null : super.leading(context); - @override Widget trailing(BuildContext context) { + final copyImage = Image.asset( + 'assets/images/copy_address.png', + color: Theme.of(context) + .extension()! + .buttonTextColor + ); + return isNewWalletCreated ? GestureDetector( - key: ValueKey('wallet_seed_page_next_button_key'), - onTap: () => onClose(context), + key: ValueKey('wallet_seed_page_copy_seeds_button_key'), + onTap: () { + ClipboardUtil.setSensitiveDataToClipboard( + ClipboardData(text: walletSeedViewModel.seed), + ); + showBar(context, S.of(context).copied_to_clipboard); + }, child: Container( - width: 100, - height: 32, + padding: EdgeInsets.all(8), + width: 40, alignment: Alignment.center, margin: EdgeInsets.only(left: 10), decoration: BoxDecoration( - borderRadius: BorderRadius.all(Radius.circular(16)), - color: Theme.of(context).cardColor), - child: Text( - S.of(context).seed_language_next, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.buttonTextColor), + borderRadius: BorderRadius.all(Radius.circular(8)), + color: Theme.of(context).cardColor, ), + child: copyImage, ), ) : Offstage(); @@ -92,118 +65,181 @@ class WalletSeedPage extends BasePage { @override Widget body(BuildContext context) { - final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight; - return WillPopScope( - onWillPop: () async => false, - child: Container( - padding: EdgeInsets.all(24), - alignment: Alignment.center, - child: ConstrainedBox( - constraints: - BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - ConstrainedBox( - constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3), - child: AspectRatio(aspectRatio: 1, child: image), - ), - Observer(builder: (_) { - return Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - key: ValueKey('wallet_seed_page_wallet_name_text_key'), - walletSeedViewModel.name, - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w600, - color: Theme.of(context).extension()!.titleColor), - ), - Padding( - padding: EdgeInsets.only(top: 20, left: 16, right: 16), - child: Text( - key: ValueKey('wallet_seed_page_wallet_seed_text_key'), - walletSeedViewModel.seed, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.normal, - color: - Theme.of(context).extension()!.secondaryTextColor), - ), - ) - ], - ); - }), - Column( - children: [ - isNewWalletCreated - ? Padding( - padding: EdgeInsets.only(bottom: 43, left: 43, right: 43), - child: Text( - key: ValueKey( - 'wallet_seed_page_wallet_seed_reminder_text_key', - ), - S.of(context).seed_reminder, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.normal, - color: Theme.of(context) - .extension()! - .detailsTitlesColor, - ), - ), - ) - : Offstage(), - Row( - mainAxisSize: MainAxisSize.max, + onWillPop: () async => false, + child: Container( + padding: EdgeInsets.symmetric(horizontal: 14, vertical: 8), + alignment: Alignment.center, + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Observer( + builder: (_) { + return Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Flexible( - child: Container( - padding: EdgeInsets.only(right: 8.0), - child: PrimaryButton( - key: ValueKey('wallet_seed_page_save_seeds_button_key'), - onPressed: () { - ShareUtil.share( - text: walletSeedViewModel.seed, - context: context, - ); - }, - text: S.of(context).save, - color: Colors.green, + Container( + padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), + decoration: BoxDecoration( + color: currentTheme.type == ThemeType.dark + ? Color.fromRGBO(132, 110, 64, 1) + : Color.fromRGBO(194, 165, 94, 1), + borderRadius: BorderRadius.all(Radius.circular(12)), + border: Border.all( + color: currentTheme.type == ThemeType.dark + ? Color.fromRGBO(177, 147, 41, 1) + : Color.fromRGBO(125, 122, 15, 1), + width: 2.0, + )), + child: Row( + children: [ + Icon( + Icons.warning_amber_rounded, + size: 64, + color: Colors.white.withOpacity(0.75), + ), + SizedBox(width: 6), + Expanded( + child: Text( + S.current.cake_seeds_save_disclaimer, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + fontWeight: FontWeight.w800, + color: currentTheme.type == ThemeType.dark + ? Colors.white.withOpacity(0.75) + : Colors.white.withOpacity(0.85), + ), + ), + ), + ], + ), + ), + SizedBox(height: 20), + Text( + key: ValueKey('wallet_seed_page_wallet_name_text_key'), + walletSeedViewModel.name, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Theme.of(context).extension()!.titleColor, + ), + ), + SizedBox(height: 20), + Expanded( + child: GridView.builder( + itemCount: walletSeedViewModel.seedSplit.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 3, + childAspectRatio: 2.8, + mainAxisSpacing: 8.0, + crossAxisSpacing: 8.0, + ), + itemBuilder: (context, index) { + final item = walletSeedViewModel.seedSplit[index]; + final numberCount = index + 1; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 8), + alignment: Alignment.center, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: Theme.of(context).cardColor, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + child: Text( + //maxLines: 1, + numberCount.toString(), + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 12, + height: 1, + fontWeight: FontWeight.w800, + color: Theme.of(context) + .extension()! + .buttonTextColor + .withOpacity(0.5)), + ), + ), + const SizedBox(width: 6), + Expanded( + child: Text( + '${item[0].toLowerCase()}${item.substring(1)}', + style: TextStyle( + fontSize: 14, + height: 0.8, + fontWeight: FontWeight.w700, + color: Theme.of(context) + .extension()! + .buttonTextColor), + ), + ), + ], + ), + ); + }, + ), + ), + ], + ), + ); + }, + ), + Column( + children: [ + Row( + mainAxisSize: MainAxisSize.max, + children: [ + Flexible( + child: Container( + padding: EdgeInsets.only(right: 8.0, top: 8.0), + child: PrimaryButton( + key: ValueKey('wallet_seed_page_save_seeds_button_key'), + onPressed: () { + ShareUtil.share( + text: walletSeedViewModel.seed, + context: context, + ); + }, + text: S.of(context).save, + color: Theme.of(context).cardColor, + textColor: currentTheme.type == ThemeType.dark + ? Theme.of(context).extension()!.textColor + : Theme.of(context).extension()!.buttonTextColor, + ), + ), + ), + Flexible( + child: Container( + padding: EdgeInsets.only(left: 8.0, top: 8.0), + child: Builder( + builder: (context) => PrimaryButton( + key: ValueKey('wallet_seed_page_verify_seed_button_key'), + onPressed: () => + Navigator.pushNamed(context, Routes.walletSeedVerificationPage), + text: S.current.verify_seed, + color: Theme.of(context).primaryColor, textColor: Colors.white, ), ), ), - Flexible( - child: Container( - padding: EdgeInsets.only(left: 8.0), - child: Builder( - builder: (context) => PrimaryButton( - key: ValueKey('wallet_seed_page_copy_seeds_button_key'), - onPressed: () { - ClipboardUtil.setSensitiveDataToClipboard( - ClipboardData(text: walletSeedViewModel.seed), - ); - showBar(context, S.of(context).copied_to_clipboard); - }, - text: S.of(context).copy, - color: Theme.of(context).extension()!.indicatorsColor, - textColor: Colors.white, - ), - ), - ), - ) - ], - ) - ], - ) - ], - ), + ) + ], + ), + SizedBox(height: 12), + ], + ) + ], ), - )); + ), + ), + ); } } diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index 7003ceafb..ca471c4f2 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -28,6 +28,7 @@ import 'package:cake_wallet/utils/request_review_handler.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/send/output.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/unspent_coin_type.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/view_model/send/send_view_model.dart'; @@ -499,95 +500,6 @@ class SendPage extends BasePage { actionRightButton: () async { Navigator.of(_dialogContext).pop(); sendViewModel.commitTransaction(context); - await showPopUp( - context: context, - builder: (BuildContext _dialogContext) { - return Observer(builder: (_) { - final state = sendViewModel.state; - - if (state is FailureState) { - Navigator.of(_dialogContext).pop(); - } - - if (state is TransactionCommitted) { - newContactAddress = - newContactAddress ?? sendViewModel.newContactAddress(); - - if (sendViewModel.coinTypeToSpendFrom != UnspentCoinType.any) { - newContactAddress = null; - } - - final successMessage = S.of(_dialogContext).send_success( - sendViewModel.selectedCryptoCurrency.toString()); - - final waitMessage = sendViewModel.walletType == WalletType.solana - ? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' - : ''; - - final newContactMessage = newContactAddress != null - ? '\n${S.of(_dialogContext).add_contact_to_address_book}' - : ''; - - String alertContent = - "$successMessage$waitMessage$newContactMessage"; - - if (newContactAddress != null) { - return AlertWithTwoActions( - alertDialogKey: ValueKey('send_page_sent_dialog_key'), - alertTitle: '', - alertContent: alertContent, - rightButtonText: S.of(_dialogContext).add_contact, - leftButtonText: S.of(_dialogContext).ignor, - alertLeftActionButtonKey: - ValueKey('send_page_sent_dialog_ignore_button_key'), - alertRightActionButtonKey: ValueKey( - 'send_page_sent_dialog_add_contact_button_key'), - actionRightButton: () { - Navigator.of(_dialogContext).pop(); - RequestReviewHandler.requestReview(); - Navigator.of(context).pushNamed( - Routes.addressBookAddContact, - arguments: newContactAddress); - newContactAddress = null; - }, - actionLeftButton: () { - Navigator.of(_dialogContext).pop(); - RequestReviewHandler.requestReview(); - newContactAddress = null; - }); - } else { - if (initialPaymentRequest?.callbackMessage?.isNotEmpty ?? - false) { - alertContent = initialPaymentRequest!.callbackMessage!; - } - return AlertWithOneAction( - alertTitle: '', - alertContent: alertContent, - buttonText: S.of(_dialogContext).ok, - buttonAction: () { - Navigator.of(_dialogContext).pop(); - RequestReviewHandler.requestReview(); - }); - } - } - - return Offstage(); - }); - }); - if (state is TransactionCommitted) { - if (initialPaymentRequest?.callbackUrl?.isNotEmpty ?? false) { - // wait a second so it's not as jarring: - await Future.delayed(Duration(seconds: 1)); - try { - launchUrl( - Uri.parse(initialPaymentRequest!.callbackUrl!), - mode: LaunchMode.externalApplication, - ); - } catch (e) { - print(e); - } - } - } }, actionLeftButton: () => Navigator.of(_dialogContext).pop()); }); @@ -596,7 +508,64 @@ class SendPage extends BasePage { } if (state is TransactionCommitted) { - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + + final successMessage = S.of(context).send_success( + sendViewModel.selectedCryptoCurrency.toString()); + + final waitMessage = sendViewModel.walletType == WalletType.solana + ? '. ${S.of(context).waitFewSecondForTxUpdate}' + : ''; + + String alertContent = "$successMessage$waitMessage"; + + await Navigator.of(context).pushNamed( + Routes.transactionSuccessPage, + arguments: alertContent + ); + + newContactAddress = newContactAddress ?? sendViewModel.newContactAddress(); + if (sendViewModel.coinTypeToSpendFrom != UnspentCoinType.any) newContactAddress = null; + + if (newContactAddress != null && sendViewModel.showAddressBookPopup) { + await showPopUp( + context: context, + builder: (BuildContext _dialogContext) => AlertWithTwoActions( + alertDialogKey: ValueKey('send_page_sent_dialog_key'), + alertTitle: '', + alertContent: S.of(_dialogContext).add_contact_to_address_book, + rightButtonText: S.of(_dialogContext).add_contact, + leftButtonText: S.of(_dialogContext).ignor, + alertLeftActionButtonKey: ValueKey('send_page_sent_dialog_ignore_button_key'), + alertRightActionButtonKey: + ValueKey('send_page_sent_dialog_add_contact_button_key'), + actionRightButton: () { + Navigator.of(_dialogContext).pop(); + RequestReviewHandler.requestReview(); + Navigator.of(context) + .pushNamed(Routes.addressBookAddContact, arguments: newContactAddress); + newContactAddress = null; + }, + actionLeftButton: () { + Navigator.of(_dialogContext).pop(); + RequestReviewHandler.requestReview(); + newContactAddress = null; + })); + } + + if (initialPaymentRequest?.callbackUrl?.isNotEmpty ?? false) { + // wait a second so it's not as jarring: + await Future.delayed(Duration(seconds: 1)); + try { + launchUrl( + Uri.parse(initialPaymentRequest!.callbackUrl!), + mode: LaunchMode.externalApplication, + ); + } catch (e) { + printV(e); + } + } + sendViewModel.clearOutputs(); }); } @@ -611,7 +580,10 @@ class SendPage extends BasePage { alertTitle: S.of(context).proceed_on_device, alertContent: S.of(context).proceed_on_device_description, buttonText: S.of(context).cancel, - buttonAction: () => Navigator.of(context).pop()); + buttonAction: () { + sendViewModel.state = InitialExecutionState(); + Navigator.of(context).pop(); + }); }); }); } diff --git a/lib/src/screens/send/transaction_success_info_page.dart b/lib/src/screens/send/transaction_success_info_page.dart new file mode 100644 index 000000000..628cc0393 --- /dev/null +++ b/lib/src/screens/send/transaction_success_info_page.dart @@ -0,0 +1,32 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/Info_page.dart'; +import 'package:flutter/cupertino.dart'; + +class TransactionSuccessPage extends InfoPage { + TransactionSuccessPage({required this.content}) + : super( + imageLightPath: 'assets/images/birthday_cake.png', + imageDarkPath: 'assets/images/birthday_cake.png', + ); + + final String content; + + @override + bool get onWillPop => false; + + @override + String get pageTitle => 'Transaction Sent Successfully'; + + @override + String get pageDescription => content; + + @override + String get buttonText => S.current.ok; + + @override + Key? get buttonKey => ValueKey('transaction_success_info_page_button_key'); + + @override + void Function(BuildContext) get onPressed => + (BuildContext context) => Navigator.of(context).pop(); +} diff --git a/lib/src/screens/settings/other_settings_page.dart b/lib/src/screens/settings/other_settings_page.dart index f6a6288f5..24f321798 100644 --- a/lib/src/screens/settings/other_settings_page.dart +++ b/lib/src/screens/settings/other_settings_page.dart @@ -6,6 +6,7 @@ import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; +import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart'; import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; import 'package:cw_core/wallet_type.dart'; @@ -62,6 +63,13 @@ class OtherSettingsPage extends BasePage { handler: (BuildContext context) => Navigator.of(context).pushNamed(Routes.readDisclaimer), ), + SettingsSwitcherCell( + title: S.of(context).show_address_book_popup, + value: _otherSettingsViewModel.showAddressBookPopup, + onValueChange: (_, bool value) { + _otherSettingsViewModel.setShowAddressBookPopup(value); + }, + ), Spacer(), SettingsVersionCell( title: S.of(context).version(_otherSettingsViewModel.currentVersion)), diff --git a/lib/src/screens/settings/tor_page.dart b/lib/src/screens/settings/tor_page.dart index 2f544be35..2eb8d6c11 100644 --- a/lib/src/screens/settings/tor_page.dart +++ b/lib/src/screens/settings/tor_page.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/store/app_store.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; // import 'package:tor/tor.dart'; @@ -57,7 +58,7 @@ class _TorPageBodyState extends State { // } // widget.appStore.wallet!.connectToNode(node: node); - print('Done awaiting; tor should be running'); + printV('Done awaiting; tor should be running'); } Future endTor() async { @@ -69,7 +70,7 @@ class _TorPageBodyState extends State { // torEnabled = Tor.instance.enabled; // Update flag // }); // - // print('Done awaiting; tor should be stopped'); + // printV('Done awaiting; tor should be stopped'); } // // @override diff --git a/lib/src/screens/setup_2fa/setup_2fa.dart b/lib/src/screens/setup_2fa/setup_2fa.dart index 5fa5cabb8..f74c2bf36 100644 --- a/lib/src/screens/setup_2fa/setup_2fa.dart +++ b/lib/src/screens/setup_2fa/setup_2fa.dart @@ -20,7 +20,7 @@ class Setup2FAPage extends BasePage { Widget body(BuildContext context) { final cake2FAGuideTitle = 'Cake 2FA Guide'; final cake2FAGuideUri = - Uri.parse('https://guides.cakewallet.com/docs/advanced-features/authentication'); + Uri.parse('https://docs.cakewallet.com/features/advanced/authentication/'); return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ diff --git a/lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart b/lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart index 70660c59d..64e8f3aab 100644 --- a/lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart +++ b/lib/src/screens/setup_2fa/setup_2fa_enter_code_page.dart @@ -3,6 +3,7 @@ import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/totp_request_details.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/view_model/auth_state.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -53,7 +54,7 @@ class TotpAuthCodePageState extends State { } if (state is FailureState) { - print(state.error); + printV(state.error); widget.totpArguments.onTotpAuthenticationFinished!(false, this); } @@ -197,8 +198,9 @@ class TOTPEnterCode extends BasePage { }, ); if (isForSetup && result) { - Navigator.pushReplacementNamed( - context, Routes.modify2FAPage); + if (context.mounted) { + Navigator.pushReplacementNamed(context, Routes.modify2FAPage); + } } }, diff --git a/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart b/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart index 3ce10b596..48a90b329 100644 --- a/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart +++ b/lib/src/screens/setup_2fa/setup_2fa_qr_page.dart @@ -6,7 +6,6 @@ import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:cake_wallet/utils/clipboard_util.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart'; @@ -30,7 +29,7 @@ class Setup2FAQRPage extends BasePage { width: 16, color: Theme.of(context).extension()!.titleColor); final cake2FAHowToUseUrl = Uri.parse( - 'https://guides.cakewallet.com/docs/advanced-features/authentication/#enabling-cake-2fa'); + 'https://docs.cakewallet.com/features/advanced/authentication/#enabling-cake-2fa'); return Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Column( diff --git a/lib/src/screens/support/support_page.dart b/lib/src/screens/support/support_page.dart index 049ab2fb7..88154e91d 100644 --- a/lib/src/screens/support/support_page.dart +++ b/lib/src/screens/support/support_page.dart @@ -70,7 +70,7 @@ class SupportPage extends BasePage { ), title: S.of(context).support_title_guides, description: S.of(context).support_description_guides, - onPressed: () => _launchUrl(supportViewModel.guidesUrl), + onPressed: () => _launchUrl(supportViewModel.docsUrl), ), ), Padding( diff --git a/lib/src/screens/support_chat/support_chat_page.dart b/lib/src/screens/support_chat/support_chat_page.dart index 97d59a2d9..203b75775 100644 --- a/lib/src/screens/support_chat/support_chat_page.dart +++ b/lib/src/screens/support_chat/support_chat_page.dart @@ -3,6 +3,7 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/support_chat/widgets/chatwoot_widget.dart'; import 'package:cake_wallet/view_model/support_view_model.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; @@ -22,7 +23,7 @@ class SupportChatPage extends BasePage { Widget body(BuildContext context) => FutureBuilder( future: getCookie(), builder: (BuildContext context, AsyncSnapshot snapshot) { - print(snapshot.data); + printV(snapshot.data); if (snapshot.hasData) return ChatwootWidget( secureStorage, diff --git a/lib/src/screens/support_chat/widgets/chatwoot_widget.dart b/lib/src/screens/support_chat/widgets/chatwoot_widget.dart index b49993f7f..4f5e58c97 100644 --- a/lib/src/screens/support_chat/widgets/chatwoot_widget.dart +++ b/lib/src/screens/support_chat/widgets/chatwoot_widget.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:cake_wallet/core/secure_storage.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; @@ -38,7 +39,7 @@ class ChatwootWidgetState extends State { final eventType = parsedMessage["event"]; if (eventType == 'loaded') { final authToken = parsedMessage["config"]["authToken"]; - print(authToken); + printV(authToken); storeCookie(authToken as String); } } diff --git a/lib/src/screens/trade_details/trade_details_list_card.dart b/lib/src/screens/trade_details/trade_details_list_card.dart index 9c543a964..64f727b91 100644 --- a/lib/src/screens/trade_details/trade_details_list_card.dart +++ b/lib/src/screens/trade_details/trade_details_list_card.dart @@ -8,7 +8,8 @@ class TradeDetailsListCardItem extends StandartListItem { {required this.id, required this.createdAt, required this.pair, - required this.onTap}) + required this.onTap, + this.extraId}) : super(title: '', value: ''); factory TradeDetailsListCardItem.tradeDetails( @@ -16,9 +17,19 @@ class TradeDetailsListCardItem extends StandartListItem { required String createdAt, required CryptoCurrency from, required CryptoCurrency to, - required void Function(BuildContext) onTap}) { + required void Function(BuildContext) onTap, + String? extraId}) { + + + final extraIdTitle = from == CryptoCurrency.xrp + ? S.current.destination_tag + : from == CryptoCurrency.xlm + ? S.current.memo + : S.current.extra_id; + return TradeDetailsListCardItem( id: '${S.current.trade_details_id} ${formatAsText(id)}', + extraId: extraId != null ? '$extraIdTitle $extraId' : null, createdAt: formatAsText(createdAt), pair: '${formatAsText(from)} → ${formatAsText(to)}', onTap: onTap); @@ -27,6 +38,7 @@ class TradeDetailsListCardItem extends StandartListItem { final String id; final String createdAt; final String pair; + final String? extraId; final void Function(BuildContext) onTap; static String formatAsText(T value) => value?.toString() ?? ''; diff --git a/lib/src/screens/trade_details/trade_details_page.dart b/lib/src/screens/trade_details/trade_details_page.dart index 1028c3939..40d14fa14 100644 --- a/lib/src/screens/trade_details/trade_details_page.dart +++ b/lib/src/screens/trade_details/trade_details_page.dart @@ -69,6 +69,7 @@ class TradeDetailsPageBodyState extends State { if (item is TradeDetailsListCardItem) return TradeDetailsStandardListCard( id: item.id, + extraId: item.extraId, create: item.createdAt, pair: item.pair, currentTheme: tradeDetailsViewModel.settingsStore.currentTheme.type, diff --git a/lib/src/screens/unspent_coins/unspent_coins_list_page.dart b/lib/src/screens/unspent_coins/unspent_coins_list_page.dart index ee6d6dc73..d44107939 100644 --- a/lib/src/screens/unspent_coins/unspent_coins_list_page.dart +++ b/lib/src/screens/unspent_coins/unspent_coins_list_page.dart @@ -1,13 +1,14 @@ -import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/widgets/unspent_coins_list_item.dart'; +import 'package:cake_wallet/src/widgets/alert_with_no_action.dart.dart'; +import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart'; -import 'package:cw_core/wallet_type.dart'; -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; class UnspentCoinsListPage extends BasePage { UnspentCoinsListPage({required this.unspentCoinsListViewModel}); @@ -15,16 +16,53 @@ class UnspentCoinsListPage extends BasePage { @override String get title => S.current.unspent_coins_title; + @override + Widget leading(BuildContext context) { + return MergeSemantics( + child: SizedBox( + height: 37, + width: 37, + child: ButtonTheme( + minWidth: double.minPositive, + child: Semantics( + label: S.of(context).seed_alert_back, + child: TextButton( + style: ButtonStyle( + overlayColor: WidgetStateColor.resolveWith((states) => Colors.transparent), + ), + onPressed: () async => await handleOnPopInvoked(context), + child: backButton(context), + ), + ), + ), + ), + ); + } + final UnspentCoinsListViewModel unspentCoinsListViewModel; + Future handleOnPopInvoked(BuildContext context) async { + final hasChanged = unspentCoinsListViewModel.hasAdjustableFieldChanged; + if (unspentCoinsListViewModel.items.isEmpty || !hasChanged) { + Navigator.of(context).pop(); + } else { + unspentCoinsListViewModel.setIsDisposing(true); + await unspentCoinsListViewModel.dispose(); + Navigator.of(context).pop(); + Navigator.of(context).pop(); + } + } + @override - Widget body(BuildContext context) => UnspentCoinsListForm(unspentCoinsListViewModel); + Widget body(BuildContext context) => + UnspentCoinsListForm(unspentCoinsListViewModel, handleOnPopInvoked); } class UnspentCoinsListForm extends StatefulWidget { - UnspentCoinsListForm(this.unspentCoinsListViewModel); + UnspentCoinsListForm(this.unspentCoinsListViewModel, this.handleOnPopInvoked); final UnspentCoinsListViewModel unspentCoinsListViewModel; + final Future Function(BuildContext context) handleOnPopInvoked; @override UnspentCoinsListFormState createState() => UnspentCoinsListFormState(unspentCoinsListViewModel); @@ -35,36 +73,126 @@ class UnspentCoinsListFormState extends State { final UnspentCoinsListViewModel unspentCoinsListViewModel; + late Future _initialization; + ReactionDisposer? _disposer; + + @override + void initState() { + super.initState(); + _initialization = unspentCoinsListViewModel.initialSetup(); + _setupReactions(); + } + + void _setupReactions() { + _disposer = reaction( + (_) => unspentCoinsListViewModel.isDisposing, + (isDisposing) { + if (isDisposing) { + _showSavingDataAlert(); + } + }, + ); + } + + void _showSavingDataAlert() { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertWithNoAction( + alertContent: 'Updating, please wait…', + alertBarrierDismissible: false, + ); + }, + ); + } + + @override + void dispose() { + _disposer?.call(); + super.dispose(); + } + @override Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.fromLTRB(24, 12, 24, 24), - child: Observer( - builder: (_) => ListView.separated( - itemCount: unspentCoinsListViewModel.items.length, - separatorBuilder: (_, __) => SizedBox(height: 15), - itemBuilder: (_, int index) { - return Observer(builder: (_) { - final item = unspentCoinsListViewModel.items[index]; + return PopScope( + canPop: false, + onPopInvokedWithResult: (bool didPop, Object? result) async { + if (didPop) return; + if(mounted) + await widget.handleOnPopInvoked(context); + }, + child: FutureBuilder( + future: _initialization, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Center(child: CircularProgressIndicator()); + } - return GestureDetector( - onTap: () => Navigator.of(context).pushNamed(Routes.unspentCoinsDetails, - arguments: [item, unspentCoinsListViewModel]), - child: UnspentCoinsListItem( - note: item.note, - amount: item.amount, - address: item.address, - isSending: item.isSending, - isFrozen: item.isFrozen, - isChange: item.isChange, - isSilentPayment: item.isSilentPayment, - onCheckBoxTap: item.isFrozen - ? null - : () async { - item.isSending = !item.isSending; - await unspentCoinsListViewModel.saveUnspentCoinInfo(item); - })); - }); - }))); + if (snapshot.hasError) return Center(child: Text('Failed to load unspent coins')); + + return Container( + padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12), + child: Observer( + builder: (_) => Column( + children: [ + if (unspentCoinsListViewModel.items.isNotEmpty) + Row( + children: [ + SizedBox(width: 12), + StandardCheckbox( + iconColor: Theme.of(context).extension()!.buttonTextColor, + value: unspentCoinsListViewModel.isAllSelected, + onChanged: (value) => unspentCoinsListViewModel.toggleSelectAll(value), + ), + SizedBox(width: 12), + Text( + S.current.all_coins, + style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + ], + ), + SizedBox(height: 15), + Expanded( + child: unspentCoinsListViewModel.items.isEmpty + ? Center(child: Text('No unspent coins available',textAlign: TextAlign.center)) + : ListView.separated( + itemCount: unspentCoinsListViewModel.items.length, + separatorBuilder: (_, __) => SizedBox(height: 15), + itemBuilder: (_, int index) { + final item = unspentCoinsListViewModel.items[index]; + return Observer( + builder: (_) => GestureDetector( + onTap: () => Navigator.of(context).pushNamed( + Routes.unspentCoinsDetails, + arguments: [item, unspentCoinsListViewModel], + ), + child: UnspentCoinsListItem( + note: item.note, + amount: item.amount, + address: item.address, + isSending: item.isSending, + isFrozen: item.isFrozen, + isChange: item.isChange, + isSilentPayment: item.isSilentPayment, + onCheckBoxTap: item.isFrozen + ? null + : () async { + item.isSending = !item.isSending; + await unspentCoinsListViewModel + .saveUnspentCoinInfo(item); + }, + ), + ), + ); + }, + ), + ), + ], + ), + ), + ); + }, + ), + ); } } diff --git a/lib/src/screens/wallet_keys/wallet_keys_page.dart b/lib/src/screens/wallet_keys/wallet_keys_page.dart index fac760516..ac00bb161 100644 --- a/lib/src/screens/wallet_keys/wallet_keys_page.dart +++ b/lib/src/screens/wallet_keys/wallet_keys_page.dart @@ -84,6 +84,7 @@ class WalletKeysPage extends BasePage { child: Observer( builder: (_) { return ListView.separated( + key: ValueKey('wallet_keys_page_credentials_list_view_key'), separatorBuilder: (context, index) => Container( height: 1, padding: EdgeInsets.only(left: 24), diff --git a/lib/src/screens/wallet_list/wallet_list_page.dart b/lib/src/screens/wallet_list/wallet_list_page.dart index 46eaa6143..9bf924f61 100644 --- a/lib/src/screens/wallet_list/wallet_list_page.dart +++ b/lib/src/screens/wallet_list/wallet_list_page.dart @@ -1,6 +1,7 @@ import 'package:another_flushbar/flushbar.dart'; import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/new_wallet_arguments.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart'; import 'package:cake_wallet/entities/wallet_list_order_types.dart'; import 'package:cake_wallet/generated/i18n.dart'; @@ -20,6 +21,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/themes/extensions/filter_theme.dart'; import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; +import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; @@ -332,6 +334,26 @@ class WalletListBodyState extends State { padding: const EdgeInsets.all(24), child: Column( children: [ + PrimaryImageButton( + key: ValueKey('wallet_list_page_restore_wallet_button_key'), + onPressed: () { + if (widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets) { + widget.authService.authenticateAction( + context, + route: Routes.restoreOptions, + arguments: false, + conditionToDetermineIfToUse2FA: widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets, + ); + } else { + Navigator.of(context).pushNamed(Routes.restoreOptions, arguments: false); + } + }, + image: restoreWalletImage, + text: S.of(context).wallet_list_restore_wallet, + color: Theme.of(context).cardColor, + textColor: Theme.of(context).extension()!.buttonTextColor, + ), + SizedBox(height: 10.0), PrimaryImageButton( key: ValueKey('wallet_list_page_create_new_wallet_button_key'), onPressed: () { @@ -371,26 +393,6 @@ class WalletListBodyState extends State { color: Theme.of(context).primaryColor, textColor: Colors.white, ), - SizedBox(height: 10.0), - PrimaryImageButton( - key: ValueKey('wallet_list_page_restore_wallet_button_key'), - onPressed: () { - if (widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets) { - widget.authService.authenticateAction( - context, - route: Routes.restoreOptions, - arguments: false, - conditionToDetermineIfToUse2FA: widget.walletListViewModel.shouldRequireTOTP2FAForCreatingNewWallets, - ); - } else { - Navigator.of(context).pushNamed(Routes.restoreOptions, arguments: false); - } - }, - image: restoreWalletImage, - text: S.of(context).wallet_list_restore_wallet, - color: Theme.of(context).cardColor, - textColor: Theme.of(context).extension()!.buttonTextColor, - ) ], ), ), @@ -420,8 +422,9 @@ class WalletListBodyState extends State { if (!isAuthenticatedSuccessfully) return; try { - if (widget.walletListViewModel - .requireHardwareWalletConnection(wallet)) { + final requireHardwareWalletConnection = widget.walletListViewModel + .requireHardwareWalletConnection(wallet); + if (requireHardwareWalletConnection) { await Navigator.of(context).pushNamed( Routes.connectDevices, arguments: ConnectDevicePageParams( @@ -443,8 +446,6 @@ class WalletListBodyState extends State { ); } - - changeProcessText( S.of(context).wallet_list_loading_wallet(wallet.name)); await widget.walletListViewModel.loadWallet(wallet); @@ -454,11 +455,17 @@ class WalletListBodyState extends State { if (responsiveLayoutUtil.shouldRenderMobileUI) { WidgetsBinding.instance.addPostFrameCallback((_) { if (this.mounted) { + if (requireHardwareWalletConnection) { + Navigator.of(context).pop(); + } widget.onWalletLoaded.call(context); } }); } } catch (e) { + await ExceptionHandler.resetLastPopupDate(); + final err = e.toString(); + await ExceptionHandler.onError(FlutterErrorDetails(exception: err)); if (this.mounted) { changeProcessText(S .of(context) diff --git a/lib/src/screens/welcome/create_pin_welcome_page.dart b/lib/src/screens/welcome/create_pin_welcome_page.dart new file mode 100644 index 000000000..d8ff1578e --- /dev/null +++ b/lib/src/screens/welcome/create_pin_welcome_page.dart @@ -0,0 +1,138 @@ +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/theme_base.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:flutter/material.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/wallet_type_utils.dart'; +import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart'; +import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; + +class CreatePinWelcomePage extends BasePage { + static const aspectRatioImage = 1.25; + final welcomeImageLight = Image.asset('assets/images/welcome_light.png'); + final welcomeImageDark = Image.asset('assets/images/welcome.png'); + + String appTitle(BuildContext context) { + if (isMoneroOnly) { + return S.of(context).monero_com; + } + + if (isHaven) { + return S.of(context).haven_app; + } + + return S.of(context).cake_wallet; + } + + String appDescription(BuildContext context) { + if (isMoneroOnly) { + return S.of(context).monero_com_wallet_text; + } + + if (isHaven) { + return S.of(context).haven_app_wallet_text; + } + + return S.of(context).new_first_wallet_text; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Theme.of(context).colorScheme.background, + resizeToAvoidBottomInset: false, + body: body(context)); + } + + @override + Widget body(BuildContext context) { + final welcomeImage = currentTheme.type == ThemeType.dark ? welcomeImageDark : welcomeImageLight; + + final newWalletImage = Image.asset('assets/images/new_wallet.png', + height: 12, + width: 12, + color: Theme.of(context).extension()!.restoreWalletButtonTextColor); + + return PopScope( + canPop: false, + child: ScrollableWithBottomSection( + content: Container( + alignment: Alignment.center, + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + SizedBox(height: 70), + AspectRatio( + aspectRatio: aspectRatioImage, + child: FittedBox(child: welcomeImage, fit: BoxFit.contain), + ), + SizedBox(height: 50), + Padding( + padding: EdgeInsets.only(top: 24), + child: Text( + S.of(context).welcome, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.hintTextColor, + ), + textAlign: TextAlign.center, + ), + ), + Padding( + padding: EdgeInsets.only(top: 5), + child: Text( + appTitle(context), + style: TextStyle( + fontSize: 36, + fontWeight: FontWeight.bold, + color: Theme.of(context).extension()!.titleColor, + ), + textAlign: TextAlign.center, + ), + ), + Padding( + padding: EdgeInsets.only(top: 5), + child: Text( + appDescription(context), + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Theme.of(context).extension()!.hintTextColor, + ), + textAlign: TextAlign.center, + ), + ), + ], + ), + ], + ), + ), + ), + bottomSection: Padding( + padding: EdgeInsets.only(top: 24), + child: PrimaryImageButton( + key: ValueKey('create_pin_welcome_page_create_a_pin_button_key'), + onPressed: () => Navigator.pushNamed(context, Routes.welcomeWallet), + image: newWalletImage, + text: S.current.set_a_pin, + color: Theme.of(context) + .extension()! + .createNewWalletButtonBackgroundColor, + textColor: + Theme.of(context).extension()!.restoreWalletButtonTextColor, + ), + ), + ), + ); + } +} diff --git a/lib/src/screens/welcome/create_welcome_page.dart b/lib/src/screens/welcome/create_welcome_page.dart deleted file mode 100644 index 2d4b3cc28..000000000 --- a/lib/src/screens/welcome/create_welcome_page.dart +++ /dev/null @@ -1,4 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:cake_wallet/src/screens/welcome/welcome_page.dart'; - -Widget createWelcomePage() => WelcomePage(); \ No newline at end of file diff --git a/lib/src/screens/welcome/welcome_page.dart b/lib/src/screens/welcome/welcome_page.dart index 5b7b7f06d..b45322996 100644 --- a/lib/src/screens/welcome/welcome_page.dart +++ b/lib/src/screens/welcome/welcome_page.dart @@ -10,42 +10,28 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart'; import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart'; +import 'package:url_launcher/url_launcher.dart'; class WelcomePage extends BasePage { static const aspectRatioImage = 1.25; - final welcomeImageLight = Image.asset('assets/images/welcome_light.png'); - final welcomeImageDark = Image.asset('assets/images/welcome.png'); - - String appTitle(BuildContext context) { - if (isMoneroOnly) { - return S.of(context).monero_com; - } - - if (isHaven) { - return S.of(context).haven_app; - } - - return S.of(context).cake_wallet; - } - - String appDescription(BuildContext context) { - if (isMoneroOnly) { - return S.of(context).monero_com_wallet_text; - } - - if (isHaven) { - return S.of(context).haven_app_wallet_text; - } - - return S.of(context).new_first_wallet_text; - } + final welcomeImageLight = Image.asset('assets/images/wallet_type_light.png'); + final welcomeImageDark = Image.asset('assets/images/wallet_type.png'); @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Theme.of(context).colorScheme.background, - resizeToAvoidBottomInset: false, - body: body(context)); + String? get title => S.current.wallet; + + @override + bool get resizeToAvoidBottomInset => false; + + @override + Widget trailing(BuildContext context) { + final Uri _url = Uri.parse('https://docs.cakewallet.com/get-started/setup/create-first-wallet/'); + return IconButton( + icon: Icon(Icons.info_outline), + onPressed: () async { + await launchUrl(_url); + }, + ); } @override @@ -59,106 +45,136 @@ class WelcomePage extends BasePage { final restoreWalletImage = Image.asset('assets/images/restore_wallet.png', height: 12, width: 12, color: Theme.of(context).extension()!.titleColor); - return WillPopScope( - onWillPop: () async => false, - child: ScrollableWithBottomSection( - content: Container( - alignment: Alignment.center, - padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24), - child: ConstrainedBox( - constraints: - BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - children: [ - AspectRatio( - aspectRatio: aspectRatioImage, - child: FittedBox(child: welcomeImage, fit: BoxFit.contain), - ), - Padding( - padding: EdgeInsets.only(top: 24), - child: Text( - S.of(context).welcome, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w500, - color: Theme.of(context).extension()!.hintTextColor, - ), - textAlign: TextAlign.center, - ), - ), - Padding( + return ScrollableWithBottomSection( + content: Container( + alignment: Alignment.center, + padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24), + child: ConstrainedBox( + constraints: + BoxConstraints(maxWidth: ResponsiveLayoutUtilBase.kDesktopMaxWidthConstraint), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Column( + children: [ + AspectRatio( + aspectRatio: aspectRatioImage, + child: FittedBox(child: welcomeImage, fit: BoxFit.contain), + ), + Padding( + padding: EdgeInsets.only(top: 20), + child: highlightText(context, S.of(context).welcome_subtitle_new_wallet, + S.of(context).create_new)), + SizedBox(height: 10), + Padding( padding: EdgeInsets.only(top: 5), - child: Text( - appTitle(context), - style: TextStyle( - fontSize: 36, - fontWeight: FontWeight.bold, - color: Theme.of(context).extension()!.titleColor, - ), - textAlign: TextAlign.center, - ), - ), - Padding( - padding: EdgeInsets.only(top: 5), - child: Text( - appDescription(context), - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Theme.of(context).extension()!.hintTextColor, - ), - textAlign: TextAlign.center, - ), - ), - ], - ), - ], - ), + child: highlightText(context, S.of(context).welcome_subtitle_restore_wallet, + S.of(context).restore_existing_wallet)), + ], + ), + ], ), ), - bottomSection: Column( - children: [ - Text( - S.of(context).please_make_selection, - style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.normal, - color: Theme.of(context).extension()!.hintTextColor, - ), - textAlign: TextAlign.center, - ), - Padding( - padding: EdgeInsets.only(top: 24), - child: PrimaryImageButton( - key: ValueKey('welcome_page_create_new_wallet_button_key'), - onPressed: () => Navigator.pushNamed(context, Routes.newWalletFromWelcome), - image: newWalletImage, - text: S.of(context).create_new, - color: Theme.of(context) - .extension()! - .createNewWalletButtonBackgroundColor, - textColor: - Theme.of(context).extension()!.restoreWalletButtonTextColor, - ), - ), - Padding( - padding: EdgeInsets.only(top: 10), - child: PrimaryImageButton( + ), + bottomSection: Column( + children: [ + Padding( + padding: EdgeInsets.only(top: 24), + child: PrimaryImageButton( key: ValueKey('welcome_page_restore_wallet_button_key'), - onPressed: () { - Navigator.pushNamed(context, Routes.restoreOptions, arguments: true); - }, - image: restoreWalletImage, - text: S.of(context).restore_wallet, - color: Theme.of(context).cardColor, - textColor: Theme.of(context).extension()!.titleColor), - ) - ], - ), + onPressed: () { + Navigator.pushNamed(context, Routes.restoreOptions, arguments: true); + }, + image: restoreWalletImage, + text: S.of(context).restore_existing_wallet, + color: Theme.of(context).cardColor, + textColor: Theme.of(context).extension()!.titleColor), + ), + Padding( + padding: EdgeInsets.only(top: 10), + child: PrimaryImageButton( + key: ValueKey('welcome_page_create_new_wallet_button_key'), + onPressed: () => Navigator.pushNamed(context, Routes.newWalletFromWelcome), + image: newWalletImage, + text: S.of(context).create_new, + color: Theme.of(context) + .extension()! + .createNewWalletButtonBackgroundColor, + textColor: + Theme.of(context).extension()!.restoreWalletButtonTextColor, + ), + ), + ], ), ); } + + RichText highlightText(BuildContext context, String text, String highlightWord) { + final regex = RegExp(highlightWord, caseSensitive: false); + final matches = regex.allMatches(text); + + if (matches.isEmpty) { + return RichText( + textAlign: TextAlign.center, + text: TextSpan( + text: text, + style: TextStyle( + fontSize: 16, + height: 1.5, + fontWeight: FontWeight.w400, + color: Theme.of(context).extension()!.secondaryTextColor, + ), + ), + ); + } + + List spans = []; + int lastMatchEnd = 0; + + for (final match in matches) { + final start = match.start; + final end = match.end; + + if (start > lastMatchEnd) { + spans.add(TextSpan( + text: text.substring(lastMatchEnd, start), + style: TextStyle( + fontSize: 16, + height: 1.5, + fontWeight: FontWeight.w400, + color: Theme.of(context).extension()!.secondaryTextColor, + ), + )); + } + + spans.add(TextSpan( + text: text.substring(start, end), + style: TextStyle( + fontSize: 16, + height: 1.5, + color: Theme.of(context).extension()!.secondaryTextColor, + fontWeight: FontWeight.bold, + ), + )); + + lastMatchEnd = end; + } + + if (lastMatchEnd < text.length) { + spans.add(TextSpan( + text: text.substring(lastMatchEnd), + style: TextStyle( + fontSize: 16, + height: 1.5, + fontWeight: FontWeight.w400, + color: Theme.of(context).extension()!.secondaryTextColor, + ), + )); + } + + return RichText( + textAlign: TextAlign.center, + text: TextSpan(children: spans), + ); + } } diff --git a/lib/src/widgets/alert_with_no_action.dart.dart b/lib/src/widgets/alert_with_no_action.dart.dart index 623656397..75c1785cd 100644 --- a/lib/src/widgets/alert_with_no_action.dart.dart +++ b/lib/src/widgets/alert_with_no_action.dart.dart @@ -3,18 +3,18 @@ import 'package:cake_wallet/src/widgets/base_alert_dialog.dart'; class AlertWithNoAction extends BaseAlertDialog { AlertWithNoAction({ - required this.alertTitle, + this.alertTitle, required this.alertContent, this.alertBarrierDismissible = true, Key? key, }); - final String alertTitle; + final String? alertTitle; final String alertContent; final bool alertBarrierDismissible; @override - String get titleText => alertTitle; + String? get titleText => alertTitle; @override String get contentText => alertContent; @@ -26,5 +26,5 @@ class AlertWithNoAction extends BaseAlertDialog { bool get isBottomDividerExists => false; @override - Widget actionButtons(BuildContext context) => Container(height: 60); + Widget actionButtons(BuildContext context) => Container(); } diff --git a/lib/src/widgets/base_alert_dialog.dart b/lib/src/widgets/base_alert_dialog.dart index 1b521a427..bede33ebf 100644 --- a/lib/src/widgets/base_alert_dialog.dart +++ b/lib/src/widgets/base_alert_dialog.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; class BaseAlertDialog extends StatelessWidget { String? get headerText => ''; - String get titleText => ''; + String? get titleText => ''; String get contentText => ''; @@ -43,7 +43,7 @@ class BaseAlertDialog extends StatelessWidget { Widget title(BuildContext context) { return Text( - titleText, + titleText!, textAlign: TextAlign.center, style: TextStyle( fontSize: 20, @@ -73,15 +73,22 @@ class BaseAlertDialog extends StatelessWidget { } Widget content(BuildContext context) { - return Text( - contentText, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.normal, - fontFamily: 'Lato', - color: Theme.of(context).extension()!.titleColor, - decoration: TextDecoration.none, + return SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + contentText, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ), + ], ), ); } @@ -191,10 +198,11 @@ class BaseAlertDialog extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ if (headerText?.isNotEmpty ?? false) headerTitle(context), + titleText != null ? Padding( padding: EdgeInsets.fromLTRB(24, 20, 24, 0), child: title(context), - ), + ) : SizedBox(height: 16), isDividerExists ? Padding( padding: EdgeInsets.only(top: 16, bottom: 8), diff --git a/lib/src/widgets/blockchain_height_widget.dart b/lib/src/widgets/blockchain_height_widget.dart index 1c6b6da02..650ee684d 100644 --- a/lib/src/widgets/blockchain_height_widget.dart +++ b/lib/src/widgets/blockchain_height_widget.dart @@ -191,11 +191,13 @@ class BlockchainHeightState extends State { height = wownero!.getHeightByDate(date: date); } } - setState(() { - dateController.text = DateFormat('yyyy-MM-dd').format(date); - restoreHeightController.text = '$height'; - _changeHeight(height); - }); + if (mounted) { + setState(() { + dateController.text = DateFormat('yyyy-MM-dd').format(date); + restoreHeightController.text = '$height'; + _changeHeight(height); + }); + } } } diff --git a/lib/src/widgets/search_bar_widget.dart b/lib/src/widgets/search_bar_widget.dart index 6c7c14db2..34ebe8560 100644 --- a/lib/src/widgets/search_bar_widget.dart +++ b/lib/src/widgets/search_bar_widget.dart @@ -17,13 +17,14 @@ class SearchBarWidget extends StatelessWidget { @override Widget build(BuildContext context) { return TextFormField( + key: ValueKey('search_bar_widget_key'), controller: searchController, style: TextStyle(color: Theme.of(context).extension()!.searchHintColor), decoration: InputDecoration( hintText: hintText ?? S.of(context).search, hintStyle: TextStyle(color: Theme.of(context).extension()!.searchHintColor), - prefixIcon: Image.asset("assets/images/search_icon.png", - color: Theme.of(context).extension()!.searchIconColor), + prefixIcon: Icon( Icons.search, + color: Theme.of(context).primaryColor), filled: true, fillColor: Theme.of(context).extension()!.searchBackgroundFillColor, alignLabelWithHint: false, diff --git a/lib/src/widgets/services_updates_widget.dart b/lib/src/widgets/services_updates_widget.dart index 1787b7118..17f231303 100644 --- a/lib/src/widgets/services_updates_widget.dart +++ b/lib/src/widgets/services_updates_widget.dart @@ -92,15 +92,17 @@ class _ServicesUpdatesWidgetState extends State { ); } return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 20), - child: Stack( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Column( children: [ - body, + Expanded(child: body), Align( alignment: Alignment.bottomCenter, child: Padding( padding: EdgeInsets.symmetric( - horizontal: MediaQuery.of(context).size.width / 8), + horizontal: MediaQuery.of(context).size.width / 8, + vertical: 20, + ), child: PrimaryImageButton( onPressed: () { try { diff --git a/lib/src/widgets/standard_checkbox.dart b/lib/src/widgets/standard_checkbox.dart index 46c5f8a34..d61b84d1d 100644 --- a/lib/src/widgets/standard_checkbox.dart +++ b/lib/src/widgets/standard_checkbox.dart @@ -26,7 +26,9 @@ class StandardCheckbox extends StatelessWidget { ], begin: Alignment.centerLeft, end: Alignment.centerRight); final boxBorder = Border.all( - color: borderColor ?? Theme.of(context).extension()!.secondaryTextColor, width: 1.0); + color: borderColor ?? Theme.of(context).extension()!.secondaryTextColor, + width: 1.0, + ); final checkedBoxDecoration = BoxDecoration( gradient: gradientBackground ? baseGradient : null, @@ -41,6 +43,7 @@ class StandardCheckbox extends StatelessWidget { child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( height: 24.0, @@ -55,13 +58,22 @@ class StandardCheckbox extends StatelessWidget { : Offstage(), ), if (caption.isNotEmpty) - Padding( + Flexible( + child: Padding( padding: EdgeInsets.only(left: 10), child: Text( caption, + softWrap: true, style: TextStyle( - fontSize: 16.0, color: Theme.of(context).extension()!.titleColor), - )) + fontSize: 16.0, + fontFamily: 'Lato', + fontWeight: FontWeight.normal, + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ), + ), + ) ], ), ); diff --git a/lib/src/widgets/standard_list_card.dart b/lib/src/widgets/standard_list_card.dart index 4b16e1ad4..c86df0b9d 100644 --- a/lib/src/widgets/standard_list_card.dart +++ b/lib/src/widgets/standard_list_card.dart @@ -6,12 +6,14 @@ import 'package:cake_wallet/themes/theme_base.dart'; class TradeDetailsStandardListCard extends StatelessWidget { TradeDetailsStandardListCard( {required this.id, + this.extraId, required this.create, required this.pair, required this.onTap, required this.currentTheme}); final String id; + final String? extraId; final String create; final String pair; final ThemeType currentTheme; @@ -57,6 +59,16 @@ class TradeDetailsStandardListCard extends StatelessWidget { SizedBox( height: 8, ), + if (extraId != null && extraId!.isNotEmpty) + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Text(extraId!, + style: TextStyle( + fontSize: 16, + fontFamily: 'Lato', + fontWeight: FontWeight.w400, + color: textColor)), + ), Text(create, style: TextStyle( fontSize: 12, diff --git a/lib/store/app_store.dart b/lib/store/app_store.dart index 24d5dc6a4..ff3ba0535 100644 --- a/lib/store/app_store.dart +++ b/lib/store/app_store.dart @@ -50,8 +50,8 @@ abstract class AppStoreBase with Store { getIt.get().create(); await getIt.get().init(); } - await getIt.get().setString(PreferencesKey.currentWalletName, wallet.name); - await getIt + getIt.get().setString(PreferencesKey.currentWalletName, wallet.name); + getIt .get() .setInt(PreferencesKey.currentWalletType, serializeToInt(wallet.type)); } diff --git a/lib/store/authentication_store.dart b/lib/store/authentication_store.dart index 815b1ed60..db4c4861e 100644 --- a/lib/store/authentication_store.dart +++ b/lib/store/authentication_store.dart @@ -4,7 +4,7 @@ part 'authentication_store.g.dart'; class AuthenticationStore = AuthenticationStoreBase with _$AuthenticationStore; -enum AuthenticationState { uninitialized, installed, allowed, _reset } +enum AuthenticationState { uninitialized, installed, allowed, allowedCreate, _reset } abstract class AuthenticationStoreBase with Store { AuthenticationStoreBase() : state = AuthenticationState.uninitialized; @@ -23,4 +23,10 @@ abstract class AuthenticationStoreBase with Store { state = AuthenticationState._reset; state = AuthenticationState.allowed; } + + @action + void allowedCreate() { + state = AuthenticationState._reset; + state = AuthenticationState.allowedCreate; + } } diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index a973609c5..088c13bb4 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -36,6 +36,7 @@ import 'package:cake_wallet/wownero/wownero.dart'; import 'package:cw_core/node.dart'; import 'package:cw_core/set_app_secure_native.dart'; import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/material.dart'; @@ -53,6 +54,7 @@ abstract class SettingsStoreBase with Store { required BackgroundTasks backgroundTasks, required SharedPreferences sharedPreferences, required bool initialShouldShowMarketPlaceInDashboard, + required bool initialShowAddressBookPopupEnabled, required FiatCurrency initialFiatCurrency, required BalanceDisplayMode initialBalanceDisplayMode, required bool initialSaveRecipientAddress, @@ -157,6 +159,7 @@ abstract class SettingsStoreBase with Store { walletListAscending = initialWalletListAscending, contactListAscending = initialContactListAscending, shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard, + showAddressBookPopupEnabled = initialShowAddressBookPopupEnabled, exchangeStatus = initialExchangeStatus, currentTheme = initialTheme, pinCodeLength = initialPinLength, @@ -355,6 +358,11 @@ abstract class SettingsStoreBase with Store { (bool value) => sharedPreferences.setBool(PreferencesKey.shouldShowMarketPlaceInDashboard, value)); + reaction( + (_) => showAddressBookPopupEnabled, + (bool value) => + sharedPreferences.setBool(PreferencesKey.showAddressBookPopupEnabled, value)); + reaction((_) => pinCodeLength, (int pinLength) => sharedPreferences.setInt(PreferencesKey.currentPinLength, pinLength)); @@ -611,6 +619,9 @@ abstract class SettingsStoreBase with Store { @observable bool shouldShowMarketPlaceInDashboard; + @observable + bool showAddressBookPopupEnabled; + @observable ObservableList actionlistDisplayMode; @@ -925,6 +936,8 @@ abstract class SettingsStoreBase with Store { final tokenTrialNumber = sharedPreferences.getInt(PreferencesKey.failedTotpTokenTrials) ?? 0; final shouldShowMarketPlaceInDashboard = sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? true; + final showAddressBookPopupEnabled = + sharedPreferences.getBool(PreferencesKey.showAddressBookPopupEnabled) ?? true; final exchangeStatus = ExchangeApiMode.deserialize( raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); @@ -1194,6 +1207,7 @@ abstract class SettingsStoreBase with Store { secureStorage: secureStorage, sharedPreferences: sharedPreferences, initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard, + initialShowAddressBookPopupEnabled: showAddressBookPopupEnabled, nodes: nodes, powNodes: powNodes, appVersion: packageInfo.version, @@ -1371,6 +1385,9 @@ abstract class SettingsStoreBase with Store { shouldShowMarketPlaceInDashboard = sharedPreferences.getBool(PreferencesKey.shouldShowMarketPlaceInDashboard) ?? shouldShowMarketPlaceInDashboard; + showAddressBookPopupEnabled = + sharedPreferences.getBool(PreferencesKey.showAddressBookPopupEnabled) ?? + showAddressBookPopupEnabled; exchangeStatus = ExchangeApiMode.deserialize( raw: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey) ?? ExchangeApiMode.enabled.raw); @@ -1674,8 +1691,8 @@ abstract class SettingsStoreBase with Store { final windowsInfo = await deviceInfoPlugin.windowsInfo; deviceName = windowsInfo.productName; } catch (e) { - print(e); - print( + printV(e); + printV( 'likely digitalProductId is null wait till https://github.com/fluttercommunity/plus_plugins/pull/3188 is merged'); deviceName = "Windows Device"; } diff --git a/lib/store/yat/yat_store.dart b/lib/store/yat/yat_store.dart index 81c5de3b5..964b96db3 100644 --- a/lib/store/yat/yat_store.dart +++ b/lib/store/yat/yat_store.dart @@ -1,5 +1,6 @@ import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cw_core/transaction_history.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/balance.dart'; import 'package:cw_core/transaction_info.dart'; @@ -250,7 +251,7 @@ abstract class YatStoreBase with Store { walletInfo!.save(); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -265,7 +266,7 @@ abstract class YatStoreBase with Store { // apiKey = await fetchYatApiKey(accessToken); // await secureStorage.write(key: yatApiKey(_wallet.walletInfo.name), value: accessToken); //} catch (e) { - // print(e.toString()); + // printV(e.toString()); //} } diff --git a/lib/utils/distribution_info.dart b/lib/utils/distribution_info.dart index 5a2cb8e9d..2fbb6a175 100644 --- a/lib/utils/distribution_info.dart +++ b/lib/utils/distribution_info.dart @@ -1,5 +1,6 @@ import 'dart:io'; import 'package:cake_wallet/utils/package_info.dart'; +import 'package:cw_core/utils/print_verbose.dart'; enum DistributionType { googleplay, github, appstore, fdroid } @@ -32,7 +33,7 @@ class DistributionInfo { final packageInfo = await PackageInfo.fromPlatform(); return packageInfo.packageName == 'com.android.vending'; } catch (e) { - print('Error: $e'); + printV('Error: $e'); return false; } } diff --git a/lib/utils/exception_handler.dart b/lib/utils/exception_handler.dart index 41ae91d41..d79dfe314 100644 --- a/lib/utils/exception_handler.dart +++ b/lib/utils/exception_handler.dart @@ -1,12 +1,15 @@ import 'dart:io'; +import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; +import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cw_core/root_dir.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:device_info_plus/device_info_plus.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -20,16 +23,29 @@ class ExceptionHandler { static const _coolDownDurationInDays = 7; static File? _file; - static void _saveException(String? error, StackTrace? stackTrace, {String? library}) async { + static Future _saveException(String? error, StackTrace? stackTrace, + {String? library}) async { final appDocDir = await getAppDir(); if (_file == null) { _file = File('${appDocDir.path}/error.txt'); } + String? walletType; + CustomTrace? programInfo; + + try { + walletType = getIt.get().wallet?.type.name; + + programInfo = CustomTrace(stackTrace ?? StackTrace.current); + } catch (_) {} + final exception = { "${DateTime.now()}": { "Error": "$error\n\n", + "WalletType": "$walletType\n\n", + "VerboseLog": + "${programInfo?.fileName}#${programInfo?.lineNumber}:${programInfo?.columnNumber} ${programInfo?.callerFunctionName}\n\n", "Library": "$library\n\n", "StackTrace": stackTrace.toString(), } @@ -66,7 +82,7 @@ class ExceptionHandler { final bool canSend = await FlutterMailer.canSendMail(); if (Platform.isIOS && !canSend) { - debugPrint('Mail app is not available'); + printV('Mail app is not available'); return; } @@ -90,14 +106,20 @@ class ExceptionHandler { } } - static void onError(FlutterErrorDetails errorDetails) async { + static Future resetLastPopupDate() async { + final sharedPrefs = await SharedPreferences.getInstance(); + await sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime(1971).toString()); + } + + static Future onError(FlutterErrorDetails errorDetails) async { if (kDebugMode || kProfileMode) { FlutterError.presentError(errorDetails); - debugPrint(errorDetails.toString()); + printV(errorDetails.toString()); return; } - if (_ignoreError(errorDetails.exception.toString())) { + if (_ignoreError(errorDetails.exception.toString()) || + _ignoreError(errorDetails.stack.toString())) { return; } @@ -124,35 +146,40 @@ class ExceptionHandler { } _hasError = true; - sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString()); + await sharedPrefs.setString(PreferencesKey.lastPopupDate, DateTime.now().toString()); - WidgetsBinding.instance.addPostFrameCallback( - (timeStamp) async { - if (navigatorKey.currentContext != null) { - await showPopUp( - context: navigatorKey.currentContext!, - builder: (context) { - return AlertWithTwoActions( - isDividerExist: true, - alertTitle: S.of(context).error, - alertContent: S.of(context).error_dialog_content, - rightButtonText: S.of(context).send, - leftButtonText: S.of(context).do_not_send, - actionRightButton: () { - Navigator.of(context).pop(); - _sendExceptionFile(); - }, - actionLeftButton: () { - Navigator.of(context).pop(); - }, - ); + // Instead of using WidgetsBinding.instance.addPostFrameCallback we + // await Future.delayed(Duration.zero), which does essentially the same ( + // but doesn't wait for actual frame to be rendered), but it allows us to + // properly await the execution - which is what we want, without awaiting + // other code may call functions like Navigator.pop(), and close the alert + // instead of the intended UI. + // WidgetsBinding.instance.addPostFrameCallback( + // (timeStamp) async { + await Future.delayed(Duration.zero); + if (navigatorKey.currentContext != null) { + await showPopUp( + context: navigatorKey.currentContext!, + builder: (context) { + return AlertWithTwoActions( + isDividerExist: true, + alertTitle: S.of(context).error, + alertContent: S.of(context).error_dialog_content, + rightButtonText: S.of(context).send, + leftButtonText: S.of(context).do_not_send, + actionRightButton: () { + Navigator.of(context).pop(); + _sendExceptionFile(); + }, + actionLeftButton: () { + Navigator.of(context).pop(); }, ); - } + }, + ); + } - _hasError = false; - }, - ); + _hasError = false; } /// Ignore User related errors or system errors @@ -188,6 +215,13 @@ class ExceptionHandler { "input stream error", "invalid signature", "invalid password", + // Temporary ignored, More context: Flutter secure storage reads the values as null some times + // probably when the device was locked and then opened on Cake + // this is solved by a restart of the app + // just ignoring until we find a solution to this issue or migrate from flutter secure storage + "core/auth_service.dart:63", + "core/key_service.dart:14", + "core/wallet_loading_service.dart:132", ]; static Future _addDeviceInfo(File file) async { @@ -272,20 +306,18 @@ class ExceptionHandler { }; } - static void showError(String error, {int? delayInSeconds}) async { + static Future showError(String error, {int? delayInSeconds}) async { if (_hasError) { return; } _hasError = true; - if (delayInSeconds != null) { Future.delayed(Duration(seconds: delayInSeconds), () => _showCopyPopup(error)); return; } - WidgetsBinding.instance.addPostFrameCallback( - (_) async => _showCopyPopup(error), - ); + await Future.delayed(Duration.zero); + await _showCopyPopup(error); } static Future _showCopyPopup(String content) async { diff --git a/lib/utils/feature_flag.dart b/lib/utils/feature_flag.dart index 86579194b..96b505fe7 100644 --- a/lib/utils/feature_flag.dart +++ b/lib/utils/feature_flag.dart @@ -3,4 +3,5 @@ class FeatureFlag { static const bool isExolixEnabled = true; static const bool isInAppTorEnabled = false; static const bool isBackgroundSyncEnabled = true; + static const int verificationWordsCount = 2; } \ No newline at end of file diff --git a/lib/view_model/anonpay_details_view_model.dart b/lib/view_model/anonpay_details_view_model.dart index fe4b9da3d..e83b939cd 100644 --- a/lib/view_model/anonpay_details_view_model.dart +++ b/lib/view_model/anonpay_details_view_model.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:mobx/mobx.dart'; @@ -47,7 +48,7 @@ abstract class AnonpayDetailsViewModelBase with Store { invoiceDetail.status = data.status; _updateItems(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/lib/view_model/backup_view_model.dart b/lib/view_model/backup_view_model.dart index bbd147e2b..53e2864d4 100644 --- a/lib/view_model/backup_view_model.dart +++ b/lib/view_model/backup_view_model.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/core/secure_storage.dart'; import 'package:cake_wallet/entities/secret_store_key.dart'; import 'package:cake_wallet/store/secret_store.dart'; import 'package:cw_core/root_dir.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/foundation.dart'; import 'package:mobx/mobx.dart'; import 'package:intl/intl.dart'; @@ -67,7 +68,7 @@ abstract class BackupViewModelBase with Store { return BackupExportFile(backupContent.toList(), name: fileName); } catch (e) { - print(e.toString()); + printV(e.toString()); state = FailureState(e.toString()); return null; } diff --git a/lib/view_model/buy/buy_item.dart b/lib/view_model/buy/buy_item.dart index 97bd661f2..b6e7523b9 100644 --- a/lib/view_model/buy/buy_item.dart +++ b/lib/view_model/buy/buy_item.dart @@ -2,6 +2,7 @@ import 'package:cake_wallet/buy/buy_amount.dart'; import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart'; +import 'package:cw_core/utils/print_verbose.dart'; class BuyItem { BuyItem({required this.provider, required this.buyAmountViewModel}); @@ -21,7 +22,7 @@ class BuyItem { .calculateAmount(amount?.toString() ?? '', fiatCurrency.title); } catch (e) { _buyAmount = BuyAmount(sourceAmount: 0.0, destAmount: 0.0); - print(e.toString()); + printV(e.toString()); } return _buyAmount; diff --git a/lib/view_model/buy/buy_sell_view_model.dart b/lib/view_model/buy/buy_sell_view_model.dart index e1c53ee56..d16307134 100644 --- a/lib/view_model/buy/buy_sell_view_model.dart +++ b/lib/view_model/buy/buy_sell_view_model.dart @@ -162,6 +162,9 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S isBuySellQuotLoaded; } + @computed + bool get isBuySellQuotFailed => buySellQuotState is BuySellQuotFailed; + @action void reset() { cryptoCurrency = wallet.currency; diff --git a/lib/view_model/buy/buy_view_model.dart b/lib/view_model/buy/buy_view_model.dart index 7c2591cbb..181276ed5 100644 --- a/lib/view_model/buy/buy_view_model.dart +++ b/lib/view_model/buy/buy_view_model.dart @@ -3,6 +3,7 @@ import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart'; import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/view_model/buy/buy_item.dart'; @@ -63,7 +64,7 @@ abstract class BuyViewModelBase with Store { try { _url = await selectedProvider!.requestUrl(doubleAmount.toString(), fiatCurrency.title); } catch (e) { - print(e.toString()); + printV(e.toString()); } return _url; @@ -77,7 +78,7 @@ abstract class BuyViewModelBase with Store { await ordersSource.add(order); ordersStore.setOrder(order); } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart b/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart index 8585da9da..442bd51b4 100644 --- a/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart +++ b/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart @@ -204,7 +204,11 @@ abstract class CakePayCardsListViewModelBase with Store { } @action - void setSelectedCountry(Country country) => settingsStore.selectedCakePayCountry = country; + void setSelectedCountry(Country country) { + // just so it triggers the reaction even when selecting the default country + settingsStore.selectedCakePayCountry = null; + settingsStore.selectedCakePayCountry = country; + } @action void togglePrepaidCards() => displayPrepaidCards = !displayPrepaidCards; diff --git a/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart b/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart index a580db054..f95f9e2b7 100644 --- a/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart +++ b/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart @@ -49,6 +49,13 @@ abstract class CakePayPurchaseViewModelBase with Store { String get fiatCurrency => paymentCredential.fiatCurrency; + bool confirmsNoVpn = false; + bool confirmsVoidedRefund = false; + bool confirmsTermsAgreed = false; + + @observable + bool isPurchasing = false; + CryptoPaymentData? get cryptoPaymentData { if (order == null) return null; @@ -86,9 +93,13 @@ abstract class CakePayPurchaseViewModelBase with Store { } try { order = await cakePayService.createOrder( - cardId: card.id, - price: paymentCredential.amount.toString(), - quantity: paymentCredential.quantity); + cardId: card.id, + price: paymentCredential.amount.toString(), + quantity: paymentCredential.quantity, + confirmsNoVpn: confirmsNoVpn, + confirmsVoidedRefund: confirmsVoidedRefund, + confirmsTermsAgreed: confirmsTermsAgreed, + ); await confirmSending(); expirationTime = order!.paymentData.expirationTime; updateRemainingTime(); diff --git a/lib/view_model/dashboard/balance_view_model.dart b/lib/view_model/dashboard/balance_view_model.dart index 20dca292c..075cf6b75 100644 --- a/lib/view_model/dashboard/balance_view_model.dart +++ b/lib/view_model/dashboard/balance_view_model.dart @@ -287,7 +287,7 @@ abstract class BalanceViewModelBase with Store { BalanceRecord( availableBalance: '---', additionalBalance: '---', - frozenBalance: '---', + frozenBalance: '', secondAvailableBalance: '---', secondAdditionalBalance: '---', fiatAdditionalBalance: isFiatDisabled ? '' : '---', @@ -488,6 +488,15 @@ abstract class BalanceViewModelBase with Store { isShowCard = cardDisplayStatus; } + @action + void switchBalanceValue() { + if (settingsStore.balanceDisplayMode == BalanceDisplayMode.displayableBalance) { + settingsStore.balanceDisplayMode = BalanceDisplayMode.hiddenBalance; + } else { + settingsStore.balanceDisplayMode = BalanceDisplayMode.displayableBalance; + } + } + String _getFiatBalance({required double price, String? cryptoAmount}) { if (cryptoAmount == null || cryptoAmount.isEmpty || double.tryParse(cryptoAmount) == null) { return '0.00'; diff --git a/lib/view_model/dashboard/home_settings_view_model.dart b/lib/view_model/dashboard/home_settings_view_model.dart index 1aeacd28f..0c3a611eb 100644 --- a/lib/view_model/dashboard/home_settings_view_model.dart +++ b/lib/view_model/dashboard/home_settings_view_model.dart @@ -15,6 +15,7 @@ import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart'; import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/erc20_token.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:mobx/mobx.dart'; import 'package:http/http.dart' as http; @@ -236,7 +237,7 @@ abstract class HomeSettingsViewModelBase with Store { return false; } catch (e) { - print('Error while checking scam via moralis: ${e.toString()}'); + printV('Error while checking scam via moralis: ${e.toString()}'); return true; } } @@ -277,7 +278,7 @@ abstract class HomeSettingsViewModelBase with Store { return false; } catch (e) { - print('Error while checking scam via explorers: ${e.toString()}'); + printV('Error while checking scam via explorers: ${e.toString()}'); return true; } } @@ -303,21 +304,21 @@ abstract class HomeSettingsViewModelBase with Store { final decodedResponse = jsonDecode(response.body) as Map; if (decodedResponse['status'] == '0') { - print('${response.body}\n'); - print('${decodedResponse['result']}\n'); + printV('${response.body}\n'); + printV('${decodedResponse['result']}\n'); return true; } if (decodedResponse['status'] == '1' && decodedResponse['result'][0]['ABI'] == 'Contract source code not verified') { - print('Call is valid but contract is not verified'); + printV('Call is valid but contract is not verified'); return true; // Contract is not verified } else { - print('Call is valid and contract is verified'); + printV('Call is valid and contract is verified'); return false; // Contract is verified } } catch (e) { - print('Error while checking contract verification: ${e.toString()}'); + printV('Error while checking contract verification: ${e.toString()}'); return true; } } diff --git a/lib/view_model/exchange/exchange_trade_view_model.dart b/lib/view_model/exchange/exchange_trade_view_model.dart index 4cb7e4cad..0c8053842 100644 --- a/lib/view_model/exchange/exchange_trade_view_model.dart +++ b/lib/view_model/exchange/exchange_trade_view_model.dart @@ -16,6 +16,7 @@ import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_item.dart' import 'package:cake_wallet/store/dashboard/trades_store.dart'; import 'package:cake_wallet/view_model/send/send_view_model.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -139,13 +140,13 @@ abstract class ExchangeTradeViewModelBase with Store { _updateItems(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } void _updateItems() { final tagFrom = - tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : ''; + tradesStore.trade!.from.tag != null ? '${tradesStore.trade!.from.tag}' + ' ' : ''; final tagTo = tradesStore.trade!.to.tag != null ? '${tradesStore.trade!.to.tag}' + ' ' : ''; items.clear(); @@ -158,16 +159,6 @@ abstract class ExchangeTradeViewModelBase with Store { ), ); - if (trade.extraId != null) { - final title = trade.from == CryptoCurrency.xrp - ? S.current.destination_tag - : trade.from == CryptoCurrency.xlm - ? S.current.memo - : S.current.extra_id; - - items.add(ExchangeTradeItem(title: title, data: '${trade.extraId}', isCopied: false)); - } - items.addAll([ ExchangeTradeItem( title: S.current.amount, @@ -175,7 +166,7 @@ abstract class ExchangeTradeViewModelBase with Store { isCopied: true, ), ExchangeTradeItem( - title: S.current.estimated_receive_amount +':', + title: S.current.estimated_receive_amount + ':', data: '${tradesStore.trade?.receiveAmount} ${trade.to}', isCopied: true, ), @@ -184,12 +175,25 @@ abstract class ExchangeTradeViewModelBase with Store { data: trade.inputAddress ?? '', isCopied: true, ), + ]); + + if (trade.extraId != null) { + final title = trade.from == CryptoCurrency.xrp + ? S.current.destination_tag + : trade.from == CryptoCurrency.xlm + ? S.current.memo + : S.current.extra_id; + + items.add(ExchangeTradeItem(title: title, data: '${trade.extraId}', isCopied: true)); + } + + items.add( ExchangeTradeItem( title: S.current.arrive_in_this_address('${tradesStore.trade!.to}', tagTo) + ':', data: trade.payoutAddress ?? '', isCopied: true, ), - ]); + ); } static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) { diff --git a/lib/view_model/exchange/exchange_view_model.dart b/lib/view_model/exchange/exchange_view_model.dart index d29b7df6b..ee8a88b6b 100644 --- a/lib/view_model/exchange/exchange_view_model.dart +++ b/lib/view_model/exchange/exchange_view_model.dart @@ -9,6 +9,7 @@ import 'package:cake_wallet/exchange/provider/stealth_ex_exchange_provider.dart' import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/sync_status.dart'; import 'package:cw_core/transaction_priority.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:hive/hive.dart'; import 'package:http/http.dart' as http; @@ -944,7 +945,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with return isContractAddress; } catch (e) { - print(e); + printV(e); return false; } } diff --git a/lib/view_model/hardware_wallet/ledger_view_model.dart b/lib/view_model/hardware_wallet/ledger_view_model.dart index 3cd131efa..4c084c778 100644 --- a/lib/view_model/hardware_wallet/ledger_view_model.dart +++ b/lib/view_model/hardware_wallet/ledger_view_model.dart @@ -4,13 +4,18 @@ import 'dart:io'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/main.dart'; import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/polygon/polygon.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart'; import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cw_core/hardware/device_connection_type.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:flutter/widgets.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as sdk; import 'package:mobx/mobx.dart'; @@ -58,15 +63,18 @@ abstract class LedgerViewModelBase with Store { bool _bleIsInitialized = false; Future _initBLE() async { if (bleIsEnabled && !_bleIsInitialized) { - ledgerPlusBLE = sdk.LedgerInterface.ble(onPermissionRequest: (_) async { - Map statuses = await [ - Permission.bluetoothScan, - Permission.bluetoothConnect, - Permission.bluetoothAdvertise, - ].request(); + ledgerPlusBLE = sdk.LedgerInterface.ble( + onPermissionRequest: (_) async { + Map statuses = await [ + Permission.bluetoothScan, + Permission.bluetoothConnect, + Permission.bluetoothAdvertise, + ].request(); - return statuses.values.where((status) => status.isDenied).isEmpty; - }); + return statuses.values.where((status) => status.isDenied).isEmpty; + }, + bleOptions: + sdk.BluetoothOptions(maxScanDuration: Duration(minutes: 5))); _bleIsInitialized = true; } } @@ -83,33 +91,62 @@ abstract class LedgerViewModelBase with Store { Stream scanForUsbDevices() => ledgerPlusUSB.scan(); + Future stopScanning() async { + await ledgerPlusBLE.stopScanning(); + if (!Platform.isIOS) { + await ledgerPlusUSB.stopScanning(); + } + } + Future connectLedger(sdk.LedgerDevice device, WalletType type) async { + _isConnecting = true; + _connectingWalletType = type; if (isConnected) { try { - await _connection!.disconnect(); + await _connection!.disconnect().catchError((_) {}); } catch (_) {} } + final ledger = device.connectionType == sdk.ConnectionType.ble ? ledgerPlusBLE : ledgerPlusUSB; - if (_connectionChangeListener == null) { - _connectionChangeListener = ledger.deviceStateChanges.listen((event) { - print('Ledger Device State Changed: $event'); - if (event == sdk.BleConnectionState.disconnected) { - _connection = null; - if (type == WalletType.monero) { - monero!.resetLedgerConnection(); - } - } - }); + if (_connectionChangeSubscription == null) { + _connectionChangeSubscription = ledger.deviceStateChanges + .listen(_connectionChangeListener); } _connection = await ledger.connect(device); + _isConnecting = false; } - StreamSubscription? _connectionChangeListener; + StreamSubscription? _connectionChangeSubscription; sdk.LedgerConnection? _connection; + bool _isConnecting = true; + WalletType? _connectingWalletType; + + void _connectionChangeListener( + sdk.BleConnectionState event, ) { + printV('Ledger Device State Changed: $event'); + if (event == sdk.BleConnectionState.disconnected && !_isConnecting) { + _connection = null; + if (_connectingWalletType == WalletType.monero) { + monero!.resetLedgerConnection(); + + Navigator.of(navigatorKey.currentContext!).pushNamed( + Routes.connectDevices, + arguments: ConnectDevicePageParams( + walletType: WalletType.monero, + allowChangeWallet: true, + isReconnect: true, + onConnectDevice: (context, ledgerVM) async { + Navigator.of(context).pop(); + }, + ), + ); + } + } + } bool get isConnected => _connection != null && !(_connection!.isDisconnected); diff --git a/lib/view_model/order_details_view_model.dart b/lib/view_model/order_details_view_model.dart index 1eab2f861..a7cd98a21 100644 --- a/lib/view_model/order_details_view_model.dart +++ b/lib/view_model/order_details_view_model.dart @@ -3,6 +3,7 @@ import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider_description.dart'; import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; @@ -65,7 +66,7 @@ abstract class OrderDetailsViewModelBase with Store { _updateItems(); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/lib/view_model/restore_from_backup_view_model.dart b/lib/view_model/restore_from_backup_view_model.dart index 432cac67e..247e6d43d 100644 --- a/lib/view_model/restore_from_backup_view_model.dart +++ b/lib/view_model/restore_from_backup_view_model.dart @@ -68,7 +68,7 @@ abstract class RestoreFromBackupViewModelBase with Store { if (msg.toLowerCase().contains("message authentication code (mac)")) { msg = 'Incorrect backup password'; } else { - ExceptionHandler.onError(FlutterErrorDetails( + await ExceptionHandler.onError(FlutterErrorDetails( exception: e, stack: s, library: this.toString(), diff --git a/lib/view_model/send/output.dart b/lib/view_model/send/output.dart index e53127e0c..f977ef003 100644 --- a/lib/view_model/send/output.dart +++ b/lib/view_model/send/output.dart @@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/wownero/wownero.dart'; import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:mobx/mobx.dart'; @@ -180,7 +181,7 @@ abstract class OutputBase with Store { return polygon!.formatterPolygonAmountToDouble(amount: BigInt.from(fee)); } } catch (e) { - print(e.toString()); + printV(e.toString()); } return 0; diff --git a/lib/view_model/send/send_view_model.dart b/lib/view_model/send/send_view_model.dart index 69011aa74..c1e0953a0 100644 --- a/lib/view_model/send/send_view_model.dart +++ b/lib/view_model/send/send_view_model.dart @@ -1,5 +1,5 @@ -import 'package:cake_wallet/di.dart'; import 'package:cake_wallet/entities/contact.dart'; +import 'package:cake_wallet/entities/evm_transaction_error_fees_handler.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; @@ -13,12 +13,12 @@ import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/reactions/wallet_connect.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/solana/solana.dart'; -import 'package:cake_wallet/src/screens/ur/animated_ur_page.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; +import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart'; import 'package:cake_wallet/wownero/wownero.dart'; import 'package:cw_core/exceptions.dart'; import 'package:cw_core/transaction_info.dart'; @@ -26,6 +26,7 @@ import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/unspent_coin_type.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cake_wallet/view_model/send/send_template_view_model.dart'; +import 'package:cw_solana/solana_exceptions.dart'; import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; @@ -64,6 +65,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor wallet.type == WalletType.tron; } + UnspentCoinsListViewModel unspentCoinsListViewModel; + SendViewModelBase( AppStore appStore, this.sendTemplateViewModel, @@ -71,7 +74,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor this.balanceViewModel, this.contactListViewModel, this.transactionDescriptionBox, - this.ledgerViewModel, { + this.ledgerViewModel, + this.unspentCoinsListViewModel, { this.coinTypeToSpendFrom = UnspentCoinType.any, }) : state = InitialExecutionState(), currencies = appStore.wallet!.balance.keys.toList(), @@ -95,6 +99,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor outputs .add(Output(wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); + + unspentCoinsListViewModel.initialSetup(); } @observable @@ -104,6 +110,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor final UnspentCoinType coinTypeToSpendFrom; + bool get showAddressBookPopup => _settingsStore.showAddressBookPopupEnabled; + @action void addOutput() { outputs @@ -129,11 +137,11 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor bool get shouldDisplaySendALL { if (walletType == WalletType.solana) return false; - if (walletType == WalletType.ethereum && selectedCryptoCurrency == CryptoCurrency.eth) - return false; + // if (walletType == WalletType.ethereum && selectedCryptoCurrency == CryptoCurrency.eth) + // return false; - if (walletType == WalletType.polygon && selectedCryptoCurrency == CryptoCurrency.matic) - return false; + // if (walletType == WalletType.polygon && selectedCryptoCurrency == CryptoCurrency.maticpoly) + // return false; return true; } @@ -419,7 +427,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor // // state = FailureState(errorMsg); // } else { - state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency)); + state = FailureState(translateErrorMessage(e, wallet.type, wallet.currency)); // } } return null; @@ -479,10 +487,11 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor try { state = TransactionCommitting(); - + if (pendingTransaction!.shouldCommitUR()) { final urstr = await pendingTransaction!.commitUR(); - final result = await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: urstr); + final result = + await Navigator.of(context).pushNamed(Routes.urqrAnimatedPage, arguments: urstr); if (result == null) { state = FailureState("Canceled by user"); return; @@ -495,18 +504,13 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor nano!.updateTransactions(wallet); } - if (pendingTransaction!.id.isNotEmpty) { - final descriptionKey = '${pendingTransaction!.id}_${wallet.walletAddresses.primaryAddress}'; _settingsStore.shouldSaveRecipientAddress ? await transactionDescriptionBox.add(TransactionDescription( - id: descriptionKey, - recipientAddress: address, - transactionNote: note)) - : await transactionDescriptionBox.add(TransactionDescription( - id: descriptionKey, - transactionNote: note)); + id: descriptionKey, recipientAddress: address, transactionNote: note)) + : await transactionDescriptionBox + .add(TransactionDescription(id: descriptionKey, transactionNote: note)); } state = TransactionCommitted(); @@ -668,10 +672,26 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor lamportsNeeded != null ? ((lamportsNeeded + 5000) / lamportsPerSol) : 0.0; return S.current.insufficient_lamports(solValueNeeded.toString()); } else { - print("No match found."); return S.current.insufficient_lamport_for_tx; } } + + if (error is SolanaSignNativeTokenTransactionRentException) { + return S.current.solana_sign_native_transaction_rent_exception; + } + + if (error is SolanaCreateAssociatedTokenAccountException) { + return S.current.solana_create_associated_token_account_exception; + } + + if (error is SolanaSignSPLTokenTransactionRentException) { + return S.current.solana_sign_spl_token_transaction_rent_exception; + } + + if (error is SolanaNoAssociatedTokenAccountException) { + return S.current.solana_no_associated_token_account_exception; + } + if (errorMessage.contains('insufficient funds for rent')) { return S.current.insufficientFundsForRentError; } @@ -681,9 +701,26 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor if (walletType == WalletType.ethereum || walletType == WalletType.polygon || walletType == WalletType.haven) { - if (errorMessage.contains('gas required exceeds allowance') || - errorMessage.contains('insufficient funds')) { - return S.current.do_not_have_enough_gas_asset(currency.toString()); + if (errorMessage.contains('gas required exceeds allowance')) { + return S.current.gas_exceeds_allowance; + } + + if (errorMessage.contains('insufficient funds')) { + final parsedErrorMessageResult = + EVMTransactionErrorFeesHandler.parseEthereumFeesErrorMessage( + errorMessage, + _fiatConversationStore.prices[currency]!, + ); + + if (parsedErrorMessageResult.error != null) { + return S.current.insufficient_funds_for_tx; + } + + return + '''${S.current.insufficient_funds_for_tx} \n\n''' + '''${S.current.balance}: ${parsedErrorMessageResult.balanceEth} ${walletType == WalletType.polygon ? "POL" : "ETH"} (${parsedErrorMessageResult.balanceUsd} ${fiatFromSettings.name})\n\n''' + '''${S.current.transaction_cost}: ${parsedErrorMessageResult.txCostEth} ${walletType == WalletType.polygon ? "POL" : "ETH"} (${parsedErrorMessageResult.txCostUsd} ${fiatFromSettings.name})\n\n''' + '''${S.current.overshot}: ${parsedErrorMessageResult.overshotEth} ${walletType == WalletType.polygon ? "POL" : "ETH"} (${parsedErrorMessageResult.overshotUsd} ${fiatFromSettings.name})'''; } return errorMessage; @@ -760,4 +797,4 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor return false; } -} +} \ No newline at end of file diff --git a/lib/view_model/settings/other_settings_view_model.dart b/lib/view_model/settings/other_settings_view_model.dart index 3036e8ae9..c7a5d0b90 100644 --- a/lib/view_model/settings/other_settings_view_model.dart +++ b/lib/view_model/settings/other_settings_view_model.dart @@ -60,6 +60,10 @@ abstract class OtherSettingsViewModelBase with Store { bool get changeRepresentativeEnabled => _wallet.type == WalletType.nano || _wallet.type == WalletType.banano; + @computed + bool get showAddressBookPopup => _settingsStore.showAddressBookPopupEnabled; + + @computed bool get displayTransactionPriority => !(changeRepresentativeEnabled || _wallet.type == WalletType.solana || @@ -114,6 +118,9 @@ abstract class OtherSettingsViewModelBase with Store { return customItem != null ? priorities.indexOf(customItem) : null; } + @action + void setShowAddressBookPopup(bool value) => _settingsStore.showAddressBookPopupEnabled = value; + int? get maxCustomFeeRate { if (_wallet.type == WalletType.bitcoin) { return bitcoin!.getMaxCustomFeeRate(_wallet); diff --git a/lib/view_model/support_view_model.dart b/lib/view_model/support_view_model.dart index 45b9cb9bf..69659916f 100644 --- a/lib/view_model/support_view_model.dart +++ b/lib/view_model/support_view_model.dart @@ -11,106 +11,107 @@ class SupportViewModel = SupportViewModelBase with _$SupportViewModel; abstract class SupportViewModelBase with Store { SupportViewModelBase() - : items = [ - LinkListItem( - title: 'Email', - icon: 'assets/images/support_icon.png', - linkTitle: 'support@cakewallet.com', - link: 'mailto:support@cakewallet.com'), - if (!isMoneroOnly) - LinkListItem( - title: 'Website', - icon: 'assets/images/global.png', - linkTitle: 'cakewallet.com', - link: 'https://cakewallet.com'), - if (!isMoneroOnly) - LinkListItem( - title: 'GitHub', - icon: 'assets/images/github.png', - hasIconColor: true, - linkTitle: S.current.apk_update, - link: 'https://github.com/cake-tech/cake_wallet/releases'), - LinkListItem( - title: 'Telegram Community', - icon: 'assets/images/Telegram.png', - linkTitle: 't.me/cakewallet', - link: 'https://t.me/cakewallet'), - LinkListItem( - title: 'Telegram Support Bot', - icon: 'assets/images/Telegram.png', - linkTitle: '@cakewallet_bot', - link: 'https://t.me/cakewallet_bot'), - LinkListItem( - title: 'ChangeNow', - icon: 'assets/images/change_now.png', - linkTitle: 'support@changenow.io', - link: 'mailto:support@changenow.io'), - LinkListItem( - title: 'SideShift', - icon: 'assets/images/sideshift.png', - linkTitle: 'help.sideshift.ai', - link: 'https://help.sideshift.ai/en/'), - LinkListItem( - title: 'SimpleSwap', - icon: 'assets/images/simpleSwap.png', - linkTitle: 'support@simpleswap.io', - link: 'mailto:support@simpleswap.io'), - LinkListItem( - title: 'Exolix', - icon: 'assets/images/exolix.png', - linkTitle: 'support@exolix.com', - link: 'mailto:support@exolix.com'), - LinkListItem( - title: 'Quantex', - icon: 'assets/images/quantex.png', - linkTitle: 'help.myquantex.com', - link: 'mailto:support@exolix.com'), - LinkListItem( - title: 'Trocador', - icon: 'assets/images/trocador.png', - linkTitle: 'mail@trocador.app', - link: 'mailto:mail@trocador.app'), - LinkListItem( - title: 'Onramper', - icon: 'assets/images/onramper_dark.png', - lightIcon: 'assets/images/onramper_light.png', - linkTitle: 'View exchanges', - link: 'https://guides.cakewallet.com/docs/service-support/buy/#onramper'), - LinkListItem( - title: 'DFX', - icon: 'assets/images/dfx_dark.png', - lightIcon: 'assets/images/dfx_light.png', - linkTitle: 'support@dfx.swiss', - link: 'mailto:support@dfx.swiss'), - if (!isMoneroOnly) ... [ - LinkListItem( - title: 'MoonPay', - icon: 'assets/images/moonpay.png', - linkTitle: S.current.submit_request, - link: 'https://support.moonpay.com/hc/en-gb/requests/new'), - LinkListItem( - title: 'Robinhood Connect', - icon: 'assets/images/robinhood_dark.png', - lightIcon: 'assets/images/robinhood_light.png', - linkTitle: S.current.submit_request, - link: 'https://robinhood.com/contact') - ] - //LinkListItem( - // title: 'Yat', - // icon: 'assets/images/yat_mini_logo.png', - // hasIconColor: true, - // linkTitle: 'support@y.at', - // link: 'mailto:support@y.at') - ]; + : items = [ + LinkListItem( + title: 'Email', + icon: 'assets/images/support_icon.png', + linkTitle: 'support@cakewallet.com', + link: 'mailto:support@cakewallet.com'), + LinkListItem( + title: 'Website', + icon: 'assets/images/global.png', + linkTitle: 'cakewallet.com', + link: 'https://cakewallet.com'), + LinkListItem( + title: 'Forum', + icon: 'assets/images/discourse.png', + linkTitle: 'forum.cakewallet.com', + link: 'https://forum.cakewallet.com'), + LinkListItem( + title: 'GitHub', + icon: 'assets/images/github.png', + hasIconColor: true, + linkTitle: S.current.apk_update, + link: 'https://github.com/cake-tech/cake_wallet/releases'), + LinkListItem( + title: 'Discord', + icon: 'assets/images/discord.png', + linkTitle: 'discord.gg/pwmWa6aFpX', + link: 'https://discord.gg/pwmWa6aFpX'), + LinkListItem( + title: 'Telegram', + icon: 'assets/images/Telegram.png', + linkTitle: 't.me/cakewallet', + link: 'https://t.me/cakewalletannouncements'), + LinkListItem( + title: 'Telegram Support Bot', + icon: 'assets/images/Telegram.png', + linkTitle: '@cakewallet_bot', + link: 'https://t.me/cakewallet_bot'), + LinkListItem( + title: 'ChangeNow', + icon: 'assets/images/change_now.png', + linkTitle: 'support@changenow.io', + link: 'mailto:support@changenow.io'), + LinkListItem( + title: 'SideShift', + icon: 'assets/images/sideshift.png', + linkTitle: 'help.sideshift.ai', + link: 'https://help.sideshift.ai/en/'), + LinkListItem( + title: 'SimpleSwap', + icon: 'assets/images/simpleSwap.png', + linkTitle: 'support@simpleswap.io', + link: 'mailto:support@simpleswap.io'), + LinkListItem( + title: 'Exolix', + icon: 'assets/images/exolix.png', + linkTitle: 'support@exolix.com', + link: 'mailto:support@exolix.com'), + LinkListItem( + title: 'Quantex', + icon: 'assets/images/quantex.png', + linkTitle: 'help.myquantex.com', + link: 'mailto:support@exolix.com'), + LinkListItem( + title: 'Trocador', + icon: 'assets/images/trocador.png', + linkTitle: 'mail@trocador.app', + link: 'mailto:mail@trocador.app'), + LinkListItem( + title: 'Onramper', + icon: 'assets/images/onramper_dark.png', + lightIcon: 'assets/images/onramper_light.png', + linkTitle: 'View exchanges', + link: 'https://docs.cakewallet.com/support/buy/#onramper'), + LinkListItem( + title: 'DFX', + icon: 'assets/images/dfx_dark.png', + lightIcon: 'assets/images/dfx_light.png', + linkTitle: 'support@dfx.swiss', + link: 'mailto:support@dfx.swiss'), + if (!isMoneroOnly) ...[ + LinkListItem( + title: 'MoonPay', + icon: 'assets/images/moonpay.png', + linkTitle: S.current.submit_request, + link: 'https://support.moonpay.com/hc/en-gb/requests/new'), + LinkListItem( + title: 'Robinhood Connect', + icon: 'assets/images/robinhood_dark.png', + lightIcon: 'assets/images/robinhood_light.png', + linkTitle: S.current.submit_request, + link: 'https://robinhood.com/contact') + ] + ]; - final guidesUrl = 'https://guides.cakewallet.com'; + final docsUrl = 'https://docs.cakewallet.com'; String fetchUrl({String locale = "en", String authToken = ""}) { var supportUrl = "https://app.chatwoot.com/widget?website_token=${secrets.chatwootWebsiteToken}&locale=${locale}"; - if (authToken.isNotEmpty) - supportUrl += "&cw_conversation=$authToken"; + if (authToken.isNotEmpty) supportUrl += "&cw_conversation=$authToken"; return supportUrl; } diff --git a/lib/view_model/trade_details_view_model.dart b/lib/view_model/trade_details_view_model.dart index 19315f40d..db7b979d9 100644 --- a/lib/view_model/trade_details_view_model.dart +++ b/lib/view_model/trade_details_view_model.dart @@ -22,6 +22,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cake_wallet/utils/show_bar.dart'; import 'package:collection/collection.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:hive/hive.dart'; @@ -134,7 +135,7 @@ abstract class TradeDetailsViewModelBase with Store { _updateItems(); } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -152,6 +153,7 @@ abstract class TradeDetailsViewModelBase with Store { items.add(TradeDetailsListCardItem.tradeDetails( id: trade.id, + extraId: trade.extraId, createdAt: trade.createdAt != null ? dateFormat.format(trade.createdAt!) : '', from: trade.from, to: trade.to, diff --git a/lib/view_model/transaction_details_view_model.dart b/lib/view_model/transaction_details_view_model.dart index a189ebe6c..9ec542361 100644 --- a/lib/view_model/transaction_details_view_model.dart +++ b/lib/view_model/transaction_details_view_model.dart @@ -1,5 +1,6 @@ import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/wownero/wownero.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/wallet_type.dart'; @@ -159,7 +160,7 @@ abstract class TransactionDetailsViewModelBase with Store { case WalletType.monero: return 'https://monero.com/tx/${txId}'; case WalletType.bitcoin: - return 'https://mempool.space/${wallet.isTestnet ? "testnet/" : ""}tx/${txId}'; + return 'https://mempool.cakewallet.com/${wallet.isTestnet ? "testnet/" : ""}tx/${txId}'; case WalletType.litecoin: return 'https://blockchair.com/litecoin/transaction/${txId}'; case WalletType.bitcoinCash: @@ -279,7 +280,7 @@ abstract class TransactionDetailsViewModelBase with Store { )); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } @@ -769,7 +770,7 @@ abstract class TransactionDetailsViewModelBase with Store { ); } } catch (e) { - print(e.toString()); + printV(e.toString()); } } diff --git a/lib/view_model/unspent_coins/unspent_coins_item.dart b/lib/view_model/unspent_coins/unspent_coins_item.dart index 4ca5a10a2..70488f8ee 100644 --- a/lib/view_model/unspent_coins/unspent_coins_item.dart +++ b/lib/view_model/unspent_coins/unspent_coins_item.dart @@ -1,10 +1,11 @@ +import 'package:cw_core/unspent_comparable_mixin.dart'; import 'package:mobx/mobx.dart'; part 'unspent_coins_item.g.dart'; class UnspentCoinsItem = UnspentCoinsItemBase with _$UnspentCoinsItem; -abstract class UnspentCoinsItemBase with Store { +abstract class UnspentCoinsItemBase with Store, UnspentComparable { UnspentCoinsItemBase({ required this.address, required this.amount, @@ -13,7 +14,7 @@ abstract class UnspentCoinsItemBase with Store { required this.note, required this.isSending, required this.isChange, - required this.amountRaw, + required this.value, required this.vout, required this.keyImage, required this.isSilentPayment, @@ -41,7 +42,7 @@ abstract class UnspentCoinsItemBase with Store { bool isChange; @observable - int amountRaw; + int value; @observable int vout; diff --git a/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart b/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart index f16b8390f..52820adcb 100644 --- a/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart +++ b/lib/view_model/unspent_coins/unspent_coins_list_view_model.dart @@ -6,10 +6,12 @@ import 'package:cake_wallet/wownero/wownero.dart'; import 'package:cw_core/unspent_coin_type.dart'; import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_transaction_output.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/cupertino.dart'; import 'package:hive/hive.dart'; +import 'package:collection/collection.dart'; import 'package:mobx/mobx.dart'; part 'unspent_coins_list_view_model.g.dart'; @@ -22,55 +24,66 @@ abstract class UnspentCoinsListViewModelBase with Store { required Box unspentCoinsInfo, this.coinTypeToSpendFrom = UnspentCoinType.any, }) : _unspentCoinsInfo = unspentCoinsInfo, - _items = ObservableList() { - _updateUnspentCoinsInfo(); - _updateUnspents(); - } + items = ObservableList(), + _originalState = {}; - WalletBase wallet; + final WalletBase wallet; final Box _unspentCoinsInfo; final UnspentCoinType coinTypeToSpendFrom; @observable - ObservableList _items; + ObservableList items; + + final Map> _originalState; + + @observable + bool isDisposing = false; @computed - ObservableList get items => _items; + bool get isAllSelected => items.every((element) => element.isFrozen || element.isSending); - Future saveUnspentCoinInfo(UnspentCoinsItem item) async { - try { - final info = - getUnspentCoinInfo(item.hash, item.address, item.amountRaw, item.vout, item.keyImage); + Future initialSetup() async { + await _updateUnspents(); + _storeOriginalState(); + } - if (info == null) { - return; - } - - info.isFrozen = item.isFrozen; - info.isSending = item.isSending; - info.note = item.note; - - await info.save(); - await _updateUnspents(); - await wallet.updateBalance(); - } catch (e) { - print(e.toString()); + void _storeOriginalState() { + _originalState.clear(); + for (final item in items) { + _originalState[item.hash] = { + 'isFrozen': item.isFrozen, + 'note': item.note, + 'isSending': item.isSending, + }; } } - UnspentCoinsInfo? getUnspentCoinInfo( - String hash, String address, int value, int vout, String? keyImage) { + bool _hasAdjustableFieldChanged(UnspentCoinsItem item) { + final original = _originalState[item.hash]; + if (original == null) return false; + return original['isFrozen'] != item.isFrozen || + original['note'] != item.note || + original['isSending'] != item.isSending; + } + + bool get hasAdjustableFieldChanged => items.any(_hasAdjustableFieldChanged); + + + Future saveUnspentCoinInfo(UnspentCoinsItem item) async { try { - return _unspentCoinsInfo.values.firstWhere((element) => - element.walletId == wallet.id && - element.hash == hash && - element.address == address && - element.value == value && - element.vout == vout && - element.keyImage == keyImage); + final existingInfo = _unspentCoinsInfo.values + .firstWhereOrNull((element) => element.walletId == wallet.id && element == item); + if (existingInfo == null) return; + + existingInfo.isFrozen = item.isFrozen; + existingInfo.isSending = item.isSending; + existingInfo.note = item.note; + + + await existingInfo.save(); + _updateUnspentCoinsInfo(); } catch (e) { - print("UnspentCoinsInfo not found for coin: $e"); - return null; + printV('Error saving coin info: $e'); } } @@ -115,37 +128,60 @@ abstract class UnspentCoinsListViewModelBase with Store { @action void _updateUnspentCoinsInfo() { - _items.clear(); + items.clear(); - List unspents = []; - _getUnspents().forEach((Unspent elem) { - try { - final info = - getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout, elem.keyImage); - if (info == null) { - return; - } + final unspents = _getUnspents() + .map((elem) { + try { + final existingItem = _unspentCoinsInfo.values + .firstWhereOrNull((item) => item.walletId == wallet.id && item == elem); - unspents.add(UnspentCoinsItem( - address: elem.address, - amount: '${formatAmountToString(elem.value)} ${wallet.currency.title}', - hash: elem.hash, - isFrozen: info.isFrozen, - note: info.note, - isSending: info.isSending, - amountRaw: elem.value, - vout: elem.vout, - keyImage: elem.keyImage, - isChange: elem.isChange, - isSilentPayment: info.isSilentPayment ?? false, - )); - } catch (e, s) { - print(s); - print(e.toString()); - ExceptionHandler.onError(FlutterErrorDetails(exception: e, stack: s)); - } - }); + if (existingItem == null) return null; - _items.addAll(unspents); + return UnspentCoinsItem( + address: elem.address, + amount: '${formatAmountToString(elem.value)} ${wallet.currency.title}', + hash: elem.hash, + isFrozen: existingItem.isFrozen, + note: existingItem.note, + isSending: existingItem.isSending, + value: elem.value, + vout: elem.vout, + keyImage: elem.keyImage, + isChange: elem.isChange, + isSilentPayment: existingItem.isSilentPayment ?? false, + ); + } catch (e, s) { + printV('Error: $e\nStack: $s'); + ExceptionHandler.onError( + FlutterErrorDetails(exception: e, stack: s), + ); + return null; + } + }) + .whereType() + .toList(); + + unspents.sort((a, b) => b.value.compareTo(a.value)); + + items.addAll(unspents); + } + + @action + void toggleSelectAll(bool value) { + for (final item in items) { + if (item.isFrozen || item.isSending == value) continue; + item.isSending = value; + saveUnspentCoinInfo(item); + } + } + + @action + void setIsDisposing(bool value) => isDisposing = value; + + @action + Future dispose() async { + await _updateUnspents(); + await wallet.updateBalance(); } } diff --git a/lib/view_model/wallet_creation_vm.dart b/lib/view_model/wallet_creation_vm.dart index bcb0a5bbe..083e076f8 100644 --- a/lib/view_model/wallet_creation_vm.dart +++ b/lib/view_model/wallet_creation_vm.dart @@ -8,10 +8,10 @@ import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/settings_store.dart'; -import 'package:cake_wallet/view_model/restore/restore_mode.dart'; import 'package:cake_wallet/view_model/restore/restore_wallet.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cw_core/pathForWallet.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; @@ -113,11 +113,11 @@ abstract class WalletCreationVMBase with Store { await _walletInfoSource.add(walletInfo); await _appStore.changeCurrentWallet(wallet); getIt.get().registerBackgroundService(); - _appStore.authenticationStore.allowed(); + _appStore.authenticationStore.allowedCreate(); state = ExecutedSuccessfullyState(); } catch (e, s) { - print("error: $e"); - print("stack: $s"); + printV("error: $e"); + printV("stack: $s"); state = FailureState(e.toString()); } } diff --git a/lib/view_model/wallet_hardware_restore_view_model.dart b/lib/view_model/wallet_hardware_restore_view_model.dart index 0971622a5..541e169d0 100644 --- a/lib/view_model/wallet_hardware_restore_view_model.dart +++ b/lib/view_model/wallet_hardware_restore_view_model.dart @@ -10,6 +10,7 @@ import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cake_wallet/view_model/seed_settings_view_model.dart'; import 'package:cake_wallet/view_model/wallet_creation_vm.dart'; import 'package:cw_core/hardware/hardware_account_data.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; @@ -82,7 +83,7 @@ abstract class WalletHardwareRestoreViewModelBase extends WalletCreationVM with // } on LedgerException catch (e) { // error = ledgerViewModel.interpretErrorCode(e.errorCode.toRadixString(16)); } catch (e) { - print(e); + printV(e); error = S.current.ledger_connection_error; } diff --git a/lib/view_model/wallet_list/wallet_list_view_model.dart b/lib/view_model/wallet_list/wallet_list_view_model.dart index c903b535f..407dce55a 100644 --- a/lib/view_model/wallet_list/wallet_list_view_model.dart +++ b/lib/view_model/wallet_list/wallet_list_view_model.dart @@ -2,6 +2,7 @@ import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/entities/wallet_group.dart'; import 'package:cake_wallet/entities/wallet_list_order_types.dart'; import 'package:cake_wallet/entities/wallet_manager.dart'; +import 'package:cake_wallet/reactions/bip39_wallet_utils.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:cake_wallet/store/app_store.dart'; @@ -90,20 +91,59 @@ abstract class WalletListViewModelBase with Store { multiWalletGroups.clear(); singleWalletsList.clear(); - wallets.addAll( - _walletInfoSource.values - .map((info) => convertWalletInfoToWalletListItem(info)), - ); + for (var info in _walletInfoSource.values) { + wallets.add(convertWalletInfoToWalletListItem(info)); + } //========== Split into shared seed groups and single wallets list _walletManager.updateWalletGroups(); - for (var group in _walletManager.walletGroups) { + final walletGroupsFromManager = _walletManager.walletGroups; + + for (var group in walletGroupsFromManager) { if (group.wallets.length == 1) { - singleWalletsList - .add(convertWalletInfoToWalletListItem(group.wallets.first)); - } else { + singleWalletsList.add(convertWalletInfoToWalletListItem(group.wallets.first)); + continue; + } + + // Identify wallets that should be moved to singleWalletsList using the filters: the type/derivation + final excludedWallets = []; + + for (var wallet in group.wallets) { + // Check for non-BIP39 wallet types + final isNonBIP39 = !isBIP39Wallet(wallet.type); + + // Check for nano derivation type + final isNanoDerivation = wallet.type == WalletType.nano && + wallet.derivationInfo?.derivationType == DerivationType.nano; + + // Check for electrum derivation type + final isElectrumDerivation = + (wallet.type == WalletType.bitcoin || wallet.type == WalletType.litecoin) && + wallet.derivationInfo?.derivationType == DerivationType.electrum; + + if (isNonBIP39 || isNanoDerivation || isElectrumDerivation) { + excludedWallets.add(wallet); + } + } + + // Add excluded wallets to singleWalletsList + for (var excludedWallet in excludedWallets) { + singleWalletsList.add(convertWalletInfoToWalletListItem(excludedWallet)); + } + + // Remove excluded wallets from the group's wallets to avoid duplication + group.wallets.removeWhere((wallet) { + return excludedWallets.any((excluded) => excluded.address == wallet.address); + }); + + // Check if the group has more than one wallet after the excluded wallets are removed. + if (group.wallets.length > 1) { + //Add the entire group to the multi wallet group list since its still a multi wallet multiWalletGroups.add(group); + } else if (group.wallets.length == 1) { + // Add the group to the wallet left to the single wallets list + singleWalletsList.add(convertWalletInfoToWalletListItem(group.wallets.first)); } } } diff --git a/lib/view_model/wallet_seed_view_model.dart b/lib/view_model/wallet_seed_view_model.dart index 8923a99da..5355c856d 100644 --- a/lib/view_model/wallet_seed_view_model.dart +++ b/lib/view_model/wallet_seed_view_model.dart @@ -1,3 +1,6 @@ +import 'dart:math'; + +import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:mobx/mobx.dart'; import 'package:cw_core/wallet_base.dart'; @@ -8,11 +11,108 @@ class WalletSeedViewModel = WalletSeedViewModelBase with _$WalletSeedViewModel; abstract class WalletSeedViewModelBase with Store { WalletSeedViewModelBase(WalletBase wallet) : name = wallet.name, - seed = wallet.seed!; + seed = wallet.seed!, + currentOptions = ObservableList(), + verificationIndices = ObservableList() { + setupSeedVerification(); + } @observable String name; @observable String seed; + + /// The Regex split the words based on any whitespace character. + /// + /// Either standard ASCII space (U+0020) or the full-width space character (U+3000) used by the Japanese. + List get seedSplit => seed.split(RegExp(r'\s+')); + + int get columnCount => seedSplit.length <= 16 ? 2 : 3; + double get columnAspectRatio => seedSplit.length <= 16 ? 1.8 : 2.8; + + /// The indices of the seed to be verified. + ObservableList verificationIndices; + + /// The index of the word in verificationIndices being verified. + @observable + int currentStepIndex = 0; + + /// The options to be displayed on the page for the current seed step. + /// + /// The user has to choose from these. + ObservableList currentOptions; + + /// The number of words to be verified, linked to a Feature Flag so we can easily modify it. + int get verificationWordCount => FeatureFlag.verificationWordsCount; + + /// Then number of wrong entries the user has selected; + /// + /// Routes the view to the seed screen if it's up to two. + @observable + int wrongEntries = 0; + + int get currentWordIndex => verificationIndices[currentStepIndex]; + + String get currentCorrectWord => seedSplit[currentWordIndex]; + + @observable + bool isVerificationComplete = false; + + void setupSeedVerification() { + generateRandomIndices(); + generateOptions(); + } + + /// Generate the indices of the seeds to be verified. + /// + /// Structured to be as random as possible. + @action + void generateRandomIndices() { + verificationIndices.clear(); + final random = Random(); + final indices = []; + while (indices.length < verificationWordCount) { + final i = random.nextInt(seedSplit.length); + if (!indices.contains(i)) { + indices.add(i); + } + } + + verificationIndices.addAll(indices); + } + + /// Generates the options for each index being verified. + @action + void generateOptions() { + currentOptions.clear(); + + final correctWord = currentCorrectWord; + final incorrectWords = seedSplit.where((word) => word != correctWord).toList(); + incorrectWords.shuffle(); + + final options = [correctWord, ...incorrectWords.take(5)]; + options.shuffle(); + + currentOptions.addAll(options); + } + + bool isChosenWordCorrect(String chosenWord) { + if (chosenWord == currentCorrectWord) { + wrongEntries = 0; + + if (currentStepIndex + 1 < verificationWordCount) { + currentStepIndex++; + generateOptions(); + } else { + // All verification steps completed + isVerificationComplete = true; + } + + return true; + } else { + wrongEntries++; + return false; + } + } } diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 001d75696..4445e5976 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -12,21 +12,21 @@ PODS: - FlutterMacOS - flutter_inappwebview_macos (0.0.1): - FlutterMacOS - - OrderedSet (~> 5.0) + - OrderedSet (~> 6.0.3) - flutter_local_authentication (1.2.0): - FlutterMacOS - flutter_secure_storage_macos (6.1.1): - FlutterMacOS - FlutterMacOS (1.0.0) - - in_app_review (0.2.0): + - in_app_review (2.0.0): - FlutterMacOS - - OrderedSet (5.0.0) + - OrderedSet (6.0.3) - package_info_plus (0.0.1): - FlutterMacOS - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS - - ReachabilitySwift (5.0.0) + - ReachabilitySwift (5.2.4) - share_plus (0.0.1): - FlutterMacOS - shared_preferences_foundation (0.0.1): @@ -34,6 +34,9 @@ PODS: - FlutterMacOS - sp_scanner (0.0.1): - FlutterMacOS + - universal_ble (0.0.1): + - Flutter + - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS - wakelock_plus (0.0.1): @@ -55,6 +58,7 @@ DEPENDENCIES: - share_plus (from `Flutter/ephemeral/.symlinks/plugins/share_plus/macos`) - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sp_scanner (from `Flutter/ephemeral/.symlinks/plugins/sp_scanner/macos`) + - universal_ble (from `Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) @@ -94,6 +98,8 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sp_scanner: :path: Flutter/ephemeral/.symlinks/plugins/sp_scanner/macos + universal_ble: + :path: Flutter/ephemeral/.symlinks/plugins/universal_ble/darwin url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos wakelock_plus: @@ -105,18 +111,19 @@ SPEC CHECKSUMS: device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f devicelocale: 9f0f36ac651cabae2c33f32dcff4f32b61c38225 fast_scanner: d31bae07e2653403a69dac99fb710c1722b16a97 - flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d + flutter_inappwebview_macos: bdf207b8f4ebd58e86ae06cd96b147de99a67c9b flutter_local_authentication: 85674893931e1c9cfa7c9e4f5973cb8c56b018b0 flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0 - OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c - package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c + in_app_review: a6a031b9acd03c7d103e341aa334adf2c493fb93 + OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 + package_info_plus: 12f1c5c2cfe8727ca46cbd0b26677728972d9a5b path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf + ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda + share_plus: 1fa619de8392a4398bfaf176d441853922614e89 shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 sp_scanner: 269d96e0ec3173e69156be7239b95182be3b8303 + universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index cd7f006e6..42212fdc0 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -2,7 +2,7 @@ import Cocoa import FlutterMacOS import IOKit.pwr_mgt -@NSApplicationMain +@main class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { return true diff --git a/model_generator.sh b/model_generator.sh index 293923d1e..730817c24 100755 --- a/model_generator.sh +++ b/model_generator.sh @@ -1,15 +1,18 @@ #!/bin/bash -cd cw_core; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_evm; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_solana; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_tron; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. -cd cw_wownero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd .. +set -x -e + +cd cw_core; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_evm; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_monero; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_bitcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_haven; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_nano; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_bitcoin_cash; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_solana; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_tron; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. +cd cw_wownero; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. cd cw_polygon; flutter pub get; cd .. cd cw_ethereum; flutter pub get; cd .. cd cw_mweb && flutter pub get && cd .. -flutter packages pub run build_runner build --delete-conflicting-outputs +dart run build_runner build --delete-conflicting-outputs + diff --git a/pubspec_base.yaml b/pubspec_base.yaml index 68ffc117c..6e79e3cc7 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -3,21 +3,21 @@ dependencies: sdk: flutter flutter_localizations: sdk: flutter - intl: ^0.18.0 - url_launcher: ^6.1.4 + intl: ^0.19.0 + url_launcher: 6.3.1 qr_flutter: git: url: https://github.com/cake-tech/qr.flutter.git ref: cake-4.0.2 version: 4.0.2 - shared_preferences: ^2.0.15 + shared_preferences: 2.3.2 # provider: ^6.0.3 rxdart: ^0.28.0 yaml: ^3.1.1 fast_scanner: git: url: https://github.com/MrCyjaneK/fast_scanner - ref: c8311b46cc67dd02250970a54d2a4526168187f3 + ref: c5a08720216a508bf1fe3d062ad19d2836545a42 http: ^1.1.0 path_provider: ^2.0.11 mobx: ^2.1.4 @@ -26,23 +26,25 @@ dependencies: share_plus: ^10.0.0 # date_range_picker: ^1.0.6 #https://api.flutter.dev/flutter/material/showDateRangePicker.html - dio: ^4.0.6 + dio: ^5.7.0 hive: ^2.2.3 hive_flutter: ^1.1.0 - local_auth_android: 1.0.21 + local_auth_android: ^1.0.46 flutter_local_authentication: git: url: https://github.com/cake-tech/flutter_local_authentication package_info_plus: ^8.0.1 - devicelocale: - git: - url: https://github.com/cake-tech/flutter-devicelocale + devicelocale: 0.8.1 auto_size_text: ^3.0.0 dotted_border: ^2.0.0+2 smooth_page_indicator: ^1.0.0+2 - flutter_inappwebview: ^6.0.0 + flutter_inappwebview: ^6.1.5 flutter_spinkit: ^5.1.0 - uni_links: ^0.5.1 + uni_links: + git: + url: https://github.com/MrCyjaneK/uni_links + ref: 8e9efa4d9beb19e4ac44009576337f1ce51c22e2 + path: uni_links lottie: ^1.3.0 animate_do: ^2.1.0 cupertino_icons: ^1.0.5 @@ -63,14 +65,17 @@ dependencies: ref: master permission_handler: ^10.0.0 device_display_brightness: - git: - url: https://github.com/cake-tech/device_display_brightness.git - ref: master - workmanager: ^0.5.1 + git: + url: https://github.com/MrCyjaneK/device_display_brightness.git + ref: 4cac18c446ce686f3d75b1565badbd7da439bbd9 + workmanager: ^0.5.2 flutter_background_service: ^5.0.9 flutter_local_notifications: ^17.2.2 wakelock_plus: ^1.2.5 - flutter_mailer: ^2.0.2 + flutter_mailer: + git: + url: https://github.com/taljacobson/flutter_mailer + ref: 2a7d04d61f56e1ca166ab42e91e0daf1bfddfaf2 device_info_plus: ^9.1.0 base32: 2.1.3 in_app_review: ^2.0.6 @@ -79,19 +84,22 @@ dependencies: url: https://github.com/cake-tech/cake_backup.git ref: main version: 1.0.0 - flutter_plugin_android_lifecycle: 2.0.9 + flutter_plugin_android_lifecycle: 2.0.23 path_provider_android: ^2.2.1 - shared_preferences_android: 2.0.17 - url_launcher_android: 6.0.24 + shared_preferences_android: 2.3.3 + url_launcher_android: 6.3.14 url_launcher_linux: 3.1.1 # https://github.com/flutter/flutter/issues/153083 - sensitive_clipboard: ^1.0.0 + sensitive_clipboard: + git: + url: https://github.com/MrCyjaneK/sensitive_clipboard + ref: 288c7ee2d63b459bc735f7dc89321b29a1f12fae walletconnect_flutter_v2: ^2.1.4 eth_sig_util: ^0.0.9 ens_dart: git: url: https://github.com/cake-tech/ens_dart.git ref: main - fluttertoast: 8.1.4 + fluttertoast: 8.2.8 # tor: # git: # url: https://github.com/cake-tech/tor.git diff --git a/pubspec_description.yaml b/pubspec_description.yaml index b51fe96d6..928bc4f1f 100644 --- a/pubspec_description.yaml +++ b/pubspec_description.yaml @@ -4,4 +4,4 @@ version: 0.0.0 publish_to: none environment: - sdk: ">=3.1.0 <4.0.0" \ No newline at end of file + sdk: ^3.5.0 \ No newline at end of file diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index 71973459f..51a116d6e 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -38,6 +38,7 @@ "agree_to": "من خلال إنشاء حساب فإنك توافق على", "alert_notice": "يلاحظ", "all": "الكل", + "all_coins": "كل العملات المعدنية", "all_trades": "جميع عمليات التداول", "all_transactions": "كل التحركات المالية", "alphabetical": "مرتب حسب الحروف الأبجدية", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "شراء بطاقات مسبقة الدفع وبطاقات الهدايا في جميع أنحاء العالم", "cake_pay_web_cards_subtitle": "اشتري بطاقات مدفوعة مسبقا وبطاقات هدايا في جميع أنحاء العالم", "cake_pay_web_cards_title": "بطاقات Cake Pay Web", + "cake_seeds_save_disclaimer": "يرجى حفظ هذه الكلمات في مكان آمن! ستحتاج إلى هذه الكلمات لاستعادة محفظتك على جهاز جديد.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "أؤكد أنني لا أستخدم وكيلًا أو VPN", + "cakepay_confirm_purchase": "تأكيد الشراء", + "cakepay_confirm_terms_agreed": "أوافق على الشروط والأحكام المقدمة هنا:", + "cakepay_confirm_voided_refund": "أفهم أن محاولات الفداء من بلد محظور سوف تبطل أي استرداد", + "cakepay_ios_not_available": "آسف ، بطاقة الهدايا هذه غير متوفرة على iOS. يمكنك شرائه على Android أو من خلال موقعنا بدلاً من ذلك.", "cakepay_prepaid_card": "بطاقة ائتمان CakePay مسبقة الدفع", "camera_consent": ".ﻞﻴﺻﺎﻔﺘﻟﺍ ﻰﻠﻋ ﻝﻮﺼﺤﻠﻟ ﻢﻬﺑ ﺔﺻﺎﺨﻟﺍ ﺔﻴﺻﻮﺼﺨﻟﺍ ﺔﺳﺎﻴﺳ ﻦﻣ ﻖﻘﺤﺘﻟﺍ ﻰﺟﺮﻳ .${provider} ﻝﻮﻠ", "camera_permission_is_required": ".ﺍﺮﻴﻣﺎﻜﻟﺍ ﻥﺫﺇ ﺏﻮﻠﻄﻣ", @@ -175,6 +182,7 @@ "copy_address": "نسخ العنوان", "copy_id": "نسخ معرف العملية", "copyWalletConnectLink": "ﺎﻨﻫ ﻪﻘﺼﻟﺍﻭ dApp ﻦﻣ WalletConnect ﻂﺑﺍﺭ ﺦﺴﻧﺍ", + "corrupted_seed_notice": "تالف ملفات هذه المحفظة ولا يمكن فتحها. يرجى الاطلاع على عبارة البذور وحفظها واستعادة المحفظة.\n\nإذا كانت القيمة فارغة ، لم تتمكن البذور من استردادها بشكل صحيح.", "countries": "بلدان", "create_account": "إنشاء حساب", "create_backup": "انشئ نسخة احتياطية", @@ -256,7 +264,7 @@ "enterTokenID": "ﺰﻴﻤﻤﻟﺍ ﺰﻣﺮﻟﺍ ﻑﺮﻌﻣ ﻞﺧﺩﺃ", "enterWalletConnectURI": "WalletConnect ـﻟ URI ﻞﺧﺩﺃ", "error": "خطأ", - "error_dialog_content": "عفوًا ، لقد حصلنا على بعض الخطأ.\n\nيرجى إرسال تقرير التعطل إلى فريق الدعم لدينا لتحسين التطبيق.", + "error_dialog_content": "عفوًا ، حصلنا على بعض الخطأ.\n\nيرجى إرسال تقرير الخطأ إلى فريق الدعم الخاص بنا لجعل التطبيق أفضل.", "error_text_account_name": "يجب أن يحتوي اسم الحساب على أحرف وأرقام فقط\nويجب أن يتراوح بين حرف واحد و 15 حرفًا", "error_text_address": "يجب أن يتوافق عنوان المحفظة مع نوع\nالعملة المشفرة", "error_text_amount": "يجب أن يحتوي المبلغ على أرقام فقط", @@ -323,6 +331,7 @@ "frequently_asked_questions": "الأسئلة الشائعة", "frozen": "مجمدة", "full_balance": "الرصيد الكامل", + "gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.", "generate_name": "توليد الاسم", "generating_gift_card": "يتم توليد بطاقة هدية", "get_a": "احصل على", @@ -350,13 +359,17 @@ "how_to_use": " ﻞﻤﻌﺘﺴﺗ ﻒﻴﻛ", "how_to_use_card": "كيفية استخدام هذه البطاقة", "id": "رقم المعرف:", + "if_you_dont_see_your_device": "إذا كنت لا ترى جهازك أعلاه ، فيرجى التأكد من أن دفتر الأستاذ الخاص بك مستيقظًا ومؤمنًا!", "ignor": "تجاهل", "import": "ﺩﺭﻮﺘﺴﻳ", "importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ", "in_store": "في المتجر", "incoming": "الواردة", "incorrect_seed": "النص الذي تم إدخاله غير صالح.", + "incorrect_seed_option": "غير صحيح. من فضلك حاول مرة أخرى", + "incorrect_seed_option_back": "غير صحيح. يرجى التأكد من حفظ البذور بشكل صحيح وحاول مرة أخرى.", "inputs": "المدخلات", + "insufficient_funds_for_tx": "أموال غير كافية لتنفيذ المعاملة بنجاح.", "insufficient_lamport_for_tx": "ليس لديك ما يكفي من SOL لتغطية المعاملة ورسوم المعاملات الخاصة بها. يرجى إضافة المزيد من SOL إلى محفظتك أو تقليل كمية SOL التي ترسلها.", "insufficient_lamports": "ليس لديك ما يكفي من SOL لتغطية المعاملة ورسوم المعاملات الخاصة بها. تحتاج على الأقل ${solValueNeeded} sol. يرجى إضافة المزيد من sol إلى محفظتك أو تقليل مبلغ sol الذي ترسله", "insufficientFundsForRentError": "ليس لديك ما يكفي من SOL لتغطية رسوم المعاملة والإيجار للحساب. يرجى إضافة المزيد من sol إلى محفظتك أو تقليل مبلغ sol الذي ترسله", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "اختر ممثلًا جديدًا", "nanogpt_subtitle": "جميع النماذج الأحدث (GPT-4 ، Claude). \\ nno اشتراك ، ادفع مع Crypto.", "narrow": "ضيق", - "new_first_wallet_text": "حافظ بسهولة على أمان العملة المشفرة", + "new_first_wallet_text": "الحفاظ على سلامة التشفير الخاص بك هو قطعة من الكعكة", "new_node_testing": "تجربة العقدة الجديدة", "new_subaddress_create": "إنشاء", "new_subaddress_label_name": "تسمية", @@ -464,6 +477,7 @@ "online": "متصل", "onramper_option_description": "شراء بسرعة التشفير مع العديد من طرق الدفع. متوفر في معظم البلدان. ينتشر وتختلف الرسوم.", "open_gift_card": "افتح بطاقة الهدية", + "open_wallet": "فتح محفظة", "optional_description": "وصف اختياري", "optional_email_hint": "البريد الإلكتروني إخطار المدفوع لأمره الاختياري", "optional_name": "اسم المستلم الاختياري", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "إذا كانت هذه المحفظة تحتوي على سييد مكونة من 12 كلمة وتم إنشاؤها في Cake ، فلا تقم بإيداع Bitcoin في هذه المحفظة. قد يتم فقد أي BTC تم تحويله إلى هذه المحفظة. قم بإنشاء محفظة جديدة مكونة من 24 كلمة (انقر فوق القائمة في الجزء العلوي الأيمن ، وحدد محافظ ، واختر إنشاء محفظة جديدة ، ثم حدد Bitcoin) وقم على الفور بنقل BTC الخاص بك هناك. محافظ BTC الجديدة (24 كلمة) من Cake آمنة", "outgoing": "الصادره", "outputs": "المخرجات", + "overshot": "طغمة", "overwrite_amount": "تغير المبلغ", "pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ", "passphrase": "عبارة الممر (اختياري)", @@ -531,6 +546,7 @@ "recipient_address": "عنوان المستلم", "reconnect": "أعد الاتصال", "reconnect_alert_text": "هل أنت متأكد من رغبتك في إعادة الاتصال؟", + "reconnect_your_hardware_wallet": "أعد توصيل محفظة الأجهزة الخاصة بك", "reconnection": "إعادة الاتصال", "red_dark_theme": "موضوع الظلام الأحمر", "red_light_theme": "موضوع الضوء الأحمر", @@ -570,6 +586,7 @@ "restore_description_from_keys": "قم باستعادة محفظتك من ضغطات المفاتيح المولدة المحفوظة من مفاتيحك الخاصة", "restore_description_from_seed": "قم باستعادة محفظتك من الرمز المكون من 25 كلمة أو 13 كلمة", "restore_description_from_seed_keys": "استرجع محفظتك من السييد / المفاتيح التي قمت بحفظها في مكان آمن", + "restore_existing_wallet": "استعادة محفظة موجودة", "restore_from_date_or_blockheight": "الرجاء إدخال تاريخ قبل إنشاء هذه المحفظة ببضعة أيام. أو إذا كنت تعرف ارتفاع البلوك، فيرجى إدخاله بدلاً من ذلك", "restore_from_seed_placeholder": "الرجاء إدخال أو لصق السييد الخاصة بك هنا", "restore_new_seed": "سييد جديدة", @@ -611,6 +628,7 @@ "seed_alert_title": "انتباه", "seed_alert_yes": "نعم، فعلت ذلك", "seed_choose": "اختر لغة السييد", + "seed_display_path": "القائمة -> الأمان والنسخ الاحتياطي -> إظهار المفتاح/البذور", "seed_hex_form": "بذور المحفظة (شكل عرافة)", "seed_key": "مفتاح البذور", "seed_language": "لغة البذور", @@ -629,9 +647,13 @@ "seed_language_russian": "الروسية", "seed_language_spanish": "الأسبانية", "seed_phrase_length": "ﺭﻭﺬﺒﻟﺍ ﺓﺭﺎﺒﻌﻟﺍ ﻝﻮﻃ", + "seed_position_question_one": "ما هو", + "seed_position_question_two": "كلمة عبارة البذور؟", "seed_reminder": "يرجى تدوينها في حالة فقد هاتفك أو مسحه", "seed_share": "شارك السييد", "seed_title": "سييد", + "seed_verified": "تم التحقق من البذور", + "seed_verified_subtext": "يمكنك استخدام البذور المحفوظة لاحقًا لاستعادة هذه المحفظة في حالة الفساد أو فقدان جهازك. \n\n يمكنك عرض هذه البذرة مرة أخرى من", "seedtype": "البذور", "seedtype_alert_content": "مشاركة البذور مع محافظ أخرى ممكن فقط مع BIP39 Seedtype.", "seedtype_alert_title": "تنبيه البذور", @@ -670,6 +692,7 @@ "sent": "تم الأرسال", "service_health_disabled": "تم تعطيل نشرة صحة الخدمة", "service_health_disabled_message": "هذه هي صفحة نشرة صحة الخدمة ، يمكنك تمكين هذه الصفحة ضمن الإعدادات -> الخصوصية", + "set_a_pin": "تعيين دبوس", "settings": "إعدادات", "settings_all": "الكل", "settings_allow_biometrical_authentication": "السماح بالمصادقة البيومترية", @@ -705,6 +728,7 @@ "share_address": "شارك العنوان", "shared_seed_wallet_groups": "مجموعات محفظة البذور المشتركة", "show": "يعرض", + "show_address_book_popup": "عرض \"إضافة إلى كتاب العناوين\" المنبثقة بعد الإرسال", "show_details": "اظهر التفاصيل", "show_keys": "اظهار السييد / المفاتيح", "show_market_place": "إظهار السوق", @@ -732,6 +756,10 @@ "silent_payments_settings": "إعدادات المدفوعات الصامتة", "single_seed_wallets_group": "محافظ بذرة واحدة", "slidable": "قابل للانزلاق", + "solana_create_associated_token_account_exception": "خطأ في إنشاء حساب رمز المرتبط بعنوان المستلم.", + "solana_no_associated_token_account_exception": "لا يوجد حساب مميز مرتبط بهذا العنوان.", + "solana_sign_native_transaction_rent_exception": "لا يمكن إكمال المعاملة. غادر SOL غير كاف للإيجار بعد المعاملة. يرجى أن تصل إلى رصيد SOL أو تقليل كمية SOL التي ترسلها.", + "solana_sign_spl_token_transaction_rent_exception": "لا يمكن إكمال المعاملة. غادر SOL غير كاف للإيجار بعد المعاملة. يرجى أن تصل إلى توازن سولك.", "sort_by": "ترتيب حسب", "spend_key_private": "مفتاح الإنفاق (خاص)", "spend_key_public": "مفتاح الإنفاق (عام)", @@ -744,7 +772,7 @@ "support_description_guides": "توثيق ودعم القضايا المشتركة", "support_description_live_chat": "حرة وسريعة! ممثلو الدعم المدربين متاحون للمساعدة", "support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى", - "support_title_guides": "أدلة محفظة كعكة", + "support_title_guides": "مستندات محفظة كعكة", "support_title_live_chat": "الدعم المباشر", "support_title_other_links": "روابط دعم أخرى", "sweeping_wallet": "كنس المحفظة", @@ -823,6 +851,7 @@ "trade_state_underpaid": "أجر أقل من اللازم", "trade_state_unpaid": "غير مدفوعة", "trades": "عمليات التداول", + "transaction_cost": "تكلفة المعاملة", "transaction_details_amount": "مقدار", "transaction_details_copied": "تم نسخ ${title} إلى الحافظة", "transaction_details_date": "تاريخ", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "هذا الزوج المتغير غير مدعوم في التبادلات المحددة", "verification": "تَحَقّق", "verify_message": "تحقق من الرسالة", + "verify_seed": "تحقق من البذور", "verify_with_2fa": "تحقق مع Cake 2FA", "version": "الإصدار ${currentVersion}", "view_all": "مشاهدة الكل", @@ -891,6 +921,7 @@ "view_transaction_on": "عرض العملية على", "voting_weight": "وزن التصويت", "waitFewSecondForTxUpdate": "ﺕﻼﻣﺎﻌﻤﻟﺍ ﻞﺠﺳ ﻲﻓ ﺔﻠﻣﺎﻌﻤﻟﺍ ﺲﻜﻌﻨﺗ ﻰﺘﺣ ﻥﺍﻮﺛ ﻊﻀﺒﻟ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ", + "wallet": "محفظة", "wallet_group": "مجموعة محفظة", "wallet_group_description_four": "لإنشاء محفظة مع بذرة جديدة تماما.", "wallet_group_description_one": "في محفظة الكيك ، يمكنك إنشاء ملف", @@ -923,6 +954,8 @@ "wallets": "المحافظ", "warning": "تحذير", "welcome": "مرحبا بك في", + "welcome_subtitle_new_wallet": "إذا كنت ترغب في البدء من جديد ، فانقر فوق إنشاء محفظة جديدة أدناه وستكون خارج السباقات.", + "welcome_subtitle_restore_wallet": "إذا كان لديك محفظة موجودة تريد إحضارها إلى كعكة ، فما عليك سوى اختيار استعادة المحفظة الموجودة وسنمشيك خلال العملية.", "welcome_to_cakepay": "مرحبا بكم في Cake Pay!", "what_is_silent_payments": "ما هي المدفوعات الصامتة؟", "widgets_address": "عنوان", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 3dc352637..92688b349 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -38,6 +38,7 @@ "agree_to": "Чрез създаването на акаунт вие се съгласявате с ", "alert_notice": "Забележете", "all": "ALL", + "all_coins": "Всички монети", "all_trades": "Всички сделкки", "all_transactions": "Всички транзакции", "alphabetical": "Азбучен ред", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Купете предплатени карти и карти за подаръци в световен мащаб", "cake_pay_web_cards_subtitle": "Купете световно признати предплатени и гифт карти", "cake_pay_web_cards_title": "Cake Pay Онлайн Карти", + "cake_seeds_save_disclaimer": "Моля, запазете тези думи на сигурно място! Ще ви трябват тези думи, за да възстановите портфейла си на ново устройство.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Потвърждавам, че не използвам прокси или VPN", + "cakepay_confirm_purchase": "Потвърдете покупката", + "cakepay_confirm_terms_agreed": "Съгласен съм с условията, представени тук:", + "cakepay_confirm_voided_refund": "Разбирам, че опитите за обратно изкупуване от ограничена държава ще анулират всяко възстановяване", + "cakepay_ios_not_available": "За съжаление тази карта за подарък не се предлага в iOS. Можете да го закупите на Android или чрез нашия уебсайт вместо това.", "cakepay_prepaid_card": "CakePay предплатена дебитна карта", "camera_consent": "Вашият фотоапарат ще бъде използван за заснемане на изображение с цел идентификация от ${provider}. Моля, проверете тяхната политика за поверителност за подробности.", "camera_permission_is_required": "Изисква се разрешение за камерата.\nМоля, активирайте го от настройките на приложението.", @@ -175,6 +182,7 @@ "copy_address": "Copy Address", "copy_id": "Копиране на ID", "copyWalletConnectLink": "Копирайте връзката WalletConnect от dApp и я поставете тук", + "corrupted_seed_notice": "Файловете за този портфейл са повредени и не могат да бъдат отворени. Моля, прегледайте фразата за семена, запазете я и възстановете портфейла.\n\nАко стойността е празна, тогава семето не успя да бъде правилно възстановено.", "countries": "Държави", "create_account": "Създаване на профил", "create_backup": "Създаване на резервно копие", @@ -256,7 +264,7 @@ "enterTokenID": "Въведете идентификатора на токена", "enterWalletConnectURI": "Въведете URI на WalletConnect", "error": "Грешка", - "error_dialog_content": "Получихме грешка.\n\nМоля, изпратете доклада до нашия отдел поддръжка, за да подобрим приложението.", + "error_dialog_content": "Ами сега, получихме някаква грешка.\n\nМоля, изпратете отчета за грешки до нашия екип за поддръжка, за да подобрите приложението.", "error_text_account_name": "Името на профила може да съдържа само букви и числа \nи трябва да е между 1 и 15 символа", "error_text_address": "Адресът на портфейла трябва да отговаря \n на вида криптовалута", "error_text_amount": "Сумата може да съдържа само числа", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Често задавани въпроси", "frozen": "Замразени", "full_balance": "Пълен баланс", + "gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.", "generate_name": "Генериране на име", "generating_gift_card": "Създаване на Gift Card", "get_a": "Вземете ", @@ -350,13 +359,17 @@ "how_to_use": "Как да използвам", "how_to_use_card": "Как се ползва тази карта", "id": "ID: ", + "if_you_dont_see_your_device": "Ако не виждате устройството си по -горе, моля, уверете се, че вашата книга е будна и отключена!", "ignor": "Игнориране", "import": "Импортиране", "importNFTs": "Импортирайте NFT", "in_store": "In Store", "incoming": "Входящи", "incorrect_seed": "Въведеният текст е невалиден.", + "incorrect_seed_option": "Неправилно. Моля, опитайте отново", + "incorrect_seed_option_back": "Неправилно. Моля, уверете се, че семето ви е запазено правилно и опитайте отново.", "inputs": "Входове", + "insufficient_funds_for_tx": "Недостатъчни средства за успешно извършване на транзакция.", "insufficient_lamport_for_tx": "Нямате достатъчно SOL, за да покриете транзакцията и таксата му за транзакция. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате.", "insufficient_lamports": "Нямате достатъчно SOL, за да покриете транзакцията и таксата му за транзакция. Имате нужда от поне ${solValueNeeded} sol. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате", "insufficientFundsForRentError": "Нямате достатъчно SOL, за да покриете таксата за транзакцията и наемането на сметката. Моля, добавете повече SOL към портфейла си или намалете сумата на SOL, която изпращате", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Изберете нов представител", "nanogpt_subtitle": "Всички най-нови модели (GPT-4, Claude). \\ Nno абонамент, платете с Crypto.", "narrow": "Тесен", - "new_first_wallet_text": "Лесно пазете криптовалутата си в безопасност", + "new_first_wallet_text": "Запазването на криптовалутата ви е парче торта", "new_node_testing": "Тестване на нов node", "new_subaddress_create": "Създаване", "new_subaddress_label_name": "Име на Label", @@ -464,6 +477,7 @@ "online": "Онлайн", "onramper_option_description": "Бързо купувайте криптовалута с много методи за плащане. Предлага се в повечето страни. Разпространенията и таксите варират.", "open_gift_card": "Отвори Gift Card", + "open_wallet": "Отворен портфейл", "optional_description": "Описание по избор", "optional_email_hint": "Незадължителен имейл за уведомяване на получателя", "optional_name": "Незадължително име на получател", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Ако този адрес има seed от 12 думи и е създаден чрез Cake, НЕ добавяйте Bitcoin в него. Всякакъв Bitcoin, изпратен на този адрес, може да бъде загубен завинаги. Създайте нов портфейл от 24 думи (натиснете менюто горе, вдясно, изберете Портфейли, изберете Създаване на нов портфейл, след това изберете Bitcoin) и НЕЗАБАВНО преместете своя Bitcoin там. Нови (такива с 24 думи) Bitcoin портфейли от Cake са надеждни", "outgoing": "Изходящи", "outputs": "Изходи", + "overshot": "Превишаване", "overwrite_amount": "Промени сума", "pairingInvalidEvent": "Невалидно събитие при сдвояване", "passphrase": "Passphrase (по избор)", @@ -531,6 +546,7 @@ "recipient_address": "Адрес на получател", "reconnect": "Reconnect", "reconnect_alert_text": "Сигурни ли сте, че искате да се свържете отново?", + "reconnect_your_hardware_wallet": "Свържете отново хардуерния си портфейл", "reconnection": "Свързване отново", "red_dark_theme": "Червена тъмна тема", "red_light_theme": "Тема на червената светлина", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Възстановяване на портфейл от генерираните от Вашите тайни ключове клавиши", "restore_description_from_seed": "Възстановяване на портфейл от кода от 13 или 25 думи", "restore_description_from_seed_keys": "Възстановете своя портфейл от seed/keys, които сте съхранили на сигурно място", + "restore_existing_wallet": "Възстановете съществуващия портфейл", "restore_from_date_or_blockheight": "Моля, въведете дата няколко дни преди създаването на този портфейл. Ако знаете blockheight-а, въведето него вместо това", "restore_from_seed_placeholder": "Моля, въведете своя seed тук", "restore_new_seed": "Нов seed", @@ -611,6 +628,7 @@ "seed_alert_title": "Внимание", "seed_alert_yes": "Да", "seed_choose": "Изберете език на seed-а", + "seed_display_path": "Меню -> Сигурност и архивиране -> Показване на ключ/семена", "seed_hex_form": "Семена от портфейл (шестнадесетична форма)", "seed_key": "Ключ за семена", "seed_language": "Език на семената", @@ -629,9 +647,13 @@ "seed_language_russian": "Руски", "seed_language_spanish": "Испански", "seed_phrase_length": "Дължина на началната фраза", + "seed_position_question_one": "Какво е", + "seed_position_question_two": "Дума на вашата фраза за семена?", "seed_reminder": "Моля, запишете го в случай на загуба на устройството.", "seed_share": "Споделяне на seed", "seed_title": "Seed", + "seed_verified": "Семена проверено", + "seed_verified_subtext": "Можете да използвате запазените си семена по -късно, за да възстановите този портфейл в случай на корупция или загуба на устройството си. \n\n Можете да видите това семе отново от", "seedtype": "Семенна тип", "seedtype_alert_content": "Споделянето на семена с други портфейли е възможно само с BIP39 Seedtype.", "seedtype_alert_title": "Сигнал за семена", @@ -670,6 +692,7 @@ "sent": "Изпратени", "service_health_disabled": "Service Health Bulletin е деактивиран", "service_health_disabled_message": "Това е страницата на Bulletin на Service Health, можете да активирате тази страница в Настройки -> Поверителност", + "set_a_pin": "Поставете щифт", "settings": "Настройки", "settings_all": "Всичко", "settings_allow_biometrical_authentication": "Позволяване на биометрично удостоверяване.", @@ -705,6 +728,7 @@ "share_address": "Сподели адрес", "shared_seed_wallet_groups": "Споделени групи за портфейли за семена", "show": "Показване", + "show_address_book_popup": "Показване на изскачането на „Добавяне към адресната книга“ след изпращане", "show_details": "Показване на подробностите", "show_keys": "Покажи seed/keys", "show_market_place": "Покажи пазар", @@ -732,6 +756,10 @@ "silent_payments_settings": "Настройки за безшумни плащания", "single_seed_wallets_group": "Портфейли с единични семена", "slidable": "Плъзгащ се", + "solana_create_associated_token_account_exception": "Грешка Създаване на свързана сметка за жетони за адреса на получател.", + "solana_no_associated_token_account_exception": "Няма свързана сметка за този адрес.", + "solana_sign_native_transaction_rent_exception": "Транзакцията не може да бъде завършена. Недостатъчен сол оставен под наем след транзакция. Любезно допълнете баланса си на SOL или намалете количеството SOL, което изпращате.", + "solana_sign_spl_token_transaction_rent_exception": "Транзакцията не може да бъде завършена. Недостатъчен сол оставен под наем след транзакция. Любезно допълнете баланса си на SOL.", "sort_by": "Сортирай по", "spend_key_private": "Spend key (таен)", "spend_key_public": "Spend key (публичен)", @@ -744,7 +772,7 @@ "support_description_guides": "Документация и подкрепа за общи проблеми", "support_description_live_chat": "Безплатно и бързо! Обучени представители на подкрепата са на разположение за подпомагане", "support_description_other_links": "Присъединете се към нашите общности или се свържете с нас нашите партньори чрез други методи", - "support_title_guides": "Ръководства за портфейл за торта", + "support_title_guides": "Документи за портфейл за торта", "support_title_live_chat": "Подкрепа на живо", "support_title_other_links": "Други връзки за поддръжка", "sweeping_wallet": "Метещ портфейл", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Недостатъчно плащане", "trade_state_unpaid": "Неплатено", "trades": "Trades", + "transaction_cost": "Транзакционни разходи", "transaction_details_amount": "Сума", "transaction_details_copied": "${title} копирано", "transaction_details_date": "Дата", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса", "verification": "Потвърждаване", "verify_message": "Проверете съобщението", + "verify_seed": "Проверете семената", "verify_with_2fa": "Проверете с Cake 2FA", "version": "Версия ${currentVersion}", "view_all": "Виж всички", @@ -891,6 +921,7 @@ "view_transaction_on": "Вижте транзакция на ", "voting_weight": "Тегло на гласуване", "waitFewSecondForTxUpdate": "Моля, изчакайте няколко секунди, докато транзакцията се отрази в историята на транзакциите", + "wallet": "Портфейл", "wallet_group": "Група на портфейла", "wallet_group_description_four": "За да създадете портфейл с изцяло ново семе.", "wallet_group_description_one": "В портфейла за торта можете да създадете a", @@ -923,6 +954,8 @@ "wallets": "Портфейли", "warning": "Внимание", "welcome": "Добре дошли в", + "welcome_subtitle_new_wallet": "Ако искате да стартирате свеж, докоснете Създайте нов портфейл по -долу и ще се откажете от състезанията.", + "welcome_subtitle_restore_wallet": "Ако имате съществуващ портфейл, който искате да внесете в тортата, просто изберете възстановяване на съществуващия портфейл и ще ви преведем през процеса.", "welcome_to_cakepay": "Добре дошли в Cake Pay!", "what_is_silent_payments": "Какво са мълчаливи плащания?", "widgets_address": "Адрес", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 71e4c55f2..b5f1cbd11 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -38,6 +38,7 @@ "agree_to": "Vytvořením účtu souhlasíte s ", "alert_notice": "Oznámení", "all": "VŠE", + "all_coins": "Všechny mince", "all_trades": "Všechny obchody", "all_transactions": "Všechny transakce", "alphabetical": "Abecední", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Kupte si celosvětové předplacené karty a dárkové karty", "cake_pay_web_cards_subtitle": "Kupte si celosvětové předplacené a dárkové karty", "cake_pay_web_cards_title": "Cake Pay webové karty", + "cake_seeds_save_disclaimer": "Uložte tato slova na bezpečném místě! Tato slova budete potřebovat k obnovení peněženky na novém zařízení.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Potvrzuji, že nepoužívám proxy nebo VPN", + "cakepay_confirm_purchase": "Potvrďte nákup", + "cakepay_confirm_terms_agreed": "Souhlasím s zde uvedenými podmínkami:", + "cakepay_confirm_voided_refund": "Chápu, že pokusy o vykoupení z omezené země zruší jakékoli vrácení peněz", + "cakepay_ios_not_available": "Je nám líto, tato dárková karta není k dispozici na iOS. Místo toho si jej můžete zakoupit na Androidu nebo prostřednictvím našeho webu.", "cakepay_prepaid_card": "CakePay předplacená debetní karta", "camera_consent": "Váš fotoaparát použije k pořízení snímku pro účely identifikace ${provider}. Podrobnosti najdete v jejich Zásadách ochrany osobních údajů.", "camera_permission_is_required": "Vyžaduje se povolení fotoaparátu.\nPovolte jej v nastavení aplikace.", @@ -175,6 +182,7 @@ "copy_address": "Zkopírovat adresu", "copy_id": "Kopírovat ID", "copyWalletConnectLink": "Zkopírujte odkaz WalletConnect z dApp a vložte jej sem", + "corrupted_seed_notice": "Soubory pro tuto peněženku jsou poškozeny a nemohou být otevřeny. Podívejte se prosím na osivo, uložte ji a obnovte peněženku.\n\nPokud je hodnota prázdná, pak semeno nebylo možné správně obnovit.", "countries": "Země", "create_account": "Vytvořit účet", "create_backup": "Vytvořit zálohu", @@ -256,7 +264,7 @@ "enterTokenID": "Zadejte ID tokenu", "enterWalletConnectURI": "Zadejte identifikátor URI WalletConnect", "error": "Chyba", - "error_dialog_content": "Nastala chyba.\n\nProsím odešlete zprávu o chybě naší podpoře, aby mohli zajistit opravu.", + "error_dialog_content": "Jejda, dostali jsme nějakou chybu.\n\nZašlete prosím chybovou zprávu našemu týmu podpory, abyste aplikaci vylepšili.", "error_text_account_name": "Název účtu může obsahovat jen písmena a čísla\na musí mít délku 1 až 15 znaků", "error_text_address": "Adresa peněženky musí odpovídat typu\nkryptoměny", "error_text_amount": "Částka může obsahovat pouze čísla", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Často kladené otázky", "frozen": "Zmraženo", "full_balance": "Celkový zůstatek", + "gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.", "generate_name": "Generovat jméno", "generating_gift_card": "Generuji dárkovou kartu", "get_a": "Získejte ", @@ -350,13 +359,17 @@ "how_to_use": "Jak používat", "how_to_use_card": "Jak použít tuto kartu", "id": "ID: ", + "if_you_dont_see_your_device": "Pokud vaše zařízení nevidíte výše, ujistěte se, že vaše kniha je vzhůru a odemknutá!", "ignor": "Ignorovat", "import": "Import", "importNFTs": "Importujte NFT", "in_store": "V obchodě", "incoming": "Příchozí", "incorrect_seed": "Zadaný text není správný.", + "incorrect_seed_option": "Nesprávný. Zkuste to prosím znovu", + "incorrect_seed_option_back": "Nesprávný. Ujistěte se, že vaše semeno je správně uloženo a zkuste to znovu.", "inputs": "Vstupy", + "insufficient_funds_for_tx": "Nedostatečné prostředky na úspěšné provedení transakce.", "insufficient_lamport_for_tx": "Nemáte dostatek SOL na pokrytí transakce a jejího transakčního poplatku. Laskavě přidejte do své peněženky více solu nebo snižte množství Sol, kterou odesíláte.", "insufficient_lamports": "Nemáte dostatek SOL na pokrytí transakce a jejího transakčního poplatku. Potřebujete alespoň ${solValueNeeded} sol. Laskavě přidejte do své peněženky více SOL nebo snižte množství Sol, kterou odesíláte", "insufficientFundsForRentError": "Nemáte dostatek SOL na pokrytí transakčního poplatku a nájemného za účet. Laskavě přidejte do své peněženky více SOL nebo snižte množství Sol, kterou odesíláte", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Vyberte nového zástupce", "nanogpt_subtitle": "Všechny nejnovější modely (GPT-4, Claude). \\ Nno předplatné, plaťte krypto.", "narrow": "Úzký", - "new_first_wallet_text": "Snadno udržujte svou kryptoměnu v bezpečí", + "new_first_wallet_text": "Udržování svého kryptového v bezpečí je kus dortu", "new_node_testing": "Testování nového uzlu", "new_subaddress_create": "Vytvořit", "new_subaddress_label_name": "Popisek", @@ -464,6 +477,7 @@ "online": "Online", "onramper_option_description": "Rychle si koupte krypto s mnoha metodami plateb. K dispozici ve většině zemí. Rozpětí a poplatky se liší.", "open_gift_card": "Otevřít dárkovou kartu", + "open_wallet": "Otevřená peněženka", "optional_description": "Volitelný popis", "optional_email_hint": "Volitelný e-mail s upozorněním na příjemce platby", "optional_name": "Volitelné jméno příjemce", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Tato peněženka má seed se 12 slovy a byla vytvořena pomocí Cake, NEUKLÁDEJTE Bitcoin na tuto peněženku. Jakékoliv BTC převedené na tuto peněženku může být ztraceno. Vytvořte si novou peněženku s 24 slovy (otevřete menu vpravo nahoře, vyberte Peněženky, zvolte Vytvořit novou peněženku a pak zvolte Bitcoin) a IHNED tam přesuňte své BTC. Nové (24-slovní) BTC peněženky z Cake jsou bezpečné", "outgoing": "Odchozí", "outputs": "Výstupy", + "overshot": "Překročení", "overwrite_amount": "Přepsat částku", "pairingInvalidEvent": "Neplatná událost párování", "passphrase": "Passphrase (volitelné)", @@ -531,6 +546,7 @@ "recipient_address": "Adresa příjemce", "reconnect": "Znovu připojit", "reconnect_alert_text": "Opravdu se chcete znovu připojit?", + "reconnect_your_hardware_wallet": "Znovu připojte svou hardwarovou peněženku", "reconnection": "Znovu připojit", "red_dark_theme": "Červené temné téma", "red_light_theme": "Téma červeného světla", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Obnovte svou peněženku pomocí generovaných stisků kláves uložených z vašich soukromých klíčů", "restore_description_from_seed": "Obnovte svou peněženku pomocí kombinace 25, nebo 13 slov", "restore_description_from_seed_keys": "Obnovte svou peněženku ze seedu/klíčů, které jste si uložili na bezpečném místě", + "restore_existing_wallet": "Obnovte stávající peněženku", "restore_from_date_or_blockheight": "Prosím zadejte datum z doby několik dnů před tím, než jste si zakládali tuto peněženku. Nebo místo toho zadejte výšku bloku, pokud ji znáte.", "restore_from_seed_placeholder": "Prosím zadejte, nebo vložte ze schránky svůj seed.", "restore_new_seed": "Nový seed", @@ -611,6 +628,7 @@ "seed_alert_title": "Pozor", "seed_alert_yes": "Ano", "seed_choose": "Zvolte si jazyk seedu", + "seed_display_path": "Nabídka -> Zabezpečení a zálohování -> Zobrazit klíč/semena", "seed_hex_form": "Semeno peněženky (hex formulář)", "seed_key": "Klíč semen", "seed_language": "Jazyk semen", @@ -629,9 +647,13 @@ "seed_language_russian": "Ruština", "seed_language_spanish": "Španělština", "seed_phrase_length": "Délka fráze semene", + "seed_position_question_one": "Co je", + "seed_position_question_two": "Slovo vaší fráze semen?", "seed_reminder": "Prosím zapište si toto pro případ ztráty, nebo poškození telefonu", "seed_share": "Sdílet seed", "seed_title": "Seed", + "seed_verified": "Ověřeno semeno", + "seed_verified_subtext": "V případě korupce nebo ztráty zařízení můžete později použít své uložené semeno později k obnovení této peněženky.", "seedtype": "SeedType", "seedtype_alert_content": "Sdílení semen s jinými peněženkami je možné pouze u BIP39 SeedType.", "seedtype_alert_title": "Upozornění seedtype", @@ -670,6 +692,7 @@ "sent": "Odesláno", "service_health_disabled": "Bulletin zdraví služeb je deaktivován", "service_health_disabled_message": "Toto je stránka Bulletin Service Health Bulletin, můžete tuto stránku povolit v rámci nastavení -> Ochrana osobních údajů", + "set_a_pin": "Nastavte špendlík", "settings": "Nastavení", "settings_all": "VŠE", "settings_allow_biometrical_authentication": "Povolit biometrické ověření", @@ -705,6 +728,7 @@ "share_address": "Sdílet adresu", "shared_seed_wallet_groups": "Skupiny sdílených semen", "show": "Show", + "show_address_book_popup": "Po odeslání zobrazíte vyskakovací okno „Přidat do adresáře“", "show_details": "Zobrazit detaily", "show_keys": "Zobrazit seed/klíče", "show_market_place": "Zobrazit trh", @@ -732,6 +756,10 @@ "silent_payments_settings": "Nastavení tichých plateb", "single_seed_wallets_group": "Jednorázové peněženky", "slidable": "Posuvné", + "solana_create_associated_token_account_exception": "Vytvoření chyby přidruženého účtu tokenů pro adresu příjmu.", + "solana_no_associated_token_account_exception": "Pro tuto adresu není přidružen žádný přidružený token.", + "solana_sign_native_transaction_rent_exception": "Transakce nelze dokončit. Po transakci nedostatek Sol odešel k pronájmu. Laskavě doplňte rovnováhu SOL nebo snižte množství SOL, které odesíláte.", + "solana_sign_spl_token_transaction_rent_exception": "Transakce nelze dokončit. Po transakci nedostatek Sol odešel k pronájmu. Laskavě doplňte rovnováhu SOL.", "sort_by": "Seřazeno podle", "spend_key_private": "Klíč pro platby (soukromý)", "spend_key_public": "Klíč pro platby (veřejný)", @@ -744,7 +772,7 @@ "support_description_guides": "Dokumentace a podpora běžných otázek", "support_description_live_chat": "Zdarma a rychle! K dispozici jsou zástupci vyškolených podpůrných podpory", "support_description_other_links": "Připojte se k našim komunitám nebo se k nám oslovte další metody", - "support_title_guides": "Průvodce peněženkami dortu", + "support_title_guides": "Dokumenty peněženky dortu", "support_title_live_chat": "Živá podpora", "support_title_other_links": "Další odkazy na podporu", "sweeping_wallet": "Zametací peněženka", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Zaplaceno méně", "trade_state_unpaid": "Nezaplaceno", "trades": "Obchody", + "transaction_cost": "Transakční náklady", "transaction_details_amount": "Částka", "transaction_details_copied": "${title} zkopírováno do schránky", "transaction_details_date": "Datum", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován", "verification": "Ověření", "verify_message": "Ověřit zprávu", + "verify_seed": "Ověřte osivo", "verify_with_2fa": "Ověřte pomocí Cake 2FA", "version": "Verze ${currentVersion}", "view_all": "Zobrazit vše", @@ -891,6 +921,7 @@ "view_transaction_on": "Zobrazit transakci na ", "voting_weight": "Hlasová váha", "waitFewSecondForTxUpdate": "Počkejte několik sekund, než se transakce projeví v historii transakcí", + "wallet": "Peněženka", "wallet_group": "Skupina peněženky", "wallet_group_description_four": "Vytvoření peněženky s zcela novým semenem.", "wallet_group_description_one": "V peněžence dortu můžete vytvořit a", @@ -923,6 +954,8 @@ "wallets": "Peněženky", "warning": "Varování", "welcome": "Vítejte v", + "welcome_subtitle_new_wallet": "Pokud chcete začít čerstvě, klepněte na Vytvořit novou peněženku níže a budete na závodech.", + "welcome_subtitle_restore_wallet": "Pokud máte existující peněženku, kterou chcete přinést do dortu, jednoduše si vyberte obnovení stávající peněženky a my vás projdeme procesem.", "welcome_to_cakepay": "Vítejte v Cake Pay!", "what_is_silent_payments": "Co jsou tiché platby?", "widgets_address": "Adresa", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 211df2e5a..59768be17 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -38,6 +38,7 @@ "agree_to": "Indem Sie ein Konto erstellen, stimmen Sie den ", "alert_notice": "Beachten", "all": "ALLES", + "all_coins": "Alle Münzen", "all_trades": "Alle Trades", "all_transactions": "Alle Transaktionen", "alphabetical": "Alphabetisch", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Kaufen Sie weltweite Prepaid-Karten und Geschenkkarten", "cake_pay_web_cards_subtitle": "Kaufen Sie weltweit Prepaid-Karten und Geschenkkarten", "cake_pay_web_cards_title": "Cake Pay-Webkarten", + "cake_seeds_save_disclaimer": "Bitte speichern Sie diese Wörter an einem sicheren Ort! Sie benötigen diese Wörter, um Ihre Brieftasche auf einem neuen Gerät wiederherzustellen.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Ich bestätige, dass ich keinen Proxy oder VPN benutze", + "cakepay_confirm_purchase": "Kauf bestätigen", + "cakepay_confirm_terms_agreed": "Ich stimme den hier vorgestellten Bedingungen zu:", + "cakepay_confirm_voided_refund": "Ich verstehe", + "cakepay_ios_not_available": "Entschuldigung, diese Geschenkkarte ist auf iOS nicht erhältlich. Sie können es stattdessen auf Android oder über unsere Website kaufen.", "cakepay_prepaid_card": "CakePay-Prepaid-Debitkarte", "camera_consent": "Mit Ihrer Kamera wird bis zum ${provider} ein Bild zur Identifizierung aufgenommen. Weitere Informationen finden Sie in deren Datenschutzbestimmungen.", "camera_permission_is_required": "Eine Kameraerlaubnis ist erforderlich.\nBitte aktivieren Sie es in den App-Einstellungen.", @@ -175,6 +182,7 @@ "copy_address": "Adresse kopieren", "copy_id": "ID kopieren", "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein", + "corrupted_seed_notice": "Die Dateien für diese Brieftasche sind beschädigt und können nicht geöffnet werden. Bitte sehen Sie sich die Saatgutphrase an, speichern Sie sie und stellen Sie die Brieftasche wieder her.\n\nWenn der Wert leer ist, konnte der Samen nicht korrekt wiederhergestellt werden.", "countries": "Länder", "create_account": "Konto erstellen", "create_backup": "Backup erstellen", @@ -256,7 +264,7 @@ "enterTokenID": "Geben Sie die Token-ID ein", "enterWalletConnectURI": "Geben Sie den WalletConnect-URI ein", "error": "Fehler", - "error_dialog_content": "Hoppla, wir haben einen Fehler.\n\nBitte senden Sie den Absturzbericht an unser Support-Team, um die Anwendung zu verbessern.", + "error_dialog_content": "Hoppla, wir haben einen Fehler.\n\nBitte senden Sie den Fehlerbericht an unser Support -Team, um die Anwendung zu verbessern.", "error_text_account_name": "Der Kontoname darf nur Buchstaben und Zahlen enthalten\nund muss zwischen 1 und 15 Zeichen lang sein", "error_text_address": "Die Walletadresse muss dem Typ der Kryptowährung\nentsprechen", "error_text_amount": "Betrag darf nur Zahlen enthalten", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Häufig gestellte Fragen", "frozen": "Gefroren", "full_balance": "Gesamtguthaben", + "gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.", "generate_name": "Namen generieren", "generating_gift_card": "Geschenkkarte wird erstellt", "get_a": "Hole ein", @@ -350,13 +359,17 @@ "how_to_use": "Wie benutzt man", "how_to_use_card": "Wie man diese Karte benutzt", "id": "ID: ", + "if_you_dont_see_your_device": "Wenn Sie Ihr Gerät nicht sehen, stellen Sie bitte sicher, dass Ihr Ledger an und entsperrt ist!", "ignor": "Ignorieren", "import": "Importieren", "importNFTs": "NFTs importieren", "in_store": "Im Geschäft", "incoming": "Eingehend", "incorrect_seed": "Der eingegebene Text ist ungültig.", + "incorrect_seed_option": "Falsch. Bitte versuchen Sie es erneut", + "incorrect_seed_option_back": "Falsch. Bitte stellen Sie sicher, dass Ihr Samen korrekt gespeichert wird, und versuchen Sie es erneut.", "inputs": "Eingänge", + "insufficient_funds_for_tx": "Unzureichende Mittel zur erfolgreichen Ausführung der Transaktion.", "insufficient_lamport_for_tx": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Bitte fügen Sie Ihrer Wallet mehr Sol hinzu oder reduzieren Sie die SOL-Menge, die Sie senden.", "insufficient_lamports": "Sie haben nicht genug SOL, um die Transaktion und ihre Transaktionsgebühr abzudecken. Sie brauchen mindestens ${solValueNeeded} Sol. Bitte fügen Sie mehr Sol zu Ihrer Wallet hinzu oder reduzieren Sie den von Ihnen gesendeten Sol-Betrag", "insufficientFundsForRentError": "Sie haben nicht genug SOL, um die Transaktionsgebühr und die Miete für das Konto zu decken. Bitte fügen Sie mehr Sol zu Ihrer Wallet hinzu oder reduzieren Sie den von Ihnen gesendeten Sol-Betrag", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Wählen Sie einen neuen Vertreter aus", "nanogpt_subtitle": "Alle neuesten Modelle (GPT-4, Claude).", "narrow": "Eng", - "new_first_wallet_text": "Bewahren Sie Ihre Kryptowährung einfach sicher auf", + "new_first_wallet_text": "Wenn Sie Ihren Krypto schützen, ist ein Kinderspiel", "new_node_testing": "Neuen Knoten testen", "new_subaddress_create": "Erstellen", "new_subaddress_label_name": "Bezeichnung", @@ -464,6 +477,7 @@ "online": "online", "onramper_option_description": "Kaufen Sie schnell Krypto mit vielen Zahlungsmethoden. In den meisten Ländern erhältlich. Spreads und Gebühren variieren.", "open_gift_card": "Geschenkkarte öffnen", + "open_wallet": "Offener Brieftasche", "optional_description": "Optionale Beschreibung", "optional_email_hint": "Optionale Benachrichtigungs-E-Mail für den Zahlungsempfänger", "optional_name": "Optionaler Empfängername", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Wenn diese Wallet einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Wallet ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher", "outgoing": "Ausgehend", "outputs": "Ausgänge", + "overshot": "Überschreiten", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Paarung ungültiges Ereignis", "passphrase": "Passphrase (optional)", @@ -532,6 +547,7 @@ "recipient_address": "Empfängeradresse", "reconnect": "Erneut verbinden", "reconnect_alert_text": "Sind Sie sicher, dass Sie sich neu verbinden möchten?", + "reconnect_your_hardware_wallet": "Hardware-Wallet neu verbinden", "reconnection": "Neu verbinden", "red_dark_theme": "Red Dark Thema", "red_light_theme": "Red Light Thema", @@ -571,6 +587,7 @@ "restore_description_from_keys": "Stellen Sie Ihr Wallet aus generierten Tastenanschlägen her, die von Ihren privaten Schlüsseln gespeichert wurden", "restore_description_from_seed": "Stellen Sie Ihre Wallet aus den 25 Wörtern oder dem 13-Wort-Kombinationscode wieder her", "restore_description_from_seed_keys": "Stellen Sie Ihr Wallet aus Seed/Schlüsseln wieder her, die Sie sicher aufbewahrt haben", + "restore_existing_wallet": "Bestehende Brieftasche wiederherstellen", "restore_from_date_or_blockheight": "Bitte geben Sie ein Datum ein, das einige Tage vor dem Erstellen dieser Wallet liegt. Oder wenn Sie die Blockhöhe kennen, geben Sie stattdessen diese ein", "restore_from_seed_placeholder": "Seed bitte hier eingeben oder einfügen", "restore_new_seed": "Neuer Seed", @@ -612,6 +629,7 @@ "seed_alert_title": "Achtung", "seed_alert_yes": "Ja, habe ich", "seed_choose": "Seed-Sprache auswählen", + "seed_display_path": "Menü -> Sicherheit und Sicherung -> Schlüssel/Samen anzeigen", "seed_hex_form": "Seed (Hexformat)", "seed_key": "Seed-Schlüssel", "seed_language": "Seed-Sprache", @@ -630,9 +648,13 @@ "seed_language_russian": "Russisch", "seed_language_spanish": "Spanisch", "seed_phrase_length": "Länge der Seed-Phrase", + "seed_position_question_one": "Was ist das", + "seed_position_question_two": "Wort Ihrer Samenphrase?", "seed_reminder": "Bitte notieren Sie diese für den Fall, dass Sie Ihr Telefon verlieren oder es kaputtgeht", "seed_share": "Seed teilen", "seed_title": "Seed", + "seed_verified": "Samen verifiziert", + "seed_verified_subtext": "Sie können Ihren gespeicherten Saat", "seedtype": "Seedtyp", "seedtype_alert_content": "Das Teilen von Seeds mit anderen Wallet ist nur mit bip39 Seedype möglich.", "seedtype_alert_title": "Seedype-Alarm", @@ -671,6 +693,7 @@ "sent": "Versendet", "service_health_disabled": "Service Health Bulletin ist deaktiviert", "service_health_disabled_message": "Dies ist die Seite \"Service Health Bulletin\", können Sie diese Seite unter Einstellungen -> Privatsphäre aktivieren", + "set_a_pin": "Setzen Sie einen Stift", "settings": "Einstellungen", "settings_all": "ALLE", "settings_allow_biometrical_authentication": "Biometrische Authentifizierung zulassen", @@ -706,6 +729,7 @@ "share_address": "Adresse teilen ", "shared_seed_wallet_groups": "Gemeinsame Walletsseed Gruppen", "show": "Zeigen", + "show_address_book_popup": "Popup \"zum Adressbuch hinzufügen\" nach dem Senden anzeigen", "show_details": "Details anzeigen", "show_keys": "Seed/Schlüssel anzeigen", "show_market_place": "Marktplatz anzeigen", @@ -733,6 +757,10 @@ "silent_payments_settings": "Einstellungen für stille Zahlungen", "single_seed_wallets_group": "Einzelne Wallets", "slidable": "Verschiebbar", + "solana_create_associated_token_account_exception": "Fehler beim Erstellen des zugehörigen Token -Kontos für die Empfängeradresse.", + "solana_no_associated_token_account_exception": "Für diese Adresse ist kein Token -Konto zugeordnet.", + "solana_sign_native_transaction_rent_exception": "Transaktion kann nicht abgeschlossen werden. Unzureichende Sol ließen nach der Transaktion zur Miete gelassen. Bitte geben Sie Ihre SOL -Balance auf oder reduzieren Sie die Menge an SOL, die Sie senden.", + "solana_sign_spl_token_transaction_rent_exception": "Transaktion kann nicht abgeschlossen werden. Unzureichende Sol ließen nach der Transaktion zur Miete gelassen. Bitte geben Sie Ihre SOL -Balance auf.", "sort_by": "Sortiere nach", "spend_key_private": "Spend Key (geheim)", "spend_key_public": "Spend Key (öffentlich)", @@ -745,7 +773,7 @@ "support_description_guides": "Dokumentation und Hilfe für bekannte Probleme", "support_description_live_chat": "Kostenlos und schnell! Ausgebildete Mitarbeiter stehen zur Unterstützung bereit, um zu helfen", "support_description_other_links": "Treten Sie unseren Communities bei oder erreichen Sie uns oder unsere Partner über andere Methoden", - "support_title_guides": "Cake Wallet Guides", + "support_title_guides": "Kuchenbrieftasche Docs", "support_title_live_chat": "Live Support", "support_title_other_links": "Andere Support-Links", "sweeping_wallet": "Wallet leeren", @@ -824,6 +852,7 @@ "trade_state_underpaid": "Unterbezahlt", "trade_state_unpaid": "Unbezahlt", "trades": "Börsen", + "transaction_cost": "Transaktionskosten", "transaction_details_amount": "Betrag", "transaction_details_copied": "${title} in die Zwischenablage kopiert", "transaction_details_date": "Datum", @@ -884,6 +913,7 @@ "variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt", "verification": "Verifizierung", "verify_message": "Nachricht überprüfen", + "verify_seed": "Saatgut überprüfen", "verify_with_2fa": "Verifizieren Sie mit Cake 2FA", "version": "Version ${currentVersion}", "view_all": "Alle anzeigen", @@ -894,6 +924,7 @@ "voting_weight": "Stimmgewicht", "waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird", "waiting_payment_confirmation": "Warte auf Zahlungsbestätigung", + "wallet": "Geldbörse", "wallet_group": "Walletgruppe", "wallet_group_description_four": "eine Wallet mit einem völlig neuen Seed schaffen.", "wallet_group_description_one": "In CakeWallet können Sie eine erstellen", @@ -926,6 +957,8 @@ "wallets": "Wallets", "warning": "Warnung", "welcome": "Willkommen bei", + "welcome_subtitle_new_wallet": "Wenn Sie frisch anfangen möchten, tippen Sie unten neue Brieftaschen und Sie werden zu den Rennen gehen.", + "welcome_subtitle_restore_wallet": "Wenn Sie über eine vorhandene Brieftasche verfügen, die Sie in Kuchen bringen möchten, wählen Sie einfach die vorhandene Brieftasche wiederherstellen und wir werden Sie durch den Prozess führen.", "welcome_to_cakepay": "Willkommen bei Cake Pay!", "what_is_silent_payments": "Was sind stille Zahlungen?", "widgets_address": "Adresse", @@ -956,4 +989,4 @@ "you_will_get": "Konvertieren zu", "you_will_send": "Konvertieren von", "yy": "YY" -} \ No newline at end of file +} diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 99c37ce16..e9ab3d5d9 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -38,6 +38,7 @@ "agree_to": "By creating account you agree to the ", "alert_notice": "Notice", "all": "ALL", + "all_coins": "All Coins", "all_trades": "All trades", "all_transactions": "All transactions", "alphabetical": "Alphabetical", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Buy worldwide prepaid cards and gift cards", "cake_pay_web_cards_subtitle": "Buy worldwide prepaid cards and gift cards", "cake_pay_web_cards_title": "Cake Pay Web Cards", + "cake_seeds_save_disclaimer": "Please save these words in a secure place! You will need these words to restore your wallet on a new device.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "I confirm I am not using a Proxy or VPN", + "cakepay_confirm_purchase": "Confirm Purchase", + "cakepay_confirm_terms_agreed": "I agree to the terms and conditions presented here:", + "cakepay_confirm_voided_refund": "I understand redemption attempts from a restricted country will void any refund", + "cakepay_ios_not_available": "Sorry, this gift card is not available on iOS. You can purchase it on Android or through our website instead.", "cakepay_prepaid_card": "CakePay Prepaid Debit Card", "camera_consent": "Your camera will be used to capture an image for identification purposes by ${provider}. Please check their Privacy Policy for details.", "camera_permission_is_required": "Camera permission is required. \nPlease enable it from app settings.", @@ -175,6 +182,7 @@ "copy_address": "Copy Address", "copy_id": "Copy ID", "copyWalletConnectLink": "Copy the WalletConnect link from dApp and paste here", + "corrupted_seed_notice": "The files for this wallet are corrupted and are unable to be opened. Please view the seed phrase, save it, and restore the wallet.\n\nIf the value is empty, then the seed was unable to be correctly recovered.", "countries": "Countries", "create_account": "Create Account", "create_backup": "Create backup", @@ -256,7 +264,7 @@ "enterTokenID": "Enter the token ID", "enterWalletConnectURI": "Enter WalletConnect URI", "error": "Error", - "error_dialog_content": "Oops, we got some error.\n\nPlease send the crash report to our support team to make the application better.", + "error_dialog_content": "Oops, we got some error.\n\nPlease send the error report to our support team to make the application better.", "error_text_account_name": "Account name can only contain letters, numbers\nand must be between 1 and 15 characters long", "error_text_address": "Wallet address must correspond to the type\nof cryptocurrency", "error_text_amount": "Amount can only contain numbers", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Frequently asked questions", "frozen": "Frozen", "full_balance": "Full Balance", + "gas_exceeds_allowance": "Gas required by transaction exceeds allowance.", "generate_name": "Generate Name", "generating_gift_card": "Generating Gift Card", "get_a": "Get a ", @@ -350,13 +359,17 @@ "how_to_use": "How to use", "how_to_use_card": "How to use this card", "id": "ID: ", + "if_you_dont_see_your_device": "If you don't see your device above, please be sure your Ledger is awake and unlocked!", "ignor": "Ignore", "import": "Import", "importNFTs": "Import NFTs", "in_store": "In Store", "incoming": "Incoming", "incorrect_seed": "The text entered is not valid.", + "incorrect_seed_option": "Incorrect. Please try again", + "incorrect_seed_option_back": "Incorrect. Please make sure your seed is saved correctly and try again.", "inputs": "Inputs", + "insufficient_funds_for_tx": "Insufficient funds to successfully execute transaction.", "insufficient_lamport_for_tx": "You do not have enough SOL to cover the transaction and its transaction fee. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending.", "insufficient_lamports": "You do not have enough SOL to cover the transaction and its transaction fee. You need at least ${solValueNeeded} SOL. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending", "insufficientFundsForRentError": "You do not have enough SOL to cover the transaction fee and rent for the account. Kindly add more SOL to your wallet or reduce the SOL amount you\\'re sending", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Pick a new representative", "nanogpt_subtitle": "All the newest models (GPT-4, Claude).\\nNo subscription, pay with crypto.", "narrow": "Narrow", - "new_first_wallet_text": "Keep your crypto safe, piece of cake", + "new_first_wallet_text": "Keeping your crypto safe is a piece of cake", "new_node_testing": "New node testing", "new_subaddress_create": "Create", "new_subaddress_label_name": "Label name", @@ -464,6 +477,7 @@ "online": "Online", "onramper_option_description": "Quickly buy crypto with many payment methods. Available in most countries. Spreads and fees vary.", "open_gift_card": "Open Gift Card", + "open_wallet": "Open Wallet", "optional_description": "Optional description", "optional_email_hint": "Optional payee notification email", "optional_name": "Optional recipient name", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "If this wallet has a 12-word seed and was created in Cake, DO NOT deposit Bitcoin into this wallet. Any BTC transferred to this wallet may be lost. Create a new 24-word wallet (tap the menu at the top right, select Wallets, choose Create New Wallet, then select Bitcoin) and IMMEDIATELY move your BTC there. New (24-word) BTC wallets from Cake are secure", "outgoing": "Outgoing", "outputs": "Outputs", + "overshot": "Overshot", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Pairing Invalid Event", "passphrase": "Passphrase (Optional)", @@ -531,6 +546,7 @@ "recipient_address": "Recipient address", "reconnect": "Reconnect", "reconnect_alert_text": "Are you sure you want to reconnect?", + "reconnect_your_hardware_wallet": "Reconnect your Hardware Wallet", "reconnection": "Reconnection", "red_dark_theme": "Red Dark Theme", "red_light_theme": "Red Light Theme", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Restore your wallet from generated keystrokes saved from your private keys", "restore_description_from_seed": "Restore your wallet from either the 25 word or 13 word combination code", "restore_description_from_seed_keys": "Get back your wallet from seed/keys that you've saved to secure place", + "restore_existing_wallet": "Restore Existing Wallet", "restore_from_date_or_blockheight": "Please enter a date a few days before you created this wallet. Or if you know the blockheight, please enter it instead", "restore_from_seed_placeholder": "Please enter or paste your seed here", "restore_new_seed": "New seed", @@ -611,6 +628,7 @@ "seed_alert_title": "Attention", "seed_alert_yes": "Yes, I have", "seed_choose": "Choose seed language", + "seed_display_path": "Menu -> Security and Backup -> Show key/seeds", "seed_hex_form": "Wallet seed (hex form)", "seed_key": "Seed key", "seed_language": "Seed language", @@ -629,9 +647,13 @@ "seed_language_russian": "Russian", "seed_language_spanish": "Spanish", "seed_phrase_length": "Seed phrase length", + "seed_position_question_one": "What is the", + "seed_position_question_two": "word of your seed phrase?", "seed_reminder": "Please write these down in case you lose or wipe your phone", "seed_share": "Share seed", "seed_title": "Seed", + "seed_verified": "Seed Verified", + "seed_verified_subtext": "You can use your saved seed later on to restore this wallet in the event of corruption or losing your device.\n\nYou can view this seed again from the", "seedtype": "Seedtype", "seedtype_alert_content": "Sharing seeds with other wallets is only possible with BIP39 SeedType.", "seedtype_alert_title": "SeedType Alert", @@ -670,6 +692,7 @@ "sent": "Sent", "service_health_disabled": "Service Health Bulletin is disabled", "service_health_disabled_message": "This is the service health bulletin page, you can enable this page under Settings -> Privacy", + "set_a_pin": "Set a PIN", "settings": "Settings", "settings_all": "ALL", "settings_allow_biometrical_authentication": "Allow biometrical authentication", @@ -705,6 +728,7 @@ "share_address": "Share address", "shared_seed_wallet_groups": "Shared Seed Wallet Groups", "show": "Show", + "show_address_book_popup": "Show 'Add to Address Book' popup after sending", "show_details": "Show Details", "show_keys": "Show seed/keys", "show_market_place": "Show Marketplace", @@ -732,6 +756,10 @@ "silent_payments_settings": "Silent Payments settings", "single_seed_wallets_group": "Single Seed Wallets", "slidable": "Slidable", + "solana_create_associated_token_account_exception": "Error creating associated token account for receipient address.", + "solana_no_associated_token_account_exception": "There is no associated token account for this address.", + "solana_sign_native_transaction_rent_exception": "Transaction cannot be completed. Insufficient SOL left for rent after transaction. Kindly top up your SOL balance or reduce the amount of SOL you are sending.", + "solana_sign_spl_token_transaction_rent_exception": "Transaction cannot be completed. Insufficient SOL left for rent after transaction. Kindly top up your SOL balance.", "sort_by": "Sort by", "spend_key_private": "Spend key (private)", "spend_key_public": "Spend key (public)", @@ -744,7 +772,7 @@ "support_description_guides": "Documentation and support for common issues", "support_description_live_chat": "Free and fast! Trained support representatives are available to assist", "support_description_other_links": "Join our communities or reach us or our partners through other methods", - "support_title_guides": "Cake Wallet guides", + "support_title_guides": "Cake Wallet docs", "support_title_live_chat": "Live support", "support_title_other_links": "Other support links", "sweeping_wallet": "Sweeping wallet", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Underpaid", "trade_state_unpaid": "Unpaid", "trades": "Trades", + "transaction_cost": "Transaction Cost", "transaction_details_amount": "Amount", "transaction_details_copied": "${title} copied to Clipboard", "transaction_details_date": "Date", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "This variable pair is not supported with the selected exchanges", "verification": "Verification", "verify_message": "Verify Message", + "verify_seed": "Verify Seed", "verify_with_2fa": "Verify with Cake 2FA", "version": "Version ${currentVersion}", "view_all": "View all", @@ -891,6 +921,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "Voting Weight", "waitFewSecondForTxUpdate": "Kindly wait for a few seconds for transaction to reflect in transactions history", + "wallet": "Wallet", "wallet_group": "Wallet Group", "wallet_group_description_four": "to create a wallet with an entirely new seed.", "wallet_group_description_one": "In Cake Wallet, you can create a", @@ -923,6 +954,8 @@ "wallets": "Wallets", "warning": "Warning", "welcome": "Welcome to", + "welcome_subtitle_new_wallet": "If you want to start fresh, tap Create New Wallet below and you'll be off to the races.", + "welcome_subtitle_restore_wallet": "If you have an existing wallet you want to bring into Cake, simply choose Restore Existing Wallet and we'll walk you through the process.", "welcome_to_cakepay": "Welcome to Cake Pay!", "what_is_silent_payments": "What are Silent Payments?", "widgets_address": "Address", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index d1004137c..1dd65af2f 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -38,6 +38,7 @@ "agree_to": "Al crear una cuenta, aceptas ", "alert_notice": "Aviso", "all": "Todos", + "all_coins": "Todas las monedas", "all_trades": "Todos los oficios", "all_transactions": "Todas las transacciones", "alphabetical": "Alfabético", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Compra tarjetas prepagadas y tarjetas de regalo en todo el mundo", "cake_pay_web_cards_subtitle": "Compra tarjetas de prepago y tarjetas de regalo en todo el mundo", "cake_pay_web_cards_title": "Tarjetas Web Cake Pay", + "cake_seeds_save_disclaimer": "¡Guarde estas palabras en un lugar seguro! Necesitará estas palabras para restaurar su billetera en un nuevo dispositivo.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Confirmo que no estoy usando un proxy o VPN", + "cakepay_confirm_purchase": "Confirmar la compra", + "cakepay_confirm_terms_agreed": "Estoy de acuerdo con los términos y condiciones presentados aquí:", + "cakepay_confirm_voided_refund": "Entiendo que los intentos de redención de un país restringido anularán cualquier reembolso", + "cakepay_ios_not_available": "Lo siento, esta tarjeta de regalo no está disponible en iOS. Puede comprarlo en Android o a través de nuestro sitio web.", "cakepay_prepaid_card": "Tarjeta de Débito Prepago CakePay", "camera_consent": "Su cámara será utilizada para capturar una imagen con fines de identificación por ${provider}. Consulta tu Política de privacidad para obtener más detalles.", "camera_permission_is_required": "Se requiere permiso de la cámara.\nHabilítalo desde la configuración de la aplicación.", @@ -175,6 +182,7 @@ "copy_address": "Copiar dirección ", "copy_id": "Copiar ID", "copyWalletConnectLink": "Copie el enlace de WalletConnect de dApp y péguelo aquí", + "corrupted_seed_notice": "Los archivos para esta billetera están dañados y no pueden abrirse. Vea la frase de semillas, guárdela y restaura la billetera.\n\nSi el valor está vacío, entonces la semilla no pudo recuperarse correctamente.", "countries": "Países", "create_account": "Crear Cuenta", "create_backup": "Crear copia de seguridad", @@ -256,7 +264,7 @@ "enterTokenID": "Ingresa el ID del token", "enterWalletConnectURI": "Ingresa el URI de WalletConnect", "error": "Error", - "error_dialog_content": "Vaya, tenemos un error.\n\nEnvía el informe de error a nuestro equipo de soporte para mejorar la aplicación.", + "error_dialog_content": "Vaya, recibimos algo de error.\n\nEnvíe el informe de error a nuestro equipo de soporte para mejorar la aplicación.", "error_text_account_name": "El nombre de la cuenta solo puede contener letras, números \ny debe tener entre 1 y 15 caracteres de longitud", "error_text_address": "La dirección de la billetera debe corresponder al tipo \nde criptomoneda", "error_text_amount": "La cantidad solo puede contener números", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Preguntas frecuentes", "frozen": "Congelada", "full_balance": "Balance completo", + "gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.", "generate_name": "Generar nombre", "generating_gift_card": "Generando tarjeta de regalo", "get_a": "Obtener un", @@ -350,13 +359,17 @@ "how_to_use": "Cómo utilizar", "how_to_use_card": "Cómo usar esta tarjeta", "id": "ID: ", + "if_you_dont_see_your_device": "Si no ve su dispositivo arriba, ¡asegúrese de que su libro mayor esté despierto y desbloqueado!", "ignor": "Pasar por alto", "import": "Importar", "importNFTs": "Importar NFT", "in_store": "En la tienda", "incoming": "Entrante", "incorrect_seed": "El texto ingresado no es válido.", + "incorrect_seed_option": "Incorrecto. Por favor intente de nuevo", + "incorrect_seed_option_back": "Incorrecto. Asegúrese de que su semilla se guarde correctamente e intente nuevamente.", "inputs": "Entradas", + "insufficient_funds_for_tx": "Fondos insuficientes para ejecutar con éxito la transacción.", "insufficient_lamport_for_tx": "No tienes suficiente SOL para cubrir la transacción y su tarifa de transacción. Por favor, agrega más SOL a su billetera o reduce la cantidad de sol que está enviando.", "insufficient_lamports": "No tienes suficiente SOL para cubrir la transacción y su tarifa de transacción. Necesita al menos ${solValueNeeded} sol. Por favor, agrega más sol a su billetera o reduzca la cantidad de sol que está enviando", "insufficientFundsForRentError": "No tienes suficiente SOL para cubrir la tarifa de transacción y alquilar para la cuenta. Por favor, agrega más sol a su billetera o reduce la cantidad de sol que está enviando", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Elija un nuevo representante", "nanogpt_subtitle": "Todos los modelos más nuevos (GPT-4, Claude). \\nSin suscripción, pague con cripto.", "narrow": "Angosto", - "new_first_wallet_text": "Mantén fácilmente tu criptomoneda segura", + "new_first_wallet_text": "Mantener su criptografía a salvo es un pedazo de pastel", "new_node_testing": "Prueba nuevos nodos", "new_subaddress_create": "Crear", "new_subaddress_label_name": "Nombre de etiqueta", @@ -464,6 +477,7 @@ "online": "En línea", "onramper_option_description": "Compra rápidamente cripto con muchos métodos de pago. Disponible en la mayoría de los países. Los diferenciales y las tarifas varían.", "open_gift_card": "Abrir tarjeta de regalo", + "open_wallet": "Billetera abierta", "optional_description": "Descripción opcional", "optional_email_hint": "Correo electrónico de notificación del beneficiario opcional", "optional_name": "Nombre del destinatario opcional", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Si esta billetera tiene una semilla de 12 palabras y se creó en Cake, NO deposite Bitcoin en esta billetera. Cualquier BTC transferido a esta billetera se puede perder. Cree una nueva billetera de 24 palabras (toque el menú en la parte superior derecha, seleccione Monederos, elija Crear nueva billetera, luego seleccione Bitcoin) e INMEDIATAMENTE mueva su BTC allí. Las nuevas carteras BTC (24 palabras) de Cake son seguras", "outgoing": "Saliente", "outputs": "Salidas", + "overshot": "Sobrepasar", "overwrite_amount": "Sobreescribir monto", "pairingInvalidEvent": "Evento de emparejamiento no válido", "passphrase": "Passfrase (opcional)", @@ -532,6 +547,7 @@ "recipient_address": "Dirección del receptor", "reconnect": "Volver a conectar", "reconnect_alert_text": "¿Estás seguro de reconectar?", + "reconnect_your_hardware_wallet": "Vuelva a conectar su billetera de hardware", "reconnection": "Reconexión", "red_dark_theme": "Tema rojo oscuro", "red_light_theme": "Tema de la luz roja", @@ -571,6 +587,7 @@ "restore_description_from_keys": "Restaure su billetera de las pulsaciones de teclas generadas guardadas de sus claves privadas", "restore_description_from_seed": "Restaure su billetera desde el código de combinación de 25 palabras i de 13 palabras", "restore_description_from_seed_keys": "Recupere su billetera de las semillas/claves que ha guardado en un lugar seguro", + "restore_existing_wallet": "Restaurar la billetera existente", "restore_from_date_or_blockheight": "Ingrese una fecha unos días antes de crear esta billetera. O si conoce la altura del bloque, ingréselo en su lugar", "restore_from_seed_placeholder": "Ingrese o pegue su frase de código aquí", "restore_new_seed": "Nueva semilla", @@ -612,6 +629,7 @@ "seed_alert_title": "Atención", "seed_alert_yes": "Sí tengo", "seed_choose": "Elige el idioma semilla", + "seed_display_path": "Menú -> Seguridad y copia de seguridad -> Mostrar llave/semillas", "seed_hex_form": "Semilla de billetera (forma hexadecimal)", "seed_key": "Llave de semilla", "seed_language": "Lenguaje de semillas", @@ -630,9 +648,13 @@ "seed_language_russian": "Ruso", "seed_language_spanish": "Español", "seed_phrase_length": "Longitud de la frase inicial", + "seed_position_question_one": "¿Qué es el", + "seed_position_question_two": "¿Palabra de tu frase de semillas?", "seed_reminder": "Anótalos en caso de que pierdas o borres tu aplicación", "seed_share": "Compartir semillas", "seed_title": "Semilla", + "seed_verified": "Semilla verificada", + "seed_verified_subtext": "Puede usar su semilla guardada más adelante para restaurar esta billetera en caso de corrupción o perder su dispositivo. \n\n Puede ver esta semilla nuevamente desde el", "seedtype": "Tipos de semillas", "seedtype_alert_content": "Compartir semillas con otras billeteras solo es posible con semillas bip39 - un tipo específico de semilla.", "seedtype_alert_title": "Alerta de tipo de semillas", @@ -671,6 +693,7 @@ "sent": "Expedido", "service_health_disabled": "El boletín de salud del servicio está deshabilitado", "service_health_disabled_message": "Esta es la página del Boletín de Salud del Servicio, puede habilitar esta página en Configuración -> Privacidad", + "set_a_pin": "Establecer un alfiler", "settings": "Configuraciones", "settings_all": "TODOS", "settings_allow_biometrical_authentication": "Permitir autenticación biométrica", @@ -706,6 +729,7 @@ "share_address": "Compartir dirección", "shared_seed_wallet_groups": "Grupos de billetera de semillas compartidas", "show": "Espectáculo", + "show_address_book_popup": "Mostrar ventana emergente 'Agregar a la libreta de direcciones' después de enviar", "show_details": "Mostrar detalles", "show_keys": "Mostrar semilla/claves", "show_market_place": "Mostrar mercado", @@ -733,6 +757,10 @@ "silent_payments_settings": "Configuración de pagos silenciosos", "single_seed_wallets_group": "Billeteras de semillas individuales", "slidable": "deslizable", + "solana_create_associated_token_account_exception": "Error a crear una cuenta de token asociada para la dirección recibida.", + "solana_no_associated_token_account_exception": "No hay una cuenta de token asociada para esta dirección.", + "solana_sign_native_transaction_rent_exception": "La transacción no se puede completar. Sol insuficiente que queda en alquiler después de la transacción. Por favor, supere su saldo de sol o reduzca la cantidad de sol que está enviando.", + "solana_sign_spl_token_transaction_rent_exception": "La transacción no se puede completar. Sol insuficiente que queda en alquiler después de la transacción. Por favor, supere su balance de sol.", "sort_by": "Ordenar por", "spend_key_private": "Llave de gasto (privada)", "spend_key_public": "Llave de gasto (pública)", @@ -745,7 +773,7 @@ "support_description_guides": "Documentación y apoyo para problemas comunes", "support_description_live_chat": "¡GRATIS y RÁPIDO! Los representantes de apoyo capacitado están disponibles para ayudar", "support_description_other_links": "Únete a nuestras comunidades o comunícate con nosotros nuestros socios a través de otros métodos", - "support_title_guides": "Guías de billetera para pastel", + "support_title_guides": "Documentos de billetera de pastel", "support_title_live_chat": "Soporte en tiempo real", "support_title_other_links": "Otros enlaces de soporte", "sweeping_wallet": "Barrer billetera (gastar todos los fondos disponibles)", @@ -824,6 +852,7 @@ "trade_state_underpaid": "Poco pagado", "trade_state_unpaid": "No pagado", "trades": "Cambios", + "transaction_cost": "Costo de transacción", "transaction_details_amount": "Cantidad", "transaction_details_copied": "${title} Copiado al portapapeles", "transaction_details_date": "Fecha", @@ -883,6 +912,7 @@ "variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados", "verification": "Verificación", "verify_message": "Mensaje de verificación", + "verify_seed": "Verificar semilla", "verify_with_2fa": "Verificar con Cake 2FA", "version": "Versión ${currentVersion}", "view_all": "Ver todo", @@ -892,6 +922,7 @@ "view_transaction_on": "Ver transacción en ", "voting_weight": "Peso de votación", "waitFewSecondForTxUpdate": "Espera unos segundos para que la transacción se refleje en el historial de transacciones.", + "wallet": "Billetera", "wallet_group": "Grupo de billetera", "wallet_group_description_four": "Para crear una billetera con una semilla completamente nueva.", "wallet_group_description_one": "En la billetera de pastel, puedes crear un", @@ -924,6 +955,8 @@ "wallets": "Carteras", "warning": "Advertencia", "welcome": "Bienvenido", + "welcome_subtitle_new_wallet": "Si desea comenzar de nuevo, toque Crear nueva billetera a continuación y se irá a las carreras.", + "welcome_subtitle_restore_wallet": "Si tiene una billetera existente que desea llevar al pastel, simplemente elija Restaurar la billetera existente y lo guiaremos a través del proceso.", "welcome_to_cakepay": "¡Bienvenido a Cake Pay!", "what_is_silent_payments": "¿Qué son los pagos silenciosos?", "widgets_address": "Dirección", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index c24e2d9d0..e11024fdc 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -38,8 +38,9 @@ "agree_to": "En créant un compte, vous acceptez les ", "alert_notice": "Avis", "all": "TOUT", - "all_trades": "Tous échanges", - "all_transactions": "Toutes transactions", + "all_coins": "Toutes les pièces", + "all_trades": "Tous les échanges", + "all_transactions": "Toutes les transactions", "alphabetical": "Alphabétique", "already_have_account": "Vous avez déjà un compte ?", "always": "toujours", @@ -54,7 +55,7 @@ "arrive_in_this_address": "${currency} ${tag}arrivera à cette adresse", "ascending": "Ascendant", "ask_each_time": "Demander à chaque fois", - "auth_store_ban_timeout": "délai de bannisement", + "auth_store_ban_timeout": "expulsion_temporaire", "auth_store_banned_for": "Banni pour ", "auth_store_banned_minutes": " minutes", "auth_store_incorrect_password": "Mauvais code PIN", @@ -84,7 +85,7 @@ "Blocks_remaining": "Blocs Restants : ${status}", "bluetooth": "Bluetooth", "bright_theme": "Vif", - "bump_fee": "Frais de bosse", + "bump_fee": "Augmenter les frais", "buy": "Acheter", "buy_alert_content": "Actuellement, nous ne prenons en charge que l'achat de Bitcoin, Ethereum, Litecoin et Monero. Veuillez créer ou basculer vers votre portefeuille Bitcoin, Ethereum, Litecoin ou Monero.", "buy_bitcoin": "Acheter du Bitcoin", @@ -93,19 +94,25 @@ "buy_with": "Acheter avec", "by_cake_pay": "par Cake Pay", "cake_2fa_preset": "Cake 2FA prédéfini", - "cake_dark_theme": "Thème sombre du gâteau", + "cake_dark_theme": "Thème sombre Cake", "cake_pay_account_note": "Inscrivez-vous avec juste une adresse e-mail pour voir et acheter des cartes. Certaines sont même disponibles à prix réduit !", "cake_pay_learn_more": "Achetez et utilisez instantanément des cartes-cadeaux dans l'application !\nBalayer de gauche à droite pour en savoir plus.", "cake_pay_save_order": "La carte doit être envoyée à votre e-mail dans un jour ouvrable \n Enregistrez votre identifiant de commande:", "cake_pay_subtitle": "Achetez des cartes et des cartes-cadeaux prépayées mondiales", "cake_pay_web_cards_subtitle": "Achetez des cartes prépayées et des cartes-cadeaux dans le monde entier", "cake_pay_web_cards_title": "Cartes Web Cake Pay", + "cake_seeds_save_disclaimer": "Veuillez enregistrer ces mots dans un endroit sécurisé! Vous aurez besoin de ces mots pour restaurer votre portefeuille sur un nouvel appareil.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Je confirme que je n'utilise pas de proxy ou de VPN", + "cakepay_confirm_purchase": "Confirmer l'achat", + "cakepay_confirm_terms_agreed": "J'accepte les termes et conditions présentés ici:", + "cakepay_confirm_voided_refund": "Je comprends que les tentatives de rachat d'un pays restreint annulent tout remboursement", + "cakepay_ios_not_available": "Désolé, cette carte-cadeau n'est pas disponible sur iOS. Vous pouvez l'acheter sur Android ou via notre site Web à la place.", "cakepay_prepaid_card": "Carte de débit prépayée Cake Pay", "camera_consent": "Votre appareil photo sera utilisé pour capturer une image à des fins d'identification par ${provider}. Veuillez consulter leur politique de confidentialité pour plus de détails.", "camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.", "cancel": "Annuler", - "card_address": "Adresse :", + "card_address": "Adresse:", "cardholder_agreement": "Contrat de titulaire de carte", "cards": "Cartes", "chains": "Chaînes", @@ -126,13 +133,13 @@ "choose_a_payment_method": "Choisissez un mode de paiement", "choose_a_provider": "Choisissez un fournisseur", "choose_account": "Choisir le compte", - "choose_address": "\n\nMerci de choisir l'adresse :", + "choose_address": "\n\nMerci de choisir l'adresse:", "choose_card_value": "Choisissez une valeur de carte", - "choose_derivation": "Choisissez le chemin de dérivation du portefeuille", - "choose_from_available_options": "Choisissez parmi les options disponibles :", + "choose_derivation": "Choisir la dérivation du portefeuille", + "choose_from_available_options": "Choisissez parmi les options disponibles:", "choose_one": "Choisissez-en un", "choose_relay": "Veuillez choisir un relais à utiliser", - "choose_wallet_currency": "Merci de choisir la devise du portefeuille (wallet) :", + "choose_wallet_currency": "Merci de choisir la devise du portefeuille (wallet):", "choose_wallet_group": "Choisissez un groupe de portefeuille", "clear": "Effacer", "clearnet_link": "Lien Clearnet", @@ -143,12 +150,12 @@ "commit_transaction_amount_fee": "Valider la transaction\nMontant : ${amount}\nFrais : ${fee}", "confirm": "Confirmer", "confirm_delete_template": "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?", - "confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous contnuer ?", + "confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous continuer ?", "confirm_fee_deduction": "Confirmer la déduction des frais", "confirm_fee_deduction_content": "Acceptez-vous de déduire les frais de la production?", "confirm_passphrase": "Confirmer la phrase passante", "confirm_sending": "Confirmer l'envoi", - "confirm_silent_payments_switch_node": "Votre nœud actuel ne prend pas en charge les paiements silencieux \\ ncake qui passera à un nœud compatible, juste pour la numérisation", + "confirm_silent_payments_switch_node": "Votre nœud actuel ne prend pas en charge les paiements silencieux.\n\nCake Wallet passera à un nœud compatible pendant l'analyse.", "confirmations": "Confirmations", "confirmed": "Solde confirmé", "confirmed_tx": "Confirmé", @@ -175,7 +182,8 @@ "copy_address": "Copier l'Adresse", "copy_id": "Copier l'ID", "copyWalletConnectLink": "Copiez le lien WalletConnect depuis l'application décentralisée (dApp) et collez-le ici", - "countries": "Des pays", + "corrupted_seed_notice": "Les fichiers de ce portefeuille sont corrompus et ne peuvent pas être ouverts. Veuillez consulter la phrase de graines, sauver et restaurer le portefeuille.\n\nSi la valeur est vide, la graine n'a pas pu être correctement récupérée.", + "countries": "Pays", "create_account": "Créer un compte", "create_backup": "Créer une sauvegarde", "create_donation_link": "Créer un lien de don", @@ -186,8 +194,8 @@ "creating_new_wallet": "Création d'un nouveau portefeuille (wallet)", "creating_new_wallet_error": "Erreur : ${description}", "creation_date": "Date de création", - "custom": "personnalisé", - "custom_drag": "Custom (maintenir et traîner)", + "custom": "Personnalisé", + "custom_drag": "Personnalisé (Maintenir et Glisser)", "custom_redeem_amount": "Montant d'échange personnalisé", "custom_value": "Valeur personnalisée", "dark_theme": "Sombre", @@ -242,7 +250,7 @@ "enable": "Activer", "enable_mempool_api": "API Mempool pour les frais et dates précis", "enable_replace_by_fee": "Activer Remplace-by-Fee", - "enable_silent_payments_scanning": "Commencez à scanner les paiements silencieux, jusqu'à ce que la pointe soit atteinte", + "enable_silent_payments_scanning": "Commencez à analyser les transactions envoyées à votre adresse de paiement silencieux.", "enabled": "Activé", "enter_amount": "Entrez le montant", "enter_backup_password": "Entrez le mot de passe de sauvegarde ici", @@ -256,7 +264,7 @@ "enterTokenID": "Entrez l'ID du jeton", "enterWalletConnectURI": "Saisissez l'URI de WalletConnect.", "error": "Erreur", - "error_dialog_content": "Oups, nous avons rencontré une erreur.\n\nMerci d'envoyer le rapport d'erreur à notre équipe d'assistance afin de nous permettre d'améliorer l'application.", + "error_dialog_content": "Oups, nous avons eu une erreur.\n\nVeuillez envoyer le rapport d'erreur à notre équipe d'assistance pour améliorer l'application.", "error_text_account_name": "Le nom de compte ne peut contenir que des lettres et des chiffres\net sa longueur doit être comprise entre 1 et 15 caractères", "error_text_address": "L'adresse du portefeuille (wallet) doit correspondre au type de\ncryptomonnaie", "error_text_amount": "Le montant ne peut comporter que des nombres", @@ -286,7 +294,7 @@ "event": "Événement", "events": "Événements", "exchange": "Échanger", - "exchange_incorrect_current_wallet_for_xmr": "Si vous souhaitez échanger XMR à partir de votre balance monero portefeuille de gâteau, veuillez d'abord passer à votre portefeuille Monero.", + "exchange_incorrect_current_wallet_for_xmr": "Si vous souhaitez échanger des XMR depuis le solde Monero de votre Cake Wallet, veuillez d'abord passer à votre portefeuille Monero.", "exchange_new_template": "Nouveau modèle d'échange", "exchange_provider_unsupported": "${providerName} n'est plus pris en charge !", "exchange_result_confirm": "En pressant confirmer, vous enverrez ${fetchingLabel} ${from} depuis votre portefeuille (wallet) nommé ${walletName} vers l'adresse ci-dessous. Vous pouvez aussi envoyer depuis votre portefeuille externe vers l'adresse/QR code ci-dessous.\n\nMerci d'appuyer sur confirmer pour continuer ou retournez en arrière pour modifier les montants.", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Foire aux questions", "frozen": "Gelées", "full_balance": "Solde Complet", + "gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.", "generate_name": "Générer un nom", "generating_gift_card": "Génération d'une carte-cadeau", "get_a": "Obtenir un ", @@ -350,13 +359,17 @@ "how_to_use": "Comment utiliser", "how_to_use_card": "Comment utiliser cette carte", "id": "ID : ", + "if_you_dont_see_your_device": "Si vous ne voyez pas votre appareil ci-dessus, assurez-vous que votre grand livre est éveillé et déverrouillé!", "ignor": "Ignorer", "import": "Importer", "importNFTs": "Importer des NFT", "in_store": "En magasin", "incoming": "Entrantes", "incorrect_seed": "Le texte entré est invalide.", + "incorrect_seed_option": "Incorrect. Veuillez réessayer", + "incorrect_seed_option_back": "Incorrect. Veuillez vous assurer que votre graine est enregistrée correctement et réessayer.", "inputs": "Contributions", + "insufficient_funds_for_tx": "Fonds insuffisants pour exécuter avec succès la transaction.", "insufficient_lamport_for_tx": "Vous n'avez pas assez de sol pour couvrir la transaction et ses frais de transaction. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de Sol que vous envoyez.", "insufficient_lamports": "Vous n'avez pas assez de sol pour couvrir la transaction et ses frais de transaction. Vous avez besoin d'au moins ${solValueNeeded} sol. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de sol que vous envoyez", "insufficientFundsForRentError": "Vous n'avez pas assez de SOL pour couvrir les frais de transaction et le loyer pour le compte. Veuillez ajouter plus de Sol à votre portefeuille ou réduire la quantité de sol que vous envoyez", @@ -367,11 +380,11 @@ "is_percentage": "est", "last_30_days": "30 derniers jours", "learn_more": "En savoir plus", - "ledger_connection_error": "Impossible de se connecter à votre grand livre. Veuillez réessayer.", - "ledger_error_device_locked": "Le grand livre est verrouillé", + "ledger_connection_error": "Impossible de se connecter à votre Ledger. Veuillez réessayer.", + "ledger_error_device_locked": "La Ledger est verrouillé", "ledger_error_tx_rejected_by_user": "Transaction rejetée sur l'appareil", - "ledger_error_wrong_app": "Veuillez vous assurer d'ouvrir la bonne application sur votre grand livre", - "ledger_please_enable_bluetooth": "Veuillez activer Bluetooth pour détecter votre grand livre", + "ledger_error_wrong_app": "Veuillez vous assurer d'ouvrir la bonne application sur votre Ledger", + "ledger_please_enable_bluetooth": "Veuillez activer le Bluetooth pour détecter votre Ledger", "light_theme": "Clair", "litecoin_enable_mweb_sync": "Activer la numérisation MWEB", "litecoin_mweb": "Mweb", @@ -383,8 +396,8 @@ "litecoin_mweb_enable_later": "Vous pouvez choisir d'activer à nouveau MWEB sous Paramètres d'affichage.", "litecoin_mweb_logs": "Journaux MWEB", "litecoin_mweb_node": "Node MWEB", - "litecoin_mweb_pegin": "Entraver", - "litecoin_mweb_pegout": "Crever", + "litecoin_mweb_pegin": "Dépôt Peg", + "litecoin_mweb_pegout": "Retrait Peg", "litecoin_mweb_scanning": "Scann mweb", "litecoin_mweb_settings": "Paramètres MWEB", "litecoin_mweb_warning": "L'utilisation de MWEB téléchargera initialement ~ 600 Mo de données et peut prendre jusqu'à 30 minutes en fonction de la vitesse du réseau. Ces données initiales ne téléchargeront qu'une seule fois et seront disponibles pour tous les portefeuilles litecoin", @@ -392,9 +405,9 @@ "live_fee_rates": "Taux de frais en direct via l'API", "load_more": "Charger plus", "loading_your_wallet": "Chargement de votre portefeuille (wallet)", - "login": "Utilisateur", + "login": "Connexion", "logout": "Déconnexion", - "low_fee": "Frais modiques", + "low_fee": "Frais faibles", "low_fee_alert": "Vous utilisez actuellement une priorité de frais de réseau peu élevés. Cela pourrait entraîner de longues attentes, des taux différents ou des transactions annulées. Nous vous recommandons de fixer des frais plus élevés pour une meilleure expérience.", "manage_nodes": "Gérer les nœuds", "manage_pow_nodes": "Gérer les nœuds PoW", @@ -425,9 +438,9 @@ "nano_current_rep": "Représentant actuel", "nano_gpt_thanks_message": "Merci d'avoir utilisé Nanogpt! N'oubliez pas de retourner au navigateur une fois votre transaction terminée!", "nano_pick_new_rep": "Choisissez un nouveau représentant", - "nanogpt_subtitle": "Tous les modèles les plus récents (GPT-4, Claude). \\ NNO abonnement, payez avec crypto.", - "narrow": "Étroit", - "new_first_wallet_text": "Gardez facilement votre crypto-monnaie en sécurité", + "nanogpt_subtitle": "Tous les modèles les plus récents (GPT-4, Claude).\nPas d'abonnement, payez avec vos crypto-monnaies.", + "narrow": "Rédruit", + "new_first_wallet_text": "Garder vos crypto-monnaies en sécurité est un jeu d'enfant.", "new_node_testing": "Test du nouveau nœud", "new_subaddress_create": "Créer", "new_subaddress_label_name": "Nom", @@ -456,7 +469,7 @@ "note_optional": "Note (optionnelle)", "note_tap_to_change": "Note (appuyez pour changer)", "nullURIError": "L'URI est nul", - "offer_expires_in": "L'Offre expire dans : ", + "offer_expires_in": "L'Offre expire dans: ", "offline": "Hors ligne", "ok": "OK", "old_fee": "Anciens", @@ -464,6 +477,7 @@ "online": "En ligne", "onramper_option_description": "Achetez rapidement des cryptomonnaies avec de nombreuses méthodes de paiement. Disponible dans la plupart des pays. Les spreads et les frais peuvent varier.", "open_gift_card": "Ouvrir la carte-cadeau", + "open_wallet": "Portefeuille ouvert", "optional_description": "Descriptif facultatif", "optional_email_hint": "E-mail de notification du bénéficiaire facultatif", "optional_name": "Nom du destinataire facultatif", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Si ce portefeuille (wallet) a une phrase secrète (seed) de 12 mots et a été créé dans Cake, NE PAS y déposer de Bitcoin. Tous les BTC transférés vers ce portefeuille seront perdus. Créez un nouveau portefeuille avec phrase secrète de 24 mots (appuyez sur le menu en haut à droite, sélectionnez Portefeuilles puis Créer un Nouveau Portefeuille et enfin Bitcoin) et transférez y IMMÉDIATEMENT vos BTC. Les nouveaux portefeuilles BTC Cake (avec phrase secrète de 24 mots) sont sécurisés", "outgoing": "Sortantes", "outputs": "Les sorties", + "overshot": "Surnommer", "overwrite_amount": "Remplacer le montant", "pairingInvalidEvent": "Événement de couplage non valide", "passphrase": "Phrase de passe (facultative)", @@ -514,7 +529,7 @@ "private_key": "Clef privée", "proceed_after_one_minute": "Si l'écran ne s'affiche pas après 1 minute, vérifiez vos e-mails.", "proceed_on_device": "Continuez sur votre appareil", - "proceed_on_device_description": "Veuillez suivre les instructions invitées sur votre portefeuille matériel", + "proceed_on_device_description": "Veuillez suivre les instructions affichées sur votre portefeuille physique.", "profile": "Profil", "provider_error": "Erreur de ${provider}", "public_key": "Clef publique", @@ -531,9 +546,10 @@ "recipient_address": "Adresse bénéficiaire", "reconnect": "Reconnecter", "reconnect_alert_text": "Êtes vous certain de vouloir vous reconnecter ?", + "reconnect_your_hardware_wallet": "Reconnectez votre portefeuille matériel", "reconnection": "Reconnexion", - "red_dark_theme": "Thème rouge noir", - "red_light_theme": "Thème de la lumière rouge", + "red_dark_theme": "Thème rouge sombre", + "red_light_theme": "Thème rouge clair", "redeemed": "Converties", "refund_address": "Adresse de Remboursement", "reject": "Rejeter", @@ -564,12 +580,13 @@ "restore_address": "Adresse", "restore_bitcoin_description_from_keys": "Restaurer votre portefeuille (wallet) d'après la chaîne WIF générée d'après vos clefs privées", "restore_bitcoin_description_from_seed": "Restaurer votre portefeuille (wallet) à l'aide d'une phrase secrète (seed) de 24 mots", - "restore_bitcoin_title_from_keys": "Restaurer depuis la chaîne WIF", + "restore_bitcoin_title_from_keys": "Restaurer à partir de WIF", "restore_description_from_backup": "Vous pouvez restaurer l'intégralité de l'application Cake Wallet depuis un fichier de sauvegarde", - "restore_description_from_hardware_wallet": "Restaurer à partir d'un portefeuille matériel de grand livre", + "restore_description_from_hardware_wallet": "Restaurer depuis un portefeuille matériel Ledger", "restore_description_from_keys": "Restaurer votre portefeuille (wallet) d'après les séquences de touches générées d'après vos clefs privées", "restore_description_from_seed": "Restaurer votre portefeuille (wallet) depuis une phrase secrète (seed) de 25 ou 13 mots", "restore_description_from_seed_keys": "Restaurez votre portefeuille (wallet) depuis une phrase secrète (seed) ou des clefs que vous avez stockées en lieu sûr", + "restore_existing_wallet": "Restaurer le portefeuille existant", "restore_from_date_or_blockheight": "Merci d'entrer une date antérieure de quelques jours à la date de création de votre portefeuille (wallet). Ou si vous connaissez la hauteur de bloc, merci de la spécifier plutôt qu'une date", "restore_from_seed_placeholder": "Merci d'entrer ou de coller votre phrase secrète (seed) ici", "restore_new_seed": "Nouvelle phrase secrète (seed)", @@ -611,6 +628,7 @@ "seed_alert_title": "Attention", "seed_alert_yes": "Oui, je suis sûr", "seed_choose": "Choisissez la langue de la phrase secrète (seed)", + "seed_display_path": "Menu -> Sécurité et sauvegarde -> Afficher la clé / les graines", "seed_hex_form": "Graine du portefeuille (forme hexagonale)", "seed_key": "Clé secrète (seed key)", "seed_language": "Langage de la phrase secrète", @@ -629,13 +647,17 @@ "seed_language_russian": "Russe", "seed_language_spanish": "Espagnol", "seed_phrase_length": "Longueur de la phrase de départ", + "seed_position_question_one": "Qu'est-ce que le", + "seed_position_question_two": "mot de votre phrase de semence?", "seed_reminder": "Merci d'écrire votre phrase secrète (seed) au cas où vous perdriez ou effaceriez votre téléphone", "seed_share": "Partager la phrase secrète (seed)", "seed_title": "Phrase secrète (seed)", - "seedtype": "Type de type graine", - "seedtype_alert_content": "Le partage de graines avec d'autres portefeuilles n'est possible qu'avec Bip39 SeedType.", - "seedtype_alert_title": "Alerte de type SeedType", - "seedtype_legacy": "Héritage (25 mots)", + "seed_verified": "Graine vérifiée", + "seed_verified_subtext": "Vous pouvez utiliser votre graine enregistrée plus tard pour restaurer ce portefeuille en cas de corruption ou de perdre votre appareil. \n\n Vous pouvez revoir cette graine à partir du", + "seedtype": "Type de graine", + "seedtype_alert_content": "Le partage de graines avec d'autres portefeuilles n'est possible qu'avec le type de graine BIP39.", + "seedtype_alert_title": "Alerte Type de Graine", + "seedtype_legacy": "Legacy (25 words)", "seedtype_polyseed": "Polyseed (16 mots)", "seedtype_wownero": "WOWNERO (14 mots)", "select_backup_file": "Sélectionnez le fichier de sauvegarde", @@ -648,13 +670,13 @@ "sell_monero_com_alert_content": "La vente de Monero n'est pas encore prise en charge", "send": "Envoyer", "send_address": "adresse ${cryptoCurrency}", - "send_amount": "Montant :", + "send_amount": "Montant:", "send_change_to_you": "Changer, pour vous:", "send_creating_transaction": "Création de la transaction", "send_error_currency": "La monnaie ne peut contenir que des nombres", "send_error_minimum_value": "La valeur minimale du montant est 0.01", "send_estimated_fee": "Estimation des frais :", - "send_fee": "Frais :", + "send_fee": "Frais:", "send_name": "Nom", "send_new": "Nouveau", "send_payment_id": "ID de paiement (optionnel)", @@ -668,8 +690,9 @@ "send_your_wallet": "Votre portefeuille (wallet)", "sending": "Envoi", "sent": "Envoyés", - "service_health_disabled": "Le bulletin de santé du service est handicapé", + "service_health_disabled": "Le bulletin de santé du service est désactivé.", "service_health_disabled_message": "Ceci est la page du Bulletin de santé du service, vous pouvez activer cette page sous Paramètres -> Confidentialité", + "set_a_pin": "Définir un code PIN", "settings": "Paramètres", "settings_all": "TOUT", "settings_allow_biometrical_authentication": "Autoriser l'authentification biométrique", @@ -699,12 +722,13 @@ "setup_pin": "Configurer le code PIN", "setup_successful": "Votre code PIN a été configuré avec succès !", "setup_totp_recommended": "Configurer TOTP", - "setup_warning_2fa_text": "Vous devrez restaurer votre portefeuille à partir de la graine mnémonique.\n\nLe support Cake ne pourra pas vous aider si vous perdez l'accès à vos graines 2FA ou mnémoniques.\nCake 2FA est une seconde authentification pour certaines actions dans le portefeuille. Avant d'utiliser Cake 2FA, nous vous recommandons de lire le guide.Ce n’est PAS aussi sécurisé que l’entreposage frigorifique.\n\nSi vous perdez l'accès à votre application 2FA ou à vos clés TOTP, vous perdrez l'accès à ce portefeuille. ", + "setup_warning_2fa_text": "Vous devrez restaurer votre portefeuille à partir de la graine mnémotechnique.\n\nLe support Cake ne pourra pas vous aider si vous perdez l'accès à vos graines 2FA ou mnémotechniques.\nCake 2FA est une seconde authentification pour certaines actions dans le portefeuille. Avant d'utiliser Cake 2FA, nous vous recommandons de lire le guide.Ce n’est PAS aussi sécurisé que l’entreposage frigorifique.\n\nSi vous perdez l'accès à votre application 2FA ou à vos clés TOTP, vous perdrez l'accès à ce portefeuille. ", "setup_your_debit_card": "Configurer votre carte de débit", "share": "Partager", "share_address": "Partager l'adresse", "shared_seed_wallet_groups": "Groupes de portefeuilles partagés", "show": "Montrer", + "show_address_book_popup": "Afficher la popup `` Ajouter au carnet d'adresses '' après avoir envoyé", "show_details": "Afficher les détails", "show_keys": "Visualiser la phrase secrète (seed) et les clefs", "show_market_place": "Afficher la place de marché", @@ -727,15 +751,19 @@ "silent_payments_scan_from_date": "Analyser à partir de la date", "silent_payments_scan_from_date_or_blockheight": "Veuillez saisir la hauteur du bloc que vous souhaitez commencer à scanner pour les paiements silencieux entrants, ou utilisez la date à la place. Vous pouvez choisir si le portefeuille continue de numériser chaque bloc ou ne vérifie que la hauteur spécifiée.", "silent_payments_scan_from_height": "Scan à partir de la hauteur du bloc", - "silent_payments_scanned_tip": "Scanné à la pointe! (${tip})", - "silent_payments_scanning": "Payments silencieux SCANNING", + "silent_payments_scanned_tip": "SCANNEZ POUR DONNER ! (${tip})", + "silent_payments_scanning": "Scan des paiements silencieux", "silent_payments_settings": "Paramètres de paiement silencieux", "single_seed_wallets_group": "Portefeuilles de semences simples", "slidable": "Glissable", + "solana_create_associated_token_account_exception": "Création d'erreur Création de jetons associés pour l'adresse détenue.", + "solana_no_associated_token_account_exception": "Il n'y a pas de compte de jeton associé pour cette adresse.", + "solana_sign_native_transaction_rent_exception": "La transaction ne peut pas être terminée. Sol insuffisant laissé à la location après la transaction. Veuillez compléter votre solde SOL ou réduire la quantité de Sol que vous envoyez.", + "solana_sign_spl_token_transaction_rent_exception": "La transaction ne peut pas être terminée. Sol insuffisant laissé à la location après la transaction. Veuillez compléter votre solde de Sol.", "sort_by": "Trier par", "spend_key_private": "Clef de dépense (spend key) (privée)", "spend_key_public": "Clef de dépense (spend key) (publique)", - "status": "Statut : ", + "status": "Statut: ", "string_default": "Défaut", "subaddress_title": "Liste des sous-adresses", "subaddresses": "Sous-adresses", @@ -744,11 +772,11 @@ "support_description_guides": "Documentation et support pour les problèmes communs", "support_description_live_chat": "GRATUIT ET RAPIDE ! Des représentants de soutien formé sont disponibles pour aider", "support_description_other_links": "Rejoignez nos communautés ou contactez-nous ou nos partenaires à travers d'autres méthodes", - "support_title_guides": "Guides de Cake Wallet", + "support_title_guides": "Docs de portefeuille à gâteau", "support_title_live_chat": "Support en direct", "support_title_other_links": "Autres liens d'assistance", "sweeping_wallet": "Portefeuille (wallet) de consolidation", - "sweeping_wallet_alert": "Cette opération ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN OU LES FONDS CONSOLIDÉS POURRAIENT ÊTRE PERDUS", + "sweeping_wallet_alert": "Cela ne devrait pas prendre longtemps. NE QUITTEZ PAS CET ÉCRAN OU LES FONDS TRANSFÉRÉS POURRAIENT ÊTRE PERDUS.", "switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer", "switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)", "symbol": "Symbole", @@ -775,7 +803,7 @@ "thorchain_contract_address_not_supported": "Thorchain ne prend pas en charge l'envoi à une adresse de contrat", "thorchain_taproot_address_not_supported": "Le fournisseur de Thorchain ne prend pas en charge les adresses de tapoot. Veuillez modifier l'adresse ou sélectionner un autre fournisseur.", "time": "${minutes}m ${seconds}s", - "tip": "Pourboire :", + "tip": "Pourboire:", "today": "Aujourd'hui", "token_contract_address": "Adresse du contrat de token", "token_decimal": "Décimales de token", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Sous payé", "trade_state_unpaid": "Non payé", "trades": "Échanges", + "transaction_cost": "Coût de la transaction", "transaction_details_amount": "Montant", "transaction_details_copied": "${title} copié vers le presse-papier", "transaction_details_date": "Date", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Cette paire variable n'est pas prise en charge avec les échanges sélectionnés", "verification": "Vérification", "verify_message": "Vérifier le message", + "verify_seed": "Vérifiez les semences", "verify_with_2fa": "Vérifier avec Cake 2FA", "version": "Version ${currentVersion}", "view_all": "Voir tout", @@ -891,6 +921,7 @@ "view_transaction_on": "Voir la Transaction sur ", "voting_weight": "Poids de vote", "waitFewSecondForTxUpdate": "Veuillez attendre quelques secondes pour que la transaction soit reflétée dans l'historique des transactions.", + "wallet": "Portefeuille", "wallet_group": "Groupe de portefeuille", "wallet_group_description_four": "Pour créer un portefeuille avec une graine entièrement nouvelle.", "wallet_group_description_one": "Dans Cake Wallet, vous pouvez créer un", @@ -920,9 +951,11 @@ "wallet_seed_legacy": "Graine de portefeuille hérité", "wallet_store_monero_wallet": "Portefeuille (Wallet) Monero", "walletConnect": "WalletConnect", - "wallets": "Portefeuilles (Wallets)", + "wallets": "Portefeuilles", "warning": "Avertissement", "welcome": "Bienvenue sur", + "welcome_subtitle_new_wallet": "Si vous souhaitez repartir de zéro, appuyez sur Créer un nouveau portefeuille ci-dessous et vous serez prêt à commencer.", + "welcome_subtitle_restore_wallet": "Si vous avez un portefeuille existant que vous souhaitez importer dans Cake, choisissez simplement Restaurer un portefeuille existant et nous vous guiderons à travers le processus.", "welcome_to_cakepay": "Bienvenue sur Cake Pay !", "what_is_silent_payments": "Qu'est-ce que les paiements silencieux?", "widgets_address": "Adresse", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 5f34b0391..fbe8257f4 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -38,6 +38,7 @@ "agree_to": "Ta hanyar ƙirƙirar asusu kun yarda da", "alert_notice": "Sanarwa", "all": "DUK", + "all_coins": "Duk tsabar kudi", "all_trades": "Duk ciniki", "all_transactions": "Dukan Ma'amaloli", "alphabetical": "Harafi", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Sayi katunan shirye-shiryen duniya da katunan kyauta", "cake_pay_web_cards_subtitle": "Sayi katunan da aka riga aka biya na duniya da katunan kyauta", "cake_pay_web_cards_title": "Cake Pay Web Cards", + "cake_seeds_save_disclaimer": "Da fatan za a ceci waɗannan kalmomin a cikin amintaccen wuri! Kuna buƙatar waɗannan kalmomin don dawo da walat ɗinku a kan sabon na'ura.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Na tabbatar ba na amfani da wakili ko VPN", + "cakepay_confirm_purchase": "Tabbatar da sayan", + "cakepay_confirm_terms_agreed": "Na yarda da sharuɗɗan da sharuɗɗan da aka gabatar anan:", + "cakepay_confirm_voided_refund": "Na fahimci fansa daga ƙasar da aka ƙuntata ba za ta yi amfani da wani maida ba", + "cakepay_ios_not_available": "Yi haƙuri, wannan katin kyautar ba a samuwa akan iOS. Kuna iya sayan shi a kan Android ko ta yanar gizo a maimakon.", "cakepay_prepaid_card": "Katin zare kudi na CakePay", "camera_consent": "Za a yi amfani da kyamarar ku don ɗaukar hoto don dalilai na tantancewa ta ${provider}. Da fatan za a duba Manufar Sirri don cikakkun bayanai.", "camera_permission_is_required": "Ana buƙatar izinin kyamara.\nDa fatan za a kunna shi daga saitunan app.", @@ -175,6 +182,7 @@ "copy_address": "Kwafi Adireshin", "copy_id": "Kwafi ID", "copyWalletConnectLink": "Kwafi hanyar haɗin WalletConnect daga dApp kuma liƙa a nan", + "corrupted_seed_notice": "Fayilolin don wannan walat ɗin sun lalata kuma ba za a iya buɗe su ba. Da fatan za a duba kalmar iri, adana shi, da dawo da walat.\n\nIdan darajar ta kasance fanko, to sai zuriyar da ba ta iya murmurewa daidai ba.", "countries": "Kasashe", "create_account": "Kirkira ajiya", "create_backup": "Ƙirƙiri madadin", @@ -256,7 +264,7 @@ "enterTokenID": "Shigar da alamar alama", "enterWalletConnectURI": "Shigar da WalletConnect URI", "error": "Kuskure", - "error_dialog_content": "Ai, yanzu muka ga alamar kuskure. \n\nDa fatan, aika rahoton kuskuren da muka kira zuwa gasar tsarinmu don gaskiyar shirya.", + "error_dialog_content": "Oops, mun sami kuskure.\n\nDon Allah a aika rahoton kuskuren zuwa ga ƙungiyar goyon bayanmu don yin aikace-aikacen da kyau.", "error_text_account_name": "Sunan ajiya zai iya ɗauka ne kawai da haruffa, lambobi\nkuma ya zama tsakanin 1 zuwa 15 haruffa", "error_text_address": "Adireshin hujja ya kamata ya dace da irin\nna cryptocurrency", "error_text_amount": "Adadin biya zai iya ƙunsar lambobi kawai", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Tambayoyin da ake yawan yi", "frozen": "Daskararre", "full_balance": "DUKAN KUDI", + "gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.", "generate_name": "Ƙirƙirar Suna", "generating_gift_card": "Samar da Katin Kyauta", "get_a": "Samu a", @@ -350,13 +359,17 @@ "how_to_use": "Yadda ake amfani da shi", "how_to_use_card": "Yadda ake amfani da wannan kati", "id": "ID:", + "if_you_dont_see_your_device": "Idan baku ga na'urarka da ke sama ba, da fatan za a tabbata Ledger dinku yana farkawa kuma a buɗe!", "ignor": "Yi watsi da shi", "import": "Shigo da", "importNFTs": "Shigo da NFTs", "in_store": "A cikin Store", "incoming": "Mai shigowa", "incorrect_seed": "rubutun da aka shigar ba shi da inganci.", + "incorrect_seed_option": "Ba daidai ba. Da fatan za a sake gwadawa", + "incorrect_seed_option_back": "Ba daidai ba. Da fatan za a tabbatar da zuriyar ku an ajiye daidai kuma a sake gwadawa.", "inputs": "Abubuwan da ke ciki", + "insufficient_funds_for_tx": "Rashin isasshen kuɗi don aiwatar da ma'amala.", "insufficient_lamport_for_tx": "Ba ku da isasshen sool don rufe ma'amala da kuɗin ma'amala. Da unara ƙara ƙarin sool a cikin walat ɗinku ko rage adadin Sol ɗin da kuke aikawa.", "insufficient_lamports": "Ba ku da isasshen sool don rufe ma'amala da kuɗin ma'amala. Kuna buƙatar aƙalla ${solValueNeeded} Sol. Da kyau ƙara ƙarin sool zuwa walat ɗinku ko rage adadin Sol ɗin da kuke aikawa", "insufficientFundsForRentError": "Ba ku da isasshen Sol don rufe kuɗin ma'amala da haya don asusun. Da kyau ƙara ƙarin sool zuwa walat ɗinku ko rage adadin Sol ɗin da kuke aikawa", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Dauki sabon wakili", "nanogpt_subtitle": "Duk sabbin samfuran (GPT-4, CLODE). \\ NNO biyan kuɗi, biya tare da crypto.", "narrow": "kunkuntar", - "new_first_wallet_text": "A sauƙaƙe kiyaye kuzarin ku", + "new_first_wallet_text": "Tsayawa kayatar da lafiya", "new_node_testing": "Sabbin gwajin kumburi", "new_subaddress_create": "Ƙirƙiri", "new_subaddress_label_name": "Lakabin suna", @@ -464,6 +477,7 @@ "online": "Kan layi", "onramper_option_description": "Da sauri sayi Crypto tare da hanyoyin biyan kuɗi da yawa. Akwai a yawancin ƙasashe. Yaduwa da kudade sun bambanta.", "open_gift_card": "Bude Katin Kyauta", + "open_wallet": "Bude Wadda", "openalias_alert_content": "Zaka aika kuɗi zuwa \n${recipient_name}", "openalias_alert_title": "An gano adireshin", "optional_description": "Bayanin zai iya ba da maki", @@ -479,6 +493,7 @@ "outdated_electrum_wallet_receive_warning": "Idan wannan walat ɗin yana da nau'in kalma 12 kuma an ƙirƙira shi a cikin Cake, KAR KA saka Bitcoin cikin wannan jakar. Duk wani BTC da aka canjawa wuri zuwa wannan walat na iya ɓacewa. Ƙirƙiri sabon walat mai kalmomi 24 (matsa menu a saman dama, zaɓi Wallets, zaɓi Ƙirƙiri Sabon Wallet, sannan zaɓi Bitcoin) kuma NAN nan take matsar da BTC ɗin ku a can. Sabbin (kalmomi 24) BTC wallets daga Cake suna da tsaro", "outgoing": "Mai fita", "outputs": "Abubuwan fashewa", + "overshot": "Oveshot", "overwrite_amount": "Rubuta adadin", "pairingInvalidEvent": "Haɗa Lamarin mara inganci", "passphrase": "Passphrase (Zabi)", @@ -533,6 +548,7 @@ "recipient_address": "Adireshin mai karɓa", "reconnect": "Sake haɗawa", "reconnect_alert_text": "Shin kun tabbata kuna son sake haɗawa?", + "reconnect_your_hardware_wallet": "Sake kunnawa kayan aiki", "reconnection": "Sake haɗawa", "red_dark_theme": "Ja duhu taken", "red_light_theme": "Ja mai haske", @@ -572,6 +588,7 @@ "restore_description_from_keys": "Maido da walat ɗin ku daga maɓallan maɓalli da aka ƙera da aka ajiye daga maɓallan ku na sirri", "restore_description_from_seed": "Dawo da kwalinku daga 25 ko 13 lambar haɗin kalma", "restore_description_from_seed_keys": "Maido da walat ɗin ku daga iri/maɓallan da kuka adana don amintaccen wuri", + "restore_existing_wallet": "Dawo da walat ɗin da yake", "restore_from_date_or_blockheight": "Don Allah shigar da wata kwanan a kafin ku ƙirƙirar wannan kwalinku. Ko idan kun san blockheight, don Allah shigar da shi", "restore_from_seed_placeholder": "Da fatan za a shigar da ko manna maɓallin ku a nan", "restore_new_seed": "Sabon iri", @@ -613,6 +630,7 @@ "seed_alert_title": "Hankali", "seed_alert_yes": "E, Na yi", "seed_choose": "Zaɓi harshen seed", + "seed_display_path": "Ming menu -> Tsaro da Ajiyayyen -> Kaben Now / Duri", "seed_hex_form": "Gany Sero (form form)", "seed_key": "Maɓallin iri", "seed_language": "Harshen Magani", @@ -631,9 +649,13 @@ "seed_language_russian": "Rashanci", "seed_language_spanish": "Spanish", "seed_phrase_length": "Tsawon jimlar iri", + "seed_position_question_one": "Menene", + "seed_position_question_two": "Maganar Je'in Seedhniyarka?", "seed_reminder": "Don Allah rubuta wadannan in case ka manta ko ka sake kwallon wayarka", "seed_share": "Raba iri", "seed_title": "iri", + "seed_verified": "Iri", + "seed_verified_subtext": "Kuna iya amfani da zuriyar da kuka tsira daga baya don mayar da wannan walat ɗin a lokacin da ya faru na cin hanci da rashawa ko rasa na'urarka. \n\n Za ku iya duba wannan iri ɗin kuma daga", "seedtype": "Seedtype", "seedtype_alert_content": "Raba tsaba tare da sauran wallets yana yiwuwa ne kawai tare da Bip39 seedtype.", "seedtype_alert_title": "Seedtype farke", @@ -672,6 +694,7 @@ "sent": "Aika", "service_health_disabled": "Ba a kashe Bayar da Kiwon Lafiya", "service_health_disabled_message": "Wannan shafin yanar gizo mai kula da sabis ne, zaka iya kunna wannan shafin a karkashin saiti -> Sirri", + "set_a_pin": "Saita PIN", "settings": "Saiti", "settings_all": "DUK", "settings_allow_biometrical_authentication": "Bada izinin tantance sawun yatsa", @@ -707,6 +730,7 @@ "share_address": "Raba adireshin", "shared_seed_wallet_groups": "Raba ƙungiya walat", "show": "Nuna", + "show_address_book_popup": "Nuna 'ƙara don magance littafin' Popup bayan aikawa", "show_details": "Nuna Cikakkun bayanai", "show_keys": "Nuna iri/maɓallai", "show_market_place": "Nuna dan kasuwa", @@ -734,6 +758,10 @@ "silent_payments_settings": "Saitunan Silent", "single_seed_wallets_group": "Guaro", "slidable": "Mai iya zamewa", + "solana_create_associated_token_account_exception": "Kuskuren ƙirƙirar asusun Asusun da aka danganta don Adireshin karɓar karɓa.", + "solana_no_associated_token_account_exception": "Babu wani haɗin yanar gizo mai alaƙa don wannan adireshin.", + "solana_sign_native_transaction_rent_exception": "Ma'amala ba za a iya kammala ba. Rashin cancanta na Sol ya bar haya bayan ma'amala. Da kyau a saman ma'auni na Solku ko rage adadin Sol da kuke aikawa.", + "solana_sign_spl_token_transaction_rent_exception": "Ma'amala ba za a iya kammala ba. Rashin cancanta na Sol ya bar haya bayan ma'amala. Da kyau sama da ma'auni na Sol.", "sort_by": "Kasa", "spend_key_private": "makullin biya (maɓallin kalmar sirri)", "spend_key_public": "makullin biya (maɓallin jama'a)", @@ -746,7 +774,7 @@ "support_description_guides": "Tallafi da tallafi don batutuwa na yau da kullun", "support_description_live_chat": "Kyauta da sauri! An horar da wakilan tallafi na tallafi don taimakawa", "support_description_other_links": "Kasance tare da al'ummominmu ko kuma ka kai mu abokanmu ta hanyar wasu hanyoyi", - "support_title_guides": "Jagorar Cake", + "support_title_guides": "Docs Bakin", "support_title_live_chat": "Tallafi na Live", "support_title_other_links": "Sauran hanyoyin tallafi", "sweeping_wallet": "Kashi na kasa", @@ -825,6 +853,7 @@ "trade_state_underpaid": "ba a biya gaba ɗaya ba", "trade_state_unpaid": "ba a biya ba", "trades": "Cinikai", + "transaction_cost": "Kudin kasuwanci", "transaction_details_amount": "Adadin", "transaction_details_copied": "${title} an kwafa zuwa cikin kwafin", "transaction_details_date": "Kwanan wata", @@ -884,6 +913,7 @@ "variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar", "verification": "tabbatar", "verify_message": "Tabbatar saƙon", + "verify_seed": "Tabbatar zuriya", "verify_with_2fa": "Tabbatar da Cake 2FA", "version": "Sigar ${currentVersion}", "view_all": "Duba duka", @@ -893,6 +923,7 @@ "view_transaction_on": "Dubo aikace-aikacen akan", "voting_weight": "Nauyi mai nauyi", "waitFewSecondForTxUpdate": "Da fatan za a jira ƴan daƙiƙa don ciniki don yin tunani a tarihin ma'amala", + "wallet": "Zabira", "wallet_group": "Wallet kungiyar", "wallet_group_description_four": "Don ƙirƙirar walat tare da sabon iri.", "wallet_group_description_one": "A cikin walat walat, zaka iya ƙirƙirar", @@ -925,6 +956,8 @@ "wallets": "Wallets", "warning": "Gargadi", "welcome": "Barka da zuwa", + "welcome_subtitle_new_wallet": "Idan kana son farawa sabo ne, matsa Newirƙiri Sabuwar Wallow a ƙasa kuma za ka tafi da tsere.", + "welcome_subtitle_restore_wallet": "Idan kuna da walat ɗin da kuke son shigo da cake, kawai zaɓi a cikin walat ɗin da yake ciki kuma za mu bi ku ta hanyar aiwatarwa.", "welcome_to_cakepay": "Barka da zuwa Cake Pay!", "what_is_silent_payments": "Menene biyan shiru?", "widgets_address": "Adireshin", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 21e030ad6..ce13b2e2a 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -38,6 +38,7 @@ "agree_to": "खाता बनाकर आप इससे सहमत होते हैं ", "alert_notice": "सूचना", "all": "सब", + "all_coins": "सभी सिक्के", "all_trades": "सभी व्यापार", "all_transactions": "सभी लेन - देन", "alphabetical": "वर्णमाला", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "दुनिया भर में प्रीपेड कार्ड और उपहार कार्ड खरीदें", "cake_pay_web_cards_subtitle": "दुनिया भर में प्रीपेड कार्ड और गिफ्ट कार्ड खरीदें", "cake_pay_web_cards_title": "केक भुगतान वेब कार्ड", + "cake_seeds_save_disclaimer": "कृपया इन शब्दों को सुरक्षित स्थान पर सहेजें! एक नए डिवाइस पर अपने बटुए को पुनर्स्थापित करने के लिए आपको इन शब्दों की आवश्यकता होगी।", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "मैं पुष्टि करता हूं कि मैं एक प्रॉक्सी या वीपीएन का उपयोग नहीं कर रहा हूं", + "cakepay_confirm_purchase": "खरीद की पुष्टि करें", + "cakepay_confirm_terms_agreed": "मैं यहां प्रस्तुत नियमों और शर्तों से सहमत हूं:", + "cakepay_confirm_voided_refund": "मैं समझता हूं कि एक प्रतिबंधित देश से मोचन प्रयास किसी भी धनवापसी को शून्य कर देंगे", + "cakepay_ios_not_available": "क्षमा करें, यह उपहार कार्ड iOS पर उपलब्ध नहीं है। आप इसे Android पर या हमारी वेबसाइट के बजाय खरीद सकते हैं।", "cakepay_prepaid_card": "केकपे प्रीपेड डेबिट कार्ड", "camera_consent": "आपके कैमरे का उपयोग ${provider} द्वारा पहचान उद्देश्यों के लिए एक छवि कैप्चर करने के लिए किया जाएगा। विवरण के लिए कृपया उनकी गोपनीयता नीति जांचें।", "camera_permission_is_required": "कैमरे की अनुमति आवश्यक है.\nकृपया इसे ऐप सेटिंग से सक्षम करें।", @@ -175,6 +182,7 @@ "copy_address": "पता कॉपी करें", "copy_id": "प्रतिलिपि ID", "copyWalletConnectLink": "dApp से वॉलेटकनेक्ट लिंक को कॉपी करें और यहां पेस्ट करें", + "corrupted_seed_notice": "इस वॉलेट की फाइलें दूषित हैं और उन्हें खोलने में असमर्थ हैं। कृपया बीज वाक्यांश देखें, इसे बचाएं, और बटुए को पुनर्स्थापित करें।\n\nयदि मूल्य खाली है, तो बीज सही ढंग से पुनर्प्राप्त करने में असमर्थ था।", "countries": "देशों", "create_account": "खाता बनाएं", "create_backup": "बैकअप बनाएँ", @@ -256,7 +264,7 @@ "enterTokenID": "टोकन आईडी दर्ज करें", "enterWalletConnectURI": "वॉलेटकनेक्ट यूआरआई दर्ज करें", "error": "त्रुटि", - "error_dialog_content": "ओह, हमसे कुछ गड़बड़ी हुई है.\n\nएप्लिकेशन को बेहतर बनाने के लिए कृपया क्रैश रिपोर्ट हमारी सहायता टीम को भेजें।", + "error_dialog_content": "उफ़, हमें कुछ त्रुटि मिली।\n\nकृपया आवेदन को बेहतर बनाने के लिए हमारी सहायता टीम को त्रुटि रिपोर्ट भेजें।", "error_text_account_name": "खाता नाम में केवल अक्षर, संख्याएं हो सकती हैं\nऔर 1 और 15 वर्णों के बीच लंबा होना चाहिए", "error_text_address": "वॉलेट पता प्रकार के अनुरूप होना चाहिए\nक्रिप्टोकरेंसी का", "error_text_amount": "राशि में केवल संख्याएँ हो सकती हैं", @@ -323,6 +331,7 @@ "frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न", "frozen": "जमा हुआ", "full_balance": "पूर्ण संतुलन", + "gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।", "generate_name": "नाम जनरेट करें", "generating_gift_card": "गिफ्ट कार्ड जनरेट कर रहा है", "get_a": "एक प्राप्त करें", @@ -350,13 +359,17 @@ "how_to_use": "का उपयोग कैसे करें", "how_to_use_card": "इस कार्ड का उपयोग कैसे करें", "id": "ID: ", + "if_you_dont_see_your_device": "यदि आप अपने डिवाइस को ऊपर नहीं देखते हैं, तो कृपया सुनिश्चित करें कि आपका लेजर जागृत और अनलॉक हो गया है!", "ignor": "नज़रअंदाज़ करना", "import": "आयात", "importNFTs": "एनएफटी आयात करें", "in_store": "स्टोर में", "incoming": "आने वाली", "incorrect_seed": "दर्ज किया गया पाठ मान्य नहीं है।", + "incorrect_seed_option": "गलत। कृपया पुन: प्रयास करें", + "incorrect_seed_option_back": "गलत। कृपया सुनिश्चित करें कि आपका बीज सही तरीके से बच गया है और फिर से प्रयास करें।", "inputs": "इनपुट", + "insufficient_funds_for_tx": "लेनदेन को सफलतापूर्वक निष्पादित करने के लिए अपर्याप्त धन।", "insufficient_lamport_for_tx": "आपके पास लेनदेन और इसके लेनदेन शुल्क को कवर करने के लिए पर्याप्त सोल नहीं है। कृपया अपने बटुए में अधिक सोल जोड़ें या आपके द्वारा भेजे जा रहे सोल राशि को कम करें।", "insufficient_lamports": "आपके पास लेनदेन और इसके लेनदेन शुल्क को कवर करने के लिए पर्याप्त सोल नहीं है। आपको कम से कम ${solValueNeeded} सोल की आवश्यकता है। कृपया अपने बटुए में अधिक सोल जोड़ें या सोल राशि को कम करें जिसे आप भेज रहे हैं", "insufficientFundsForRentError": "आपके पास लेन -देन शुल्क और खाते के लिए किराए को कवर करने के लिए पर्याप्त सोल नहीं है। कृपया अपने बटुए में अधिक सोल जोड़ें या सोल राशि को कम करें जिसे आप भेज रहे हैं", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "एक नया प्रतिनिधि चुनें", "nanogpt_subtitle": "सभी नवीनतम मॉडल (GPT-4, क्लाउड)। \\ nno सदस्यता, क्रिप्टो के साथ भुगतान करें।", "narrow": "सँकरा", - "new_first_wallet_text": "आसानी से अपनी क्रिप्टोक्यूरेंसी को सुरक्षित रखें", + "new_first_wallet_text": "अपने क्रिप्टो को सुरक्षित रखना केक का एक टुकड़ा है", "new_node_testing": "नई नोड परीक्षण", "new_subaddress_create": "सर्जन करना", "new_subaddress_label_name": "लेबल का नाम", @@ -464,6 +477,7 @@ "online": "ऑनलाइन", "onramper_option_description": "जल्दी से कई भुगतान विधियों के साथ क्रिप्टो खरीदें। अधिकांश देशों में उपलब्ध है। फैलता है और फीस अलग -अलग होती है।", "open_gift_card": "गिफ्ट कार्ड खोलें", + "open_wallet": "खुला बटुआ", "optional_description": "वैकल्पिक विवरण", "optional_email_hint": "वैकल्पिक प्राप्तकर्ता सूचना ईमेल", "optional_name": "वैकल्पिक प्राप्तकर्ता नाम", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "अगर इस वॉलेट में 12 शब्दों का बीज है और इसे केक में बनाया गया है, तो इस वॉलेट में बिटकॉइन जमा न करें। इस वॉलेट में स्थानांतरित किया गया कोई भी बीटीसी खो सकता है। एक नया 24-शब्द वॉलेट बनाएं (ऊपर दाईं ओर स्थित मेनू पर टैप करें, वॉलेट चुनें, नया वॉलेट बनाएं चुनें, फिर बिटकॉइन चुनें) और तुरंत अपना बीटीसी वहां ले जाएं। केक से नए (24-शब्द) बीटीसी वॉलेट सुरक्षित हैं", "outgoing": "निवर्तमान", "outputs": "आउटपुट", + "overshot": "कम पड़ गया", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना", "passphrase": "पासफ्रेज़ (वैकल्पिक)", @@ -533,6 +548,7 @@ "recipient_address": "प्राप्तकर्ता का पता", "reconnect": "रिकनेक्ट", "reconnect_alert_text": "क्या आप पुन: कनेक्ट होना सुनिश्चित करते हैं?", + "reconnect_your_hardware_wallet": "अपने हार्डवेयर वॉलेट को फिर से कनेक्ट करें", "reconnection": "पुनर्संयोजन", "red_dark_theme": "लाल डार्क थीम", "red_light_theme": "लाल प्रकाश थीम", @@ -572,6 +588,7 @@ "restore_description_from_keys": "अपने वॉलेट को जेनरेट से पुनर्स्थापित करें आपकी निजी कुंजी से कीस्ट्रोक्स सहेजे गए", "restore_description_from_seed": "या तो 25 शब्द से अपने वॉलेट को पुनर्स्थापित करें या 13 शब्द संयोजन कोड", "restore_description_from_seed_keys": "अपने बटुए को बीज से वापस लें/वे कुंजियाँ जिन्हें आपने सुरक्षित स्थान पर सहेजा है", + "restore_existing_wallet": "मौजूदा बटुए को पुनर्स्थापित करें", "restore_from_date_or_blockheight": "कृपया इस वॉलेट को बनाने से कुछ दिन पहले एक तारीख दर्ज करें। या यदि आप ब्लॉकचेट जानते हैं, तो कृपया इसके बजाय इसे दर्ज करें", "restore_from_seed_placeholder": "कृपया अपना कोड वाक्यांश यहां दर्ज करें या पेस्ट करें", "restore_new_seed": "नया बीज", @@ -613,6 +630,7 @@ "seed_alert_title": "ध्यान", "seed_alert_yes": "हाँ मेरे पास है", "seed_choose": "बीज भाषा चुनें", + "seed_display_path": "मेनू -> सुरक्षा और बैकअप -> कुंजी/बीज दिखाएं", "seed_hex_form": "वॉलेट सीड (हेक्स फॉर्म)", "seed_key": "बीज कुंजी", "seed_language": "बीज", @@ -631,9 +649,13 @@ "seed_language_russian": "रूसी", "seed_language_spanish": "स्पेनिश", "seed_phrase_length": "बीज वाक्यांश की लंबाई", + "seed_position_question_one": "क्या है", + "seed_position_question_two": "आपके बीज वाक्यांश का शब्द?", "seed_reminder": "यदि आप अपना फोन खो देते हैं या मिटा देते हैं तो कृपया इन्हें लिख लें", "seed_share": "बीज साझा करें", "seed_title": "बीज", + "seed_verified": "बीज सत्यापित", + "seed_verified_subtext": "आप भ्रष्टाचार की स्थिति में इस बटुए को पुनर्स्थापित करने या अपने डिवाइस को खोने के लिए बाद में अपने सहेजे गए बीज का उपयोग कर सकते हैं। \n\n आप इस बीज को फिर से देख सकते हैं", "seedtype": "बीज", "seedtype_alert_content": "अन्य पर्स के साथ बीज साझा करना केवल BIP39 सीडटाइप के साथ संभव है।", "seedtype_alert_title": "बीजगणित अलर्ट", @@ -672,6 +694,7 @@ "sent": "भेज दिया", "service_health_disabled": "सेवा स्वास्थ्य बुलेटिन अक्षम है", "service_health_disabled_message": "यह सेवा स्वास्थ्य बुलेटिन पृष्ठ है, आप इस पृष्ठ को सेटिंग्स के तहत सक्षम कर सकते हैं -> गोपनीयता", + "set_a_pin": "एक पिन सेट करना", "settings": "समायोजन", "settings_all": "सब", "settings_allow_biometrical_authentication": "बायोमेट्रिक प्रमाणीकरण की अनुमति दें", @@ -707,6 +730,7 @@ "share_address": "पता साझा करें", "shared_seed_wallet_groups": "साझा बीज बटुए समूह", "show": "दिखाओ", + "show_address_book_popup": "भेजने के बाद 'एड एड्रेस बुक' पॉपअप दिखाएं", "show_details": "विवरण दिखाएं", "show_keys": "बीज / कुंजियाँ दिखाएँ", "show_market_place": "बाज़ार दिखाएँ", @@ -734,6 +758,10 @@ "silent_payments_settings": "मूक भुगतान सेटिंग्स", "single_seed_wallets_group": "एकल बीज बटुए", "slidable": "फिसलने लायक", + "solana_create_associated_token_account_exception": "रसीद पते के लिए संबद्ध टोकन खाता बनाने में त्रुटि।", + "solana_no_associated_token_account_exception": "इस पते के लिए कोई जुड़ा हुआ टोकन खाता नहीं है।", + "solana_sign_native_transaction_rent_exception": "लेन -देन पूरा नहीं किया जा सकता है। अपर्याप्त सोल लेनदेन के बाद किराए के लिए छोड़ दिया। कृपया अपने सोल बैलेंस को टॉप करें या आपके द्वारा भेजे जा रहे सोल की मात्रा को कम करें।", + "solana_sign_spl_token_transaction_rent_exception": "लेन -देन पूरा नहीं किया जा सकता है। अपर्याप्त सोल लेनदेन के बाद किराए के लिए छोड़ दिया। कृपया अपने सोल बैलेंस को ऊपर रखें।", "sort_by": "इसके अनुसार क्रमबद्ध करें", "spend_key_private": "खर्च करना (निजी)", "spend_key_public": "खर्च करना (जनता)", @@ -746,7 +774,7 @@ "support_description_guides": "सामान्य मुद्दों के लिए प्रलेखन और समर्थन", "support_description_live_chat": "मुक्त और तेजी से! प्रशिक्षित सहायता प्रतिनिधि सहायता के लिए उपलब्ध हैं", "support_description_other_links": "हमारे समुदायों में शामिल हों या अन्य तरीकों के माध्यम से हमारे साथी तक पहुंचें", - "support_title_guides": "केक वॉलेट गाइड", + "support_title_guides": "केक बटुए डॉक्स", "support_title_live_chat": "लाइव सहायता", "support_title_other_links": "अन्य समर्थन लिंक", "sweeping_wallet": "स्वीपिंग वॉलेट", @@ -825,6 +853,7 @@ "trade_state_underpaid": "के तहत भुगतान किया", "trade_state_unpaid": "अवैतनिक", "trades": "ट्रेडों", + "transaction_cost": "लेन -देन लागत", "transaction_details_amount": "रकम", "transaction_details_copied": "${title} क्लिपबोर्ड पर नकल", "transaction_details_date": "तारीख", @@ -884,6 +913,7 @@ "variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है", "verification": "सत्यापन", "verify_message": "संदेश सत्यापित करें", + "verify_seed": "बीज सत्यापित करें", "verify_with_2fa": "केक 2FA के साथ सत्यापित करें", "version": "संस्करण ${currentVersion}", "view_all": "सभी देखें", @@ -893,6 +923,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "वोटिंग वेट", "waitFewSecondForTxUpdate": "लेन-देन इतिहास में लेन-देन प्रतिबिंबित होने के लिए कृपया कुछ सेकंड प्रतीक्षा करें", + "wallet": "बटुआ", "wallet_group": "बटुए समूह", "wallet_group_description_four": "एक पूरी तरह से नए बीज के साथ एक बटुआ बनाने के लिए।", "wallet_group_description_one": "केक बटुए में, आप एक बना सकते हैं", @@ -925,6 +956,8 @@ "wallets": "पर्स", "warning": "चेतावनी", "welcome": "स्वागत हे सेवा मेरे", + "welcome_subtitle_new_wallet": "यदि आप ताजा शुरू करना चाहते हैं, तो नीचे नया बटुआ बनाएं और आप दौड़ से दूर हो जाएंगे।", + "welcome_subtitle_restore_wallet": "यदि आपके पास एक मौजूदा बटुआ है जिसे आप केक में लाना चाहते हैं, तो बस मौजूदा बटुए को पुनर्स्थापित करें और हम आपको प्रक्रिया के माध्यम से चलेंगे।", "welcome_to_cakepay": "केकपे में आपका स्वागत है!", "what_is_silent_payments": "मूक भुगतान क्या है?", "widgets_address": "पता", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 8d4f1334f..ca3c2700b 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -38,6 +38,7 @@ "agree_to": "Stvaranjem računa pristajete na ", "alert_notice": "Obavijest", "all": "SVE", + "all_coins": "Sve kovanice", "all_trades": "Svi obrti", "all_transactions": "Sve transakcije", "alphabetical": "Abecedno", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Kupite svjetske unaprijed plaćene kartice i poklon kartice", "cake_pay_web_cards_subtitle": "Kupujte prepaid kartice i poklon kartice diljem svijeta", "cake_pay_web_cards_title": "Cake Pay Web kartice", + "cake_seeds_save_disclaimer": "Molimo spremite ove riječi na sigurno mjesto! Trebat će vam ove riječi da biste vratili novčanik na novi uređaj.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Potvrđujem da ne koristim proxy ili vpn", + "cakepay_confirm_purchase": "Potvrdi kupnju", + "cakepay_confirm_terms_agreed": "Slažem se s ovdje predstavljenim uvjetima:", + "cakepay_confirm_voided_refund": "Razumijem da će pokušaji otkupa od ograničene zemlje poništiti bilo koji povrat novca", + "cakepay_ios_not_available": "Oprostite, ova poklon kartica nije dostupna na iOS -u. Umjesto toga, možete ga kupiti na Androidu ili putem naše web stranice.", "cakepay_prepaid_card": "CakePay unaprijed plaćena debitna kartica", "camera_consent": "Vaš će fotoaparat koristiti za snimanje slike u svrhu identifikacije od strane ${provider}. Pojedinosti potražite u njihovoj politici privatnosti.", "camera_permission_is_required": "Potrebno je dopuštenje kamere.\nOmogućite ga u postavkama aplikacije.", @@ -175,6 +182,7 @@ "copy_address": "Kopiraj adresu", "copy_id": "Kopirati ID", "copyWalletConnectLink": "Kopirajte vezu WalletConnect iz dApp-a i zalijepite je ovdje", + "corrupted_seed_notice": "Datoteke za ovaj novčanik su oštećene i nisu u mogućnosti otvoriti. Molimo pogledajte sjemensku frazu, spremite je i vratite novčanik.\n\nAko je vrijednost prazna, tada sjeme nije bilo u stanju ispravno oporaviti.", "countries": "Zemalja", "create_account": "Stvori račun", "create_backup": "Stvori sigurnosnu kopiju", @@ -256,7 +264,7 @@ "enterTokenID": "Unesite ID tokena", "enterWalletConnectURI": "Unesite WalletConnect URI", "error": "Greška", - "error_dialog_content": "Ups, imamo grešku.\n\nPošaljite izvješće o padu našem timu za podršku kako bismo poboljšali aplikaciju.", + "error_dialog_content": "Ups, dobili smo pogrešku.\n\nMolimo pošaljite izvještaj o pogrešci našem timu za podršku kako biste poboljšali aplikaciju.", "error_text_account_name": "Ime računa smije sadržavati samo slova i brojeve\nte mora biti dužine između 1 i 15 znakova", "error_text_address": "Adresa novčanika mora odgovarati\nvrsti kriptovalute", "error_text_amount": "Iznos smije sadržavati samo brojeve", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Često postavljana pitanja", "frozen": "Smrznuto", "full_balance": "Pun iznos", + "gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.", "generate_name": "Generiraj ime", "generating_gift_card": "Generiranje darovne kartice", "get_a": "Nabavite ", @@ -350,13 +359,17 @@ "how_to_use": "Kako koristiti", "how_to_use_card": "Kako koristiti ovu karticu", "id": "ID: ", + "if_you_dont_see_your_device": "Ako svoj uređaj ne vidite gore, budite sigurni da je vaša knjiga budna i otključana!", "ignor": "Zanemariti", "import": "Uvoz", "importNFTs": "Uvoz NFT-ova", "in_store": "U trgovini", "incoming": "Dolazno", "incorrect_seed": "Uneseni tekst nije valjan.", + "incorrect_seed_option": "Netočno. Pokušajte ponovo", + "incorrect_seed_option_back": "Netočno. Provjerite je li vaše sjeme ispravno spasilo i pokušajte ponovo.", "inputs": "Unosi", + "insufficient_funds_for_tx": "Nedovoljna sredstva za uspješno izvršavanje transakcije.", "insufficient_lamport_for_tx": "Nemate dovoljno SOL -a da pokriva transakciju i njegovu transakcijsku naknadu. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete.", "insufficient_lamports": "Nemate dovoljno SOL -a da pokriva transakciju i njegovu transakcijsku naknadu. Trebate najmanje ${solValueNeeded} sol. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete", "insufficientFundsForRentError": "Nemate dovoljno SOL -a za pokrivanje naknade za transakciju i najamninu za račun. Ljubazno dodajte više sol u svoj novčanik ili smanjite količinu SOL -a koju šaljete", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Odaberite novog predstavnika", "nanogpt_subtitle": "Svi najnoviji modeli (GPT-4, Claude). \\ NNO pretplata, plaćajte kripto.", "narrow": "Usko", - "new_first_wallet_text": "Jednostavno čuvajte svoju kripto valutu", + "new_first_wallet_text": "Čuvanje kriptovaluta je komad torte", "new_node_testing": "Provjera novog nodea", "new_subaddress_create": "Izradi", "new_subaddress_label_name": "Oznaka", @@ -464,6 +477,7 @@ "online": "Na mreži", "onramper_option_description": "Brzo kupite kriptovalute s mnogim načinima plaćanja. Dostupno u većini zemalja. Širenja i naknade variraju.", "open_gift_card": "Otvori darovnu karticu", + "open_wallet": "Otvoreni novčanik", "optional_description": "Opcijski opis", "optional_email_hint": "Neobavezna e-pošta za obavijest primatelja", "optional_name": "Izborno ime primatelja", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Ako ovaj novčanik sadrži sjeme od 12 riječi i stvoren je u Torti, NEMOJTE polagati Bitcoin u ovaj novčanik. Bilo koji BTC prebačen u ovaj novčanik može se izgubiti. Stvorite novi novčanik od 24 riječi (taknite izbornik u gornjem desnom dijelu, odaberite Novčanici, odaberite Stvori novi novčanik, a zatim odaberite Bitcoin) i ODMAH premjestite svoj BTC tamo. Novi BTC novčanici (s 24 riječi) tvrtke Cake sigurni su", "outgoing": "Odlazno", "outputs": "Izlazi", + "overshot": "Zalijepiti", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Nevažeći događaj uparivanja", "passphrase": "Prolaznica (neobavezno)", @@ -531,6 +546,7 @@ "recipient_address": "Primateljeva adresa", "reconnect": "Ponovno povezivanje", "reconnect_alert_text": "Jeste li sigurni da se želite ponovno povezati?", + "reconnect_your_hardware_wallet": "Ponovno spojite svoj hardverski novčanik", "reconnection": "Ponovno povezivanje", "red_dark_theme": "Crvena tamna tema", "red_light_theme": "Tema crvenog svjetla", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Oporavi novčanik pomoću generiranih pritisaka na tipke spremljenih od vlastitih privatnih ključeva (keys)", "restore_description_from_seed": "Oporavi novčanik pomoću koda koji sadrži kombinaciju od 25 ili 13 riječi", "restore_description_from_seed_keys": "Oporavi novčanik pomoću pristupnog izraza/ključa spremljenog na sigurno mjesto", + "restore_existing_wallet": "Vratite postojeći novčanik", "restore_from_date_or_blockheight": "Molimo unesite datum od nekoliko dana prije nego što ste izradili ovaj novčanik ili ako znate visinu bloka, molimo unesite je.", "restore_from_seed_placeholder": "Molimo unesite ili zalijepite svoj pristupni izraz ovdje", "restore_new_seed": "Novi pristupi izraz", @@ -611,6 +628,7 @@ "seed_alert_title": "Upozorenje", "seed_alert_yes": "Jesam", "seed_choose": "Odaberi jezik pristupnog izraza", + "seed_display_path": "Izbornik -> Sigurnost i sigurnosna kopija -> Prikaži ključ/sjemenke", "seed_hex_form": "Sjeme novčanika (šesterokutni oblik)", "seed_key": "Sjemenski ključ", "seed_language": "Sjemeni jezik", @@ -629,9 +647,13 @@ "seed_language_russian": "Ruski", "seed_language_spanish": "Španjolski", "seed_phrase_length": "Duljina početne fraze", + "seed_position_question_one": "Što je", + "seed_position_question_two": "Riječ vaše sjemenske fraze?", "seed_reminder": "Molimo zapišite ih u slučaju da izgubite mobitel ili izbrišete podatke", "seed_share": "Podijeli pristupni izraz", "seed_title": "Prisupni izraz", + "seed_verified": "Potvrđeno sjeme", + "seed_verified_subtext": "Svoje spremljeno sjeme možete kasnije koristiti za vraćanje ovog novčanika u slučaju korupcije ili gubitka uređaja. \n\n To sjeme možete ponovo pogledati iz", "seedtype": "Sjemenska vrsta", "seedtype_alert_content": "Dijeljenje sjemena s drugim novčanicima moguće je samo s BIP39 sjemenom.", "seedtype_alert_title": "Upozorenje o sjemenu", @@ -670,6 +692,7 @@ "sent": "Poslano", "service_health_disabled": "Zdravstveni bilten usluge je onemogućen", "service_health_disabled_message": "Ovo je stranica zdravstvenog biltena o usluzi, možete omogućiti ovu stranicu pod postavkama -> privatnost", + "set_a_pin": "Postavite pin", "settings": "Postavke", "settings_all": "SVE", "settings_allow_biometrical_authentication": "Dopusti biometrijsku autentifikaciju", @@ -705,6 +728,7 @@ "share_address": "Podijeli adresu", "shared_seed_wallet_groups": "Zajedničke grupe za sjeme novčanika", "show": "Pokazati", + "show_address_book_popup": "Pokažite \"dodaj u adresar\" skočni prozor nakon slanja", "show_details": "Prikaži pojedinosti", "show_keys": "Prikaži pristupni izraz/ključ", "show_market_place": "Prikaži tržište", @@ -732,6 +756,10 @@ "silent_payments_settings": "Postavke tihih plaćanja", "single_seed_wallets_group": "Jednostruki novčanici", "slidable": "Klizna", + "solana_create_associated_token_account_exception": "Pogreška u stvaranju povezanog token računa za adresu primanja.", + "solana_no_associated_token_account_exception": "Za ovu adresu ne postoji povezani token račun.", + "solana_sign_native_transaction_rent_exception": "Transakcija se ne može završiti. Nedovoljno sol ostao je za najam nakon transakcije. Ljubazno nadopunite svoj SOL saldo ili smanjite količinu SOL -a koju šaljete.", + "solana_sign_spl_token_transaction_rent_exception": "Transakcija se ne može završiti. Nedovoljno sol ostao je za najam nakon transakcije. Ljubazno nadopunite svoju sol ravnotežu.", "sort_by": "Poredaj po", "spend_key_private": "Spend key (privatni)", "spend_key_public": "Spend key (javni)", @@ -744,7 +772,7 @@ "support_description_guides": "Dokumentacija i podrška za uobičajena pitanja", "support_description_live_chat": "Besplatno i brzo! Obučeni predstavnici podrške dostupni su za pomoć", "support_description_other_links": "Pridružite se našim zajednicama ili nam dosegnu naše partnere drugim metodama", - "support_title_guides": "Vodiči za torte", + "support_title_guides": "Dokumenti s kolačem kolača", "support_title_live_chat": "Podrška uživo", "support_title_other_links": "Ostale veze za podršku", "sweeping_wallet": "Čisti novčanik", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Nedovoljno plaćen", "trade_state_unpaid": "Neplaćen", "trades": "Razmjene", + "transaction_cost": "Trošak transakcije", "transaction_details_amount": "Iznos", "transaction_details_copied": "${title} kopiran u međuspremnik", "transaction_details_date": "Datum", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama", "verification": "Potvrda", "verify_message": "Provjerite poruku", + "verify_seed": "Provjerite sjeme", "verify_with_2fa": "Provjerite s Cake 2FA", "version": "Verzija ${currentVersion}", "view_all": "Prikaži sve", @@ -891,6 +921,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "Težina glasanja", "waitFewSecondForTxUpdate": "Pričekajte nekoliko sekundi da se transakcija prikaže u povijesti transakcija", + "wallet": "Novčanik", "wallet_group": "Skupina novčanika", "wallet_group_description_four": "Da biste stvorili novčanik s potpuno novim sjemenom.", "wallet_group_description_one": "U novčaniku kolača možete stvoriti a", @@ -923,6 +954,8 @@ "wallets": "Novčanici", "warning": "Upozorenje", "welcome": "Dobrodošli na", + "welcome_subtitle_new_wallet": "Ako želite započeti svježe, dodirnite Create New Wallet u nastavku i krenite na utrke.", + "welcome_subtitle_restore_wallet": "Ako imate postojeći novčanik koji želite unijeti u tortu, jednostavno odaberite Vratite postojeći novčanik i prošetat ćemo vas kroz postupak.", "welcome_to_cakepay": "Dobro došli u Cake Pay!", "what_is_silent_payments": "Što je tiha plaćanja?", "widgets_address": "Adresa", diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb index 9a1f617eb..be7022c91 100644 --- a/res/values/strings_hy.arb +++ b/res/values/strings_hy.arb @@ -38,6 +38,7 @@ "agree_to": "Ստեղծելով հաշիվ դուք համաձայնում եք ", "alert_notice": "Ծանուցում", "all": "Բոլորը", + "all_coins": "Բոլոր մետաղադրամները", "all_trades": "Բոլոր գործարքները", "all_transactions": "Բոլոր գործառնությունները", "alphabetical": "Այբբենական", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Գնեք համաշխարհային նախավճարային քարտեր և նվեր քարտեր", "cake_pay_web_cards_subtitle": "Գնեք համաշխարհային նախավճարային քարտեր և նվեր քարտեր", "cake_pay_web_cards_title": "Cake Pay Վեբ Քարտեր", + "cake_seeds_save_disclaimer": "Խնդրում ենք պահպանել այս բառերը անվտանգ տեղում: Ձեզ հարկավոր կլինի այս բառերը `ձեր դրամապանակը նոր սարքում վերականգնելու համար:", "cake_wallet": "Cake Գաղտնապահոց", + "cakepay_confirm_no_vpn": "Ես հաստատում եմ, որ ես չեմ օգտագործում վստահված անձ կամ VPN", + "cakepay_confirm_purchase": "Հաստատեք գնումը", + "cakepay_confirm_terms_agreed": "Ես համաձայն եմ այստեղ ներկայացված պայմաններին.", + "cakepay_confirm_voided_refund": "Ես հասկանում եմ, որ սահմանափակված երկրի մարման փորձերը կվերականգնեն ցանկացած փոխհատուցում", + "cakepay_ios_not_available": "Ներեցեք, այս նվեր քարտը հասանելի չէ iOS- ում: Փոխարենը կարող եք այն գնել Android- ում կամ մեր կայքում:", "cakepay_prepaid_card": "CakePay Նախավճարային Դեբետային Քարտ", "camera_consent": "Ձեր տեսախցիկը կօգտագործվի ${provider}-ի կողմից ինքնությունը հաստատելու նպատակով: Խնդրում ենք ծանոթանալ նրանց Գաղտնիության Քաղաքականության հետ:", "camera_permission_is_required": "Տեսախցիկի թույլտվություն է պահանջվում: \nԽնդրում ենք այն ակտիվացնել հավելվածի կարգավորումներից:", @@ -175,6 +182,7 @@ "copy_address": "Պատճենել հասցեն", "copy_id": "Պատճենել ID", "copyWalletConnectLink": "Պատճենել WalletConnect հղումը dApp-ից և տեղադրել այստեղ", + "corrupted_seed_notice": "Այս դրամապանակի համար ֆայլերը կոռումպացված են եւ չեն կարողանում բացվել: Խնդրում ենք դիտել սերմերի արտահայտությունը, պահպանել այն եւ վերականգնել դրամապանակը:\n\nԵթե ​​արժեքը դատարկ է, ապա սերմը չկարողացավ ճիշտ վերականգնվել:", "countries": "Երկրներ", "create_account": "Ստեղծել հաշիվ", "create_backup": "Ստեղծել կրկնօրինակ", @@ -256,7 +264,7 @@ "enterTokenID": "Մուտքագրեք Token ID֊ն", "enterWalletConnectURI": "Մուտքագրեք WalletConnect URI", "error": "Սխալ", - "error_dialog_content": "Օպս, մենք սխալ ենք ստացել: \n\nԽնդրում ենք ուղարկել սխալի հաշվետվությունը մեր աջակցության թիմին ծրագիրը բարելավելու համար:", + "error_dialog_content": "Վայ, մենք որոշակի սխալ ստացանք:\n\nԽնդրում ենք ուղարկել սխալի մասին զեկույցը մեր աջակցության թիմին `դիմումը ավելի լավ դարձնելու համար:", "error_text_account_name": "Հաշվի անունը կարող է պարունակել միայն տառեր և թվեր և պետք է լինի 1-15 նիշ", "error_text_address": "Դրամապանակի հասցեն պետք է համապատասխանի կրիպտոարժույթի տեսակին", "error_text_amount": "Գումարը կարող է պարունակել միայն թվեր", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Հաճախ տրվող հարցեր", "frozen": "Կասեցված", "full_balance": "Լրիվ մնացորդ", + "gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:", "generate_name": "Գեներացնել անուն", "generating_gift_card": "Գեներացնում է նվեր քարտ", "get_a": "Ստանալ ", @@ -350,13 +359,17 @@ "how_to_use": "Ինչպես օգտագործել", "how_to_use_card": "Ինչպես օգտագործել այս քարտը", "id": "ID: ", + "if_you_dont_see_your_device": "Եթե ​​ձեր սարքը վերեւում չեք տեսնում, համոզվեք, որ ձեր Ledger- ը արթուն է եւ բացված:", "ignor": "Անտեսել", "import": "Ներմուծել", "importNFTs": "Ներմուծել NFT-ներ", "in_store": "Տեղում", "incoming": "Մուտքային", "incorrect_seed": "Տեքստը սխալ է", + "incorrect_seed_option": "Սխալ Խնդրում ենք կրկին փորձել", + "incorrect_seed_option_back": "Սխալ Խնդրում ենք համոզվեք, որ ձեր սերմը ճիշտ պահվում է եւ կրկին փորձեք:", "inputs": "Մուտքեր", + "insufficient_funds_for_tx": "Անբավարար միջոցներ `գործարքը հաջողությամբ կատարելու համար:", "insufficient_lamport_for_tx": "Դուք չունեք բավարար SOL՝ գործարքն և գործարքի վարձը ծածկելու համար։ Խնդրում ենք ավելացնել ավելի շատ SOL ձեր դրամապանակում կամ նվազեցնել ուղարկվող SOL-ի քանակը։", "insufficient_lamports": "Դուք չունեք բավարար SOL՝ գործարքն և գործարքի վարձը ծածկելու համար։ Ձեզ անհրաժեշտ է առնվազն ${solValueNeeded} SOL։ Խնդրում ենք ավելացնել ավելի շատ SOL ձեր դրամապանակում կամ նվազեցնել ուղարկվող SOL-ի քանակը։", "insufficientFundsForRentError": "Ձեր մնացորդը բավարար չէ վարձակալության համար: Խնդրում ենք ավելացնել մնացորդը կամ նվազեցնել ուղարկվող գումարը", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Ընտրեք նոր ներկայացուցիչ", "nanogpt_subtitle": "Բոլոր ամենանոր մոդելներ (GPT-4, Claude).\\nԱռանց բաժանորդագրության, վճարեք կրիպտոարժույթով", "narrow": "Նեղ", - "new_first_wallet_text": "Ինչպես պահել ձեր կրիպտոգրաֆիան անվտանգ, կարկանդակ", + "new_first_wallet_text": "Ձեր ծպտյալ անվտանգ պահելը տորթի մի կտոր է", "new_node_testing": "Նոր հանգույցի փորձարկում", "new_subaddress_create": "Ստեղծել", "new_subaddress_label_name": "Պիտակի անուն", @@ -464,6 +477,7 @@ "online": "Առցանց", "onramper_option_description": "Արագ գնեք կրիպտոցուլեր շատ վճարման մեթոդներով։ Հասանելի է մեծ մասամբ երկրներում։ Տարածված և վճարները փոփոխվում են", "open_gift_card": "Բացեք նվեր քարտ", + "open_wallet": "Բաց դրամապանակ", "optional_description": "Ոչ պարտադիր նկարագրություն", "optional_email_hint": "Ոչ պարտադիր վճարողի ծանուցման էլեկտրոնային փոստ", "optional_name": "Ոչ պարտադիր ստացողի անուն", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Եթե այս դրամապանակը 12 բառանոց սերմ ունի և ստեղծվել է Cake-ում, Bitcoin մուծել այս դրամապանակ մի տեղափոխեք։ Որեւէ Bitcoin այս դրամապանակ տեղափոխվել կարող է կորած լինել։ Ստեղծեք նոր 24-բառանոց Bitcoin դրամապանակ (սեղմեք վերևի աջ մենյուն, ընտրեք Դրամապանակներ, ընտրեք Նոր Դրամապանակ, ապա ընտրեք Bitcoin) և տեղափոխեք ձեր ԲԻՏԿ-ն այնտեղ", "outgoing": "Ելքային", "outputs": "Ելքեր", + "overshot": "Ցանց", "overwrite_amount": "Գրեք գումարը", "pairingInvalidEvent": "Սխալ միացում", "passphrase": "Պարող արտահայտություն (Ոչ պարտադիր)", @@ -531,6 +546,7 @@ "recipient_address": "Ստացողի հասցե", "reconnect": "Վերակապվել", "reconnect_alert_text": "Դուք վստահ եք, որ ուզում եք վերակապվել?", + "reconnect_your_hardware_wallet": "Միացրեք ձեր ապարատային դրամապանակը", "reconnection": "Վերակապում", "red_dark_theme": "Կարմիր մութ տեսք", "red_light_theme": "Կարմիր պայծառ տեսք", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Վերականգնեք ձեր դրամապանակը ձեր գախտնի բանալիների հիման վրա ստեղծված մուտքագրումներից", "restore_description_from_seed": "Վերականգնեք ձեր դրամապպանակը 25 բառերի կամ 13 բառերի համադրությամբ", "restore_description_from_seed_keys": "Վերականգնեք ձեր դրամապանակը սերմից/բանալիներից, որը դուք պահպանել եք ապահով վայրում", + "restore_existing_wallet": "Վերականգնել առկա դրամապանակը", "restore_from_date_or_blockheight": "Խնդրում ենք մուտքագրել այն ամսաթիվը, երբ դուք ստեղծել եք այս դրամապանակը։ Կամ, եթե դուք գիտեք բլոկի բարձրությունը, խնդրում ենք մուտքագրել այն", "restore_from_seed_placeholder": "Խնդրում ենք մուտքագրել կամ տեղադրել ձեր սերմը այստեղ", "restore_new_seed": "Նոր սերմ", @@ -611,6 +628,7 @@ "seed_alert_title": "Ուշադրություն", "seed_alert_yes": "Այո, ես արդեն գրի եմ առել այն", "seed_choose": "Ընտրել սերմի լեզուն", + "seed_display_path": "MENU -> Անվտանգություն եւ պահուստավորում -> Show ույց տալ ստեղնը / սերմերը", "seed_hex_form": "Դրամապանակի սերմ (hex ֆորմատ)", "seed_key": "Սերմի բանալի", "seed_language": "Սերմի լեզու", @@ -629,9 +647,13 @@ "seed_language_russian": "Ռուսերեն", "seed_language_spanish": "Իսպաներեն", "seed_phrase_length": "Սերմի արտահայտության երկարություն", + "seed_position_question_one": "Ինչ է", + "seed_position_question_two": "Ձեր սերմի արտահայտության խոսքը:", "seed_reminder": "Խնդրում ենք գրի առնել այս տեղեկությունը, եթե դուք կորցնեք կամ ջնջեք ձեր հեռախոսը", "seed_share": "Կիսվել սերմով", "seed_title": "Սերմ", + "seed_verified": "SEED- ը հաստատեց", + "seed_verified_subtext": "Դուք կարող եք ավելի ուշ օգտագործել ձեր պահպանված սերմը `վերականգնելու այս դրամապանակը կոռուպցիայի դեպքում կամ ձեր սարքը կորցնելու դեպքում: \n\n կարող եք կրկին դիտել այս սերմը", "seedtype": "Սերմի տեսակ", "seedtype_alert_content": "Այլ դրամապանակներով սերմերի փոխանակումը հնարավոր է միայն BIP39 SEEDTYPE- ով:", "seedtype_alert_title": "SEEDTYPE ALERT", @@ -670,6 +692,7 @@ "sent": "Ուղարկված", "service_health_disabled": "Ծառայության առողջությունը անջատված է", "service_health_disabled_message": "Սա ծառայության առողջության էջն է, դուք կարող եք այս էջը միացնել Կարգավորումներ -> Գաղտնիություն", + "set_a_pin": "Սեփական քորոց սահմանեք", "settings": "Կարգավորումներ", "settings_all": "Բոլորը", "settings_allow_biometrical_authentication": "Թույլատրել կենսաչափական վավերացում", @@ -705,6 +728,7 @@ "share_address": "Կիսվել հասցեով", "shared_seed_wallet_groups": "Համօգտագործված սերմերի դրամապանակների խմբեր", "show": "Ցուցահանդես", + "show_address_book_popup": "Show ույց տալ «Ուղարկելուց հետո« Հասցեների գրքի »թռուցիկ", "show_details": "Ցուցադրել մանրամասներ", "show_keys": "Ցուցադրել բանալիներ", "show_market_place": "Ցուցադրել շուկան", @@ -732,6 +756,10 @@ "silent_payments_settings": "Լուռ Վճարումներ Կարգավորումներ", "single_seed_wallets_group": "Մեկ սերմերի դրամապանակներ", "slidable": "Սահելի", + "solana_create_associated_token_account_exception": "Recesient Advent- ի համար հարակից նշանների հաշիվ ստեղծելու սխալ:", + "solana_no_associated_token_account_exception": "Այս հասցեի համար կապված նշանների հաշիվ չկա:", + "solana_sign_native_transaction_rent_exception": "Գործարքը հնարավոր չէ լրացնել: Անբավարար սոլը գործարքից հետո վարձով է մնացել: Սիրով վերացրեք ձեր SOL հավասարակշռությունը կամ նվազեցրեք ձեր ուղարկած սոլի քանակը:", + "solana_sign_spl_token_transaction_rent_exception": "Գործարքը հնարավոր չէ լրացնել: Անբավարար սոլը գործարքից հետո վարձով է մնացել: Սիրով վերացրեք ձեր SOL հավասարակշռությունը:", "sort_by": "Դասավորել ըստ", "spend_key_private": "Վճարման բանալի (գախտնի)", "spend_key_public": "Վճարման բանալի (հանրային)", @@ -744,7 +772,7 @@ "support_description_guides": "Տարածված խնդիրների փաստաթղթավորում և աջակցություն", "support_description_live_chat": "Անվճար և արագ աջակցություն! Պատրաստված մասնագետները պատրաստ են օգնել", "support_description_other_links": "Միացեք մեր համայնքին կամ հասեք մեզ այլ միջոցներով", - "support_title_guides": "Cake Wallet ուղեցույց", + "support_title_guides": "Տորթ դրամապանակի փաստաթղթեր", "support_title_live_chat": "Անմիջական աջակցություն", "support_title_other_links": "Այլ աջակցության հղումներ", "sweeping_wallet": "Դրամապանակը մաքրվում է", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Վճարված է, բայց ոչ ամբողջությամբ", "trade_state_unpaid": "Վճարված չէ", "trades": "Գործարքներ", + "transaction_cost": "Գործարքի արժեքը", "transaction_details_amount": "Գումար", "transaction_details_copied": "${title} պատճենված է գրանցամատյան", "transaction_details_date": "Ամսաթիվ", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Այս փոփոխականի զույգը չի աջակցվում ընտրված բորսաների հետ", "verification": "Ստուգում", "verify_message": "Ստուգել հաղորդագրությունը", + "verify_seed": "Ստուգեք սերմը", "verify_with_2fa": "Ստուգեք Cake 2FA-ով", "version": "Տարբերակ ${currentVersion}", "view_all": "Դիտել բոլորը", @@ -891,6 +921,7 @@ "view_transaction_on": "Դիտել Գործարքը ", "voting_weight": "Քվեարկության Քաշ", "waitFewSecondForTxUpdate": "Խնդրում ենք սպասել մի քանի վայրկյան, որպեսզի գործարքը արտացոլվի գործարքների պատմության մեջ", + "wallet": "Դրամապանակ", "wallet_group": "Դրամապանակների խումբ", "wallet_group_description_four": "Ամբողջովին նոր սերմով դրամապանակ ստեղծելու համար:", "wallet_group_description_one": "Տորթի դրամապանակում կարող եք ստեղծել ա", @@ -923,6 +954,8 @@ "wallets": "Դրամապանակներ", "warning": "Զգուշացում", "welcome": "Բարի գալուստ", + "welcome_subtitle_new_wallet": "Եթե ​​ցանկանում եք սկսել թարմ, հպեք Ստեղծեք նոր դրամապանակ ներքեւում եւ դուրս կգաք ցեղերի:", + "welcome_subtitle_restore_wallet": "Եթե ​​ունեք գոյություն ունեցող դրամապանակ, որը ցանկանում եք տորթի մեջ մտցնել, պարզապես ընտրեք վերականգնել առկա դրամապանակը, եւ մենք ձեզ քայլելու ենք գործընթացի միջոցով:", "welcome_to_cakepay": "Բարի գալուստ Cake Pay!", "what_is_silent_payments": "Ի՞նչ է Լուռ Վճարումները:", "widgets_address": "Հասցե", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 25c15215d..bd612cbf8 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -38,6 +38,7 @@ "agree_to": "Dengan membuat akun Anda setuju dengan ", "alert_notice": "Melihat", "all": "SEMUA", + "all_coins": "Semua koin", "all_trades": "Semua perdagangan", "all_transactions": "Semua transaksi", "alphabetical": "Alfabetis", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Beli kartu prabayar di seluruh dunia dan kartu hadiah", "cake_pay_web_cards_subtitle": "Beli kartu prabayar dan kartu hadiah secara global", "cake_pay_web_cards_title": "Kartu Web Cake Pay", + "cake_seeds_save_disclaimer": "Harap simpan kata -kata ini di tempat yang aman! Anda akan membutuhkan kata -kata ini untuk mengembalikan dompet Anda pada perangkat baru.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Saya mengkonfirmasi saya tidak menggunakan proxy atau vpn", + "cakepay_confirm_purchase": "Konfirmasi pembelian", + "cakepay_confirm_terms_agreed": "Saya setuju dengan syarat dan ketentuan yang disajikan di sini:", + "cakepay_confirm_voided_refund": "Saya mengerti upaya penebusan dari negara terbatas akan membatalkan pengembalian dana", + "cakepay_ios_not_available": "Maaf, kartu hadiah ini tidak tersedia di iOS. Anda dapat membelinya di Android atau melalui situs web kami sebagai gantinya.", "cakepay_prepaid_card": "Kartu Debit Prabayar CakePay", "camera_consent": "Kamera Anda akan digunakan untuk mengambil gambar untuk tujuan identifikasi oleh ${provider}. Silakan periksa Kebijakan Privasi mereka untuk detailnya.", "camera_permission_is_required": "Izin kamera diperlukan.\nSilakan aktifkan dari pengaturan aplikasi.", @@ -175,6 +182,7 @@ "copy_address": "Salin Alamat", "copy_id": "Salin ID", "copyWalletConnectLink": "Salin tautan WalletConnect dari dApp dan tempel di sini", + "corrupted_seed_notice": "File untuk dompet ini rusak dan tidak dapat dibuka. Silakan lihat frasa benih, simpan, dan kembalikan dompet.\n\nJika nilainya kosong, maka benih tidak dapat dipulihkan dengan benar.", "countries": "Negara", "create_account": "Buat Akun", "create_backup": "Buat cadangan", @@ -256,7 +264,7 @@ "enterTokenID": "Masukkan ID tokennya", "enterWalletConnectURI": "Masukkan URI WalletConnect", "error": "Kesalahan", - "error_dialog_content": "Ups, kami mendapat kesalahan.\n\nSilakan kirim laporan crash ke tim dukungan kami untuk membuat aplikasi lebih baik.", + "error_dialog_content": "Ups, kami mendapat kesalahan.\n\nSilakan kirim laporan kesalahan ke tim dukungan kami untuk membuat aplikasi lebih baik.", "error_text_account_name": "Nama akun hanya dapat berisi huruf, angka\ndan harus antara 1 dan 15 karakter panjang", "error_text_address": "Alamat dompet harus sesuai dengan tipe\nmata uang kripto", "error_text_amount": "Jumlah hanya dapat berisi angka", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Pertanyaan yang sering diajukan", "frozen": "Dibekukan", "full_balance": "Saldo Penuh", + "gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.", "generate_name": "Hasilkan Nama", "generating_gift_card": "Membuat Kartu Hadiah", "get_a": "Dapatkan ", @@ -350,13 +359,17 @@ "how_to_use": "Cara Penggunaan", "how_to_use_card": "Bagaimana menggunakan kartu ini", "id": "ID: ", + "if_you_dont_see_your_device": "Jika Anda tidak melihat perangkat Anda di atas, pastikan buku besar Anda terjaga dan tidak terkunci!", "ignor": "Abaikan", "import": "Impor", "importNFTs": "Impor NFT", "in_store": "Di Toko", "incoming": "Masuk", "incorrect_seed": "Teks yang dimasukkan tidak valid.", + "incorrect_seed_option": "Salah. Tolong coba lagi", + "incorrect_seed_option_back": "Salah. Pastikan benih Anda disimpan dengan benar dan coba lagi.", "inputs": "Input", + "insufficient_funds_for_tx": "Dana yang tidak mencukupi untuk berhasil menjalankan transaksi.", "insufficient_lamport_for_tx": "Anda tidak memiliki cukup SOL untuk menutupi transaksi dan biaya transaksinya. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim.", "insufficient_lamports": "Anda tidak memiliki cukup SOL untuk menutupi transaksi dan biaya transaksinya. Anda membutuhkan setidaknya ${solValueNeeded} sol. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim", "insufficientFundsForRentError": "Anda tidak memiliki cukup SOL untuk menutupi biaya transaksi dan menyewa untuk akun tersebut. Mohon tambahkan lebih banyak sol ke dompet Anda atau kurangi jumlah sol yang Anda kirim", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Pilih perwakilan baru", "nanogpt_subtitle": "Semua model terbaru (GPT-4, Claude). \\ Nno langganan, bayar dengan crypto.", "narrow": "Sempit", - "new_first_wallet_text": "Dengan mudah menjaga cryptocurrency Anda aman", + "new_first_wallet_text": "Menjaga crypto Anda aman adalah sepotong kue", "new_node_testing": "Pengujian node baru", "new_subaddress_create": "Buat", "new_subaddress_label_name": "Nama label", @@ -464,6 +477,7 @@ "online": "Online", "onramper_option_description": "Beli crypto dengan cepat dengan banyak metode pembayaran. Tersedia di sebagian besar negara. Spread dan biaya bervariasi.", "open_gift_card": "Buka Kartu Hadiah", + "open_wallet": "Dompet Buka", "openalias_alert_content": "Anda akan mengirim dana ke\n${recipient_name}", "openalias_alert_title": "Alamat Terdeteksi", "optional_description": "Deskripsi opsional", @@ -479,6 +493,7 @@ "outdated_electrum_wallet_receive_warning": "Jika dompet ini memiliki biji semai 12 kata dan dibuat di Cake, JANGAN deposit Bitcoin ke dalam dompet ini. BTC apapun yang ditransfer ke dompet ini mungkin hilang. Buat dompet 24 kata baru (ketuk menu di pojok kanan atas, pilih Dompet, pilih Buat Dompet Baru, lalu pilih Bitcoin) dan SEGERA pindahkan BTC Anda ke sana. Dompet BTC (24 kata) baru dari Cake aman", "outgoing": "Keluar", "outputs": "Output", + "overshot": "Overshot", "overwrite_amount": "Timpa jumlah", "pairingInvalidEvent": "Menyandingkan Acara Tidak Valid", "passphrase": "Frasa sandi (opsional)", @@ -533,6 +548,7 @@ "recipient_address": "Alamat penerima", "reconnect": "Sambungkan kembali", "reconnect_alert_text": "Apakah Anda yakin ingin menyambungkan kembali?", + "reconnect_your_hardware_wallet": "Hubungkan kembali dompet perangkat keras Anda", "reconnection": "Koneksi kembali", "red_dark_theme": "Tema gelap merah", "red_light_theme": "Tema lampu merah", @@ -572,6 +588,7 @@ "restore_description_from_keys": "Pulihkan dompet Anda dari tombol yang dihasilkan yang disimpan dari kunci pribadi Anda", "restore_description_from_seed": "Pulihkan dompet Anda dari kombinasi kode 25 atau 13 kata", "restore_description_from_seed_keys": "Dapatkan kembali dompet Anda dari seed/kunci yang Anda simpan di tempat yang aman", + "restore_existing_wallet": "Kembalikan dompet yang ada", "restore_from_date_atau_blockheight": "Silakan masukkan tanggal beberapa hari sebelum Anda membuat dompet ini. Atau jika Anda tahu blockheight, silakan masukkannya sebagai gantinya", "restore_from_date_or_blockheight": "Harap masukkan tanggal beberapa hari sebelum Anda membuat dompet ini. Atau jika Anda tahu blockheight, silakan masukkan sebagai gantinya", "restore_from_seed_placeholder": "Silakan masukkan atau tempel seed Anda di sini", @@ -614,6 +631,7 @@ "seed_alert_title": "Perhatian", "seed_alert_yes": "Ya, sudah", "seed_choose": "Pilih bahasa bibit", + "seed_display_path": "Menu -> Keamanan dan Cadangan -> Tampilkan kunci/biji", "seed_hex_form": "Biji dompet (bentuk hex)", "seed_key": "Kunci benih", "seed_language": "Bahasa benih", @@ -632,9 +650,13 @@ "seed_language_russian": "Rusia", "seed_language_spanish": "Spanyol", "seed_phrase_length": "Panjang frase benih", + "seed_position_question_one": "Apakah yang", + "seed_position_question_two": "Kata frasa benih Anda?", "seed_reminder": "Silakan tulis ini di tempat yang aman jika kamu kehilangan atau menghapus ponselmu", "seed_share": "Bagikan bibit", "seed_title": "Bibit", + "seed_verified": "Benih diverifikasi", + "seed_verified_subtext": "Anda dapat menggunakan benih yang disimpan nanti untuk mengembalikan dompet ini jika terjadi korupsi atau kehilangan perangkat Anda. \n\n Anda dapat melihat benih ini lagi dari", "seedtype": "Seedtype", "seedtype_alert_content": "Berbagi biji dengan dompet lain hanya dimungkinkan dengan BIP39 seedtype.", "seedtype_alert_title": "Peringatan seedtype", @@ -673,6 +695,7 @@ "sent": "Dikirim", "service_health_disabled": "Buletin Kesehatan Layanan dinonaktifkan", "service_health_disabled_message": "Ini adalah halaman Buletin Kesehatan Layanan, Anda dapat mengaktifkan halaman ini di bawah Pengaturan -> Privasi", + "set_a_pin": "Atur pin", "settings": "Pengaturan", "settings_all": "SEMUA", "settings_allow_biometrical_authentication": "Izinkan otentikasi biometrik", @@ -708,6 +731,7 @@ "share_address": "Bagikan alamat", "shared_seed_wallet_groups": "Kelompok dompet benih bersama", "show": "Menunjukkan", + "show_address_book_popup": "Tampilkan popup 'Tambahkan ke Alamat' setelah mengirim", "show_details": "Tampilkan Rincian", "show_keys": "Tampilkan seed/kunci", "show_market_place": "Tampilkan Pasar", @@ -735,6 +759,10 @@ "silent_payments_settings": "Pengaturan pembayaran diam", "single_seed_wallets_group": "Dompet biji tunggal", "slidable": "Dapat digeser", + "solana_create_associated_token_account_exception": "Kesalahan Membuat Akun Token Terkait untuk Alamat Penerima.", + "solana_no_associated_token_account_exception": "Tidak ada akun token terkait untuk alamat ini.", + "solana_sign_native_transaction_rent_exception": "Transaksi tidak dapat diselesaikan. SOL yang tidak mencukupi pergi untuk disewa setelah transaksi. Mohon tambah saldo SOL Anda atau kurangi jumlah SOL yang Anda kirim.", + "solana_sign_spl_token_transaction_rent_exception": "Transaksi tidak dapat diselesaikan. SOL yang tidak mencukupi pergi untuk disewa setelah transaksi. Mohon tambah saldo SOL Anda.", "sort_by": "Sortir dengan", "spend_key_private": "Kunci pengeluaran (privat)", "spend_key_public": "Kunci pengeluaran (publik)", @@ -747,7 +775,7 @@ "support_description_guides": "Dokumentasi dan dukungan untuk masalah umum", "support_description_live_chat": "Gratis dan Cepat! Perwakilan dukungan terlatih tersedia untuk membantu", "support_description_other_links": "Bergabunglah dengan komunitas kami atau hubungi kami mitra kami melalui metode lain", - "support_title_guides": "Panduan Dompet Kue", + "support_title_guides": "DOKS DOKO CAKE", "support_title_live_chat": "Dukungan langsung", "support_title_other_links": "Tautan dukungan lainnya", "sweeping_wallet": "Dompet menyapu", @@ -826,6 +854,7 @@ "trade_state_underpaid": "Kurang bayar", "trade_state_unpaid": "Belum dibayar", "trades": "Perdagangan", + "transaction_cost": "Biaya transaksi", "transaction_details_amount": "Jumlah", "transaction_details_copied": "${title} disalin ke Clipboard", "transaction_details_date": "Tanggal", @@ -885,6 +914,7 @@ "variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih", "verification": "Verifikasi", "verify_message": "Verifikasi pesan", + "verify_seed": "Verifikasi benih", "verify_with_2fa": "Verifikasi dengan Cake 2FA", "version": "Versi ${currentVersion}", "view_all": "Lihat Semua", @@ -894,6 +924,7 @@ "view_transaction_on": "Lihat Transaksi di ", "voting_weight": "Berat voting", "waitFewSecondForTxUpdate": "Mohon tunggu beberapa detik hingga transaksi terlihat di riwayat transaksi", + "wallet": "Dompet", "wallet_group": "Kelompok dompet", "wallet_group_description_four": "Untuk membuat dompet dengan benih yang sama sekali baru.", "wallet_group_description_one": "Di dompet kue, Anda dapat membuat file", @@ -926,6 +957,8 @@ "wallets": "Dompet", "warning": "Peringatan", "welcome": "Selamat datang di", + "welcome_subtitle_new_wallet": "Jika Anda ingin memulai segar, ketuk membuat dompet baru di bawah ini dan Anda akan pergi ke balapan.", + "welcome_subtitle_restore_wallet": "Jika Anda memiliki dompet yang ada yang ingin Anda bawa ke dalam kue, cukup pilih kembalikan dompet yang ada dan kami akan memandu Anda melalui prosesnya.", "welcome_to_cakepay": "Selamat Datang di Cake Pay!", "what_is_silent_payments": "Apa itu pembayaran diam?", "widgets_address": "Alamat", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 6d57c8247..6a994c1c1 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -38,6 +38,7 @@ "agree_to": "Creando un account accetti il ​​", "alert_notice": "Avviso", "all": "TUTTO", + "all_coins": "Tutte le monete", "all_trades": "Svi obrti", "all_transactions": "Sve transakcije", "alphabetical": "Alfabetico", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Acquista carte prepagate in tutto il mondo e carte regalo", "cake_pay_web_cards_subtitle": "Acquista carte prepagate e carte regalo in tutto il mondo", "cake_pay_web_cards_title": "Carte Web Cake Pay", + "cake_seeds_save_disclaimer": "Si prega di salvare queste parole in un posto sicuro! Avrai bisogno di queste parole per ripristinare il portafoglio su un nuovo dispositivo.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Conferma che non sto usando un proxy o una VPN", + "cakepay_confirm_purchase": "Conferma l'acquisto", + "cakepay_confirm_terms_agreed": "Accetto i termini e le condizioni presentati qui:", + "cakepay_confirm_voided_refund": "Capisco che i tentativi di rimborso da un paese limitato annullano qualsiasi rimborso", + "cakepay_ios_not_available": "Mi dispiace, questa carta regalo non è disponibile su iOS. Puoi acquistarlo su Android o tramite il nostro sito Web.", "cakepay_prepaid_card": "Carta di debito prepagata CakePay", "camera_consent": "La tua fotocamera verrà utilizzata per acquisire un'immagine a scopo identificativo da ${provider}. Si prega di controllare la loro Informativa sulla privacy per i dettagli.", "camera_permission_is_required": "È richiesta l'autorizzazione della fotocamera.\nAbilitalo dalle impostazioni dell'app.", @@ -176,6 +183,7 @@ "copy_address": "Copia Indirizzo", "copy_id": "Copia ID", "copyWalletConnectLink": "Copia il collegamento WalletConnect dalla dApp e incollalo qui", + "corrupted_seed_notice": "I file per questo portafoglio sono corrotti e non sono in grado di essere aperti. Visualizza la frase del seme, salvala e ripristina il portafoglio.\n\nSe il valore è vuoto, il seme non è stato in grado di essere recuperato correttamente.", "countries": "Paesi", "create_account": "Crea account", "create_backup": "Crea backup", @@ -257,7 +265,7 @@ "enterTokenID": "Inserisci l'ID del token", "enterWalletConnectURI": "Inserisci l'URI di WalletConnect", "error": "Errore", - "error_dialog_content": "Spiacenti, abbiamo riscontrato un errore.\n\nSi prega di inviare il rapporto sull'arresto anomalo al nostro team di supporto per migliorare l'applicazione.", + "error_dialog_content": "Oops, abbiamo ricevuto qualche errore.\n\nSi prega di inviare il rapporto di errore al nostro team di supporto per migliorare l'applicazione.", "error_text_account_name": "Il nome del conto può contenere solo lettere, numeri\ne deve avere una lunghezza compresa tra 1 e 15 caratteri", "error_text_address": "L'indirizzo del Portafoglio deve corrispondere alla tipologia\ndi criptovaluta", "error_text_amount": "L'ammontare può contenere solo numeri", @@ -324,6 +332,7 @@ "frequently_asked_questions": "Domande frequenti", "frozen": "Congelato", "full_balance": "Saldo Completo", + "gas_exceeds_allowance": "Il gas richiesto dalla transazione supera l'indennità.", "generate_name": "Genera nome", "generating_gift_card": "Generazione carta regalo", "get_a": "Prendi un ", @@ -351,13 +360,17 @@ "how_to_use": "Come usare", "how_to_use_card": "Come usare questa carta", "id": "ID: ", + "if_you_dont_see_your_device": "Se non vedi il tuo dispositivo sopra, assicurati che il tuo libro mastro sia sveglio e sbloccato!", "ignor": "Ignorare", "import": "Importare", "importNFTs": "Importa NFT", "in_store": "In negozio", "incoming": "In arrivo", "incorrect_seed": "Il testo inserito non è valido.", + "incorrect_seed_option": "Errato. Per favore riprova", + "incorrect_seed_option_back": "Errato. Assicurati che il tuo seme venga salvato correttamente e riprova.", "inputs": "Input", + "insufficient_funds_for_tx": "Fondi insufficienti per eseguire correttamente la transazione.", "insufficient_lamport_for_tx": "Non hai abbastanza SOL per coprire la transazione e la sua quota di transazione. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando.", "insufficient_lamports": "Non hai abbastanza SOL per coprire la transazione e la sua quota di transazione. Hai bisogno di almeno ${solValueNeeded} sol. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando", "insufficientFundsForRentError": "Non hai abbastanza SOL per coprire la tassa di transazione e l'affitto per il conto. Si prega di aggiungere più SOL al tuo portafoglio o ridurre l'importo SOL che stai inviando", @@ -428,7 +441,7 @@ "nano_pick_new_rep": "Scegli un nuovo rappresentante", "nanogpt_subtitle": "Tutti i modelli più recenti (GPT-4, Claude). Abbonamento nno, paga con cripto.", "narrow": "Stretto", - "new_first_wallet_text": "Mantieni facilmente la tua criptovaluta al sicuro", + "new_first_wallet_text": "Mantenere la tua criptovaluta è un pezzo di torta", "new_node_testing": "Test novo nodo", "new_subaddress_create": "Crea", "new_subaddress_label_name": "Nome etichetta", @@ -465,6 +478,7 @@ "online": "in linea", "onramper_option_description": "Acquista rapidamente la criptovaluta con molti metodi di pagamento. Disponibile nella maggior parte dei paesi. Gli spread e le commissioni variano.", "open_gift_card": "Apri carta regalo", + "open_wallet": "Portafoglio aperto", "optional_description": "Descrizione facoltativa", "optional_email_hint": "Email di notifica del beneficiario facoltativa", "optional_name": "Nome del destinatario facoltativo", @@ -479,6 +493,7 @@ "outdated_electrum_wallet_receive_warning": "Se questo portafoglio ha un seme di 12 parole ed è stato creato in Cake, NON depositare Bitcoin in questo portafoglio. Qualsiasi BTC trasferito su questo portafoglio potrebbe andare perso. Crea un nuovo portafoglio di 24 parole (tocca il menu in alto a destra, seleziona Portafogli, scegli Crea nuovo portafoglio, quindi seleziona Bitcoin) e sposta IMMEDIATAMENTE lì il tuo BTC. I nuovi portafogli BTC (24 parole) di Cake sono sicuri", "outgoing": "In uscita", "outputs": "Output", + "overshot": "Overs -shot", "overwrite_amount": "Sovrascrivi quantità", "pairingInvalidEvent": "Associazione evento non valido", "passphrase": "Passphrase (opzionale)", @@ -533,6 +548,7 @@ "recipient_address": "Indirizzo di destinazione", "reconnect": "Riconnetti", "reconnect_alert_text": "Sei sicuro di volerti riconnettere?", + "reconnect_your_hardware_wallet": "Ricollega il tuo portafoglio hardware", "reconnection": "Riconnessione", "red_dark_theme": "Red Dark Theme", "red_light_theme": "Tema della luce rossa", @@ -572,6 +588,7 @@ "restore_description_from_keys": "Recupera il tuo portafoglio da una sequenza di caratteri generati dalle tue chiavi private", "restore_description_from_seed": "Recupera il tuo portafoglio da una combinazione di 25 o 13 parole", "restore_description_from_seed_keys": "Recupera il tuo portafoglio dal seme/chiavi che hai salvato in un posto sicuro", + "restore_existing_wallet": "Ripristina il portafoglio esistente", "restore_from_date_or_blockheight": "Gentilmente inserisci la data di un paio di giorni prima che hai creato questo portafoglio. Oppure inserisci l'altezza del blocco se la conosci", "restore_from_seed_placeholder": "Gentilmente inserisci o incolla il tuo seme qui", "restore_new_seed": "Nuovo seme", @@ -613,6 +630,7 @@ "seed_alert_title": "Attenzione", "seed_alert_yes": "Sì, l'ho fatto", "seed_choose": "Scegli la lingua del seme", + "seed_display_path": "Menu -> Sicurezza e backup -> Mostra chiave/Semi", "seed_hex_form": "Seme di portafoglio (forma esadecimale)", "seed_key": "Chiave di semi", "seed_language": "Linguaggio di semi", @@ -631,9 +649,13 @@ "seed_language_russian": "Russo", "seed_language_spanish": "Spagnolo", "seed_phrase_length": "Lunghezza della frase seed", + "seed_position_question_one": "Qual è il", + "seed_position_question_two": "Parola della tua frase di semi?", "seed_reminder": "Gentilmente trascrivi le parole. Ti tornerà utile in caso perdessi o ripristinassi il tuo telefono", "seed_share": "Condividi seme", "seed_title": "Seme", + "seed_verified": "Semi verificato", + "seed_verified_subtext": "Puoi usare il tuo seme salvato in seguito per ripristinare questo portafoglio in caso di corruzione o perdere il dispositivo. \n\n Puoi visualizzare di nuovo questo seme dal", "seedtype": "Seedtype", "seedtype_alert_content": "La condivisione di semi con altri portafogli è possibile solo con Bip39 SeedType.", "seedtype_alert_title": "Avviso seedType", @@ -672,6 +694,7 @@ "sent": "Inviato", "service_health_disabled": "Il Bollettino sanitario di servizio è disabilitato", "service_health_disabled_message": "Questa è la pagina del Bollettino sanitario del servizio, è possibile abilitare questa pagina in Impostazioni -> Privacy", + "set_a_pin": "Imposta un pin", "settings": "Impostazioni", "settings_all": "TUTTO", "settings_allow_biometrical_authentication": "Consenti autenticazione biometrica", @@ -707,6 +730,7 @@ "share_address": "Condividi indirizzo", "shared_seed_wallet_groups": "Gruppi di portafoglio di semi condivisi", "show": "Spettacolo", + "show_address_book_popup": "Mostra il popup \"Aggiungi alla rubrica\" ​​dopo l'invio", "show_details": "Mostra dettagli", "show_keys": "Mostra seme/chiavi", "show_market_place": "Mostra mercato", @@ -734,6 +758,10 @@ "silent_payments_settings": "Impostazioni di pagamenti silenziosi", "single_seed_wallets_group": "Portafogli singoli", "slidable": "Scorrevole", + "solana_create_associated_token_account_exception": "Errore Creazione di account token associato per l'indirizzo dei ricevimenti.", + "solana_no_associated_token_account_exception": "Non esiste un account token associato per questo indirizzo.", + "solana_sign_native_transaction_rent_exception": "La transazione non può essere completata. Sol insufficiente lasciato in affitto dopo la transazione. Si prega di ricaricare il saldo SOL o ridurre la quantità di sol che stai inviando.", + "solana_sign_spl_token_transaction_rent_exception": "La transazione non può essere completata. Sol insufficiente lasciato in affitto dopo la transazione. Si prega di ricaricare il tuo equilibrio sol.", "sort_by": "Ordina per", "spend_key_private": "Chiave di spesa (privata)", "spend_key_public": "Chiave di spesa (pubblica)", @@ -746,7 +774,7 @@ "support_description_guides": "Documentazione e supporto per problemi comuni", "support_description_live_chat": "Gratuito e veloce! I rappresentanti di supporto qualificati sono disponibili per assistere", "support_description_other_links": "Unisciti alle nostre comunità o raggiungici i nostri partner attraverso altri metodi", - "support_title_guides": "Guide del portafoglio per torte", + "support_title_guides": "Documenti del portafoglio per torta", "support_title_live_chat": "Supporto dal vivo", "support_title_other_links": "Altri collegamenti di supporto", "sweeping_wallet": "Portafoglio ampio", @@ -825,6 +853,7 @@ "trade_state_underpaid": "Sottopagato", "trade_state_unpaid": "Non pagato", "trades": "Scambi", + "transaction_cost": "Costo delle transazioni", "transaction_details_amount": "Ammontare", "transaction_details_copied": "${title} copiati negli Appunti", "transaction_details_date": "Data", @@ -884,6 +913,7 @@ "variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati", "verification": "Verifica", "verify_message": "Verificare il messaggio", + "verify_seed": "Verifica il seme", "verify_with_2fa": "Verifica con Cake 2FA", "version": "Versione ${currentVersion}", "view_all": "Visualizza tutto", @@ -894,6 +924,7 @@ "voting_weight": "Peso di voto", "waitFewSecondForTxUpdate": "Attendi qualche secondo affinché la transazione venga riflessa nella cronologia delle transazioni", "waiting_payment_confirmation": "In attesa di conferma del pagamento", + "wallet": "Portafoglio", "wallet_group": "Gruppo di portafoglio", "wallet_group_description_four": "Per creare un portafoglio con un seme completamente nuovo.", "wallet_group_description_one": "Nel portafoglio di torte, puoi creare un", @@ -926,6 +957,8 @@ "wallets": "Portafogli", "warning": "Avvertimento", "welcome": "Benvenuto", + "welcome_subtitle_new_wallet": "Se vuoi ricominciare da capo, tocca Crea un nuovo portafoglio di seguito e sarai alle gare.", + "welcome_subtitle_restore_wallet": "Se hai un portafoglio esistente che vuoi portare nella torta, scegli semplicemente il ripristino del portafoglio esistente e ti guideremo attraverso il processo.", "welcome_to_cakepay": "Benvenuto in Cake Pay!", "what_is_silent_payments": "Che cos'è i pagamenti silenziosi?", "widgets_address": "Indirizzo", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index b0a3bb8cc..1130cd949 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -38,6 +38,7 @@ "agree_to": "アカウントを作成することにより、", "alert_notice": "知らせ", "all": "すべて", + "all_coins": "すべてのコイン", "all_trades": "すべての取引", "all_transactions": "全取引", "alphabetical": "アルファベット順", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "世界中のプリペイドカードとギフトカードを購入します", "cake_pay_web_cards_subtitle": "世界中のプリペイド カードとギフト カードを購入する", "cake_pay_web_cards_title": "Cake Pay ウェブカード", + "cake_seeds_save_disclaimer": "これらの言葉を安全な場所に保存してください!新しいデバイスで財布を復元するには、これらの単語が必要です。", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "私はプロキシまたはVPNを使用していないことを確認します", + "cakepay_confirm_purchase": "購入を確認します", + "cakepay_confirm_terms_agreed": "ここに提示されている条件に同意します。", + "cakepay_confirm_voided_refund": "制限された国からの償還の試みが払い戻しを無効にすることを理解しています", + "cakepay_ios_not_available": "申し訳ありませんが、このギフトカードはiOSでは利用できません。代わりにAndroidまたは当社のWebサイトから購入できます。", "cakepay_prepaid_card": "CakePayプリペイドデビットカード", "camera_consent": "あなたのカメラは、${provider}_ までに識別目的で画像を撮影するために使用されます。詳細については、プライバシー ポリシーをご確認ください。", "camera_permission_is_required": "カメラの許可が必要です。\nアプリの設定から有効にしてください。", @@ -175,6 +182,7 @@ "copy_address": "住所をコピー", "copy_id": "IDをコピー", "copyWalletConnectLink": "dApp から WalletConnect リンクをコピーし、ここに貼り付けます", + "corrupted_seed_notice": "このウォレットのファイルは破損しており、開くことができません。シードフレーズを表示し、保存し、財布を復元してください。\n\n値が空の場合、種子を正しく回復することができませんでした。", "countries": "国", "create_account": "アカウントの作成", "create_backup": "バックアップを作成", @@ -256,7 +264,7 @@ "enterTokenID": "トークンIDを入力してください", "enterWalletConnectURI": "WalletConnect URI を入力してください", "error": "エラー", - "error_dialog_content": "エラーが発生しました。\n\nアプリケーションを改善するために、クラッシュ レポートをサポート チームに送信してください。", + "error_dialog_content": "おっと、エラーが発生しました。\n\nサポートチームにエラーレポートを送信して、アプリケーションを改善してください。", "error_text_account_name": "アカウント名には文字のみを含めることができます \n1〜15文字である必要があります", "error_text_address": "ウォレットアドレスは、\n暗号通貨", "error_text_amount": "金額には数字のみを含めることができます", @@ -323,6 +331,7 @@ "frequently_asked_questions": "よくある質問", "frozen": "凍った", "full_balance": "フルバランス", + "gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。", "generate_name": "名前の生成", "generated_gift_card": "ギフトカードの生成", "generating_gift_card": "ギフトカードの生成", @@ -351,13 +360,17 @@ "how_to_use": "使い方", "how_to_use_card": "このカードの使用方法", "id": "ID: ", + "if_you_dont_see_your_device": "上記のデバイスが表示されない場合は、元帳が目を覚ましてロック解除されていることを確認してください!", "ignor": "無視", "import": "輸入", "importNFTs": "NFTのインポート", "in_store": "インストア", "incoming": "着信", "incorrect_seed": "入力されたテキストは無効です。", + "incorrect_seed_option": "正しくない。もう一度やり直してください", + "incorrect_seed_option_back": "正しくない。種子が正しく保存されていることを確認し、再試行してください。", "inputs": "入力", + "insufficient_funds_for_tx": "トランザクションを正常に実行するための資金が不十分です。", "insufficient_lamport_for_tx": "トランザクションとその取引手数料をカバーするのに十分なSOLがありません。財布にソルを追加するか、送信するソル量を減らしてください。", "insufficient_lamports": "トランザクションとその取引手数料をカバーするのに十分なSOLがありません。少なくとも${solValueNeeded} solが必要です。財布にソルを追加するか、送信するソル量を減らしてください", "insufficientFundsForRentError": "アカウントの取引料金とレンタルをカバーするのに十分なソルがありません。財布にソルを追加するか、送信するソル量を減らしてください", @@ -428,7 +441,7 @@ "nano_pick_new_rep": "新しい代表者を選びます", "nanogpt_subtitle": "すべての最新モデル(GPT-4、Claude)。\\ nnoサブスクリプション、暗号で支払います。", "narrow": "狭い", - "new_first_wallet_text": "暗号通貨を簡単に安全に保ちます", + "new_first_wallet_text": "暗号を安全に保つことはケーキです", "new_node_testing": "新しいノードのテスト", "new_subaddress_create": "作成する", "new_subaddress_label_name": "ラベル名", @@ -465,6 +478,7 @@ "online": "オンライン", "onramper_option_description": "多くの支払い方法で暗号をすばやく購入してください。ほとんどの国で利用可能です。スプレッドと料金は異なります。", "open_gift_card": "オープンギフトカード", + "open_wallet": "開いたウォレット", "optional_description": "オプションの説明", "optional_email_hint": "オプションの受取人通知メール", "optional_name": "オプションの受信者名", @@ -478,6 +492,7 @@ "outdated_electrum_wallet_receive_warning": "このウォレットに 12 ワードのシードがあり、Cake で作成された場合、このウォレットにビットコインを入金しないでください。 このウォレットに転送された BTC は失われる可能性があります。 新しい 24 ワードのウォレットを作成し (右上のメニューをタップし、[ウォレット]、[新しいウォレットの作成]、[ビットコイン] の順に選択)、すぐに BTC をそこに移動します。 Cake の新しい (24 ワード) BTC ウォレットは安全です", "outgoing": "発信", "outputs": "出力", + "overshot": "オーバーショット", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "ペアリング無効イベント", "passphrase": "パスフレーズ(オプション)", @@ -532,6 +547,7 @@ "recipient_address": "受信者のアドレス", "reconnect": "再接続", "reconnect_alert_text": "再接続しますか?", + "reconnect_your_hardware_wallet": "ハードウェアウォレットを再接続します", "reconnection": "再接続", "red_dark_theme": "赤い暗いテーマ", "red_light_theme": "赤色光のテーマ", @@ -571,6 +587,7 @@ "restore_description_from_keys": "生成されたウォレットを復元します秘密鍵から保存されたキーストローク", "restore_description_from_seed": "25ワードからウォレットを復元しますまたは13ワードの組み合わせコード", "restore_description_from_seed_keys": "安全な場所に保存したシード/キーから財布を取り戻す", + "restore_existing_wallet": "既存のウォレットを復元します", "restore_from_date_or_blockheight": "このウォレットを作成する数日前に日付を入力してください。 または、ブロックの高さがわかっている場合は、代わりに入力してください", "restore_from_seed_placeholder": "ここにコードフレーズを入力または貼り付けてください", "restore_new_seed": "新しい種", @@ -612,6 +629,7 @@ "seed_alert_title": "注意", "seed_alert_yes": "はい、あります", "seed_choose": "シード言語を選択してください", + "seed_display_path": "メニュー - >セキュリティとバックアップ - >キー/シードを表示します", "seed_hex_form": "ウォレットシード(ヘックスフォーム)", "seed_key": "シードキー", "seed_language": "シード言語", @@ -630,9 +648,13 @@ "seed_language_russian": "ロシア", "seed_language_spanish": "スペイン語", "seed_phrase_length": "シードフレーズの長さ", + "seed_position_question_one": "何ですか", + "seed_position_question_two": "あなたの種のフレーズの言葉?", "seed_reminder": "スマートフォンを紛失したりワイプした場合に備えて、これらを書き留めてください", "seed_share": "シードを共有する", "seed_title": "シード", + "seed_verified": "種子確認済み", + "seed_verified_subtext": "後で保存された種子を使用して、腐敗やデバイスの紛失の場合にこの財布を復元することができます。\n\nこのシードを再度見ることができます", "seedtype": "SeedType", "seedtype_alert_content": "他の財布と種子を共有することは、BIP39 SeedTypeでのみ可能です。", "seedtype_alert_title": "SeedTypeアラート", @@ -671,6 +693,7 @@ "sent": "送信済み", "service_health_disabled": "サービスヘルス速報は無効です", "service_health_disabled_message": "これはService Health Bulletinページです。設定の下でこのページを有効にすることができます - >プライバシー", + "set_a_pin": "ピンを設定します", "settings": "設定", "settings_all": "すべて", "settings_allow_biometrical_authentication": "生体認証を許可する", @@ -706,6 +729,7 @@ "share_address": "住所を共有する", "shared_seed_wallet_groups": "共有シードウォレットグループ", "show": "見せる", + "show_address_book_popup": "送信後に「アドレスブックに追加」ポップアップを表示します", "show_details": "詳細を表示", "show_keys": "シード/キーを表示する", "show_market_place": "マーケットプレイスを表示", @@ -733,6 +757,10 @@ "silent_payments_settings": "サイレントペイメント設定", "single_seed_wallets_group": "シングルシードウォレット", "slidable": "スライド可能", + "solana_create_associated_token_account_exception": "関連するトークンの作成エラー受信アドレスのアカウント。", + "solana_no_associated_token_account_exception": "このアドレスに関連付けられたトークンアカウントはありません。", + "solana_sign_native_transaction_rent_exception": "トランザクションは完了できません。取引後にレンタルのために残された不十分なソル。ソルバランスを補充するか、送信するソルの量を減らしてください。", + "solana_sign_spl_token_transaction_rent_exception": "トランザクションは完了できません。取引後にレンタルのために残された不十分なソル。ソルバランスを補充してください。", "sort_by": "並び替え", "spend_key_private": "キーを使う (プライベート)", "spend_key_public": "キーを使う (パブリック)", @@ -745,7 +773,7 @@ "support_description_guides": "一般的な問題のドキュメントとサポート", "support_description_live_chat": "無料で速い!訓練されたサポート担当者が支援することができます", "support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください", - "support_title_guides": "ケーキウォレットガイド", + "support_title_guides": "ケーキウォレットドキュメント", "support_title_live_chat": "ライブサポート", "support_title_other_links": "その他のサポートリンク", "sweeping_wallet": "スイープウォレット", @@ -824,6 +852,7 @@ "trade_state_underpaid": "支払不足", "trade_state_unpaid": "未払い", "trades": "取引", + "transaction_cost": "取引コスト", "transaction_details_amount": "量", "transaction_details_copied": "${title} クリップボードにコピーしました", "transaction_details_date": "日付", @@ -883,6 +912,7 @@ "variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません", "verification": "検証", "verify_message": "メッセージを確認します", + "verify_seed": "シードを確認します", "verify_with_2fa": "Cake 2FA で検証する", "version": "バージョン ${currentVersion}", "view_all": "すべて表示", @@ -892,6 +922,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "投票重み", "waitFewSecondForTxUpdate": "取引履歴に取引が反映されるまで数秒お待ちください。", + "wallet": "財布", "wallet_group": "ウォレットグループ", "wallet_group_description_four": "まったく新しい種子の財布を作成します。", "wallet_group_description_one": "ケーキウォレットでは、aを作成できます", @@ -924,6 +955,8 @@ "wallets": "財布", "warning": "警告", "welcome": "ようこそ に", + "welcome_subtitle_new_wallet": "新鮮な開始したい場合は、以下の新しい財布を作成すると、レースに出かけることができます。", + "welcome_subtitle_restore_wallet": "ケーキに持ち込みたい既存のウォレットがある場合は、既存のウォレットを復元するだけで、プロセスを説明します。", "welcome_to_cakepay": "Cake Payへようこそ!", "what_is_silent_payments": "サイレント支払いとは何ですか?", "widgets_address": "住所", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 7b16bc3ce..e19b50ab6 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -38,6 +38,7 @@ "agree_to": "계정을 생성하면 ", "alert_notice": "알아채다", "all": "모든", + "all_coins": "모든 동전", "all_trades": "A모든 거래", "all_transactions": "모든 거래 창구", "alphabetical": "알파벳순", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "전세계 선불 카드와 기프트 카드를 구입하십시오", "cake_pay_web_cards_subtitle": "전 세계 선불 카드 및 기프트 카드 구매", "cake_pay_web_cards_title": "케이크페이 웹카드", + "cake_seeds_save_disclaimer": "이 단어를 안전한 장소에 저장하십시오! 새 장치에서 지갑을 복원하려면이 단어가 필요합니다.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "프록시 나 VPN을 사용하지 않는지 확인합니다.", + "cakepay_confirm_purchase": "구매 확인", + "cakepay_confirm_terms_agreed": "여기에 제시된 이용 약관에 동의합니다.", + "cakepay_confirm_voided_refund": "제한된 국가의 상환 시도는 환불을 무효화한다는 것을 이해합니다.", + "cakepay_ios_not_available": "죄송합니다.이 기프트 카드는 iOS에서 사용할 수 없습니다. Android 또는 웹 사이트를 통해 구매할 수 있습니다.", "cakepay_prepaid_card": "CakePay 선불 직불 카드", "camera_consent": "귀하의 카메라는 ${provider}의 식별 목적으로 이미지를 캡처하는 데 사용됩니다. 자세한 내용은 해당 개인정보 보호정책을 확인하세요.", "camera_permission_is_required": "카메라 권한이 필요합니다.\n앱 설정에서 활성화해 주세요.", @@ -175,6 +182,7 @@ "copy_address": "주소 복사", "copy_id": "부 ID", "copyWalletConnectLink": "dApp에서 WalletConnect 링크를 복사하여 여기에 붙여넣으세요.", + "corrupted_seed_notice": "이 지갑의 파일은 손상되어 열 수 없습니다. 씨앗 문구를보고 저장하고 지갑을 복원하십시오.\n\n값이 비어 있으면 씨앗을 올바르게 회수 할 수 없었습니다.", "countries": "국가", "create_account": "계정 만들기", "create_backup": "백업 생성", @@ -256,7 +264,7 @@ "enterTokenID": "토큰 ID를 입력하세요", "enterWalletConnectURI": "WalletConnect URI를 입력하세요.", "error": "오류", - "error_dialog_content": "죄송합니다. 오류가 발생했습니다.\n\n응용 프로그램을 개선하려면 지원 팀에 충돌 보고서를 보내주십시오.", + "error_dialog_content": "죄송합니다. 오류가 발생했습니다.\n\n오류 보고서를 지원 팀에 보내 응용 프로그램을 개선하십시오.", "error_text_account_name": "계정 이름은 문자, 숫자 만 포함 할 수 있습니다\n1 ~ 15 자 사이 여야합니다", "error_text_address": "지갑 주소는 유형과 일치해야합니다\n암호 화폐", "error_text_amount": "금액은 숫자 만 포함 할 수 있습니다", @@ -323,6 +331,7 @@ "frequently_asked_questions": "자주 묻는 질문", "frozen": "겨울 왕국", "full_balance": "풀 밸런스", + "gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.", "generate_name": "이름 생성", "generating_gift_card": "기프트 카드 생성 중", "get_a": "가져오기", @@ -350,13 +359,17 @@ "how_to_use": "사용하는 방법", "how_to_use_card": "이 카드를 사용하는 방법", "id": "ID: ", + "if_you_dont_see_your_device": "위의 장치가 표시되지 않으면 원장이 깨어 있고 잠금 해제되었는지 확인하십시오!", "ignor": "무시하다", "import": "수입", "importNFTs": "NFT 가져오기", "in_store": "매장 내", "incoming": "들어오는", "incorrect_seed": "입력하신 텍스트가 유효하지 않습니다.", + "incorrect_seed_option": "잘못된. 다시 시도하십시오", + "incorrect_seed_option_back": "잘못된. 씨앗이 올바르게 저장되어 있는지 확인하고 다시 시도하십시오.", "inputs": "입력", + "insufficient_funds_for_tx": "거래를 성공적으로 실행하기위한 자금이 충분하지 않습니다.", "insufficient_lamport_for_tx": "거래 및 거래 수수료를 충당하기에 충분한 SOL이 없습니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄입니다.", "insufficient_lamports": "거래 및 거래 수수료를 충당하기에 충분한 SOL이 없습니다. 최소 ${solValueNeeded} sol이 필요합니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄이십시오.", "insufficientFundsForRentError": "거래 수수료와 계좌 임대료를 충당하기에 충분한 SOL이 없습니다. 지갑에 더 많은 솔을 추가하거나 보내는 솔을 줄이십시오.", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "새로운 담당자를 선택하십시오", "nanogpt_subtitle": "모든 최신 모델 (GPT-4, Claude). \\ nno 구독, Crypto로 지불하십시오.", "narrow": "좁은", - "new_first_wallet_text": "cryptocurrency를 쉽게 안전하게 유지하십시오", + "new_first_wallet_text": "암호화를 안전하게 유지하는 것은 케이크 조각입니다", "new_node_testing": "새로운 노드 테스트", "new_subaddress_create": "몹시 떠들어 대다", "new_subaddress_label_name": "라벨 이름", @@ -464,6 +477,7 @@ "online": "온라인", "onramper_option_description": "많은 결제 방법으로 암호화를 신속하게 구입하십시오. 대부분의 국가에서 사용할 수 있습니다. 스프레드와 수수료는 다양합니다.", "open_gift_card": "기프트 카드 열기", + "open_wallet": "오픈 지갑", "optional_description": "선택적 설명", "optional_email_hint": "선택적 수취인 알림 이메일", "optional_name": "선택적 수신자 이름", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "이 지갑에 12 단어 시드가 있고 Cake에서 생성 된 경우이 지갑에 비트 코인을 입금하지 마십시오. 이 지갑으로 전송 된 모든 BTC는 손실 될 수 있습니다. 새로운 24 단어 지갑을 생성하고 (오른쪽 상단의 메뉴를 탭하고 지갑을 선택한 다음 새 지갑 생성을 선택한 다음 비트 코인을 선택하십시오) 즉시 BTC를 그곳으로 이동하십시오. Cake의 새로운 (24 단어) BTC 지갑은 안전합니다", "outgoing": "나가는", "outputs": "출력", + "overshot": "오버 샷", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "잘못된 이벤트 페어링", "passphrase": "암호화 (선택 사항)", @@ -532,6 +547,7 @@ "recipient_address": "받는 사람 주소", "reconnect": "다시 연결", "reconnect_alert_text": "다시 연결 하시겠습니까?", + "reconnect_your_hardware_wallet": "하드웨어 지갑을 다시 연결하십시오", "reconnection": "재 연결", "red_dark_theme": "빨간 어두운 테마", "red_light_theme": "빨간불 테마", @@ -571,6 +587,7 @@ "restore_description_from_keys": "개인 키에서 저장된 생성 된 키 스트로크에서 월렛 복원", "restore_description_from_seed": "25 단어 또는 13 단어 조합 코드에서 지갑을 복원하십시오.", "restore_description_from_seed_keys": "안전한 장소에 저장 한 종자 / 키로 지갑을 되 찾으십시오.", + "restore_existing_wallet": "기존 지갑을 복원하십시오", "restore_from_date_or_blockheight": "이 지갑을 생성하기 며칠 전에 날짜를 입력하십시오. 또는 블록 높이를 알고있는 경우 대신 입력하십시오.", "restore_from_seed_placeholder": "여기에 코드 문구를 입력하거나 붙여 넣으십시오.", "restore_new_seed": "새로운 씨앗", @@ -612,6 +629,7 @@ "seed_alert_title": "주의", "seed_alert_yes": "네, 있어요", "seed_choose": "시드 언어를 선택하십시오", + "seed_display_path": "메뉴 -> 보안 및 백업 -> 키/씨앗 표시", "seed_hex_form": "지갑 씨앗 (16 진 양식)", "seed_key": "시드 키", "seed_language": "종자 언어", @@ -630,9 +648,13 @@ "seed_language_russian": "러시아인", "seed_language_spanish": "스페인의", "seed_phrase_length": "시드 문구 길이", + "seed_position_question_one": "무엇입니까", + "seed_position_question_two": "당신의 씨앗 문구의 말?", "seed_reminder": "휴대 전화를 분실하거나 닦을 경우를 대비해 적어 두세요.", "seed_share": "시드 공유", "seed_title": "씨", + "seed_verified": "종자 확인", + "seed_verified_subtext": "나중에 저장된 씨앗을 사용하여 부패 또는 장치를 잃을 때이 지갑을 복원 할 수 있습니다.\n\n이 씨앗을 다시 볼 수 있습니다.", "seedtype": "시드 타입", "seedtype_alert_content": "다른 지갑과 씨앗을 공유하는 것은 BIP39 SeedType에서만 가능합니다.", "seedtype_alert_title": "종자 경보", @@ -671,6 +693,7 @@ "sent": "보냄", "service_health_disabled": "서비스 건강 게시판이 장애가되었습니다", "service_health_disabled_message": "이것은 서비스 건강 게시판 페이지입니다. 설정 에서이 페이지를 활성화 할 수 있습니다 -> 개인 정보", + "set_a_pin": "핀을 설정하십시오", "settings": "설정", "settings_all": "모든", "settings_allow_biometrical_authentication": "생체 인증 허용", @@ -706,6 +729,7 @@ "share_address": "주소 공유", "shared_seed_wallet_groups": "공유 종자 지갑 그룹", "show": "보여주다", + "show_address_book_popup": "전송 후 '주소 책에 추가'팝업을 표시하십시오", "show_details": "세부정보 표시", "show_keys": "시드 / 키 표시", "show_market_place": "마켓플레이스 표시", @@ -733,6 +757,10 @@ "silent_payments_settings": "조용한 지불 설정", "single_seed_wallets_group": "단일 씨앗 지갑", "slidable": "슬라이딩 가능", + "solana_create_associated_token_account_exception": "오류 생성 관련 토큰 계정 수령자 주소에 대한 계정.", + "solana_no_associated_token_account_exception": "이 주소에는 관련 토큰 계정이 없습니다.", + "solana_sign_native_transaction_rent_exception": "거래는 완료 될 수 없습니다. 거래 후 SOL이 임대료로 남았습니다. SOL 밸런스를 친절하게 위로 올리거나 보내는 솔의 양을 줄입니다.", + "solana_sign_spl_token_transaction_rent_exception": "거래는 완료 될 수 없습니다. 거래 후 SOL이 임대료로 남았습니다. SOL 균형을 친절하게 위에 올리십시오.", "sort_by": "정렬 기준", "spend_key_private": "지출 키 (은밀한)", "spend_key_public": "지출 키 (공공의)", @@ -745,7 +773,7 @@ "support_description_guides": "일반적인 문제에 대한 문서화 및 지원", "support_description_live_chat": "자유롭고 빠릅니다! 훈련 된 지원 담당자가 지원할 수 있습니다", "support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오.", - "support_title_guides": "케이크 지갑 가이드", + "support_title_guides": "케이크 지갑 문서", "support_title_live_chat": "실시간 지원", "support_title_other_links": "다른 지원 링크", "sweeping_wallet": "스위핑 지갑", @@ -824,6 +852,7 @@ "trade_state_underpaid": "미지급", "trade_state_unpaid": "미지급", "trades": "거래", + "transaction_cost": "거래 비용", "transaction_details_amount": "양", "transaction_details_copied": "${title} 클립 보드에 복사", "transaction_details_date": "날짜", @@ -883,6 +912,7 @@ "variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.", "verification": "검증", "verify_message": "메시지를 확인하십시오", + "verify_seed": "씨앗을 확인하십시오", "verify_with_2fa": "케이크 2FA로 확인", "version": "버전 ${currentVersion}", "view_all": "모두 보기", @@ -892,6 +922,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "투표 중량", "waitFewSecondForTxUpdate": "거래 내역에 거래가 반영될 때까지 몇 초 정도 기다려 주세요.", + "wallet": "지갑", "wallet_group": "지갑 그룹", "wallet_group_description_four": "완전히 새로운 씨앗으로 지갑을 만듭니다.", "wallet_group_description_one": "케이크 지갑에서는 a를 만들 수 있습니다", @@ -924,6 +955,8 @@ "wallets": "지갑", "warning": "경고", "welcome": "환영 에", + "welcome_subtitle_new_wallet": "신선하게 시작하려면 아래에서 새 지갑을 만들면 레이스로 떠날 것입니다.", + "welcome_subtitle_restore_wallet": "케이크에 가져 오려는 기존 지갑이 있다면 기존 지갑 복원을 선택하면 프로세스를 안내해 드리겠습니다.", "welcome_to_cakepay": "Cake Pay에 오신 것을 환영합니다!", "what_is_silent_payments": "조용한 지불이란 무엇입니까?", "widgets_address": "주소", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index bb3d070fa..fa7ac2c17 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -38,6 +38,7 @@ "agree_to": "အကောင့်ဖန်တီးခြင်းဖြင့် သင်သည် ဤအရာကို သဘောတူပါသည်။", "alert_notice": "မှတ်သား", "all": "အားလုံး", + "all_coins": "အားလုံးဒင်္ဂါးများ", "all_trades": "ကုန်သွယ်မှုအားလုံး", "all_transactions": "အရောင်းအဝယ်အားလုံး", "alphabetical": "အက္ခရာစဉ်", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Worldwide ကြိုတင်ငွေဖြည့်ကဒ်များနှင့်လက်ဆောင်ကဒ်များကို 0 ယ်ပါ", "cake_pay_web_cards_subtitle": "ကမ္ဘာတစ်ဝှမ်း ကြိုတင်ငွေပေးကတ်များနှင့် လက်ဆောင်ကတ်များကို ဝယ်ယူပါ။", "cake_pay_web_cards_title": "Cake Pay ဝဘ်ကတ်များ", + "cake_seeds_save_disclaimer": "ကျေးဇူးပြုပြီးဒီစကားလုံးတွေကိုလုံခြုံတဲ့နေရာမှာသိမ်းထားပါ။ သင်၏ပိုက်ဆံအိတ်ကိုကိရိယာအသစ်တစ်ခုတွင်သင်၏ပိုက်ဆံအိတ်ကိုပြန်လည်ရယူရန်ဤစကားလုံးများကိုသင်လိုအပ်လိမ့်မည်။", "cake_wallet": "Cake ပိုက်ဆံအိတ်", + "cakepay_confirm_no_vpn": "ငါ proxy သို့မဟုတ် vpn ကိုမသုံးပါ", + "cakepay_confirm_purchase": "ဝယ်ယူမှုအတည်ပြုပါ", + "cakepay_confirm_terms_agreed": "ဒီမှာတင်ပြထားတဲ့စည်းကမ်းချက်များကိုငါသဘောတူတယ်။", + "cakepay_confirm_voided_refund": "ကန့်သတ်ထားသောနိုင်ငံမှရွေးနုတ်ခြင်းကြိုးပမ်းမှုများကိုကျွန်ုပ်နားလည်ပါသည်", + "cakepay_ios_not_available": "တောင်းပန်ပါတယ်, ဒီလက်ဆောင်ကဒ်ကို iOS မှာမရနိုင်ပါ။ ၎င်းကို Android တွင်သို့မဟုတ်ကျွန်ုပ်တို့၏ဝက်ဘ်ဆိုက်တွင် 0 ယ်နိုင်သည်။", "cakepay_prepaid_card": "CakePay ကြိုတင်ငွေဖြည့်ဒက်ဘစ်ကတ်", "camera_consent": "မှတ်ပုံတင်ခြင်းရည်ရွယ်ချက်များအတွက် ${provider} တွင် သင့်ကင်မရာကို အသုံးပြုပါမည်။ အသေးစိတ်အတွက် ၎င်းတို့၏ ကိုယ်ရေးကိုယ်တာမူဝါဒကို စစ်ဆေးပါ။", "camera_permission_is_required": "ကင်မရာခွင့်ပြုချက် လိုအပ်ပါသည်။\nအက်ပ်ဆက်တင်များမှ ၎င်းကိုဖွင့်ပါ။", @@ -175,6 +182,7 @@ "copy_address": "လိပ်စာကို ကူးယူပါ။", "copy_id": "ID ကူးယူပါ။", "copyWalletConnectLink": "dApp မှ WalletConnect လင့်ခ်ကို ကူးယူပြီး ဤနေရာတွင် ကူးထည့်ပါ။", + "corrupted_seed_notice": "ဤပိုက်ဆံအိတ်အတွက်ဖိုင်များသည်အကျင့်ပျက်ခြစားမှုများနှင့်မဖွင့်နိုင်ပါ။ ကျေးဇူးပြု. မျိုးစေ့များကိုကြည့်ပါ, ၎င်းကိုသိမ်းဆည်းပါ, ပိုက်ဆံအိတ်ကိုပြန်ယူပါ။\n\nအကယ်. တန်ဖိုးသည်အချည်းနှီးဖြစ်ပါကမျိုးစေ့ကိုမှန်ကန်စွာပြန်လည်ကောင်းမွန်မရရှိနိုင်ပါ။", "countries": "နိုင်ငံများ", "create_account": "အကောင့်ပြုလုပ်ပါ", "create_backup": "အရန်သိမ်းခြင်းကို ဖန်တီးပါ။", @@ -256,7 +264,7 @@ "enterTokenID": "တိုကင် ID ကိုထည့်ပါ။", "enterWalletConnectURI": "WalletConnect URI ကိုရိုက်ထည့်ပါ။", "error": "အမှား", - "error_dialog_content": "အိုး၊ ကျွန်ုပ်တို့တွင် အမှားအယွင်းအချို့ရှိသည်။\n\nအပလီကေးရှင်းကို ပိုမိုကောင်းမွန်စေရန်အတွက် ပျက်စီးမှုအစီရင်ခံစာကို ကျွန်ုပ်တို့၏ပံ့ပိုးကူညီရေးအဖွဲ့ထံ ပေးပို့ပါ။", + "error_dialog_content": "အိုး, ငါတို့အမှားအယွင်းတွေရတယ်။\n\nလျှောက်လွှာကိုပိုကောင်းအောင်လုပ်ရန်ကျွန်ုပ်တို့၏ထောက်ခံမှုအဖွဲ့သို့အမှားအယွင်းများပေးပို့ပါ။", "error_text_account_name": "အကောင့်အမည်သည် အက္ခရာများ၊ နံပါတ်များသာ ပါဝင်နိုင်သည်\nနှင့် စာလုံးရေ 1 နှင့် 15 ကြားရှိရပါမည်။", "error_text_address": "Wallet လိပ်စာသည် အမျိုးအစား\no cryptocurrency နှင့် ကိုက်ညီရပါမည်။", "error_text_amount": "ပမာဏသည် နံပါတ်များသာ ပါဝင်နိုင်သည်။", @@ -323,6 +331,7 @@ "frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ", "frozen": "ဖြူဖြူ", "full_balance": "Balance အပြည့်", + "gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။", "generate_name": "အမည်ဖန်တီးပါ။", "generating_gift_card": "လက်ဆောင်ကတ်ထုတ်ပေးခြင်း။", "get_a": "တစ်ခုရယူပါ။", @@ -350,13 +359,17 @@ "how_to_use": "အသုံးပြုနည်း", "how_to_use_card": "ဒီကတ်ကို ဘယ်လိုသုံးမလဲ။", "id": "ID:", + "if_you_dont_see_your_device": "သင်၏စက်ကိုအထက်တွင်မတွေ့ပါကသင်၏ Ledger သည်နိုးလာပြီးသော့ဖွင့်နေသည်ကိုသေချာပါစေ။", "ignor": "လျစ်လျူရှုပါ။", "import": "သွင်းကုန်", "importNFTs": "NFTs များကို တင်သွင်းပါ။", "in_store": "စတိုးတွင်", "incoming": "ဝင်လာ", "incorrect_seed": "ထည့်သွင်းထားသော စာသားသည် မမှန်ကန်ပါ။", + "incorrect_seed_option": "မမှန်ကန်ပါ ကျေးဇူးပြုပြီးထပ်ကြိုးစားပါ", + "incorrect_seed_option_back": "မမှန်ကန်ပါ သင်၏မျိုးစေ့ကိုမှန်ကန်စွာသိမ်းဆည်းပြီးထပ်မံကြိုးစားပါ။", "inputs": "သွင်းငေှ", + "insufficient_funds_for_tx": "ငွေပေးငွေယူအောင်မြင်စွာလုပ်ဆောင်ရန်ရန်ပုံငွေမလုံလောက်ပါ။", "insufficient_lamport_for_tx": "သငျသညျငွေပေးငွေယူနှင့်၎င်း၏ငွေပေးငွေယူကြေးကိုဖုံးလွှမ်းရန် sol ရှိသည်မဟုတ်ကြဘူး။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုထပ်ထည့်ပါသို့မဟုတ်သင်ပို့လွှတ်ခြင်း sol ပမာဏကိုလျှော့ချပါ။", "insufficient_lamports": "သငျသညျငွေပေးငွေယူနှင့်၎င်း၏ငွေပေးငွေယူကြေးကိုဖုံးလွှမ်းရန် sol ရှိသည်မဟုတ်ကြဘူး။ သင်အနည်းဆုံး ${solValueNeeded} s ကိုလိုအပ်ပါတယ်။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုထပ်ထည့်ပါသို့မဟုတ်သင်ပို့နေသော sol ပမာဏကိုလျှော့ချပါ", "insufficientFundsForRentError": "သင်ငွေပေးချေမှုအခကြေးငွေကိုဖုံးအုပ်ရန်နှင့်အကောင့်ငှားရန်လုံလောက်သော sol ရှိသည်မဟုတ်ကြဘူး။ ကြင်နာစွာသင်၏ပိုက်ဆံအိတ်သို့ပိုမို sol ကိုပိုမိုထည့်ပါသို့မဟုတ်သင်ပို့ခြင်း sol ပမာဏကိုလျှော့ချပါ", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "အသစ်တစ်ခုကိုရွေးပါ", "nanogpt_subtitle": "အားလုံးနောက်ဆုံးပေါ်မော်ဒယ်များ (GPT-4, Claude) ။ \\ nno subscription, crypto နှင့်အတူပေးဆောင်။", "narrow": "ကျဉ်းသော", - "new_first_wallet_text": "သင့်ရဲ့ cryptocurrencrencres ကိုအလွယ်တကူလုံခြုံစွာထားရှိပါ", + "new_first_wallet_text": "သင်၏ Crypto Safe ကိုလုံခြုံအောင်ပြုလုပ်ခြင်းသည်ကိတ်မုန့်တစ်မျိုးဖြစ်သည်", "new_node_testing": "နှာခေါင်း အသစ်စမ်းသပ်ခြင်း။", "new_subaddress_create": "ဖန်တီးပါ။", "new_subaddress_label_name": "အညွှန်းအမည်", @@ -464,6 +477,7 @@ "online": "အွန်လိုင်း", "onramper_option_description": "ငွေပေးချေမှုနည်းလမ်းများစွာဖြင့် Crypto ကိုလျင်မြန်စွာ 0 ယ်ပါ။ နိုင်ငံအများစုတွင်ရရှိနိုင်ပါသည်။ ဖြန့်ဖြူးနှင့်အခကြေးငွေကွဲပြားခြားနားသည်။", "open_gift_card": "Gift Card ကိုဖွင့်ပါ။", + "open_wallet": "ပွင့်လင်းပိုက်ဆံအိတ်", "optional_description": "ရွေးချယ်နိုင်သော ဖော်ပြချက်", "optional_email_hint": "ရွေးချယ်နိုင်သော ငွေလက်ခံသူ အကြောင်းကြားချက် အီးမေးလ်", "optional_name": "ရွေးချယ်နိုင်သော လက်ခံသူအမည်", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "ဤပိုက်ဆံအိတ်တွင် စာလုံး 12 လုံးပါပြီး ကိတ်မုန့်တွင် ဖန်တီးပါက၊ Bitcoin ကို ဤပိုက်ဆံအိတ်ထဲသို့ မထည့်ပါနှင့်။ ဤပိုက်ဆံအိတ်သို့ လွှဲပြောင်းပေးသည့် မည်သည့် BTC မဆို ဆုံးရှုံးနိုင်သည်။ 24 စကားလုံးပိုက်ဆံအိတ်အသစ်တစ်ခုဖန်တီးပါ (ညာဘက်အပေါ်ထောင့်ရှိမီနူးကိုနှိပ်ပါ၊ Wallets ကိုရွေးချယ်ပါ၊ ပိုက်ဆံအိတ်အသစ်ဖန်တီးရန်ကိုရွေးချယ်ပါ၊ ထို့နောက် Bitcoin ကိုရွေးချယ်ပါ) နှင့်သင်၏ BTC ကိုထိုနေရာသို့ချက်ချင်းရွှေ့ပါ။ Cake မှ (24 စာလုံး) BTC ပိုက်ဆံအိတ်အသစ်များသည် လုံခြုံပါသည်။", "outgoing": "အထွက်", "outputs": "ထုတ်လုပ်မှု", + "overshot": "အလွန်အကျွံအိုး", "overwrite_amount": "ပမာဏကို ထပ်ရေးပါ။", "pairingInvalidEvent": "မမှန်ကန်သောဖြစ်ရပ်ကို တွဲချိတ်ခြင်း။", "passphrase": "passphrase (optional)", @@ -531,6 +546,7 @@ "recipient_address": "လက်ခံသူလိပ်စာ", "reconnect": "ပြန်လည်ချိတ်ဆက်ပါ။", "reconnect_alert_text": "ပြန်လည်ချိတ်ဆက်လိုသည်မှာ သေချာပါသလား။ ?", + "reconnect_your_hardware_wallet": "သင့်ရဲ့ hardware ပိုက်ဆံအိတ်ကိုပြန်လည်ချိတ်ဆက်ပါ", "reconnection": "ပြန်လည်ချိတ်ဆက်မှု", "red_dark_theme": "အနီရောင်မှောင်မိုက်ဆောင်ပုဒ်", "red_light_theme": "အနီရောင်အလင်းအကြောင်းအရာ", @@ -570,6 +586,7 @@ "restore_description_from_keys": "သင့်ကိုယ်ပိုင်သော့များမှ သိမ်းဆည်းထားသော ထုတ်ပေးထားသော သော့ချက်များမှ သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူပါ။", "restore_description_from_seed": "25 စကားလုံး သို့မဟုတ် 13 စကားလုံးပေါင်းစပ်ကုဒ်မှ သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူပါ။", "restore_description_from_seed_keys": "သင့်ပိုက်ဆံအိတ်ကို လုံခြုံသောနေရာတွင် သိမ်းဆည်းထားသော မျိုးစေ့/သော့များမှ ပြန်လည်ရယူပါ။", + "restore_existing_wallet": "ရှိပြီးသားပိုက်ဆံအိတ်ကို restore", "restore_from_date_or_blockheight": "ဤပိုက်ဆံအိတ်ကို သင်မဖန်တီးမီ ရက်အနည်းငယ်အလိုတွင် ရက်စွဲတစ်ခု ထည့်သွင်းပါ။ သို့မဟုတ် ဘလော့ခ်ဟိုက် ကို သိပါက ၎င်းအစား ၎င်းကို ထည့်ပါ။", "restore_from_seed_placeholder": "သင့်အစေ့ကို ဤနေရာတွင် ထည့်ပါ သို့မဟုတ် ကူးထည့်ပါ။", "restore_new_seed": "မျိုးစေ့အသစ်", @@ -611,6 +628,7 @@ "seed_alert_title": "အာရုံ", "seed_alert_yes": "ဟုတ်ကဲ့၊", "seed_choose": "မျိုးစေ့ဘာသာစကားကို ရွေးချယ်ပါ။", + "seed_display_path": "Menu -> Security နှင့် Backup -> သော့ / အစေ့များကိုပြပါ", "seed_hex_form": "ပိုက်ဆံအိတ်မျိုးစေ့ (Hex Form)", "seed_key": "မျိုးစေ့သော့", "seed_language": "မျိုးစေ့ဘာသာ", @@ -629,9 +647,13 @@ "seed_language_russian": "ရုရှ", "seed_language_spanish": "ငပိ", "seed_phrase_length": "မျိုးစေ့စာပိုဒ်တိုအရှည်", + "seed_position_question_one": "ဘာလဲ", + "seed_position_question_two": "သင်၏အမျိုးအနွယ်စကားစု၏စကားဟူမူကား,", "seed_reminder": "ကျေးဇူးပြု၍ သင့်ဖုန်းကို ပျောက်ဆုံးသွားပါက သို့မဟုတ် ဖျက်မိပါက ၎င်းတို့ကို ချရေးပါ။", "seed_share": "မျိုးစေ့မျှဝေပါ။", "seed_title": "မျိုးစေ့", + "seed_verified": "မျိုးစေ့အတည်ပြု", + "seed_verified_subtext": "နောက်မှသင်သိမ်းဆည်းထားသောမျိုးစေ့ကိုနောက်ပိုင်းတွင်ဤပိုက်ဆံအိတ်ကိုအဂတိလိုက်စားမှုသို့မဟုတ်သင်၏စက်ပစ္စည်းကိုဆုံးရှုံးစေသည့်အခါဤပိုက်ဆံအိတ်ကိုပြန်ယူရန်နောက်မှသင်အသုံးပြုနိုင်သည်။ \n\n ဤမျိုးစေ့ကိုနောက်တဖန်ကြည့်ရှုနိုင်သည်", "seedtype": "မျိုးပွားခြင်း", "seedtype_alert_content": "အခြားပိုက်ဆံအိတ်များနှင့်မျိုးစေ့များကိုမျှဝေခြင်းသည် BIP39 sebyspe ဖြင့်သာဖြစ်သည်။", "seedtype_alert_title": "ပျိုးပင်သတိပေးချက်", @@ -670,6 +692,7 @@ "sent": "ပို့လိုက်ပါတယ်။", "service_health_disabled": "ဝန်ဆောင်မှုကျန်းမာရေးစာစောင်အားပိတ်ထားသည်", "service_health_disabled_message": "ဤသည်မှာ 0 န်ဆောင်မှုကျန်းမာရေးစာစောင်စာမျက်နှာတွင်ဤစာမျက်နှာကို Settings အောက်တွင်ဖွင့်ထားနိုင်သည်", + "set_a_pin": "PIN နံပါတ်ကိုသတ်မှတ်ပါ", "settings": "ဆက်တင်များ", "settings_all": "အားလုံး", "settings_allow_biometrical_authentication": "ဇီဝဗေဒဆိုင်ရာ အထောက်အထားစိစစ်ခြင်းကို ခွင့်ပြုပါ။", @@ -705,6 +728,7 @@ "share_address": "လိပ်စာမျှဝေပါ။", "shared_seed_wallet_groups": "shared မျိုးစေ့ပိုက်ဆံအိတ်အုပ်စုများ", "show": "ပြသ", + "show_address_book_popup": "ပေးပို့ပြီးနောက် 'address book' popup ကိုပြပါ", "show_details": "အသေးစိတ်ပြ", "show_keys": "မျိုးစေ့ /သော့များကို ပြပါ။", "show_market_place": "စျေးကွက်ကိုပြသပါ။", @@ -732,6 +756,10 @@ "silent_payments_settings": "အသံတိတ်ငွေပေးချေမှုဆက်တင်များ", "single_seed_wallets_group": "တစ်ခုတည်းမျိုးစေ့ပိုက်ဆံအိတ်", "slidable": "လျှောချနိုင်သည်။", + "solana_create_associated_token_account_exception": "Encipient Token အကောင့်ကိုလက်ခံသည့်လိပ်စာအတွက်အကောင့်များဖန်တီးခြင်းအတွက်အမှားအယွင်းများဖန်တီးခြင်း။", + "solana_no_associated_token_account_exception": "ဒီလိပ်စာအတွက်မပေါင်းသင်းတဲ့လက်ခဏာသက်သေအကောင့်မရှိဘူး။", + "solana_sign_native_transaction_rent_exception": "ငွေပေးငွေယူကိုမပြီးစီးနိုင်ပါ။ ငွေပေးငွေယူပြီးနောက်ငှားရန် Sol မလုံလောက်ပါ။ ကြင်နာစွာသင်၏ SOR ချိန်ခွင်လျှာကိုငွေဖြည့်ပါသို့မဟုတ်သင်ပို့နေသည့်ပမာဏကိုလျှော့ချပါ။", + "solana_sign_spl_token_transaction_rent_exception": "ငွေပေးငွေယူကိုမပြီးစီးနိုင်ပါ။ ငွေပေးငွေယူပြီးနောက်ငှားရန် Sol မလုံလောက်ပါ။ ကြင်နာစွာသင်၏ s ကိုချိန်ခွင်လျှာကိုတက်ပါ။", "sort_by": "အလိုက်စဥ်သည်", "spend_key_private": "သော့သုံးရန် (သီးသန့်)", "spend_key_public": "သုံးစွဲရန်သော့ (အများပြည်သူ)", @@ -744,7 +772,7 @@ "support_description_guides": "ဘုံပြ issues နာများအတွက်စာရွက်စာတမ်းများနှင့်ထောက်ခံမှု", "support_description_live_chat": "အခမဲ့နှင့်အစာရှောင်ခြင်း! လေ့ကျင့်ထားသောထောက်ခံသူကိုယ်စားလှယ်များသည်ကူညီနိုင်သည်", "support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ", - "support_title_guides": "ကိတ်မုန့်ပိုက်ဆံအိတ်လမ်းညွှန်များ", + "support_title_guides": "ကိတ်မုန့်ပိုက်ဆံအိတ်များ", "support_title_live_chat": "တိုက်ရိုက်ပံ့ပိုးမှု", "support_title_other_links": "အခြားအထောက်အပံ့လင့်များ", "sweeping_wallet": "ိုက်ဆံအိတ် တံမြက်လှည်း", @@ -823,6 +851,7 @@ "trade_state_underpaid": "ပေးချေမှုနည်းပါးသည်။", "trade_state_unpaid": "အခကြေးငွေမယူရသေး", "trades": "ကုန်သွယ်မှုများ", + "transaction_cost": "ငွေပေးငွေယူကုန်ကျစရိတ်", "transaction_details_amount": "ပမာဏ", "transaction_details_copied": "${title} ကို Clipboard သို့ ကူးယူထားသည်။", "transaction_details_date": "ရက်စွဲ", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "ရွေးချယ်ထားသော ဖလှယ်မှုများဖြင့် ဤပြောင်းလဲနိုင်သောအတွဲကို ပံ့ပိုးမထားပါ။", "verification": "စိစစ်ခြင်း။", "verify_message": "မက်ဆေ့ခ်ျကိုအတည်ပြုရန်", + "verify_seed": "မျိုးစေ့ကိုစစ်ဆေးပါ", "verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။", "version": "ဗားရှင်း ${currentVersion}", "view_all": "အားလုံးကိုကြည့်ရှုပါ။", @@ -891,6 +921,7 @@ "view_transaction_on": "ငွေလွှဲခြင်းကို ဖွင့်ကြည့်ပါ။", "voting_weight": "မဲပေးအလေးချိန်", "waitFewSecondForTxUpdate": "ငွေပေးငွေယူ မှတ်တမ်းတွင် ရောင်ပြန်ဟပ်ရန် စက္ကန့်အနည်းငယ်စောင့်ပါ။", + "wallet": "ပိုက်ဆံအိတ်", "wallet_group": "ပိုက်ဆံအိတ်အုပ်စု", "wallet_group_description_four": "လုံးဝအသစ်သောမျိုးစေ့နှင့်အတူပိုက်ဆံအိတ်ဖန်တီးရန်။", "wallet_group_description_one": "ကိတ်မုန့်၌, သင်တစ် ဦး ဖန်တီးနိုင်ပါတယ်", @@ -923,6 +954,8 @@ "wallets": "ပိုက်ဆံအိတ်", "warning": "သတိပေးချက်", "welcome": "မှကြိုဆိုပါတယ်။", + "welcome_subtitle_new_wallet": "လတ်ဆတ်စွာစတင်လိုပါကအောက်ကပိုက်ဆံအိတ်အသစ်ကိုဖန်တီးပါ။", + "welcome_subtitle_restore_wallet": "အကယ်. သင့်တွင်သင်ကိတ်မုန့်ထဲသို့ယူဆောင်လိုသောလက်ရှိပိုက်ဆံအိတ်ရှိပါက Restore Lestore Wallet ကိုရွေးပါ။", "welcome_to_cakepay": "Cake Pay မှကြိုဆိုပါသည်။", "what_is_silent_payments": "အသံတိတ်ငွေပေးချေမှုဆိုတာဘာလဲ", "widgets_address": "လိပ်စာ", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 58fcdec6a..e71be3c23 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -38,6 +38,7 @@ "agree_to": "Door een account aan te maken gaat u akkoord met de ", "alert_notice": "Kennisgeving", "all": "ALLE", + "all_coins": "Alle munten", "all_trades": "Alle transacties", "all_transactions": "Alle transacties", "alphabetical": "Alfabetisch", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Koop wereldwijde prepaid -kaarten en cadeaubonnen", "cake_pay_web_cards_subtitle": "Koop wereldwijd prepaidkaarten en cadeaubonnen", "cake_pay_web_cards_title": "Cake Pay-webkaarten", + "cake_seeds_save_disclaimer": "Bewaar deze woorden op een veilige plek! U hebt deze woorden nodig om uw portemonnee op een nieuw apparaat te herstellen.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Ik bevestig dat ik geen proxy of VPN gebruik", + "cakepay_confirm_purchase": "Bevestig aankoop", + "cakepay_confirm_terms_agreed": "Ik ga akkoord met de hier gepresenteerde algemene voorwaarden:", + "cakepay_confirm_voided_refund": "Ik begrijp dat de aflossingspogingen van een beperkt land elke terugbetaling zullen ongeldig maken", + "cakepay_ios_not_available": "Sorry, deze cadeaubon is niet beschikbaar op iOS. U kunt het in plaats daarvan kopen op Android of via onze website.", "cakepay_prepaid_card": "CakePay Prepaid Debetkaart", "camera_consent": "Uw camera wordt gebruikt om vóór ${provider} een beeld vast te leggen voor identificatiedoeleinden. Raadpleeg hun privacybeleid voor meer informatie.", "camera_permission_is_required": "Cameratoestemming is vereist.\nSchakel dit in via de app-instellingen.", @@ -175,6 +182,7 @@ "copy_address": "Adres kopiëren", "copy_id": "ID kopiëren", "copyWalletConnectLink": "Kopieer de WalletConnect-link van dApp en plak deze hier", + "corrupted_seed_notice": "De bestanden voor deze portemonnee zijn beschadigd en kunnen niet worden geopend. Bekijk de zaadzin, bewaar deze en herstel de portemonnee.\n\nAls de waarde leeg is, kon het zaad niet correct worden hersteld.", "countries": "Landen", "create_account": "Account aanmaken", "create_backup": "Maak een back-up", @@ -256,7 +264,7 @@ "enterTokenID": "Voer de token-ID in", "enterWalletConnectURI": "Voer WalletConnect-URI in", "error": "Fout", - "error_dialog_content": "Oeps, er is een fout opgetreden.\n\nStuur het crashrapport naar ons ondersteuningsteam om de applicatie te verbeteren.", + "error_dialog_content": "Oeps, we hebben wat fout.\n\nStuur het foutrapport naar ons ondersteuningsteam om de applicatie beter te maken.", "error_text_account_name": "Accountnaam mag alleen letters, cijfers bevatten\nen moet tussen de 1 en 15 tekens lang zijn", "error_text_address": "Portemonnee-adres moet overeenkomen met het type\nvan cryptocurrency", "error_text_amount": "Bedrag kan alleen cijfers bevatten", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Veelgestelde vragen", "frozen": "Bevroren", "full_balance": "Volledig saldo", + "gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.", "generate_name": "Naam genereren", "generating_gift_card": "Cadeaubon genereren", "get_a": "Krijg een ", @@ -350,13 +359,17 @@ "how_to_use": "Hoe te gebruiken", "how_to_use_card": "Hoe deze kaart te gebruiken", "id": "ID: ", + "if_you_dont_see_your_device": "Als u uw apparaat hierboven niet ziet, zorg er dan voor dat uw grootboek wakker is en ontgrendeld is!", "ignor": "Negeren", "import": "Importeren", "importNFTs": "NFT's importeren", "in_store": "In winkel", "incoming": "inkomend", "incorrect_seed": "De ingevoerde tekst is niet geldig.", + "incorrect_seed_option": "Onjuist. Probeer het opnieuw", + "incorrect_seed_option_back": "Onjuist. Zorg ervoor dat uw zaad correct is opgeslagen en probeer het opnieuw.", "inputs": "Invoer", + "insufficient_funds_for_tx": "Onvoldoende fondsen om de transactie met succes uit te voeren.", "insufficient_lamport_for_tx": "U hebt niet genoeg SOL om de transactie en de transactiekosten te dekken. Voeg vriendelijk meer SOL toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt.", "insufficient_lamports": "U hebt niet genoeg SOL om de transactie en de transactiekosten te dekken. Je hebt minstens ${solValueNeeded} sol nodig. Voeg vriendelijk meer Sol toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt", "insufficientFundsForRentError": "U hebt niet genoeg SOL om de transactiekosten en huur voor de rekening te dekken. Voeg vriendelijk meer SOL toe aan uw portemonnee of verminder de SOL -hoeveelheid die u verzendt", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Kies een nieuwe vertegenwoordiger", "nanogpt_subtitle": "Alle nieuwste modellen (GPT-4, Claude). \\ Nno-abonnement, betalen met crypto.", "narrow": "Smal", - "new_first_wallet_text": "Houd uw cryptocurrency gemakkelijk veilig", + "new_first_wallet_text": "Je crypto veilig houden is een fluitje van een cent", "new_node_testing": "Nieuwe knooppunttest", "new_subaddress_create": "Creëren", "new_subaddress_label_name": "Label naam", @@ -464,6 +477,7 @@ "online": "online", "onramper_option_description": "Koop snel crypto met veel betaalmethoden. Beschikbaar in de meeste landen. Spreads en vergoedingen variëren.", "open_gift_card": "Geschenkkaart openen", + "open_wallet": "Open portemonnee", "optional_description": "Optionele beschrijving", "optional_email_hint": "Optionele kennisgeving per e-mail aan de begunstigde", "optional_name": "Optionele naam ontvanger", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Als deze portemonnee een seed van 12 woorden heeft en is gemaakt in Cake, stort dan GEEN Bitcoin in deze portemonnee. Elke BTC die naar deze portemonnee is overgebracht, kan verloren gaan. Maak een nieuwe portemonnee van 24 woorden (tik op het menu rechtsboven, selecteer Portefeuilles, kies Nieuwe portemonnee maken en selecteer vervolgens Bitcoin) en verplaats je BTC ONMIDDELLIJK daar. Nieuwe (24-woorden) BTC-portefeuilles van Cake zijn veilig", "outgoing": "Uitgaande", "outputs": "Uitgangen", + "overshot": "Overschrijden", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Koppelen Ongeldige gebeurtenis", "passphrase": "PassaspHRASE (optioneel)", @@ -531,6 +546,7 @@ "recipient_address": "Adres ontvanger", "reconnect": "Sluit", "reconnect_alert_text": "Weet u zeker dat u opnieuw verbinding wilt maken?", + "reconnect_your_hardware_wallet": "Sluit uw hardware -portemonnee opnieuw aan", "reconnection": "Reconnection", "red_dark_theme": "Rood donker thema", "red_light_theme": "Rood licht thema", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Herstel uw portemonnee van gegenereerd toetsaanslagen opgeslagen van uw privésleutels", "restore_description_from_seed": "Herstel uw portemonnee van het 25 woord of 13 woord combinatiecode", "restore_description_from_seed_keys": "Ontvang uw portemonnee terug uit seed / keys die u hebt opgeslagen op een veilige plaats", + "restore_existing_wallet": "Herstel de bestaande portemonnee", "restore_from_date_or_blockheight": "Voer een datum in een paar dagen voordat u deze portemonnee heeft gemaakt. Of als u de blokhoogte kent, voert u deze in", "restore_from_seed_placeholder": "Voer hier uw codefrase in of plak deze", "restore_new_seed": "Nieuw zaad", @@ -611,6 +628,7 @@ "seed_alert_title": "Aandacht", "seed_alert_yes": "Ja ik heb", "seed_choose": "Kies een starttaal", + "seed_display_path": "Menu -> Beveiliging en back -up -> Key/Seeds tonen", "seed_hex_form": "Portemonnee zaad (hexvorm)", "seed_key": "Zaadsleutel", "seed_language": "Zaadtaal", @@ -629,9 +647,13 @@ "seed_language_russian": "Russisch", "seed_language_spanish": "Spaans", "seed_phrase_length": "Lengte van de zaadzin", + "seed_position_question_one": "Wat is de", + "seed_position_question_two": "woord van je zaadzin?", "seed_reminder": "Schrijf deze op voor het geval u uw telefoon kwijtraakt of veegt", "seed_share": "Deel zaad", "seed_title": "Zaad", + "seed_verified": "Zaad geverifieerd", + "seed_verified_subtext": "U kunt uw opgeslagen zaad later gebruiken om deze portemonnee te herstellen in het geval van corruptie of het verliezen van uw apparaat. \n\n U kunt dit zaad opnieuw bekijken van de", "seedtype": "Zaadtype", "seedtype_alert_content": "Het delen van zaden met andere portefeuilles is alleen mogelijk met BIP39 SeedType.", "seedtype_alert_title": "Zaadtype alert", @@ -670,6 +692,7 @@ "sent": "Verzonden", "service_health_disabled": "Service Health Bulletin is uitgeschakeld", "service_health_disabled_message": "Dit is de Service Health Bulletin -pagina, u kunt deze pagina instellingen inschakelen -> Privacy", + "set_a_pin": "Zet een speld", "settings": "Instellingen", "settings_all": "ALLE", "settings_allow_biometrical_authentication": "Biometrische authenticatie toestaan", @@ -705,6 +728,7 @@ "share_address": "Deel adres", "shared_seed_wallet_groups": "Gedeelde zaadportelgroepen", "show": "Show", + "show_address_book_popup": "Toon 'Toevoegen aan adresboek' pop -up na verzenden", "show_details": "Toon details", "show_keys": "Toon zaad/sleutels", "show_market_place": "Toon Marktplaats", @@ -732,6 +756,10 @@ "silent_payments_settings": "Stille betalingsinstellingen", "single_seed_wallets_group": "Enkele zaadportefeuilles", "slidable": "Verschuifbaar", + "solana_create_associated_token_account_exception": "Fout bij het maken van een geassocieerd tokenaccount voor ontvangingsadres.", + "solana_no_associated_token_account_exception": "Er is geen bijbehorende tokenaccount voor dit adres.", + "solana_sign_native_transaction_rent_exception": "Transactie kan niet worden voltooid. Onvoldoende Sol vertrok naar huur na transactie. Vul uw SOL -balans aan of verminder de hoeveelheid SOL die u verzendt.", + "solana_sign_spl_token_transaction_rent_exception": "Transactie kan niet worden voltooid. Onvoldoende Sol vertrok naar huur na transactie. Vul uw SOL -balans op.", "sort_by": "Sorteer op", "spend_key_private": "Sleutel uitgeven (privaat)", "spend_key_public": "Sleutel uitgeven (openbaar)", @@ -744,7 +772,7 @@ "support_description_guides": "Documentatie en ondersteuning voor gemeenschappelijke problemen", "support_description_live_chat": "Gratis en snel! Getrainde ondersteuningsvertegenwoordigers zijn beschikbaar om te helpen", "support_description_other_links": "Word lid van onze gemeenschappen of bereik ons ​​onze partners via andere methoden", - "support_title_guides": "Cake -portemonnee gidsen", + "support_title_guides": "Cake -portemonnee documenten", "support_title_live_chat": "Live ondersteuning", "support_title_other_links": "Andere ondersteuningslinks", "sweeping_wallet": "Vegende portemonnee", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Slecht betaald", "trade_state_unpaid": "Onbetaald", "trades": "Trades", + "transaction_cost": "Transactiekosten", "transaction_details_amount": "Bedrag", "transaction_details_copied": "${title} gekopieerd naar het klembord", "transaction_details_date": "Datum", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen", "verification": "Verificatie", "verify_message": "Verifieer bericht", + "verify_seed": "Controleer zaad", "verify_with_2fa": "Controleer met Cake 2FA", "version": "Versie ${currentVersion}", "view_all": "Alles bekijken", @@ -892,6 +922,7 @@ "voting_weight": "Stemgewicht", "waitFewSecondForTxUpdate": "Wacht een paar seconden totdat de transactie wordt weergegeven in de transactiegeschiedenis", "waiting_payment_confirmation": "In afwachting van betalingsbevestiging", + "wallet": "Portemonnee", "wallet_group": "Portemonnee", "wallet_group_description_four": "om een ​​portemonnee te maken met een geheel nieuw zaadje.", "wallet_group_description_one": "In cakeballet kun je een", @@ -924,6 +955,8 @@ "wallets": "Portefeuilles", "warning": "Waarschuwing", "welcome": "Welkom bij", + "welcome_subtitle_new_wallet": "Als u opnieuw wilt beginnen, tikt u op de nieuwe portemonnee hieronder en u bent op weg naar de races.", + "welcome_subtitle_restore_wallet": "Als je een bestaande portemonnee hebt die je in cake wilt brengen, kies dan gewoon om de bestaande portemonnee te herstellen en we zullen je door het proces leiden.", "welcome_to_cakepay": "Welkom bij Cake Pay!", "what_is_silent_payments": "Wat zijn stille betalingen?", "widgets_address": "Adres", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 80d2ecf50..bc7f70ca2 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -38,6 +38,7 @@ "agree_to": "Tworząc konto wyrażasz zgodę na ", "alert_notice": "Ogłoszenie", "all": "WSZYSTKO", + "all_coins": "Wszystkie monety", "all_trades": "Wszystkie operacje", "all_transactions": "Wszystkie transakcje", "alphabetical": "Alfabetyczny", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Kup na całym świecie karty przedpłacone i karty podarunkowe", "cake_pay_web_cards_subtitle": "Kupuj na całym świecie karty przedpłacone i karty podarunkowe", "cake_pay_web_cards_title": "Cake Pay Web Cards", + "cake_seeds_save_disclaimer": "Zapisz te słowa w bezpiecznym miejscu! Będziesz potrzebować tych słów, aby przywrócić portfel na nowym urządzeniu.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Potwierdzam, że nie używam proxy ani VPN", + "cakepay_confirm_purchase": "Potwierdź zakup", + "cakepay_confirm_terms_agreed": "Zgadzam się na przedstawione tutaj warunki:", + "cakepay_confirm_voided_refund": "Rozumiem, że próby odkupienia z ograniczonego kraju nie unieważają wszelkich", + "cakepay_ios_not_available": "Przepraszam, ta karta podarunkowa nie jest dostępna na iOS. Zamiast tego możesz go kupić na Android lub za pośrednictwem naszej strony internetowej.", "cakepay_prepaid_card": "Przedpłacona karta debetowa CakePay", "camera_consent": "Twój aparat zostanie użyty do przechwycenia obrazu w celach identyfikacyjnych przez ${provider}. Aby uzyskać szczegółowe informacje, sprawdź ich Politykę prywatności.", "camera_permission_is_required": "Wymagane jest pozwolenie na korzystanie z aparatu.\nWłącz tę funkcję w ustawieniach aplikacji.", @@ -175,6 +182,7 @@ "copy_address": "Skopiuj adress", "copy_id": "skopiuj ID", "copyWalletConnectLink": "Skopiuj link do WalletConnect z dApp i wklej tutaj", + "corrupted_seed_notice": "Pliki dla tego portfela są uszkodzone i nie można ich otworzyć. Zobacz wyrażenie nasion, zapisz je i przywróć portfel.\n\nJeśli wartość jest pusta, ziarno nie można było poprawnie odzyskać.", "countries": "Kraje", "create_account": "Utwórz konto", "create_backup": "Utwórz kopię zapasową", @@ -256,7 +264,7 @@ "enterTokenID": "Wprowadź identyfikator tokena", "enterWalletConnectURI": "Wprowadź identyfikator URI WalletConnect", "error": "Błąd", - "error_dialog_content": "Ups, wystąpił błąd.\n\nPrześlij raport o awarii do naszego zespołu wsparcia, aby ulepszyć aplikację.", + "error_dialog_content": "Ups, mamy trochę błędu.\n\nProszę o przesłanie raportu o błędach do naszego zespołu wsparcia, aby aplikacja była lepsza.", "error_text_account_name": "Nazwa konta może zawierać tylko litery, cyfry\ni musi mieć od 1 do 15 znaków", "error_text_address": "Adres musi odpowiadać typowi kryptowaluty", "error_text_amount": "Kwota może zawierać tylko liczby", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Często zadawane pytania", "frozen": "Zamrożone", "full_balance": "Pełne saldo", + "gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.", "generate_name": "Wygeneruj nazwę", "generating_gift_card": "Generowanie karty podarunkowej", "get_a": "Zdobądź ", @@ -350,13 +359,17 @@ "how_to_use": "Jak używać", "how_to_use_card": "Jak korzystać z tej karty?", "id": "ID: ", + "if_you_dont_see_your_device": "Jeśli nie widzisz swojego urządzenia powyżej, upewnij się, że Twoja księga nie śpi i odblokowana!", "ignor": "Ignorować", "import": "Import", "importNFTs": "Importuj NFT", "in_store": "W Sklepie", "incoming": "Przychodzące", "incorrect_seed": "Wprowadzony seed jest nieprawidłowy.", + "incorrect_seed_option": "Błędny. Spróbuj ponownie", + "incorrect_seed_option_back": "Błędny. Upewnij się, że twoje ziarno jest prawidłowo zapisane i spróbuj ponownie.", "inputs": "Wejścia", + "insufficient_funds_for_tx": "Niewystarczające fundusze na skuteczne wykonanie transakcji.", "insufficient_lamport_for_tx": "Nie masz wystarczającej ilości SOL, aby pokryć transakcję i opłatę za transakcję. Uprzejmie dodaj więcej sol do portfela lub zmniejsz wysyłaną kwotę SOL.", "insufficient_lamports": "Nie masz wystarczającej ilości SOL, aby pokryć transakcję i opłatę za transakcję. Potrzebujesz przynajmniej ${solValueNeeded} sol. Uprzejmie dodaj więcej sol do portfela lub zmniejsz wysyłaną kwotę SOL, którą wysyłasz", "insufficientFundsForRentError": "Nie masz wystarczającej ilości SOL, aby pokryć opłatę za transakcję i czynsz za konto. Uprzejmie dodaj więcej sol do portfela lub zmniejsz solę, którą wysyłasz", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Wybierz nowego przedstawiciela", "nanogpt_subtitle": "Wszystkie najnowsze modele (GPT-4, Claude). \\ Nno subskrypcja, płacą za pomocą kryptografii.", "narrow": "Wąski", - "new_first_wallet_text": "Łatwo zapewnić bezpieczeństwo kryptowalut", + "new_first_wallet_text": "Zachowanie bezpieczeństwa kryptograficznego jest kawałkiem ciasta", "new_node_testing": "Testowanie nowych węzłów", "new_subaddress_create": "Stwórz", "new_subaddress_label_name": "Etykieta nazwy adresu", @@ -464,6 +477,7 @@ "online": "online", "onramper_option_description": "Szybko kup kryptowaluty z wieloma metodami płatności. Dostępne w większości krajów. Spready i opłaty różnią się.", "open_gift_card": "Otwórz kartę podarunkową", + "open_wallet": "Otwarty portfel", "optional_description": "Opcjonalny opis", "optional_email_hint": "Opcjonalny e-mail z powiadomieniem odbiorcy płatności", "optional_name": "Opcjonalna nazwa odbiorcy", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Jeśli ten portfel ma 12-wyrazowy seed i został utworzony w Cake, NIE Wpłacaj Bitcoina do tego portfela. Wszelkie BTC przeniesione do tego portfela mogą zostać utracone. Utwórz nowy portfel z 24 słowami (dotknij menu w prawym górnym rogu, wybierz Portfele, wybierz Utwórz nowy portfel, a następnie Bitcoin) i NATYCHMIAST przenieś tam swoje BTC. Nowe (24 słowa) portfele BTC Cake Wallet są bezpieczne", "outgoing": "Wychodzące", "outputs": "Wyjścia", + "overshot": "Przesadzanie", "overwrite_amount": "Nadpisz ilość", "pairingInvalidEvent": "Nieprawidłowe zdarzenie parowania", "passphrase": "PassPhraza (opcjonalnie)", @@ -531,6 +546,7 @@ "recipient_address": "Adres odbiorcy", "reconnect": "Połącz ponownie", "reconnect_alert_text": "Czy na pewno ponownie się ponownie połączysz?", + "reconnect_your_hardware_wallet": "Ponownie podłącz portfel sprzętowy", "reconnection": "Ponowne łączenie", "red_dark_theme": "Czerwony Mroczny motyw", "red_light_theme": "Motyw czerwony światło", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Przywróć swój portfel z kluczy prywatnych", "restore_description_from_seed": "Przywróć swój portfel z 25 lub 13-słownej frazy seed", "restore_description_from_seed_keys": "Odzyskaj swój portfel z seedów / kluczy, które zapisałeś w bezpiecznym miejscu", + "restore_existing_wallet": "Przywróć istniejący portfel", "restore_from_date_or_blockheight": "Wprowadź datę na kilka dni przed utworzeniem tego portfela, lub jeśli znasz wysokość bloku, wprowadź go zamiast daty", "restore_from_seed_placeholder": "Wpisz lub wklej tutaj swoją frazę seed", "restore_new_seed": "Nowy seed", @@ -611,6 +628,7 @@ "seed_alert_title": "Uwaga", "seed_alert_yes": "Tak", "seed_choose": "Wybierz język", + "seed_display_path": "Menu -> Bezpieczeństwo i kopia zapasowa -> Pokaż klucz/nasiona", "seed_hex_form": "Nasiona portfela (forma sześciokątna)", "seed_key": "Klucz nasion", "seed_language": "Język nasion", @@ -629,9 +647,13 @@ "seed_language_russian": "Rosyjski", "seed_language_spanish": "Hiszpański", "seed_phrase_length": "Długość frazy początkowej", + "seed_position_question_one": "Co to jest", + "seed_position_question_two": "Słowo twojego wyrażenia nasion?", "seed_reminder": "Musisz zapisać tą fraze, bo bez niej możesz nie odzyskać portfela!", "seed_share": "Udostępnij seed", "seed_title": "Seed", + "seed_verified": "Ziarno zweryfikowane", + "seed_verified_subtext": "Możesz później użyć zapisanego ziarna, aby przywrócić ten portfel w przypadku uszkodzenia lub utraty urządzenia. \n\n Możesz ponownie obejrzeć to ziarno z", "seedtype": "Sedtype", "seedtype_alert_content": "Dzielenie się nasionami z innymi portfelami jest możliwe tylko z BIP39 sededType.", "seedtype_alert_title": "Ustanowienie typu sedype", @@ -670,6 +692,7 @@ "sent": "Wysłano", "service_health_disabled": "Biuletyn zdrowia usług jest wyłączony", "service_health_disabled_message": "To jest strona Biuletynu Zdrowie Service, możesz włączyć tę stronę w Ustawieniach -> Prywatność", + "set_a_pin": "Ustaw szpilkę", "settings": "Ustawienia", "settings_all": "Wszystkie", "settings_allow_biometrical_authentication": "Zezwalaj na uwierzytelnianie biometryczne", @@ -705,6 +728,7 @@ "share_address": "Udostępnij adres", "shared_seed_wallet_groups": "Wspólne grupy portfeli nasion", "show": "Pokazywać", + "show_address_book_popup": "Pokaż wysypkę „Dodaj do książki” po wysłaniu", "show_details": "Pokaż szczegóły", "show_keys": "Pokaż seed/klucze", "show_market_place": "Pokaż rynek", @@ -732,6 +756,10 @@ "silent_payments_settings": "Ustawienia o cichej płatności", "single_seed_wallets_group": "Pojedyncze portfele nasion", "slidable": "Przesuwne", + "solana_create_associated_token_account_exception": "Błąd tworzenia powiązanego konta tokena dla adresu wpływającego.", + "solana_no_associated_token_account_exception": "Nie ma powiązanego konta tokena dla tego adresu.", + "solana_sign_native_transaction_rent_exception": "Transakcji nie można zakończyć. Niewystarczający SOL w lewo do czynszu po transakcji. Uprzejmie uzupełnij saldo Sol lub zmniejsz ilość wysyłanej przez Ciebie rozwiązania.", + "solana_sign_spl_token_transaction_rent_exception": "Transakcji nie można zakończyć. Niewystarczający SOL w lewo do czynszu po transakcji. Uprzejmie uzupełnij saldo Sol.", "sort_by": "Sortuj według", "spend_key_private": "Klucz prywatny", "spend_key_public": "Klucz publiczny", @@ -744,7 +772,7 @@ "support_description_guides": "Dokumentacja i wsparcie dla typowych problemów", "support_description_live_chat": "Darmowe i szybkie! Do pomocy są dostępni przeszkoleni przedstawiciele wsparcia", "support_description_other_links": "Dołącz do naszych społeczności lub skontaktuj się z nami naszymi partnerami za pomocą innych metod", - "support_title_guides": "Przewodniki portfela ciasta", + "support_title_guides": "Dokumenty portfela ciasta", "support_title_live_chat": "Wsparcie na żywo", "support_title_other_links": "Inne linki wsparcia", "sweeping_wallet": "Zamiatanie portfela", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Niedopłacone", "trade_state_unpaid": "Nie opłacona", "trades": "Transakcje", + "transaction_cost": "Koszt transakcji", "transaction_details_amount": "Ilość", "transaction_details_copied": "${title} skopiowane do schowka", "transaction_details_date": "Data", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach", "verification": "Weryfikacja", "verify_message": "Sprawdź wiadomość", + "verify_seed": "Zweryfikować ziarno", "verify_with_2fa": "Sprawdź za pomocą Cake 2FA", "version": "Wersja ${currentVersion}", "view_all": "Wyświetl wszystko", @@ -891,6 +921,7 @@ "view_transaction_on": "Zobacz transakcje na ", "voting_weight": "Waga głosu", "waitFewSecondForTxUpdate": "Poczekaj kilka sekund, aż transakcja zostanie odzwierciedlona w historii transakcji", + "wallet": "Portfel", "wallet_group": "Grupa portfela", "wallet_group_description_four": "Aby stworzyć portfel z zupełnie nowym ziarnem.", "wallet_group_description_one": "W portfelu ciasta możesz stworzyć", @@ -923,6 +954,8 @@ "wallets": "Portfele", "warning": "Ostrzeżenie", "welcome": "Witamy w", + "welcome_subtitle_new_wallet": "Jeśli chcesz zacząć od nowa, dotknij Utwórz nowy portfel poniżej, a będziesz na wyścigach.", + "welcome_subtitle_restore_wallet": "Jeśli masz istniejący portfel, który chcesz wnieść do ciasta, po prostu wybierz przywróć istniejący portfel, a my przeprowadzimy Cię przez proces.", "welcome_to_cakepay": "Witamy w Cake Pay!", "what_is_silent_payments": "Co to są ciche płatności?", "widgets_address": "Adres", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 25f6a9f7c..e101343e0 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -38,6 +38,7 @@ "agree_to": "Ao criar conta você concorda com ", "alert_notice": "Perceber", "all": "TUDO", + "all_coins": "Todas as moedas", "all_trades": "Todas as negociações", "all_transactions": "Todas as transacções", "alphabetical": "alfabética", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Compre cartões pré -pagos em todo o mundo e cartões -presente", "cake_pay_web_cards_subtitle": "Compre cartões pré-pagos e cartões-presente em todo o mundo", "cake_pay_web_cards_title": "Cartões Cake Pay Web", + "cake_seeds_save_disclaimer": "Por favor, salve estas palavras em um local seguro! Você precisará dessas palavras para restaurar sua carteira em um novo dispositivo.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Eu confirmo que não estou usando um proxy ou VPN", + "cakepay_confirm_purchase": "Confirme a compra", + "cakepay_confirm_terms_agreed": "Eu concordo com os termos e condições apresentados aqui:", + "cakepay_confirm_voided_refund": "Eu entendo que as tentativas de resgate de um país restrito anularão qualquer reembolso", + "cakepay_ios_not_available": "Desculpe, este cartão -presente não está disponível no iOS. Você pode comprá -lo no Android ou através do nosso site.", "cakepay_prepaid_card": "Cartão de débito pré-pago CakePay", "camera_consent": "Sua câmera será usada para capturar uma imagem para fins de identificação por ${provider}. Por favor, verifique a Política de Privacidade para obter detalhes.", "camera_permission_is_required": "É necessária permissão da câmera.\nAtive-o nas configurações do aplicativo.", @@ -175,6 +182,7 @@ "copy_address": "Copiar endereço", "copy_id": "Copiar ID", "copyWalletConnectLink": "Copie o link WalletConnect do dApp e cole aqui", + "corrupted_seed_notice": "Os arquivos para esta carteira estão corrompidos e não podem ser abertos. Veja a frase das sementes, salve -a e restaure a carteira.\n\nSe o valor estiver vazio, a semente não pôde ser recuperada corretamente.", "countries": "Países", "create_account": "Criar conta", "create_backup": "Criar backup", @@ -256,7 +264,7 @@ "enterTokenID": "Insira o ID do token", "enterWalletConnectURI": "Insira o URI do WalletConnect", "error": "Erro", - "error_dialog_content": "Ops, houve algum erro.\n\nPor favor, envie o relatório de falha para nossa equipe de suporte para melhorar o aplicativo.", + "error_dialog_content": "Opa, recebemos algum erro.\n\nEnvie o relatório de erro à nossa equipe de suporte para melhorar o aplicativo.", "error_text_account_name": "O nome da conta só pode conter letras, números\ne deve ter entre 1 e 15 caracteres", "error_text_address": "O endereço da carteira deve corresponder à\ncriptomoeda selecionada", "error_text_amount": "A quantia deve conter apenas números", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Perguntas frequentes", "frozen": "Congeladas", "full_balance": "Saldo total", + "gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.", "generate_name": "Gerar nome", "generating_gift_card": "Gerando Cartão Presente", "get_a": "Obter um ", @@ -350,13 +359,17 @@ "how_to_use": "Como usar", "how_to_use_card": "Como usar este cartão", "id": "ID: ", + "if_you_dont_see_your_device": "Se você não vê seu dispositivo acima, certifique -se de que seu livro esteja acordado e desbloqueado!", "ignor": "Ignorar", "import": "Importar", "importNFTs": "Importar NFTs", "in_store": "Na loja", "incoming": "Recebidas", "incorrect_seed": "O texto digitado não é válido.", + "incorrect_seed_option": "Incorreto. Por favor, tente novamente", + "incorrect_seed_option_back": "Incorreto. Certifique -se de que sua semente seja salva corretamente e tente novamente.", "inputs": "Entradas", + "insufficient_funds_for_tx": "Fundos insuficientes para executar com sucesso a transação.", "insufficient_lamport_for_tx": "Você não tem Sol suficiente para cobrir a transação e sua taxa de transação. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você envia.", "insufficient_lamports": "Você não tem Sol suficiente para cobrir a transação e sua taxa de transação. Você precisa de pelo menos ${solValueNeeded} sol. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você está enviando", "insufficientFundsForRentError": "Você não tem Sol suficiente para cobrir a taxa de transação e o aluguel da conta. Por favor, adicione mais sol à sua carteira ou reduza a quantidade de sol que você envia", @@ -426,9 +439,9 @@ "nano_current_rep": "Representante atual", "nano_gpt_thanks_message": "Obrigado por usar o Nanogpt! Lembre -se de voltar para o navegador após a conclusão da transação!", "nano_pick_new_rep": "Escolha um novo representante", - "nanogpt_subtitle": "Todos os modelos mais recentes (GPT-4, Claude). \\ Nno assinatura, pagam com criptografia.", + "nanogpt_subtitle": "Todos os modelos mais recentes (GPT-4, Claude). \\nSem assinatura, pague com criptomoeda.", "narrow": "Estreito", - "new_first_wallet_text": "Mantenha sua criptomoeda facilmente segura", + "new_first_wallet_text": "Manter sua cripto segura é um pedaço de bolo", "new_node_testing": "Teste de novo nó", "new_subaddress_create": "Criar", "new_subaddress_label_name": "Nome", @@ -466,6 +479,7 @@ "onramper_option_description": "Compre rapidamente criptografia com muitos métodos de pagamento. Disponível na maioria dos países. Os spreads e taxas variam.", "opcionalmente_order_card": "Opcionalmente, peça um cartão físico.", "open_gift_card": "Abrir vale-presente", + "open_wallet": "Carteira aberta", "optional_description": "Descrição opcional", "optional_email_hint": "E-mail opcional de notificação do beneficiário", "optional_name": "Nome do destinatário opcional", @@ -479,6 +493,7 @@ "outdated_electrum_wallet_receive_warning": "Se esta carteira tiver uma semente de 12 palavras e foi criada no Cake, NÃO deposite Bitcoin nesta carteira. Qualquer BTC transferido para esta carteira pode ser perdido. Crie uma nova carteira de 24 palavras (toque no menu no canto superior direito, selecione Carteiras, escolha Criar Nova Carteira e selecione Bitcoin) e mova IMEDIATAMENTE seu BTC para lá. As novas carteiras BTC (24 palavras) da Cake são seguras", "outgoing": "Enviadas", "outputs": "Saídas", + "overshot": "Ultrapassado", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Emparelhamento de evento inválido", "passphrase": "Senha (opcional)", @@ -533,6 +548,7 @@ "recipient_address": "Endereço do destinatário", "reconnect": "Reconectar", "reconnect_alert_text": "Você tem certeza de que deseja reconectar?", + "reconnect_your_hardware_wallet": "Reconecte sua carteira de hardware", "reconnection": "Reconectar", "red_dark_theme": "Tema escuro vermelho", "red_light_theme": "Tema da luz vermelha", @@ -572,6 +588,7 @@ "restore_description_from_keys": "Restaure sua carteira a partir de suas chaves privadas", "restore_description_from_seed": "Restaure sua carteira a partir de semente com 25 palavras ou 13 palavras", "restore_description_from_seed_keys": "Restaure a sua carteira a partir de sementes/chaves que você salvou em um local seguro", + "restore_existing_wallet": "Restaure a carteira existente", "restore_from_date_or_blockheight": "Insira uma data alguns dias antes de criar esta carteira. Ou se você souber a altura do bloco, insira-o", "restore_from_seed_placeholder": "Digite ou cole sua frase de código aqui", "restore_new_seed": "Nova semente", @@ -613,6 +630,7 @@ "seed_alert_title": "Atenção", "seed_alert_yes": "Sim, eu tenho", "seed_choose": "Escolha o idioma da semente", + "seed_display_path": "Menu -> Segurança e Backup -> Mostrar chave/sementes", "seed_hex_form": "Semente de carteira (forma hexadecimal)", "seed_key": "Chave de semente", "seed_language": "Linguagem de semente", @@ -631,9 +649,13 @@ "seed_language_russian": "Russa", "seed_language_spanish": "Espanhola", "seed_phrase_length": "Comprimento da frase-semente", + "seed_position_question_one": "Qual é o", + "seed_position_question_two": "Palavra da sua frase de semente?", "seed_reminder": "Anote-os para o caso de perder ou limpar seu telefone", "seed_share": "Compartilhar semente", "seed_title": "Semente", + "seed_verified": "Semente verificada", + "seed_verified_subtext": "Você pode usar sua semente salva mais tarde para restaurar esta carteira em caso de corrupção ou perda do seu dispositivo. \n\n Você pode ver essa semente novamente do", "seedtype": "SeedType", "seedtype_alert_content": "Compartilhar sementes com outras carteiras só é possível com o BIP39 SeedType.", "seedtype_alert_title": "Alerta de SeedType", @@ -672,6 +694,7 @@ "sent": "Enviada", "service_health_disabled": "O Boletim de Saúde de Serviço está desativado", "service_health_disabled_message": "Esta é a página do Boletim de Saúde de Serviço, você pode ativar esta página em Configurações -> Privacidade", + "set_a_pin": "Defina um pino", "settings": "Configurações", "settings_all": "Tudo", "settings_allow_biometrical_authentication": "Permitir autenticação biométrica", @@ -707,6 +730,7 @@ "share_address": "Compartilhar endereço", "shared_seed_wallet_groups": "Grupos de carteira de sementes compartilhados", "show": "Mostrar", + "show_address_book_popup": "Mostre pop -up 'Adicionar ao livro de endereços' depois de enviar", "show_details": "Mostrar detalhes", "show_keys": "Mostrar semente/chaves", "show_market_place": "Mostrar mercado", @@ -734,6 +758,10 @@ "silent_payments_settings": "Configurações de pagamentos silenciosos", "single_seed_wallets_group": "Carteiras de sementes únicas", "slidable": "Deslizável", + "solana_create_associated_token_account_exception": "Erro a criação de um token associado Conta do endereço de recebimento.", + "solana_no_associated_token_account_exception": "Não existe uma conta de token associada para este endereço.", + "solana_sign_native_transaction_rent_exception": "A transação não pode ser concluída. Sol insuficiente deixou para alugar após a transação. Por favor, complete seu saldo sol ou reduza a quantidade de sol que você está enviando.", + "solana_sign_spl_token_transaction_rent_exception": "A transação não pode ser concluída. Sol insuficiente deixou para alugar após a transação. Por favor, complete seu equilíbrio sol.", "sort_by": "Ordenar por", "spend_key_private": "Chave de gastos (privada)", "spend_key_public": "Chave de gastos (pública)", @@ -746,7 +774,7 @@ "support_description_guides": "Documentação e suporte para problemas comuns", "support_description_live_chat": "Livre e rápido! Representantes de suporte treinado estão disponíveis para ajudar", "support_description_other_links": "Junte -se às nossas comunidades ou chegue a nós nossos parceiros por meio de outros métodos", - "support_title_guides": "Guias da carteira de bolo", + "support_title_guides": "Documentos da carteira de bolo", "support_title_live_chat": "Apoio ao vivo", "support_title_other_links": "Outros links de suporte", "sweeping_wallet": "Carteira varrendo", @@ -825,6 +853,7 @@ "trade_state_underpaid": "Parcialmente paga", "trade_state_unpaid": "Não paga", "trades": "Trocas", + "transaction_cost": "Custo da transação", "transaction_details_amount": "Quantia", "transaction_details_copied": "${title} copiados para a área de transferência", "transaction_details_date": "Data", @@ -884,6 +913,7 @@ "variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas", "verification": "Verificação", "verify_message": "Verifique a mensagem", + "verify_seed": "Verifique a semente", "verify_with_2fa": "Verificar com Cake 2FA", "version": "Versão ${currentVersion}", "view_all": "Ver todos", @@ -894,6 +924,7 @@ "voting_weight": "Peso de votação", "waitFewSecondForTxUpdate": "Aguarde alguns segundos para que a transação seja refletida no histórico de transações", "waiting_payment_confirmation": "Aguardando confirmação de pagamento", + "wallet": "Carteira", "wallet_group": "Grupo de carteira", "wallet_group_description_four": "Para criar uma carteira com uma semente totalmente nova.", "wallet_group_description_one": "Na carteira de bolo, você pode criar um", @@ -926,6 +957,8 @@ "wallets": "Carteiras", "warning": "Aviso", "welcome": "Bem-vindo ao", + "welcome_subtitle_new_wallet": "Se você quiser começar de novo, toque em criar uma nova carteira abaixo e você estará nas corridas.", + "welcome_subtitle_restore_wallet": "Se você tem uma carteira existente que deseja trazer para o bolo, basta escolher a carteira existente e nós o guiaremos pelo processo.", "welcome_to_cakepay": "Bem-vindo ao Cake Pay!", "what_is_silent_payments": "O que são pagamentos silenciosos?", "widgets_address": "Endereço", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index c30d30519..799d88e85 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -38,6 +38,7 @@ "agree_to": "Создавая аккаунт, вы соглашаетесь с ", "alert_notice": "Уведомление", "all": "ВСЕ", + "all_coins": "Все монеты", "all_trades": "Все сделки", "all_transactions": "Все транзакции", "alphabetical": "Алфавитный", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Купить карты с предоплатой и подарочными картами по всему миру", "cake_pay_web_cards_subtitle": "Покупайте карты предоплаты и подарочные карты по всему миру", "cake_pay_web_cards_title": "Веб-карты Cake Pay", + "cake_seeds_save_disclaimer": "Пожалуйста, сохраните эти слова в безопасном месте! Вам понадобятся эти слова, чтобы восстановить свой кошелек на новом устройстве.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Я подтверждаю, что не использую прокси или VPN", + "cakepay_confirm_purchase": "Подтвердите покупку", + "cakepay_confirm_terms_agreed": "Я согласен с условиями, представленными здесь:", + "cakepay_confirm_voided_refund": "Я понимаю, что попытки выкупа из ограниченной страны будут аннулировать любые возмещение", + "cakepay_ios_not_available": "Извините, эта подарочная карта недоступна на iOS. Вместо этого вы можете приобрести его на Android или через наш веб -сайт.", "cakepay_prepaid_card": "Предоплаченная дебетовая карта CakePay", "camera_consent": "Ваша камера будет использоваться для захвата изображения в целях идентификации ${provider}. Пожалуйста, ознакомьтесь с их Политикой конфиденциальности для получения подробной информации.", "camera_permission_is_required": "Требуется разрешение камеры.\nПожалуйста, включите его в настройках приложения.", @@ -175,6 +182,7 @@ "copy_address": "Cкопировать адрес", "copy_id": "Скопировать ID", "copyWalletConnectLink": "Скопируйте ссылку WalletConnect из dApp и вставьте сюда.", + "corrupted_seed_notice": "Файлы для этого кошелька повреждены и не могут быть открыты. Пожалуйста, просмотрите семенную фразу, сохраните ее и восстановите кошелек.\n\nЕсли значение пустое, то семя не смог правильно восстановить.", "countries": "Страны", "create_account": "Создать аккаунт", "create_backup": "Создать резервную копию", @@ -256,7 +264,7 @@ "enterTokenID": "Введите идентификатор токена", "enterWalletConnectURI": "Введите URI WalletConnect", "error": "Ошибка", - "error_dialog_content": "Ой, у нас какая-то ошибка.\n\nПожалуйста, отправьте отчет о сбое в нашу службу поддержки, чтобы сделать приложение лучше.", + "error_dialog_content": "Упс, мы получили некоторую ошибку.\n\nПожалуйста, отправьте отчет об ошибках в нашу команду поддержки, чтобы сделать приложение лучше.", "error_text_account_name": "Имя аккаунта может содержать только буквы, цифры\nи должно быть от 1 до 15 символов в длину", "error_text_address": "Адрес кошелька должен соответствовать типу\nкриптовалюты", "error_text_amount": "Баланс может содержать только цифры", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Часто задаваемые вопросы", "frozen": "Заморожено", "full_balance": "Весь баланс", + "gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.", "generate_name": "Создать имя", "generating_gift_card": "Создание подарочной карты", "get_a": "Получить ", @@ -350,13 +359,17 @@ "how_to_use": "Как использовать", "how_to_use_card": "Как использовать эту карту", "id": "ID: ", + "if_you_dont_see_your_device": "Если вы не видите свое устройство выше, пожалуйста, убедитесь, что ваша бухгалтерская книга бодрствует и разблокирована!", "ignor": "Игнорировать", "import": "Импортировать", "importNFTs": "Импортировать NFT", "in_store": "В магазине", "incoming": "Входящие", "incorrect_seed": "Введённый текст некорректный.", + "incorrect_seed_option": "Неверный. Пожалуйста, попробуйте еще раз", + "incorrect_seed_option_back": "Неверный. Пожалуйста, убедитесь, что ваше семя сохранено правильно, и попробуйте еще раз.", "inputs": "Входы", + "insufficient_funds_for_tx": "Недостаточно средств для успешного выполнения транзакции.", "insufficient_lamport_for_tx": "У вас недостаточно Sol, чтобы покрыть транзакцию и плату за транзакцию. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете.", "insufficient_lamports": "У вас недостаточно Sol, чтобы покрыть транзакцию и плату за транзакцию. Вам нужен как минимум ${solValueNeeded} sol. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете", "insufficientFundsForRentError": "У вас недостаточно Sol, чтобы покрыть плату за транзакцию и аренду для счета. Пожалуйста, добавьте больше Sol в свой кошелек или уменьшите сумму Sol, которую вы отправляете", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Выберите нового представителя", "nanogpt_subtitle": "Все новейшие модели (GPT-4, Claude). \\ Nno Подписка, платите с крипто.", "narrow": "Узкий", - "new_first_wallet_text": "Легко сохранить свою криптовалюту в безопасности", + "new_first_wallet_text": "Сохранение вашего криптографии - это кусок торта", "new_node_testing": "Тестирование новой ноды", "new_subaddress_create": "Создать", "new_subaddress_label_name": "Имя", @@ -464,6 +477,7 @@ "online": "Онлайн", "onramper_option_description": "Быстро купите крипто со многими способами оплаты. Доступно в большинстве стран. Спреды и сборы различаются.", "open_gift_card": "Открыть подарочную карту", + "open_wallet": "Открытый кошелек", "optional_description": "Дополнительное описание", "optional_email_hint": "Необязательное электронное письмо с уведомлением получателя платежа", "optional_name": "Необязательное имя получателя", @@ -478,6 +492,7 @@ "outdated_electrum_wallet_receive_warning": "Если этот кошелек имеет мнемоническую фразу из 12 слов и был создан в Cake, НЕ переводите биткойны на этот кошелек. Любые BTC, переведенные на этот кошелек, могут быть потеряны. Создайте новый кошелек с мнемоническои фразы из 24 слов (коснитесь меню в правом верхнем углу, выберите «Кошельки», выберите «Создать новый кошелек», затем выберите «Bitcoin») и НЕМЕДЛЕННО переведите туда свои BTC. Новые (24 слова) кошельки BTC от Cake безопасны", "outgoing": "Исходящие", "outputs": "Выходы", + "overshot": "Перевернуть", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Недействительное событие сопряжения", "passphrase": "Passfrase (необязательно)", @@ -532,6 +547,7 @@ "recipient_address": "Адрес получателя", "reconnect": "Переподключиться", "reconnect_alert_text": "Вы хотите переподключиться?", + "reconnect_your_hardware_wallet": "Воссоедините свой аппаратный кошелек", "reconnection": "Переподключение", "red_dark_theme": "Красная темная тема", "red_light_theme": "Тема красного света", @@ -571,6 +587,7 @@ "restore_description_from_keys": "Вы можете восстановить кошелёк с помощью приватных ключей", "restore_description_from_seed": "Вы можете восстановить кошелёк используя 25-ти значную мнемоническую фразу", "restore_description_from_seed_keys": "Вы можете восстановить кошелёк из мнемонической фразы/ключей, которые вы сохранили ранее", + "restore_existing_wallet": "Восстановите существующий кошелек", "restore_from_date_or_blockheight": "Пожалуйста, введите дату за несколько дней до создания этого кошелька. Или, если вы знаете высоту блока, введите ее значение", "restore_from_seed_placeholder": "Введите или вставьте мнемоническую фразу вашего кошелька", "restore_new_seed": "Новая мнемоническая фраза", @@ -612,6 +629,7 @@ "seed_alert_title": "Внимание", "seed_alert_yes": "Да", "seed_choose": "Выберите язык мнемонической фразы", + "seed_display_path": "Меню -> Безопасность и резервное копирование -> Показать ключ/семена", "seed_hex_form": "Семя кошелька (шестнадцатеричная форма)", "seed_key": "Ключ семян", "seed_language": "Язык семян", @@ -630,9 +648,13 @@ "seed_language_russian": "Русский", "seed_language_spanish": "Испанский", "seed_phrase_length": "Длина исходной фразы", + "seed_position_question_one": "Что такое", + "seed_position_question_two": "Слово вашей семенной фразы?", "seed_reminder": "Пожалуйста, запишите мнемоническую фразу на случай потери или очистки телефона", "seed_share": "Поделиться мнемонической фразой", "seed_title": "Мнемоническая фраза", + "seed_verified": "Семя проверено", + "seed_verified_subtext": "Позже вы можете использовать сохраненное семя, чтобы восстановить этот кошелек в случае коррупции или потери вашего устройства. \n\n Вы можете снова просмотреть это семя из", "seedtype": "SEEDTYPE", "seedtype_alert_content": "Обмен семенами с другими кошельками возможно только с BIP39 SeedType.", "seedtype_alert_title": "SEEDTYPE ALERT", @@ -671,6 +693,7 @@ "sent": "Отправленные", "service_health_disabled": "Бюллетень для здоровья обслуживания инвалид", "service_health_disabled_message": "Это страница бюллетени обслуживания услуг, вы можете включить эту страницу в соответствии с настройками -> Конфиденциальность", + "set_a_pin": "Установить булавку", "settings": "Настройки", "settings_all": "ВСЕ", "settings_allow_biometrical_authentication": "Включить биометрическую аутентификацию", @@ -706,6 +729,7 @@ "share_address": "Поделиться адресом", "shared_seed_wallet_groups": "Общие группы кошелька семян", "show": "Показывать", + "show_address_book_popup": "Покажите всплывающее окно «Добавить в адрес адреса» после отправки", "show_details": "Показать детали", "show_keys": "Показать мнемоническую фразу/ключи", "show_market_place": "Показать торговую площадку", @@ -733,6 +757,10 @@ "silent_payments_settings": "Silent Payments Settings", "single_seed_wallets_group": "Одиночные кошельки", "slidable": "Скользящий", + "solana_create_associated_token_account_exception": "Ошибка создания ассоциированной учетной записи для адреса для адреса.", + "solana_no_associated_token_account_exception": "Для этого адреса нет связанной учетной записи токена.", + "solana_sign_native_transaction_rent_exception": "Сделка не может быть завершена. Недостаточный соль ушел в аренду после транзакции. Пожалуйста, поместите свой баланс Sol или уменьшите количество Sol, которое вы отправляете.", + "solana_sign_spl_token_transaction_rent_exception": "Сделка не может быть завершена. Недостаточный соль ушел в аренду после транзакции. Пожалуйста, пополните свой баланс Sol.", "sort_by": "Сортировать по", "spend_key_private": "Приватный ключ траты", "spend_key_public": "Публичный ключ траты", @@ -745,7 +773,7 @@ "support_description_guides": "Документация и поддержка общих вопросов", "support_description_live_chat": "Бесплатно и быстро! Обученные представители поддержки доступны для оказания помощи", "support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов", - "support_title_guides": "Корт -гиды", + "support_title_guides": "Корт кошелек документов", "support_title_live_chat": "Живая поддержка", "support_title_other_links": "Другие ссылки на поддержку", "sweeping_wallet": "Подметание кошелька", @@ -824,6 +852,7 @@ "trade_state_underpaid": "Недоплаченная", "trade_state_unpaid": "Неоплаченная", "trades": "Сделки", + "transaction_cost": "Транзакционная стоимость", "transaction_details_amount": "Сумма", "transaction_details_copied": "${title} скопировано в буфер обмена", "transaction_details_date": "Дата", @@ -883,6 +912,7 @@ "variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.", "verification": "Проверка", "verify_message": "Проверьте сообщение", + "verify_seed": "Проверьте семя", "verify_with_2fa": "Подтвердить с помощью Cake 2FA", "version": "Версия ${currentVersion}", "view_all": "Просмотреть все", @@ -892,6 +922,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "Вес голоса", "waitFewSecondForTxUpdate": "Пожалуйста, подождите несколько секунд, чтобы транзакция отразилась в истории транзакций.", + "wallet": "Кошелек", "wallet_group": "Группа кошелька", "wallet_group_description_four": "создать кошелек с совершенно новым семенем.", "wallet_group_description_one": "В кошельке для торта вы можете создать", @@ -924,6 +955,8 @@ "wallets": "Кошельки", "warning": "Предупреждение", "welcome": "Приветствуем в", + "welcome_subtitle_new_wallet": "Если вы хотите начать Fresh, нажмите «Создать новый кошелек» ниже, и вы отправитесь на гонки.", + "welcome_subtitle_restore_wallet": "Если у вас есть существующий кошелек, который вы хотите принести в торт, просто выберите «Восстановить существующий кошелек», и мы проведем вас через процесс.", "welcome_to_cakepay": "Добро пожаловать в Cake Pay!", "what_is_silent_payments": "Что такое молчаливые платежи?", "widgets_address": "Адрес", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 898a64cc9..54eaa5a01 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -38,6 +38,7 @@ "agree_to": "การสร้างบัญชีของคุณยอมรับเงื่อนไขของ", "alert_notice": "สังเกต", "all": "ทั้งหมด", + "all_coins": "เหรียญทั้งหมด", "all_trades": "การซื้อขายทั้งหมด", "all_transactions": "การทำธุรกรรมทั้งหมด", "alphabetical": "ตามตัวอักษร", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "ซื้อบัตรเติมเงินและบัตรของขวัญทั่วโลก", "cake_pay_web_cards_subtitle": "ซื้อบัตรพร้อมเงินระดับโลกและบัตรของขวัญ", "cake_pay_web_cards_title": "Cake Pay Web Cards", + "cake_seeds_save_disclaimer": "โปรดบันทึกคำเหล่านี้ในสถานที่ที่ปลอดภัย! คุณจะต้องใช้คำเหล่านี้เพื่อกู้คืนกระเป๋าเงินของคุณในอุปกรณ์ใหม่", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "ฉันยืนยันว่าฉันไม่ได้ใช้พร็อกซีหรือ VPN", + "cakepay_confirm_purchase": "ยืนยันการซื้อ", + "cakepay_confirm_terms_agreed": "ฉันเห็นด้วยกับข้อกำหนดและเงื่อนไขที่นำเสนอที่นี่:", + "cakepay_confirm_voided_refund": "ฉันเข้าใจความพยายามในการไถ่ถอนจากประเทศที่ถูก จำกัด จะทำให้คืนเงินใด ๆ", + "cakepay_ios_not_available": "ขออภัยบัตรของขวัญนี้ไม่มีใน iOS คุณสามารถซื้อได้บน Android หรือผ่านเว็บไซต์ของเราแทน", "cakepay_prepaid_card": "บัตรเดบิตเติมเงินของ CakePay", "camera_consent": "กล้องของคุณจะถูกนำมาใช้เพื่อจับภาพเพื่อวัตถุประสงค์ในการระบุตัวตนภายใน ${provider} โปรดตรวจสอบนโยบายความเป็นส่วนตัวเพื่อดูรายละเอียด", "camera_permission_is_required": "ต้องได้รับอนุญาตจากกล้อง\nโปรดเปิดใช้งานจากการตั้งค่าแอป", @@ -175,6 +182,7 @@ "copy_address": "คัดลอกที่อยู่", "copy_id": "คัดลอก ID", "copyWalletConnectLink": "คัดลอกลิงก์ WalletConnect จาก dApp แล้ววางที่นี่", + "corrupted_seed_notice": "ไฟล์สำหรับกระเป๋าเงินนี้เสียหายและไม่สามารถเปิดได้ โปรดดูวลีเมล็ดบันทึกและกู้คืนกระเป๋าเงิน\n\nหากค่าว่างเปล่าเมล็ดก็ไม่สามารถกู้คืนได้อย่างถูกต้อง", "countries": "ประเทศ", "create_account": "สร้างบัญชี", "create_backup": "สร้างการสำรองข้อมูล", @@ -256,7 +264,7 @@ "enterTokenID": "ป้อนรหัสโทเค็น", "enterWalletConnectURI": "เข้าสู่ WalletConnect URI", "error": "ข้อผิดพลาด", - "error_dialog_content": "อ๊ะ เราพบข้อผิดพลาดบางอย่าง\n\nโปรดส่งรายงานข้อขัดข้องไปยังทีมสนับสนุนของเราเพื่อปรับปรุงแอปพลิเคชันให้ดียิ่งขึ้น", + "error_dialog_content": "อ๊ะเรามีข้อผิดพลาดบางอย่าง\n\nโปรดส่งรายงานข้อผิดพลาดไปยังทีมสนับสนุนของเราเพื่อให้แอปพลิเคชันดีขึ้น", "error_text_account_name": "ชื่อบัญชีสามารถเป็นเพียงตัวอักษรหรือตัวเลขเท่านั้น\nและต้องมีความยาวระหว่าง 1 ถึง 15 ตัวอักษร", "error_text_address": "ที่อยู่กระเป๋าจะต้องสอดคล้องกับประเภท\nของเหรียญคริปโตเนียม", "error_text_amount": "จำนวนจะต้องประกอบด้วยตัวเลขเท่านั้น", @@ -323,6 +331,7 @@ "frequently_asked_questions": "คำถามที่พบบ่อย", "frozen": "ถูกดักจับ", "full_balance": "ยอดคงเหลือทั้งหมด", + "gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ", "generate_name": "สร้างชื่อ", "generating_gift_card": "กำลังสร้างบัตรของขวัญ", "get_a": "รับ ", @@ -350,13 +359,17 @@ "how_to_use": "วิธีใช้", "how_to_use_card": "วิธีใช้บัตรนี้", "id": "ID: ", + "if_you_dont_see_your_device": "หากคุณไม่เห็นอุปกรณ์ของคุณด้านบนโปรดตรวจสอบให้แน่ใจว่าบัญชีแยกประเภทของคุณตื่นและปลดล็อค!", "ignor": "ละเว้น", "import": "นำเข้า", "importNFTs": "นำเข้า NFT", "in_store": "ในร้าน", "incoming": "ขาเข้า", "incorrect_seed": "ข้อความที่ป้อนไม่ถูกต้อง", + "incorrect_seed_option": "ไม่ถูกต้อง. โปรดลองอีกครั้ง", + "incorrect_seed_option_back": "ไม่ถูกต้อง. โปรดตรวจสอบให้แน่ใจว่าเมล็ดพันธุ์ของคุณได้รับการบันทึกอย่างถูกต้องและลองอีกครั้ง", "inputs": "อินพุต", + "insufficient_funds_for_tx": "เงินทุนไม่เพียงพอที่จะดำเนินการทำธุรกรรมได้สำเร็จ", "insufficient_lamport_for_tx": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมการทำธุรกรรมและค่าธรรมเนียมการทำธุรกรรม กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณส่งมา", "insufficient_lamports": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมการทำธุรกรรมและค่าธรรมเนียมการทำธุรกรรม คุณต้องการอย่างน้อย ${solValueNeeded} SOL กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณกำลังส่ง", "insufficientFundsForRentError": "คุณไม่มีโซลเพียงพอที่จะครอบคลุมค่าธรรมเนียมการทำธุรกรรมและค่าเช่าสำหรับบัญชี กรุณาเพิ่มโซลให้มากขึ้นลงในกระเป๋าเงินของคุณหรือลดจำนวนโซลที่คุณส่งมา", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "เลือกตัวแทนใหม่", "nanogpt_subtitle": "รุ่นใหม่ล่าสุดทั้งหมด (GPT-4, Claude). การสมัครสมาชิก \\ nno, จ่ายด้วย crypto", "narrow": "แคบ", - "new_first_wallet_text": "ทำให้สกุลเงินดิจิตอลของคุณปลอดภัยได้อย่างง่ายดาย", + "new_first_wallet_text": "การรักษา crypto ของคุณให้ปลอดภัยเป็นเค้กชิ้นหนึ่ง", "new_node_testing": "การทดสอบโหนดใหม่", "new_subaddress_create": "สร้าง", "new_subaddress_label_name": "ชื่อป้ายกำกับ", @@ -464,6 +477,7 @@ "online": "ออนไลน์", "onramper_option_description": "ซื้อ crypto อย่างรวดเร็วด้วยวิธีการชำระเงินจำนวนมาก มีให้บริการในประเทศส่วนใหญ่ สเปรดและค่าธรรมเนียมแตกต่างกันไป", "open_gift_card": "เปิดบัตรของขวัญ", + "open_wallet": "กระเป๋าสตางค์เปิด", "optional_description": "คำอธิบายเพิ่มเติม", "optional_email_hint": "อีเมลแจ้งผู้รับเงินเพิ่มเติม", "optional_name": "ชื่อผู้รับเพิ่มเติม", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "หากกระเป๋านี้มีซีดีที่มี 12 คำและถูกสร้างขึ้นใน Cake อย่าโอน Bitcoin เข้ากระเป๋านี้ ทุกจำนวน BTC ที่โอนเข้ากระเป๋านี้อาจสูญหาย สร้างกระเป๋าใหม่ที่มีซีดีที่มี 24 คำ (กดที่เมนูที่มุมขวาบนแล้วเลือก Wallets และเลือก Create New Wallet จากนั้นเลือก Bitcoin) และย้าย BTC ไปที่นั้นทันที กระเป๋า BTC ที่มีซีดีที่มี 24 คำของ Cake ปลอดภัย", "outgoing": "ขาออก", "outputs": "เอาต์พุต", + "overshot": "โอเวอร์คล็อต", "overwrite_amount": "เขียนทับจำนวน", "pairingInvalidEvent": "การจับคู่เหตุการณ์ที่ไม่ถูกต้อง", "passphrase": "ข้อความรหัสผ่าน (ไม่บังคับ)", @@ -531,6 +546,7 @@ "recipient_address": "ที่อยู่ผู้รับ", "reconnect": "เชื่อมต่อใหม่", "reconnect_alert_text": "คุณแน่ใจหรือไม่ว่าต้องการเชื่อมต่อใหม่?", + "reconnect_your_hardware_wallet": "เชื่อมต่อกระเป๋าเงินฮาร์ดแวร์ของคุณอีกครั้ง", "reconnection": "เชื่อมต่อใหม่", "red_dark_theme": "ธีมสีแดงเข้ม", "red_light_theme": "ธีมแสงสีแดง", @@ -570,6 +586,7 @@ "restore_description_from_keys": "กู้กระเป๋าของคุณจากการกดปุ่มที่สร้างขึ้นจาก private keys ของคุณที่บันทึกไว้", "restore_description_from_seed": "กู้กระเป๋าของคุณจากรหัสผสมของ 25 คำหรือ 13 คำ", "restore_description_from_seed_keys": "เรียกกระเป๋าของคุณกลับมาจาก seed/keys ที่คุณได้บันทึกไว้ในที่ปลอดภัย", + "restore_existing_wallet": "คืนค่ากระเป๋าเงินที่มีอยู่", "restore_from_date_or_blockheight": "โปรดป้อนวันที่หลายวันก่อนที่คุณสร้างกระเป๋านี้ หรือหากคุณรู้ความสูงของบล็อก (blockheight) โปรดป้อนมันแทน", "restore_from_seed_placeholder": "โปรดป้อนหรือวาง seed ของคุณที่นี่", "restore_new_seed": "ซีดใหม่", @@ -611,6 +628,7 @@ "seed_alert_title": "ความสนใจ", "seed_alert_yes": "ใช่ ฉันได้เขียน", "seed_choose": "เลือกภาษาของ seed", + "seed_display_path": "เมนู -> ความปลอดภัยและการสำรองข้อมูล -> แสดงคีย์/เมล็ดพันธุ์", "seed_hex_form": "เมล็ดกระเป๋าเงิน (รูปแบบฐานสิบหก)", "seed_key": "คีย์เมล็ดพันธุ์", "seed_language": "ภาษาเมล็ด", @@ -629,9 +647,13 @@ "seed_language_russian": "รัสเซีย", "seed_language_spanish": "สเปน", "seed_phrase_length": "ความยาววลีของเมล็ด", + "seed_position_question_one": "ไฟล์", + "seed_position_question_two": "คำพูดของวลีเมล็ด?", "seed_reminder": "โปรดเขียนข้อมูลนี้ลงสมุดเพื่อความปลอดภัยหากคุณสูญเสียหรือล้างโทรศัพท์ของคุณ", "seed_share": "แบ่งปัน seed", "seed_title": "Seed", + "seed_verified": "ตรวจสอบเมล็ดพันธุ์", + "seed_verified_subtext": "คุณสามารถใช้เมล็ดพันธุ์ที่บันทึกไว้ในภายหลังเพื่อคืนค่ากระเป๋าเงินนี้ในกรณีที่เกิดการทุจริตหรือสูญเสียอุปกรณ์ของคุณ \n\n คุณสามารถดูเมล็ดพันธุ์นี้ได้อีกครั้งจากไฟล์", "seedtype": "เมล็ดพันธุ์", "seedtype_alert_content": "การแบ่งปันเมล็ดกับกระเป๋าเงินอื่น ๆ เป็นไปได้เฉพาะกับ bip39 seedtype", "seedtype_alert_title": "การแจ้งเตือน seedtype", @@ -670,6 +692,7 @@ "sent": "ส่ง", "service_health_disabled": "Service Health Bulletin ถูกปิดใช้งาน", "service_health_disabled_message": "นี่คือหน้า Service Health Bulletin คุณสามารถเปิดใช้งานหน้านี้ภายใต้การตั้งค่า -> ความเป็นส่วนตัว", + "set_a_pin": "ตั้งพิน", "settings": "การตั้งค่า", "settings_all": "ทั้งหมด", "settings_allow_biometrical_authentication": "อนุญาตให้ใช้การยืนยันตัวตนทางระบบชีวภาพ", @@ -705,6 +728,7 @@ "share_address": "แชร์ที่อยู่", "shared_seed_wallet_groups": "กลุ่มกระเป๋าเงินที่ใช้ร่วมกัน", "show": "แสดง", + "show_address_book_popup": "แสดง 'เพิ่มในสมุดรายชื่อ' ป๊อปอัพหลังจากส่ง", "show_details": "แสดงรายละเอียด", "show_keys": "แสดงซีด/คีย์", "show_market_place": "แสดงตลาดกลาง", @@ -732,6 +756,10 @@ "silent_payments_settings": "การตั้งค่าการชำระเงินแบบเงียบ", "single_seed_wallets_group": "กระเป๋าเงินเดียว", "slidable": "เลื่อนได้", + "solana_create_associated_token_account_exception": "ข้อผิดพลาดในการสร้างบัญชีโทเค็นที่เกี่ยวข้องสำหรับที่อยู่รับ", + "solana_no_associated_token_account_exception": "ไม่มีบัญชีโทเค็นที่เกี่ยวข้องสำหรับที่อยู่นี้", + "solana_sign_native_transaction_rent_exception": "การทำธุรกรรมไม่สามารถเสร็จสิ้นได้ SOL ไม่เพียงพอเหลือให้เช่าหลังการทำธุรกรรม กรุณาเติมยอดคงเหลือโซลของคุณหรือลดจำนวนโซลที่คุณกำลังส่ง", + "solana_sign_spl_token_transaction_rent_exception": "การทำธุรกรรมไม่สามารถเสร็จสิ้นได้ SOL ไม่เพียงพอเหลือให้เช่าหลังการทำธุรกรรม กรุณาเติมยอดสมดุลโซลของคุณ", "sort_by": "เรียงตาม", "spend_key_private": "คีย์จ่าย (ส่วนตัว)", "spend_key_public": "คีย์จ่าย (สาธารณะ)", @@ -744,7 +772,7 @@ "support_description_guides": "เอกสารและการสนับสนุนสำหรับปัญหาทั่วไป", "support_description_live_chat": "ฟรีและรวดเร็ว! ตัวแทนฝ่ายสนับสนุนที่ผ่านการฝึกอบรมพร้อมให้ความช่วยเหลือ", "support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ", - "support_title_guides": "คู่มือกระเป๋าเงินเค้ก", + "support_title_guides": "เอกสารกระเป๋าเงินเค้ก", "support_title_live_chat": "การสนับสนุนสด", "support_title_other_links": "ลิงค์สนับสนุนอื่น ๆ", "sweeping_wallet": "กวาดกระเป๋าสตางค์", @@ -823,6 +851,7 @@ "trade_state_underpaid": "จ่ายไม่ครบ", "trade_state_unpaid": "ยังไม่ได้จ่าย", "trades": "การซื้อขาย", + "transaction_cost": "ต้นทุนการทำธุรกรรม", "transaction_details_amount": "จำนวน", "transaction_details_copied": "${title} ถูกคัดลอกไปยังคลิปบอร์ด", "transaction_details_date": "วันที่", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "คู่ความสัมพันธ์ที่เปลี่ยนแปลงได้นี้ไม่สนับสนุนกับหุ้นที่เลือก", "verification": "การตรวจสอบ", "verify_message": "ยืนยันข้อความ", + "verify_seed": "ตรวจสอบเมล็ดพันธุ์", "verify_with_2fa": "ตรวจสอบกับ Cake 2FA", "version": "เวอร์ชัน ${currentVersion}", "view_all": "ดูทั้งหมด", @@ -891,6 +921,7 @@ "view_transaction_on": "ดูการทำธุรกรรมบน ", "voting_weight": "น้ำหนักโหวต", "waitFewSecondForTxUpdate": "กรุณารอสักครู่เพื่อให้ธุรกรรมปรากฏในประวัติการทำธุรกรรม", + "wallet": "กระเป๋าสตางค์", "wallet_group": "กลุ่มกระเป๋าเงิน", "wallet_group_description_four": "เพื่อสร้างกระเป๋าเงินที่มีเมล็ดพันธุ์ใหม่ทั้งหมด", "wallet_group_description_one": "ในกระเป๋าเงินเค้กคุณสามารถสร้างไฟล์", @@ -923,6 +954,8 @@ "wallets": "กระเป๋า", "warning": "คำเตือน", "welcome": "ยินดีต้อนรับสู่", + "welcome_subtitle_new_wallet": "หากคุณต้องการเริ่มต้นใหม่ให้แตะสร้างกระเป๋าเงินใหม่ด้านล่างและคุณจะออกจากการแข่งขัน", + "welcome_subtitle_restore_wallet": "หากคุณมีกระเป๋าเงินที่มีอยู่ที่คุณต้องการนำเข้าเค้กให้เลือกคืนกระเป๋าเงินที่มีอยู่แล้วเราจะพาคุณผ่านกระบวนการ", "welcome_to_cakepay": "ยินดีต้อนรับสู่ Cake Pay!", "what_is_silent_payments": "การชำระเงินเงียบคืออะไร?", "widgets_address": "ที่อยู่", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index cdbbda925..68d5439bb 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -38,6 +38,7 @@ "agree_to": "Sa pamamagitan ng paggawa ng account sumasang-ayon ka sa ", "alert_notice": "PAUNAWA", "all": "LAHAT", + "all_coins": "Lahat ng mga barya", "all_trades": "Lahat ng mga trade", "all_transactions": "Lahat ng mga transaksyon", "alphabetical": "Alpabeto", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Bumili ng mga pandaigdigang prepaid card at gift card", "cake_pay_web_cards_subtitle": "Bumili ng mga pandaigdigang prepaid card at gift card", "cake_pay_web_cards_title": "Cake Pay Web Cards", + "cake_seeds_save_disclaimer": "Mangyaring i -save ang mga salitang ito sa isang ligtas na lugar! Kakailanganin mo ang mga salitang ito upang maibalik ang iyong pitaka sa isang bagong aparato.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Kinukumpirma kong hindi ako gumagamit ng isang proxy o vpn", + "cakepay_confirm_purchase": "Kumpirmahin ang pagbili", + "cakepay_confirm_terms_agreed": "Sumasang -ayon ako sa mga termino at kundisyon na ipinakita dito:", + "cakepay_confirm_voided_refund": "Naiintindihan ko ang mga pagtatangka sa pagtubos mula sa isang pinigilan na bansa ay walang bisa sa anumang refund", + "cakepay_ios_not_available": "Paumanhin, ang gift card na ito ay hindi magagamit sa iOS. Maaari mo itong bilhin sa Android o sa pamamagitan ng aming website sa halip.", "cakepay_prepaid_card": "CakePay Prepaid Debit Card", "camera_consent": "Gagamitin ang iyong camera upang kumuha ng larawan para sa mga layunin ng pagkakakilanlan sa pamamagitan ng ${provider}. Pakisuri ang kanilang Patakaran sa Privacy para sa mga detalye.", "camera_permission_is_required": "Kinakailangan ang pahintulot sa camera.\nMangyaring paganahin ito mula sa mga setting ng app.", @@ -175,6 +182,7 @@ "copy_address": "Kopyahin ang Address", "copy_id": "Kopyahin ang ID", "copyWalletConnectLink": "Kopyahin ang link ng WalletConnect mula sa dApp at i-paste dito", + "corrupted_seed_notice": "Ang mga file para sa pitaka na ito ay nasira at hindi mabubuksan. Mangyaring tingnan ang parirala ng binhi, i -save ito, at ibalik ang pitaka.\n\nKung ang halaga ay walang laman, kung gayon ang binhi ay hindi ma -recover nang tama.", "countries": "Mga bansa", "create_account": "Lumikha ng Account", "create_backup": "Lumikha ng backup", @@ -256,7 +264,7 @@ "enterTokenID": "Ipasok ang token ID", "enterWalletConnectURI": "Ipasok ang WalletConnect URI", "error": "Error", - "error_dialog_content": "Oops, nakakuha kami ng ilang error.\n\nMangyaring ipadala ang crash report sa aming koponan ng suporta upang maging mas mahusay ang application.", + "error_dialog_content": "Oops, nakakuha kami ng ilang error.\n\nMangyaring ipadala ang ulat ng error sa aming koponan ng suporta upang maging mas mahusay ang application.", "error_text_account_name": "Ang pangalan ng account ay maaari lamang maglaman ng mga titik, numero\nat dapat sa pagitan ng 1 at 15 character ang haba", "error_text_address": "Ang wallet address ay dapat na tumutugma sa uri\nng cryptocurrency", "error_text_amount": "Ang halaga ay maaari lamang maglaman ng mga numero", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Mga madalas itanong", "frozen": "Frozen", "full_balance": "Buong Balanse", + "gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.", "generate_name": "Bumuo ng pangalan", "generating_gift_card": "Bumubuo ng Gift Card", "get_a": "Kumuha ng ", @@ -350,13 +359,17 @@ "how_to_use": "Paano gamitin", "how_to_use_card": "Paano gamitin ang card na ito", "id": "ID: ", + "if_you_dont_see_your_device": "Kung hindi mo nakikita ang iyong aparato sa itaas, siguraduhin na ang iyong ledger ay gising at naka -lock!", "ignor": "Huwag pansinin", "import": "Mag-import", "importNFTs": "Mag-import ng mga NFT", "in_store": "Nasa Stock", "incoming": "Papasok", "incorrect_seed": "Ang text na ipinasok ay hindi wasto.", + "incorrect_seed_option": "Maling. Mangyaring subukang muli", + "incorrect_seed_option_back": "Maling. Mangyaring tiyakin na ang iyong binhi ay nai -save nang tama at subukang muli.", "inputs": "Mga input", + "insufficient_funds_for_tx": "Hindi sapat na pondo upang matagumpay na magsagawa ng transaksyon.", "insufficient_lamport_for_tx": "Wala kang sapat na SOL upang masakop ang transaksyon at ang bayad sa transaksyon nito. Mabuting magdagdag ng higit pa sa iyong pitaka o bawasan ang sol na halaga na iyong ipinapadala.", "insufficient_lamports": "Wala kang sapat na SOL upang masakop ang transaksyon at ang bayad sa transaksyon nito. Kailangan mo ng hindi bababa sa ${solValueNeeded} sol. Mabait na magdagdag ng higit pang sol sa iyong pitaka o bawasan ang dami ng iyong ipinapadala", "insufficientFundsForRentError": "Wala kang sapat na SOL upang masakop ang fee sa transaksyon at upa para sa account. Mabait na magdagdag ng higit pa sa iyong wallet o bawasan ang halaga ng SOL na iyong ipinapadala", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Pumili ng isang bagong representative", "nanogpt_subtitle": "Ang lahat ng mga pinakabagong modelo (GPT-4, Claude). \nNo subscription, magbayad gamit ang crypto.", "narrow": "Makitid", - "new_first_wallet_text": "Panatilihing ligtas ang iyong crypto, piraso ng cake", + "new_first_wallet_text": "Ang pagpapanatiling ligtas sa iyong crypto ay isang piraso ng cake", "new_node_testing": "Bagong node testing", "new_subaddress_create": "Lumikha", "new_subaddress_label_name": "Pangalan ng label", @@ -464,6 +477,7 @@ "online": "Online", "onramper_option_description": "Mabilis na bumili ng crypto na may maraming paraan ng pagbabayad. Available sa karamihan ng mga bansa. Iba-iba ang mga spread at fee.", "open_gift_card": "Buksan ang Gift Card", + "open_wallet": "Buksan ang pitaka", "optional_description": "Opsyonal na paglalarawan", "optional_email_hint": "Opsyonal na payee notification email", "optional_name": "Opsyonal na pangalan ng tatanggap", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Kung ang wallet na ito ay may 12-word seed na ginawa sa Cake, huwag magdeposito ng Bitcoin sa wallet na ito. Anumang BTC na inilipat sa wallet na ito ay maaaring mawala. Lumikha ng bagong 24 na salita na wallet (i-tap ang menu sa kanang taas, piliin ang Mga Wallets, piliin ang Lumikha ng Bagong Wallet, pagkatapos ay piliin ang Bitcoin) at agad na ilipat ang iyong BTC doon. Bagong (24 na salita) BTC wallet mula sa Cake ay ligtas", "outgoing": "Palabas", "outputs": "Mga output", + "overshot": "Overshot", "overwrite_amount": "I-overwrite ang halaga", "pairingInvalidEvent": "Pairing Invalid Event", "passphrase": "Passphrase (opsyonal)", @@ -531,6 +546,7 @@ "recipient_address": "Address ng tatanggap", "reconnect": "Kumonekta muli", "reconnect_alert_text": "Sigurado ka bang gusto mong kumonekta uli?", + "reconnect_your_hardware_wallet": "Ikonekta muli ang iyong wallet ng hardware", "reconnection": "Muling pagkakakonekta", "red_dark_theme": "Red Dark Theme", "red_light_theme": "Red Light Theme", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Ibalik ang iyong wallet mula sa nabuong mga keystrokes na na-save mula sa iyong mga private key", "restore_description_from_seed": "Ibalik ang iyong wallet mula sa alinman sa 25 na salita o 13 na salita na seed", "restore_description_from_seed_keys": "Ibalik ang inyong wallet mula sa inyong seed/keys na iyong na-save sa ligtas na lugar", + "restore_existing_wallet": "Ibalik ang umiiral na pitaka", "restore_from_date_or_blockheight": "Mangyaring maglagay ng petsa ilang araw bago mo ginawa ang wallet na ito. O kung alam mo ang block height pwede ilagay ito sa halip", "restore_from_seed_placeholder": "Mangyaring ipasok o idikit ang iyong seed dito", "restore_new_seed": "Bagong seed", @@ -611,6 +628,7 @@ "seed_alert_title": "Attention", "seed_alert_yes": "Oo meron ako", "seed_choose": "Pumili ng seed language", + "seed_display_path": "Menu -> Seguridad at Pag -backup -> Ipakita ang mga susi/buto", "seed_hex_form": "Wallet seed (hex form)", "seed_key": "Seed key", "seed_language": "Wika ng seed", @@ -629,9 +647,13 @@ "seed_language_russian": "Russian", "seed_language_spanish": "Spanish", "seed_phrase_length": "Haba ng parirala ng seed", + "seed_position_question_one": "Ano ang", + "seed_position_question_two": "Salita ng iyong pariralang binhi?", "seed_reminder": "Mangyaring isulat ang mga ito kung sakaling mawala o mabura sa inyong telepono", "seed_share": "Ibahagi ang seed", "seed_title": "Seed", + "seed_verified": "Napatunayan ang binhi", + "seed_verified_subtext": "Maaari mong gamitin ang iyong nai -save na binhi sa ibang pagkakataon upang maibalik ang pitaka na ito kung sakaling may katiwalian o mawala ang iyong aparato.\n\nMaaari mong tingnan muli ang binhi na ito mula sa", "seedtype": "Seed type", "seedtype_alert_content": "Ang pagbabahagi ng mga buto sa iba pang mga pitaka ay posible lamang sa bip39 seedtype.", "seedtype_alert_title": "Alerto ng Seedtype", @@ -670,6 +692,7 @@ "sent": "Ipinadala", "service_health_disabled": "Hindi pinagana ang Service Health Bulletin", "service_health_disabled_message": "Ito ang pahina ng Service Health Bulletin, maaari mong paganahin ang pahinang ito sa ilalim ng Mga Setting -> Pagkapribado", + "set_a_pin": "Magtakda ng isang pin", "settings": "Mga Setting", "settings_all": "LAHAT", "settings_allow_biometrical_authentication": "Payagan ang biometrical authentication", @@ -705,6 +728,7 @@ "share_address": "Ibahagi ang address", "shared_seed_wallet_groups": "Ibinahaging mga pangkat ng pitaka ng binhi", "show": "Ipakita", + "show_address_book_popup": "Ipakita ang popup na 'Idagdag sa Address Book' pagkatapos magpadala", "show_details": "Ipakita ang mga detalye", "show_keys": "Ipakita ang mga seed/key", "show_market_place": "Ipakita ang Marketplace", @@ -732,6 +756,10 @@ "silent_payments_settings": "Mga setting ng tahimik na pagbabayad", "single_seed_wallets_group": "Solong mga pitaka ng binhi", "slidable": "Slidable", + "solana_create_associated_token_account_exception": "Error sa paglikha ng nauugnay na token account para sa resibo address.", + "solana_no_associated_token_account_exception": "Walang nauugnay na token account para sa address na ito.", + "solana_sign_native_transaction_rent_exception": "Hindi makumpleto ang transaksyon. Hindi sapat na SOL na naiwan para sa upa pagkatapos ng transaksyon. Mabuting itaas ang iyong balanse sa sol o bawasan ang dami ng sol na iyong ipinapadala.", + "solana_sign_spl_token_transaction_rent_exception": "Hindi makumpleto ang transaksyon. Hindi sapat na SOL na naiwan para sa upa pagkatapos ng transaksyon. Mabuting itaas ang iyong balanse sa sol.", "sort_by": "Pag-uri-uriin sa pamamagitan ng", "spend_key_private": "Spend key (private)", "spend_key_public": "Spend key (public)", @@ -744,7 +772,7 @@ "support_description_guides": "Dokumentasyon at suporta para sa mga karaniwang isyu", "support_description_live_chat": "Libre at mabilis! Ang mga bihasang kinatawan ng suporta ay magagamit upang tulungan", "support_description_other_links": "Sumali sa aming mga komunidad o maabot sa amin ang aming mga kasosyo sa pamamagitan ng iba pang mga pamamaraan", - "support_title_guides": "Mga guide sa Cake Wallet", + "support_title_guides": "Cake wallet doc", "support_title_live_chat": "Live na suporta", "support_title_other_links": "Iba pang mga link sa suporta", "sweeping_wallet": "Sweeping wallet", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Kulang sa bayad", "trade_state_unpaid": "Hindi nabayaran", "trades": "Pangangalakal", + "transaction_cost": "Gastos sa transaksyon", "transaction_details_amount": "Halaga", "transaction_details_copied": "${title} kinopya sa clipboard", "transaction_details_date": "Petsa", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Ang variable na pares na ito ay hindi suportado sa mga napiling exchange", "verification": "Pag-verify", "verify_message": "I -verify ang mensahe", + "verify_seed": "I -verify ang binhi", "verify_with_2fa": "Mag-verify sa Cake 2FA", "version": "Bersyon ${currentVersion}", "view_all": "Tingnan lahat", @@ -891,6 +921,7 @@ "view_transaction_on": "Tingnan ang transaksyon sa ", "voting_weight": "Bigat ng pagboto", "waitFewSecondForTxUpdate": "Mangyaring maghintay ng ilang segundo para makita ang transaksyon sa history ng mga transaksyon", + "wallet": "Wallet", "wallet_group": "Group ng Wallet", "wallet_group_description_four": "Upang lumikha ng isang pitaka na may ganap na bagong binhi.", "wallet_group_description_one": "Sa cake wallet, maaari kang lumikha ng isang", @@ -923,6 +954,8 @@ "wallets": "Mga Wallet", "warning": "Babala", "welcome": "Maligayang pagdating sa", + "welcome_subtitle_new_wallet": "Kung nais mong simulan ang sariwa, tapikin ang Lumikha ng Bagong Wallet sa ibaba at pupunta ka sa mga karera.", + "welcome_subtitle_restore_wallet": "Kung mayroon kang isang umiiral na pitaka na nais mong dalhin sa cake, piliin lamang ang ibalik ang umiiral na pitaka at lalakad ka namin sa proseso.", "welcome_to_cakepay": "Maligayang pagdating sa Cake Pay!", "what_is_silent_payments": "Ano ang tahimik na pagbabayad?", "widgets_address": "Address", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 7d98aa412..6314f3fb9 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -38,6 +38,7 @@ "agree_to": "Hesap oluşturarak bunları kabul etmiş olursunuz ", "alert_notice": "Fark etme", "all": "HEPSİ", + "all_coins": "Tüm Paralar", "all_trades": "Tüm takaslar", "all_transactions": "Tüm transferler", "alphabetical": "Alfabetik", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Dünya çapında ön ödemeli kartlar ve hediye kartları satın alın", "cake_pay_web_cards_subtitle": "Dünya çapında ön ödemeli kartlar ve hediye kartları satın alın", "cake_pay_web_cards_title": "Cake Pay Web Kartları", + "cake_seeds_save_disclaimer": "Lütfen bu kelimeleri güvenli bir yerde kaydedin! Cüzdanınızı yeni bir cihazda geri yüklemek için bu kelimelere ihtiyacınız olacak.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Bir proxy veya vpn kullanmadığımı onaylıyorum", + "cakepay_confirm_purchase": "Satın Alma Onay", + "cakepay_confirm_terms_agreed": "Burada sunulan şartlar ve koşulları kabul ediyorum:", + "cakepay_confirm_voided_refund": "Kısıtlı bir ülkeden kurtuluş girişimlerinin herhangi bir geri ödemeyi geçersiz kılacağını anlıyorum", + "cakepay_ios_not_available": "Üzgünüm, bu hediye kartı iOS'ta mevcut değil. Bunun yerine Android'de veya web sitemizden satın alabilirsiniz.", "cakepay_prepaid_card": "CakePay Ön Ödemeli Kart", "camera_consent": "Kameranız ${provider} tarihine kadar tanımlama amacıyla bir görüntü yakalamak için kullanılacaktır. Ayrıntılar için lütfen Gizlilik Politikalarını kontrol edin.", "camera_permission_is_required": "Kamera izni gereklidir.\nLütfen uygulama ayarlarından etkinleştirin.", @@ -175,6 +182,7 @@ "copy_address": "Adresi kopyala", "copy_id": "ID'yi kopyala", "copyWalletConnectLink": "WalletConnect bağlantısını dApp'ten kopyalayıp buraya yapıştırın", + "corrupted_seed_notice": "Bu cüzdanın dosyaları bozuk ve açılamıyor. Lütfen tohum ifadesini görüntüleyin, kaydedin ve cüzdanı geri yükleyin.\n\nDeğer boşsa, tohum doğru bir şekilde geri kazanılamadı.", "countries": "Ülkeler", "create_account": "Hesap oluştur", "create_backup": "Yedek oluştur", @@ -256,7 +264,7 @@ "enterTokenID": "Belirteç kimliğini girin", "enterWalletConnectURI": "WalletConnect URI'sini girin", "error": "Hata", - "error_dialog_content": "Hay aksi, bir hatamız var.\n\nUygulamayı daha iyi hale getirmek için lütfen kilitlenme raporunu destek ekibimize gönderin.", + "error_dialog_content": "Oops, biraz hata aldık.\n\nLütfen uygulamayı daha iyi hale getirmek için hata raporunu destek ekibimize gönderin.", "error_text_account_name": "Hesap ismi yalnızca harf, rakam \nve 1 ile 15 uzunluğunda karakter içermelidir.", "error_text_address": "Cüzdan adresi kripto para biriminin\ntürüne karşılık gelmelidir", "error_text_amount": "Miktar sadece sayı içerebilir", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Sıkça sorulan sorular", "frozen": "Dondurulmuş", "full_balance": "Tüm bakiye", + "gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.", "generate_name": "İsim Oluştur", "generating_gift_card": "Hediye Kartı Oluşturuluyor", "get_a": "Bir ", @@ -350,13 +359,17 @@ "how_to_use": "Nasıl kullanılır", "how_to_use_card": "Bu kart nasıl kullanılır", "id": "ID: ", + "if_you_dont_see_your_device": "Cihazınızı yukarıda görmüyorsanız, lütfen defterinizin uyanık olduğundan ve kilidinin açıldığından emin olun!", "ignor": "Yoksay", "import": "İçe aktarmak", "importNFTs": "NFT'leri içe aktar", "in_store": "Mağazada", "incoming": "Gelen", "incorrect_seed": "Girilen metin geçerli değil.", + "incorrect_seed_option": "Yanlış. Lütfen tekrar deneyin", + "incorrect_seed_option_back": "Yanlış. Lütfen tohumunuzun doğru bir şekilde kaydedildiğinden emin olun ve tekrar deneyin.", "inputs": "Girişler", + "insufficient_funds_for_tx": "İşlemi başarıyla yürütmek için yeterli fon.", "insufficient_lamport_for_tx": "İşlemi ve işlem ücretini karşılamak için yeterli SOL'unuz yok. Lütfen cüzdanınıza daha fazla SOL ekleyin veya gönderdiğiniz sol miktarını azaltın.", "insufficient_lamports": "İşlemi ve işlem ücretini karşılamak için yeterli SOL'unuz yok. En az ${solValueNeeded} Sol'a ihtiyacınız var. Lütfen cüzdanınıza daha fazla sol ekleyin veya gönderdiğiniz sol miktarını azaltın", "insufficientFundsForRentError": "İşlem ücretini karşılamak ve hesap için kiralamak için yeterli SOL'nuz yok. Lütfen cüzdanınıza daha fazla sol ekleyin veya gönderdiğiniz sol miktarını azaltın", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Yeni bir temsilci seçin", "nanogpt_subtitle": "En yeni modeller (GPT-4, Claude). \\ Nno aboneliği, kripto ile ödeme yapın.", "narrow": "Dar", - "new_first_wallet_text": "Kripto para biriminizi kolayca güvende tutun", + "new_first_wallet_text": "Kripto'nuzu güvende tutmak bir parça kek", "new_node_testing": "Yeni düğüm test ediliyor", "new_subaddress_create": "Oluştur", "new_subaddress_label_name": "Etiket ismi", @@ -464,6 +477,7 @@ "online": "Çevrimiçi", "onramper_option_description": "Birçok ödeme yöntemi ile hızlı bir şekilde kripto satın alın. Çoğu ülkede mevcuttur. Forma ve ücretler değişir.", "open_gift_card": "Hediye Kartını Aç", + "open_wallet": "Açık cüzdan", "optional_description": "İsteğe bağlı açıklama", "optional_email_hint": "İsteğe bağlı alacaklı bildirim e-postası", "optional_name": "İsteğe bağlı alıcı adı", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Bu cüzdanın 12 kelimelik bir tohumu varsa ve Cake'te oluşturulduysa, bu cüzdana Bitcoin YATIRMAYIN. Bu cüzdana aktarılan tüm BTC'ler kaybolabilir. 24 kelimelik yeni bir cüzdan oluşturun (sağ üstteki menüye dokunun, Cüzdanlar'ı seçin, Yeni Cüzdan Oluştur'u seçin, ardından Bitcoin'i seçin) ve BTC'nizi HEMEN oraya taşıyın. Cake'in yeni (24 kelimelik) BTC cüzdanları güvenlidir", "outgoing": "Giden", "outputs": "çıktılar", + "overshot": "Aşmak", "overwrite_amount": "Miktarın üzerine yaz", "pairingInvalidEvent": "Geçersiz Etkinliği Eşleştirme", "passphrase": "Passfrase (isteğe bağlı)", @@ -531,6 +546,7 @@ "recipient_address": "Alıcı adresi", "reconnect": "Yeniden Bağlan", "reconnect_alert_text": "Yeniden bağlanmak istediğinden emin misin?", + "reconnect_your_hardware_wallet": "Donanım cüzdanınızı yeniden bağlayın", "reconnection": "Yeniden bağlantı", "red_dark_theme": "Kırmızı Karanlık Tema", "red_light_theme": "Kırmızı Işık Teması", @@ -570,6 +586,7 @@ "restore_description_from_keys": "Cüzdanınızı özel anahtarlarınızdan kaydedilen oluşturulmuş tuş vuruşlarından geri yükleyin", "restore_description_from_seed": "Cüzdanınızı 25 veya 13 kelimelik kombinasyon kodundan geri döndürün", "restore_description_from_seed_keys": "Güvenli bir yere kaydettiğin tohumdan/anahtarlardan cüzdanını geri döndür", + "restore_existing_wallet": "Mevcut cüzdanı geri yükleyin", "restore_from_date_or_blockheight": "Lütfen bu cüzdanı oluşturmadan birkaç gün önceki bir tarihi girin. Veya blok yüksekliğini biliyorsan, lütfen bunu gir", "restore_from_seed_placeholder": "Lütfen tohumunu buraya gir veya yapıştır", "restore_new_seed": "Yeni tohum", @@ -611,6 +628,7 @@ "seed_alert_title": "Dikkat", "seed_alert_yes": "Evet yazdım", "seed_choose": "Tohum dilini seçin", + "seed_display_path": "Menü -> Güvenlik ve Yedekleme -> Anahtar/Tohumları Göster", "seed_hex_form": "Cüzdan tohumu (onaltılık form)", "seed_key": "Tohum", "seed_language": "Tohum dili", @@ -629,9 +647,13 @@ "seed_language_russian": "Rusça", "seed_language_spanish": "İspanyolca", "seed_phrase_length": "Çekirdek cümle uzunluğu", + "seed_position_question_one": "Nedir", + "seed_position_question_two": "Tohum ifadenizin kelimesi?", "seed_reminder": "Telefonunu kaybetmen veya silinmesi ihtimaline karşı lütfen bunları not et", "seed_share": "Tohumu paylaş", "seed_title": "Tohum", + "seed_verified": "Tohum doğrulandı", + "seed_verified_subtext": "Kaydedilen tohumunuzu daha sonra, yolsuzluk veya cihazınızı kaybetme durumunda bu cüzdanı geri yüklemek için kullanabilirsiniz. \n\n Bu tohumu tekrar görüntüleyebilirsiniz.", "seedtype": "Tohum", "seedtype_alert_content": "Tohumları diğer cüzdanlarla paylaşmak sadece BIP39 tohumu ile mümkündür.", "seedtype_alert_title": "SeedType uyarısı", @@ -670,6 +692,7 @@ "sent": "Gönderildi", "service_health_disabled": "Service Health Bülten devre dışı bırakıldı", "service_health_disabled_message": "Bu Hizmet Sağlığı Bülten Sayfası, bu sayfayı Ayarlar -> Gizlilik altında etkinleştirebilirsiniz", + "set_a_pin": "Bir pim ayarlamak", "settings": "ayarlar", "settings_all": "HEPSİ", "settings_allow_biometrical_authentication": "Biyometrik doğrulamaya izin ver", @@ -705,6 +728,7 @@ "share_address": "Adresi paylaş", "shared_seed_wallet_groups": "Paylaşılan tohum cüzdan grupları", "show": "Göstermek", + "show_address_book_popup": "Gönderdikten sonra 'adres defterine ekle' açılır", "show_details": "Detayları Göster", "show_keys": "Tohumları/anahtarları göster", "show_market_place": "Pazar Yerini Göster", @@ -732,6 +756,10 @@ "silent_payments_settings": "Sessiz Ödeme Ayarları", "single_seed_wallets_group": "Tek tohum cüzdanları", "slidable": "kaydırılabilir", + "solana_create_associated_token_account_exception": "ALIPITIENT ADRESİ İÇİN BAŞLANGIÇ HESABI oluşturma Hata.", + "solana_no_associated_token_account_exception": "Bu adres için ilişkili belirteç hesabı yoktur.", + "solana_sign_native_transaction_rent_exception": "İşlem tamamlanamaz. Yetersiz Sol işlemden sonra kira için kaldı. Lütfen sol bakiyenizi doldurun veya gönderdiğiniz Sol miktarını azaltın.", + "solana_sign_spl_token_transaction_rent_exception": "İşlem tamamlanamaz. Yetersiz Sol işlemden sonra kira için kaldı. Lütfen sol bakiyenizi doldurun.", "sort_by": "Göre sırala", "spend_key_private": "Harcama anahtarı (özel)", "spend_key_public": "Harcama anahtarı (genel)", @@ -744,7 +772,7 @@ "support_description_guides": "Ortak sorunlara belge ve destek", "support_description_live_chat": "Ücretsiz ve hızlı! Eğitimli destek temsilcileri yardımcı olmak için mevcuttur", "support_description_other_links": "Topluluklarımıza katılın veya ortaklarımıza diğer yöntemlerle bize ulaşın", - "support_title_guides": "Kek Cüzdan Kılavuzları", + "support_title_guides": "Kek Cüzdan Dokümanlar", "support_title_live_chat": "Canlı destek", "support_title_other_links": "Diğer destek bağlantıları", "sweeping_wallet": "Süpürme cüzdanı", @@ -823,6 +851,7 @@ "trade_state_underpaid": "Eksik ödendi", "trade_state_unpaid": "Ödenmedi", "trades": "Takaslar", + "transaction_cost": "İşlem maliyeti", "transaction_details_amount": "Miktar", "transaction_details_copied": "${title} panoya kopyalandı", "transaction_details_date": "Tarih", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "Bu değişken paritesi seçilen borsalarda desteklenmemekte", "verification": "Doğrulama", "verify_message": "Mesajı Doğrula", + "verify_seed": "Tohumu doğrulamak", "verify_with_2fa": "Cake 2FA ile Doğrulayın", "version": "Sürüm ${currentVersion}", "view_all": "Hepsini göster", @@ -891,6 +921,7 @@ "view_transaction_on": "İşlemi şurada görüntüle ", "voting_weight": "Oy kullanma", "waitFewSecondForTxUpdate": "İşlemin işlem geçmişine yansıması için lütfen birkaç saniye bekleyin", + "wallet": "Cüzdan", "wallet_group": "Cüzdan grubu", "wallet_group_description_four": "Tamamen yeni bir tohumla bir cüzdan oluşturmak için.", "wallet_group_description_one": "Kek cüzdanında bir", @@ -923,6 +954,8 @@ "wallets": "Cüzdanlar", "warning": "Uyarı", "welcome": "Hoş Geldiniz", + "welcome_subtitle_new_wallet": "Taze başlamak istiyorsanız, aşağıda yeni cüzdan oluşturun ve yarışlara gidersiniz.", + "welcome_subtitle_restore_wallet": "Mevcut bir cüzdanınız varsa, kek içine getirmek istediğiniz, mevcut cüzdanı geri yüklemeyi seçin ve bu süreç boyunca size yol gösterelim.", "welcome_to_cakepay": "Cake Pay'e Hoş Geldiniz!", "what_is_silent_payments": "Sessiz ödemeler nedir?", "widgets_address": "Adres", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 9ce3bcc45..ee2765764 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -38,6 +38,7 @@ "agree_to": "Створюючи обліковий запис, ви погоджуєтеся з ", "alert_notice": "Ув'язнення", "all": "ВСЕ", + "all_coins": "Всі монети", "all_trades": "Всі операції", "all_transactions": "Всі транзакції", "alphabetical": "Алфавітний", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Купіть у всьому світі передплачені картки та подарункові картки", "cake_pay_web_cards_subtitle": "Купуйте передоплачені та подарункові картки по всьому світу", "cake_pay_web_cards_title": "Веб-картки Cake Pay", + "cake_seeds_save_disclaimer": "Збережіть ці слова в безпечному місці! Вам знадобляться ці слова, щоб відновити гаманець на новому пристрої.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Я підтверджую, що не використовую проксі або VPN", + "cakepay_confirm_purchase": "Підтвердьте покупку", + "cakepay_confirm_terms_agreed": "Я погоджуюся з представленими тут умовами та умовами:", + "cakepay_confirm_voided_refund": "Я розумію, що спроби викупу з обмеженої країни пошкодять будь -яке повернення коштів", + "cakepay_ios_not_available": "Вибачте, ця подарункова карта недоступна на iOS. Ви можете придбати його на Android або через наш веб -сайт.", "cakepay_prepaid_card": "Передплачена дебетова картка CakePay", "camera_consent": "Ваша камера використовуватиметься для зйомки зображення з метою ідентифікації ${provider}. Будь ласка, ознайомтеся з їхньою політикою конфіденційності, щоб дізнатися більше.", "camera_permission_is_required": "Потрібен дозвіл камери.\nУвімкніть його в налаштуваннях програми.", @@ -175,6 +182,7 @@ "copy_address": "Cкопіювати адресу", "copy_id": "Скопіювати ID", "copyWalletConnectLink": "Скопіюйте посилання WalletConnect із dApp і вставте сюди", + "corrupted_seed_notice": "Файли для цього гаманця пошкоджені і не можуть бути відкриті. Перегляньте насіннєву фразу, збережіть її та відновіть гаманець.\n\nЯкщо значення порожнє, то насіння не могло бути правильно відновленим.", "countries": "Країни", "create_account": "Створити обліковий запис", "create_backup": "Створити резервну копію", @@ -256,7 +264,7 @@ "enterTokenID": "Введіть ідентифікатор токена", "enterWalletConnectURI": "Введіть URI WalletConnect", "error": "Помилка", - "error_dialog_content": "На жаль, ми отримали помилку.\n\nБудь ласка, надішліть звіт про збій нашій команді підтримки, щоб покращити додаток.", + "error_dialog_content": "На жаль, ми отримали певну помилку.\n\nБудь ласка, надішліть звіт про помилку нашій команді підтримки, щоб зробити заявку кращим.", "error_text_account_name": "Ім'я акаунту може містити тільки букви, цифри\nі повинно бути від 1 до 15 символів в довжину", "error_text_address": "Адреса гаманця повинна відповідати типу\nкриптовалюти", "error_text_amount": "Баланс може містити тільки цифри", @@ -323,6 +331,7 @@ "frequently_asked_questions": "Часті запитання", "frozen": "Заморожено", "full_balance": "Весь баланс", + "gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.", "generate_name": "Згенерувати назву", "generating_gift_card": "Створення подарункової картки", "get_a": "Отримати ", @@ -350,13 +359,17 @@ "how_to_use": "Як використовувати", "how_to_use_card": "Як використовувати цю картку", "id": "ID: ", + "if_you_dont_see_your_device": "Якщо ви не бачите свого пристрою вище, будь ласка, переконайтеся, що ваша книга прокинеться і розблокована!", "ignor": "Ігнорувати", "import": "Імпорт", "importNFTs": "Імпорт NFT", "in_store": "У магазині", "incoming": "Вхідні", "incorrect_seed": "Введений текст невірний.", + "incorrect_seed_option": "Неправильно. Будь ласка, спробуйте ще раз", + "incorrect_seed_option_back": "Неправильно. Будь ласка, переконайтеся, що ваше насіння зберігається правильно і повторіть спробу.", "inputs": "Вхoди", + "insufficient_funds_for_tx": "Недостатні кошти для успішного виконання транзакції.", "insufficient_lamport_for_tx": "У вас недостатньо SOL, щоб покрити транзакцію та її плату за трансакцію. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму, яку ви надсилаєте.", "insufficient_lamports": "У вас недостатньо SOL, щоб покрити транзакцію та її плату за трансакцію. Вам потрібно щонайменше ${solValueNeeded} sol. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму Sol, яку ви надсилаєте", "insufficientFundsForRentError": "У вас недостатньо SOL, щоб покрити плату за транзакцію та оренду на рахунок. Будь ласка, додайте до свого гаманця більше SOL або зменшіть суму, яку ви надсилаєте", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "Виберіть нового представника", "nanogpt_subtitle": "Усі найновіші моделі (GPT-4, Claude). \\ Nno підписка, оплата криптовалютою.", "narrow": "вузькі", - "new_first_wallet_text": "Легко зберігайте свою криптовалюту в безпеці", + "new_first_wallet_text": "Зберігання вашої криптовалюти це просто як шматок торта", "new_node_testing": "Тестування нового вузла", "new_subaddress_create": "Створити", "new_subaddress_label_name": "Ім'я", @@ -464,6 +477,7 @@ "online": "Онлайн", "onramper_option_description": "Швидко купуйте криптовалюту з багатьма методами оплати. Доступний у більшості країн. Поширення та збори різняться.", "open_gift_card": "Відкрити подарункову картку", + "open_wallet": "Відкритий гаманець", "optional_description": "Додатковий опис", "optional_email_hint": "Додаткова електронна адреса для сповіщення одержувача", "optional_name": "Додаткове ім'я одержувача", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "Якщо цей гаманець має мнемонічну фразу з 12 слів і був створений у Cake, НЕ переводьте біткойни на цей гаманець. Будь-які BTC, переведений на цей гаманець, можуть бути втраченими. Створіть новий гаманець з мнемонічною фразою з 24 слів (торкніться меню у верхньому правому куті, виберіть Гаманці, виберіть Створити новий гаманець, потім виберіть Bitcoin) і НЕГАЙНО переведіть туди свії BTC. Нові (з мнемонічною фразою з 24 слів) гаманці BTC від Cake надійно захищені", "outgoing": "Вихідні", "outputs": "Виходи", + "overshot": "Затьмарювати", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "Недійсна подія сполучення", "passphrase": "Пасофрази (необов’язково)", @@ -531,6 +546,7 @@ "recipient_address": "Адреса одержувача", "reconnect": "Перепідключитися", "reconnect_alert_text": "Ви хочете перепідключитися?", + "reconnect_your_hardware_wallet": "Повторно підключіть свій апаратний гаманець", "reconnection": "Перепідключення", "red_dark_theme": "Червона темна тема", "red_light_theme": "Тема червоного світла", @@ -571,6 +587,7 @@ "restore_description_from_keys": "Ви можете відновити гаманець за допомогою приватних ключів", "restore_description_from_seed": "Ви можете відновити гаманець використовуючи 25-ти слівну мнемонічну фразу", "restore_description_from_seed_keys": "Ви можете відновити гаманець з мнемонічної фрази/ключів, які ви зберегли раніше", + "restore_existing_wallet": "Відновити існуючий гаманець", "restore_from_date_or_blockheight": "Будь ласка, введіть дату за кілька днів до створення цього гаманця. Або, якщо ви знаєте висоту блоку, введіть її значення", "restore_from_seed_placeholder": "Введіть або вставте мнемонічну фразу вашого гаманця", "restore_new_seed": "Нова мнемонічна фраза", @@ -612,6 +629,7 @@ "seed_alert_title": "Увага", "seed_alert_yes": "Так", "seed_choose": "Виберіть мову мнемонічної фрази", + "seed_display_path": "Меню -> Безпека та резервна копія -> Показати ключ/насіння", "seed_hex_form": "Насіння гаманця (шістнадцяткова форма)", "seed_key": "Насіннєвий ключ", "seed_language": "Насіннєва мова", @@ -630,9 +648,13 @@ "seed_language_russian": "Російська", "seed_language_spanish": "Іспанська", "seed_phrase_length": "Довжина початкової фрази", + "seed_position_question_one": "Що таке", + "seed_position_question_two": "Слово вашої насіннєвої фрази?", "seed_reminder": "Будь ласка, запишіть мнемонічну фразу на випадок втрати або очищення телефону", "seed_share": "Поділитися мнемонічною фразою", "seed_title": "Мнемонічна фраза", + "seed_verified": "Насіння перевірено", + "seed_verified_subtext": "Пізніше ви можете скористатися збереженим насінням, щоб відновити цей гаманець у разі пошкодження або втрату пристрою. \n\n Ви можете переглянути це насіння ще раз з", "seedtype": "Насіннєвий тип", "seedtype_alert_content": "Спільний доступ до інших гаманців можливе лише за допомогою BIP39 Seedtype.", "seedtype_alert_title": "Попередження насінника", @@ -671,6 +693,7 @@ "sent": "Відправлені", "service_health_disabled": "Вісник охорони здоров'я інвалідів", "service_health_disabled_message": "Це сторінка бюлетеня Health Service, ви можете включити цю сторінку в налаштуваннях -> конфіденційність", + "set_a_pin": "Встановити PIN", "settings": "Налаштування", "settings_all": "ВСІ", "settings_allow_biometrical_authentication": "Включити біометричну аутентифікацію", @@ -706,6 +729,7 @@ "share_address": "Поділитися адресою", "shared_seed_wallet_groups": "Спільні групи насіннєвих гаманців", "show": "Показувати", + "show_address_book_popup": "Показати спливаюче вікно \"Додати до адресної книги\" після надсилання", "show_details": "Показати деталі", "show_keys": "Показати мнемонічну фразу/ключі", "show_market_place": "Відображати маркетплейс", @@ -733,6 +757,10 @@ "silent_payments_settings": "Налаштування мовчазних платежів", "single_seed_wallets_group": "Поодинокі насінні гаманці", "slidable": "Розсувний", + "solana_create_associated_token_account_exception": "Помилка створення пов’язаного облікового запису Token для адреси приймання.", + "solana_no_associated_token_account_exception": "Для цієї адреси немає пов’язаного облікового запису маркера.", + "solana_sign_native_transaction_rent_exception": "Транзакція не може бути завершена. Недостатня SOL залишила оренду після транзакції. Будь ласка, поповніть свій баланс SOL або зменшіть кількість SOL, який ви надсилаєте.", + "solana_sign_spl_token_transaction_rent_exception": "Транзакція не може бути завершена. Недостатня SOL залишила оренду після транзакції. Будь ласка, наповніть свій баланс SOL.", "sort_by": "Сортувати за", "spend_key_private": "Приватний ключ витрати", "spend_key_public": "Публічний ключ витрати", @@ -745,7 +773,7 @@ "support_description_guides": "Документація та підтримка загальних питань", "support_description_live_chat": "Безкоштовно і швидко! Навчені представники підтримки доступні для надання допомоги", "support_description_other_links": "Приєднуйтесь до наших спільнот або досягайте нас нашими партнерами іншими методами", - "support_title_guides": "Поклики для гаманців тортів", + "support_title_guides": "Торт гаманці", "support_title_live_chat": "Жива підтримка", "support_title_other_links": "Інші посилання на підтримку", "sweeping_wallet": "Підмітаня гаманця", @@ -824,6 +852,7 @@ "trade_state_underpaid": "Недоплачена", "trade_state_unpaid": "Неоплачена", "trades": "Торгові операції", + "transaction_cost": "Вартість транзакції", "transaction_details_amount": "Сума", "transaction_details_copied": "${title} скопійовано в буфер обміну", "transaction_details_date": "Дата", @@ -883,6 +912,7 @@ "variable_pair_not_supported": "Ця пара змінних не підтримується вибраними біржами", "verification": "Перевірка", "verify_message": "Перевірте повідомлення", + "verify_seed": "Перевірте насіння", "verify_with_2fa": "Перевірте за допомогою Cake 2FA", "version": "Версія ${currentVersion}", "view_all": "Переглянути все", @@ -892,6 +922,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "Вага голосування", "waitFewSecondForTxUpdate": "Будь ласка, зачекайте кілька секунд, поки транзакція відобразиться в історії транзакцій", + "wallet": "Гаманець", "wallet_group": "Група гаманців", "wallet_group_description_four": "створити гаманець з абсолютно новим насінням.", "wallet_group_description_one": "У гаманці тортів ви можете створити a", @@ -924,6 +955,8 @@ "wallets": "Гаманці", "warning": "УВАГА", "welcome": "Вітаємо в", + "welcome_subtitle_new_wallet": "Якщо ви хочете почати спочатку, торкніться Створити новий гаманець нижче, і ви будете поза конкуренціею.", + "welcome_subtitle_restore_wallet": "Якщо у вас є існуючий гаманець, який ви хочете ввести в торт, просто виберіть Відновити існуючий гаманець, і ми проведемо вас через процес.", "welcome_to_cakepay": "Ласкаво просимо до Cake Pay!", "what_is_silent_payments": "Що таке мовчазні платежі?", "widgets_address": "Адреса", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 23ccb45f4..1a342a8a5 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -38,6 +38,7 @@ "agree_to": "اکاؤنٹ بنا کر آپ اس سے اتفاق کرتے ہیں۔", "alert_notice": "نوٹس", "all": "تمام", + "all_coins": "تمام سکے", "all_trades": "تمام تجارت", "all_transactions": "تمام لین دین", "alphabetical": "حروف تہجی کے مطابق", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "دنیا بھر میں پری پیڈ کارڈز اور گفٹ کارڈ خریدیں", "cake_pay_web_cards_subtitle": "دنیا بھر میں پری پیڈ کارڈز اور گفٹ کارڈز خریدیں۔", "cake_pay_web_cards_title": "Cake پے ویب کارڈز", + "cake_seeds_save_disclaimer": "براہ کرم ان الفاظ کو ایک محفوظ جگہ پر محفوظ کریں! اپنے بٹوے کو کسی نئے آلے پر بحال کرنے کے ل You آپ کو ان الفاظ کی ضرورت ہوگی۔", "cake_wallet": "Cake والیٹ", + "cakepay_confirm_no_vpn": "میں تصدیق کرتا ہوں کہ میں پراکسی یا وی پی این استعمال نہیں کر رہا ہوں", + "cakepay_confirm_purchase": "خریداری کی تصدیق کریں", + "cakepay_confirm_terms_agreed": "میں یہاں پیش کردہ شرائط و ضوابط سے اتفاق کرتا ہوں:", + "cakepay_confirm_voided_refund": "میں سمجھتا ہوں کہ کسی محدود ملک سے چھٹکارے کی کوششیں کسی بھی رقم کی واپسی کو کالعدم کردیں گی", + "cakepay_ios_not_available": "معذرت ، یہ گفٹ کارڈ iOS پر دستیاب نہیں ہے۔ اس کے بجائے آپ اسے اینڈروئیڈ پر یا ہماری ویب سائٹ کے ذریعے خرید سکتے ہیں۔", "cakepay_prepaid_card": "Cake پے پری پیڈ ڈیبٹ کارڈ", "camera_consent": "۔ﮟﯿﮭﮑﯾﺩ ﯽﺴﯿﻟﺎﭘ ﯽﺴﯾﻮﯿﺋﺍﺮﭘ ﯽﮐ ﻥﺍ ﻡﺮﮐ ﮦﺍﺮﺑ ﮯﯿﻟ ﮯﮐ ﺕﻼ${provider}ﯿﺼﻔﺗ ۔ﺎﮔ ﮯﺋﺎﺟ ﺎﯿﮐ ﻝﺎﻤﻌﺘﺳﺍ ﮯﯿﻟ", "camera_permission_is_required": "۔ﮯﮨ ﺭﺎﮐﺭﺩ ﺕﺯﺎﺟﺍ ﯽﮐ ﮮﺮﻤﯿﮐ", @@ -175,6 +182,7 @@ "copy_address": "ایڈریس کاپی کریں۔", "copy_id": "کاپی ID", "copyWalletConnectLink": "dApp ﮯﺳ WalletConnect ۔ﮟﯾﺮﮐ ﭧﺴﯿﭘ ﮞﺎﮩﯾ ﺭﻭﺍ ﮟﯾﺮﮐ ﯽﭘﺎﮐ ﻮﮐ ﮏﻨﻟ", + "corrupted_seed_notice": "اس پرس کے لئے فائلیں خراب ہیں اور کھولنے سے قاصر ہیں۔ براہ کرم بیج کے فقرے کو دیکھیں ، اسے بچائیں ، اور بٹوے کو بحال کریں۔\n\nاگر قیمت خالی ہے ، تو بیج صحیح طور پر بازیافت کرنے سے قاصر تھا۔", "countries": "ممالک", "create_account": "اکاؤنٹ بنائیں", "create_backup": "بیک اپ بنائیں", @@ -256,7 +264,7 @@ "enterTokenID": " ۔ﮟﯾﺮﮐ ﺝﺭﺩ ID ﻦﮐﻮﭨ", "enterWalletConnectURI": "WalletConnect URI ۔ﮟﯾﺮﮐ ﺝﺭﺩ", "error": "خرابی", - "error_dialog_content": "افوہ، ہمیں کچھ خرابی ملی۔\n\nایپلی کیشن کو بہتر بنانے کے لیے براہ کرم کریش رپورٹ ہماری سپورٹ ٹیم کو بھیجیں۔", + "error_dialog_content": "افوہ ، ہمیں کچھ غلطی ہوئی۔\n\nبراہ کرم درخواست کو بہتر بنانے کے لئے ہماری سپورٹ ٹیم کو غلطی کی رپورٹ بھیجیں۔", "error_text_account_name": "اکاؤنٹ کا نام صرف حروف، اعداد پر مشتمل ہو سکتا ہے\\nاور 1 سے 15 حروف کے درمیان ہونا چاہیے۔", "error_text_address": "والیٹ کا پتہ cryptocurrency کی قسم\\nکے مطابق ہونا چاہیے۔", "error_text_amount": "رقم صرف اعداد پر مشتمل ہو سکتی ہے۔", @@ -323,6 +331,7 @@ "frequently_asked_questions": "اکثر پوچھے گئے سوالات", "frozen": "منجمد", "full_balance": "مکمل بیلنس", + "gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔", "generate_name": "نام پیدا کریں۔", "generating_gift_card": "گفٹ کارڈ تیار کرنا", "get_a": "حاصل", @@ -350,13 +359,17 @@ "how_to_use": " ﮧﻘﯾﺮﻃ ﺎﮐ ﮯﻧﺮﮐ ﻝﺎﻤﻌﺘﺳﺍ", "how_to_use_card": "اس کارڈ کو استعمال کرنے کا طریقہ", "id": "ID:", + "if_you_dont_see_your_device": "اگر آپ اوپر اپنا آلہ نہیں دیکھتے ہیں تو ، براہ کرم یقینی بنائیں کہ آپ کا لیجر بیدار اور غیر مقفل ہے!", "ignor": "نظر انداز کرنا", "import": " ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ", "importNFTs": "NFTs ۔ﮟﯾﺮﮐ ﺪﻣﺁﺭﺩ", "in_store": "اسٹور میں", "incoming": "آنے والا", "incorrect_seed": "درج کردہ متن درست نہیں ہے۔", + "incorrect_seed_option": "غلط براہ کرم دوبارہ کوشش کریں", + "incorrect_seed_option_back": "غلط براہ کرم یقینی بنائیں کہ آپ کا بیج صحیح طریقے سے محفوظ ہے اور دوبارہ کوشش کریں۔", "inputs": "آدانوں", + "insufficient_funds_for_tx": "لین دین کو کامیابی کے ساتھ انجام دینے کے لئے ناکافی فنڈز۔", "insufficient_lamport_for_tx": "آپ کے پاس ٹرانزیکشن اور اس کے لین دین کی فیس کا احاطہ کرنے کے لئے کافی SOL نہیں ہے۔ برائے مہربانی اپنے بٹوے میں مزید سول شامل کریں یا آپ کو بھیجنے والی سول رقم کو کم کریں۔", "insufficient_lamports": "آپ کے پاس ٹرانزیکشن اور اس کے لین دین کی فیس کا احاطہ کرنے کے لئے کافی SOL نہیں ہے۔ آپ کو کم از کم ${solValueNeeded} sol کی ضرورت ہے۔ برائے مہربانی اپنے بٹوے میں مزید SOL شامل کریں یا آپ جس SOL رقم کو بھیج رہے ہو اسے کم کریں", "insufficientFundsForRentError": "آپ کے پاس ٹرانزیکشن فیس اور اکاؤنٹ کے لئے کرایہ لینے کے ل enough اتنا SOL نہیں ہے۔ برائے مہربانی اپنے بٹوے میں مزید سول شامل کریں یا آپ کو بھیجنے والی سول رقم کو کم کریں", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "ایک نیا نمائندہ منتخب کریں", "nanogpt_subtitle": "تمام تازہ ترین ماڈل (GPT-4 ، کلاڈ)۔ n n no سبسکرپشن ، کریپٹو کے ساتھ ادائیگی کریں۔", "narrow": "تنگ", - "new_first_wallet_text": "آسانی سے اپنے cryptocurrency محفوظ رکھیں", + "new_first_wallet_text": "اپنے کریپٹو کو محفوظ رکھنا کیک کا ایک ٹکڑا ہے", "new_node_testing": "نیا نوڈ ٹیسٹنگ", "new_subaddress_create": "بنانا", "new_subaddress_label_name": "لیبل کا نام", @@ -464,6 +477,7 @@ "online": "آن لائن", "onramper_option_description": "ادائیگی کے بہت سے طریقوں سے جلدی سے کرپٹو خریدیں۔ زیادہ تر ممالک میں دستیاب ہے۔ پھیلاؤ اور فیس مختلف ہوتی ہے۔", "open_gift_card": "گفٹ کارڈ کھولیں۔", + "open_wallet": "کھلا پرس", "openalias_alert_content": "آپ کو فنڈز بھیجیں گے\\n${recipient_name}", "openalias_alert_title": "پتہ کا پتہ چلا", "optional_description": "اختیاری تفصیل", @@ -479,6 +493,7 @@ "outdated_electrum_wallet_receive_warning": "اگر اس پرس میں 12 الفاظ کا بیج ہے اور اسے Cake میں بنایا گیا ہے، تو اس بٹوے میں Bitcoin جمع نہ کریں۔ اس بٹوے میں منتقل کیا گیا کوئی بھی BTC ضائع ہو سکتا ہے۔ ایک نیا 24 الفاظ والا والیٹ بنائیں (اوپر دائیں جانب مینو کو تھپتھپائیں، Wallets کو منتخب کریں، نیا والیٹ بنائیں، پھر Bitcoin کو منتخب کریں) اور فوری طور پر اپنے BTC کو وہاں منتقل کریں۔ Cake کے نئے (24-لفظوں) BTC بٹوے محفوظ ہیں۔", "outgoing": "سبکدوش ہونے والے", "outputs": "نتائج", + "overshot": "اوورشوٹ", "overwrite_amount": "رقم کو اوور رائٹ کریں۔", "pairingInvalidEvent": "ﭧﻧﻮﯾﺍ ﻂﻠﻏ ﺎﻧﺎﻨﺑ ﺍﮌﻮﺟ", "passphrase": "پاسفریز (اختیاری)", @@ -533,6 +548,7 @@ "recipient_address": "وصول کنندہ کا پتہ", "reconnect": "دوبارہ جڑیں۔", "reconnect_alert_text": "کیا آپ واقعی دوبارہ جڑنا چاہتے ہیں؟", + "reconnect_your_hardware_wallet": "اپنے ہارڈ ویئر پرس کو دوبارہ مربوط کریں", "reconnection": "دوبارہ رابطہ", "red_dark_theme": "ریڈ ڈارک تھیم", "red_light_theme": "ریڈ لائٹ تھیم", @@ -572,6 +588,7 @@ "restore_description_from_keys": "اپنے بٹوے کو اپنی نجی کلیدوں سے محفوظ کردہ کی اسٹروکس سے بحال کریں۔", "restore_description_from_seed": "اپنے بٹوے کو 25 لفظ یا 13 الفاظ کے مجموعہ کوڈ سے بحال کریں۔", "restore_description_from_seed_keys": "اپنے بٹوے کو بیج / چابیاں سے واپس حاصل کریں جنہیں آپ نے محفوظ جگہ پر محفوظ کیا ہے۔", + "restore_existing_wallet": "موجودہ پرس کو بحال کریں", "restore_from_date_or_blockheight": "براہ کرم یہ پرس بنانے سے چند دن پہلے کی تاریخ درج کریں۔ یا اگر آپ کو بلاک ہائیٹ معلوم ہے تو براہ کرم اس کی بجائے اسے درج کریں۔", "restore_from_seed_placeholder": "براہ کرم اپنا بیج یہاں درج کریں یا پیسٹ کریں۔", "restore_new_seed": "نیا بیج", @@ -613,6 +630,7 @@ "seed_alert_title": "توجہ", "seed_alert_yes": "ہاں میرے پاس ہے", "seed_choose": "بیج کی زبان کا انتخاب کریں۔", + "seed_display_path": "مینو -> سیکیورٹی اور بیک اپ -> کلیدی/بیج دکھائیں", "seed_hex_form": "پرس بیج (ہیکس فارم)", "seed_key": "بیج کی کلید", "seed_language": "بیج کی زبان", @@ -631,9 +649,13 @@ "seed_language_russian": "روسی", "seed_language_spanish": "ہسپانوی", "seed_phrase_length": "ﯽﺋﺎﺒﻤﻟ ﯽﮐ ﮯﻠﻤﺟ ﮯﮐ ﺞﯿﺑ", + "seed_position_question_one": "کیا ہے؟", + "seed_position_question_two": "آپ کے بیج کے فقرے کا کلام؟", "seed_reminder": "اگر آپ اپنا فون کھو دیتے ہیں یا صاف کرتے ہیں تو براہ کرم یہ لکھ دیں۔", "seed_share": "بیج بانٹیں۔", "seed_title": "بیج", + "seed_verified": "بیج کی تصدیق", + "seed_verified_subtext": "آپ بدعنوانی یا اپنے آلے کو کھونے کی صورت میں اس پرس کو بحال کرنے کے لئے بعد میں اپنے محفوظ کردہ بیج کا استعمال کرسکتے ہیں۔ \n\n آپ اس بیج کو دوبارہ سے دیکھ سکتے ہیں", "seedtype": "سیڈ ٹائپ", "seedtype_alert_content": "دوسرے بٹوے کے ساتھ بیجوں کا اشتراک صرف BIP39 بیج ٹائپ کے ساتھ ہی ممکن ہے۔", "seedtype_alert_title": "سیڈ ٹائپ الرٹ", @@ -672,6 +694,7 @@ "sent": "بھیجا", "service_health_disabled": "سروس ہیلتھ بلیٹن غیر فعال ہے", "service_health_disabled_message": "یہ سروس ہیلتھ بلیٹن پیج ہے ، آپ اس صفحے کو ترتیبات کے تحت اہل بنا سکتے ہیں -> رازداری", + "set_a_pin": "ایک پن مرتب کریں", "settings": "ترتیبات", "settings_all": "تمام", "settings_allow_biometrical_authentication": "بایومیٹریکل تصدیق کی اجازت دیں۔", @@ -707,6 +730,7 @@ "share_address": "پتہ شیئر کریں۔", "shared_seed_wallet_groups": "مشترکہ بیج پرس گروپ", "show": "دکھائیں", + "show_address_book_popup": "بھیجنے کے بعد 'ایڈریس میں شامل کریں کتاب' پاپ اپ دکھائیں", "show_details": "تفصیلات دکھائیں", "show_keys": "بیج / چابیاں دکھائیں۔", "show_market_place": "بازار دکھائیں۔", @@ -734,6 +758,10 @@ "silent_payments_settings": "خاموش ادائیگی کی ترتیبات", "single_seed_wallets_group": "سنگل بیج کے بٹوے", "slidable": "سلائیڈ ایبل", + "solana_create_associated_token_account_exception": "وصول کنندہ ایڈریس کے لئے وابستہ ٹوکن اکاؤنٹ بنانے میں غلطی۔", + "solana_no_associated_token_account_exception": "اس پتے کے لئے کوئی وابستہ ٹوکن اکاؤنٹ نہیں ہے۔", + "solana_sign_native_transaction_rent_exception": "لین دین مکمل نہیں کیا جاسکتا۔ ٹرانزیکشن کے بعد کرایہ کے لئے ناکافی SOL چھوڑ دیا گیا ہے۔ برائے مہربانی اپنے سول توازن کو اوپر کریں یا آپ بھیج رہے ہیں اس کی مقدار کو کم کریں۔", + "solana_sign_spl_token_transaction_rent_exception": "لین دین مکمل نہیں کیا جاسکتا۔ ٹرانزیکشن کے بعد کرایہ کے لئے ناکافی SOL چھوڑ دیا گیا ہے۔ برائے مہربانی اپنے سول توازن کو اوپر رکھیں۔", "sort_by": "ترتیب دیں", "spend_key_private": "خرچ کی کلید (نجی)", "spend_key_public": "خرچ کی کلید (عوامی)", @@ -746,7 +774,7 @@ "support_description_guides": "عام مسائل کے لئے دستاویزات اور مدد", "support_description_live_chat": "مفت اور تیز! تربیت یافتہ معاون نمائندے مدد کے لئے دستیاب ہیں", "support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں", - "support_title_guides": "کیک پرس گائڈز", + "support_title_guides": "کیک پرس کے دستاویزات", "support_title_live_chat": "براہ راست مدد", "support_title_other_links": "دوسرے سپورٹ لنکس", "sweeping_wallet": "جھاڑو دینے والا پرس", @@ -825,6 +853,7 @@ "trade_state_underpaid": "کم معاوضہ", "trade_state_unpaid": "بلا معاوضہ", "trades": "تجارت", + "transaction_cost": "لین دین کی لاگت", "transaction_details_amount": "رقم", "transaction_details_copied": "${title} کو کلپ بورڈ پر کاپی کیا گیا۔", "transaction_details_date": "تاریخ", @@ -884,6 +913,7 @@ "variable_pair_not_supported": "یہ متغیر جوڑا منتخب ایکسچینجز کے ساتھ تعاون یافتہ نہیں ہے۔", "verification": "تصدیق", "verify_message": "پیغام کی تصدیق کریں", + "verify_seed": "بیج کی تصدیق کریں", "verify_with_2fa": "کیک 2FA سے تصدیق کریں۔", "version": "ورژن ${currentVersion}", "view_all": "سب دیکھیں", @@ -893,6 +923,7 @@ "view_transaction_on": "لین دین دیکھیں آن", "voting_weight": "ووٹ کا وزن", "waitFewSecondForTxUpdate": "۔ﮟﯾﺮﮐ ﺭﺎﻈﺘﻧﺍ ﺎﮐ ﮉﻨﮑﯿﺳ ﺪﻨﭼ ﻡﺮﮐ ﮦﺍﺮﺑ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﯽﺳﺎﮑﻋ ﯽﮐ ﻦﯾﺩ ﻦﯿﻟ ﮟﯿﻣ ﺦﯾﺭﺎﺗ ﯽﮐ ﻦ", + "wallet": "پرس", "wallet_group": "پرس گروپ", "wallet_group_description_four": "مکمل طور پر نئے بیج کے ساتھ پرس بنانے کے ل.", "wallet_group_description_one": "کیک پرس میں ، آپ بنا سکتے ہیں", @@ -925,6 +956,8 @@ "wallets": "بٹوے", "warning": "وارننگ", "welcome": "میں خوش آمدید", + "welcome_subtitle_new_wallet": "اگر آپ تازہ شروع کرنا چاہتے ہیں تو ، نیچے نیا پرس بنائیں پر تھپتھپائیں اور آپ ریسوں پر جائیں گے۔", + "welcome_subtitle_restore_wallet": "اگر آپ کے پاس موجودہ پرس ہے تو آپ کیک میں لانا چاہتے ہیں تو ، موجودہ بٹوے کو بحال کریں کا انتخاب کریں اور ہم آپ کو اس عمل میں چلیں گے۔", "welcome_to_cakepay": "Cake پے میں خوش آمدید!", "what_is_silent_payments": "خاموش ادائیگی کیا ہے؟", "widgets_address": "پتہ", diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb index 4b06248df..885c4a13d 100644 --- a/res/values/strings_vi.arb +++ b/res/values/strings_vi.arb @@ -38,6 +38,7 @@ "agree_to": "Bằng cách tạo tài khoản, bạn đồng ý với ", "alert_notice": "Để ý", "all": "TẤT CẢ", + "all_coins": "Tất cả các đồng tiền", "all_trades": "Tất cả giao dịch", "all_transactions": "Tất cả giao dịch", "alphabetical": "Theo thứ tự chữ cái", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Mua thẻ trả trước toàn cầu và thẻ quà tặng", "cake_pay_web_cards_subtitle": "Mua thẻ trả trước toàn cầu và thẻ quà tặng", "cake_pay_web_cards_title": "Thẻ Cake Pay Web", + "cake_seeds_save_disclaimer": "Vui lòng lưu những từ này ở một nơi an toàn! Bạn sẽ cần những từ này để khôi phục ví của bạn trên một thiết bị mới.", "cake_wallet": "Ví Cake", + "cakepay_confirm_no_vpn": "Tôi xác nhận tôi không sử dụng proxy hoặc VPN", + "cakepay_confirm_purchase": "Xác nhận mua hàng", + "cakepay_confirm_terms_agreed": "Tôi đồng ý với các điều khoản và điều kiện được trình bày ở đây:", + "cakepay_confirm_voided_refund": "Tôi hiểu những nỗ lực cứu chuộc từ một quốc gia bị hạn chế sẽ vô hiệu hóa bất kỳ khoản hoàn trả nào", + "cakepay_ios_not_available": "Xin lỗi, thẻ quà tặng này không có sẵn trên iOS. Thay vào đó, bạn có thể mua nó trên Android hoặc thông qua trang web của chúng tôi.", "cakepay_prepaid_card": "Thẻ Ghi Nợ Trả Trước CakePay", "camera_consent": "Máy ảnh của bạn sẽ được sử dụng để chụp hình nhằm mục đích xác minh danh tính bởi ${provider}. Vui lòng kiểm tra Chính sách quyền riêng tư của họ để biết thêm chi tiết.", "camera_permission_is_required": "Cần có quyền truy cập máy ảnh. \nVui lòng bật nó từ cài đặt ứng dụng.", @@ -174,6 +181,7 @@ "copy_address": "Sao chép Địa chỉ", "copy_id": "Sao chép ID", "copyWalletConnectLink": "Sao chép liên kết WalletConnect từ dApp và dán vào đây", + "corrupted_seed_notice": "Các tệp cho ví này bị hỏng và không thể mở. Vui lòng xem cụm từ hạt giống, lưu nó và khôi phục ví.\n\nNếu giá trị trống, thì hạt giống không thể được phục hồi chính xác.", "countries": "Quốc gia", "create_account": "Tạo tài khoản", "create_backup": "Tạo sao lưu", @@ -255,7 +263,7 @@ "enterTokenID": "Nhập ID token", "enterWalletConnectURI": "Nhập URI WalletConnect", "error": "Lỗi", - "error_dialog_content": "Oops, chúng tôi gặp một số lỗi.\n\nVui lòng gửi báo cáo sự cố cho nhóm hỗ trợ của chúng tôi để cải thiện ứng dụng.", + "error_dialog_content": "Rất tiếc, chúng tôi đã gặp một số lỗi.\n\nVui lòng gửi báo cáo lỗi cho nhóm hỗ trợ của chúng tôi để làm cho ứng dụng tốt hơn.", "error_text_account_name": "Tên tài khoản chỉ được chứa chữ cái, số\nvà phải từ 1 đến 15 ký tự", "error_text_address": "Địa chỉ ví phải tương ứng với loại tiền điện tử", "error_text_amount": "Số tiền chỉ được chứa số", @@ -322,6 +330,7 @@ "frequently_asked_questions": "Các câu hỏi thường gặp", "frozen": "Đã đóng băng", "full_balance": "Số dư đầy đủ", + "gas_exceeds_allowance": "Gas theo yêu cầu của giao dịch vượt quá trợ cấp.", "generate_name": "Tạo tên", "generating_gift_card": "Đang tạo thẻ quà tặng", "get_a": "Nhận một ", @@ -349,13 +358,17 @@ "how_to_use": "Cách sử dụng", "how_to_use_card": "Cách sử dụng thẻ này", "id": "ID: ", + "if_you_dont_see_your_device": "Nếu bạn không thấy thiết bị của mình ở trên, xin hãy chắc chắn rằng sổ cái của bạn đã tỉnh táo và mở khóa!", "ignor": "Bỏ qua", "import": "Nhập", "importNFTs": "Nhập NFT", "in_store": "Tại cửa hàng", "incoming": "Đang nhận", "incorrect_seed": "Văn bản nhập không hợp lệ.", + "incorrect_seed_option": "Không đúng. Hãy thử lại", + "incorrect_seed_option_back": "Không đúng. Vui lòng đảm bảo hạt giống của bạn được lưu chính xác và thử lại.", "inputs": "Đầu vào", + "insufficient_funds_for_tx": "Không đủ tiền để thực hiện thành công giao dịch.", "insufficient_lamport_for_tx": "Bạn không có đủ SOL để thanh toán giao dịch và phí giao dịch. Vui lòng thêm SOL vào ví của bạn hoặc giảm số lượng SOL bạn đang gửi.", "insufficient_lamports": "Bạn không có đủ SOL để thanh toán giao dịch và phí giao dịch. Bạn cần ít nhất ${solValueNeeded} SOL. Vui lòng thêm SOL vào ví của bạn hoặc giảm số lượng SOL bạn đang gửi", "insufficientFundsForRentError": "Bạn không có đủ SOL để thanh toán phí giao dịch và phí thuê cho tài khoản. Vui lòng thêm SOL vào ví của bạn hoặc giảm số lượng SOL bạn đang gửi", @@ -426,7 +439,7 @@ "nano_pick_new_rep": "Chọn đại diện mới", "nanogpt_subtitle": "Tất cả các mẫu mới nhất (GPT-4, Claude).\\nKhông cần đăng ký, thanh toán bằng tiền điện tử.", "narrow": "Hẹp", - "new_first_wallet_text": "Giữ an toàn cho tiền điện tử của bạn, dễ dàng như ăn bánh", + "new_first_wallet_text": "Giữ tiền điện tử của bạn an toàn là một miếng bánh", "new_node_testing": "Đang thử nghiệm nút mới", "new_subaddress_create": "Tạo", "new_subaddress_label_name": "Tên nhãn", @@ -463,6 +476,7 @@ "online": "Trực tuyến", "onramper_option_description": "Mua tiền điện tử nhanh chóng với nhiều phương thức thanh toán. Có sẵn ở hầu hết các quốc gia. Chênh lệch và phí thay đổi.", "open_gift_card": "Mở thẻ quà tặng", + "open_wallet": "Mở ví", "optional_description": "Mô tả tùy chọn", "optional_email_hint": "Email thông báo cho người nhận (tùy chọn)", "optional_name": "Tên người nhận (tùy chọn)", @@ -476,6 +490,7 @@ "outdated_electrum_wallet_receive_warning": "Nếu ví này có hạt giống 12 từ và được tạo trong Cake, ĐỪNG gửi Bitcoin vào ví này. Bất kỳ BTC nào chuyển vào ví này có thể bị mất. Tạo ví 24 từ mới (nhấn menu ở góc trên bên phải, chọn Ví, chọn Tạo Ví Mới, sau đó chọn Bitcoin) và NGAY LẬP TỨC chuyển BTC của bạn vào đó. Ví BTC mới (24 từ) từ Cake là an toàn", "outgoing": "Đang gửi", "outputs": "Đầu ra", + "overshot": "Quá sức", "overwrite_amount": "Ghi đè số tiền", "pairingInvalidEvent": "Sự kiện ghép nối không hợp lệ", "passphrase": "Cụm từ bảo mật (Tùy chọn)", @@ -530,6 +545,7 @@ "recipient_address": "Địa chỉ người nhận", "reconnect": "Kết nối lại", "reconnect_alert_text": "Bạn có chắc chắn muốn kết nối lại không?", + "reconnect_your_hardware_wallet": "Kết nối lại ví phần cứng của bạn", "reconnection": "Kết nối lại", "red_dark_theme": "Chủ đề tối đỏ", "red_light_theme": "Chủ đề sáng đỏ", @@ -569,6 +585,7 @@ "restore_description_from_keys": "Khôi phục ví của bạn từ các thao tác nhập được lưu từ khóa riêng của bạn", "restore_description_from_seed": "Khôi phục ví của bạn từ mã kết hợp 25 từ hoặc 13 từ", "restore_description_from_seed_keys": "Khôi phục ví của bạn từ hạt giống/khóa mà bạn đã lưu ở nơi an toàn", + "restore_existing_wallet": "Khôi phục ví hiện có", "restore_from_date_or_blockheight": "Vui lòng nhập một ngày vài ngày trước khi bạn tạo ví này. Hoặc nếu bạn biết chiều cao khối, hãy nhập nó thay thế", "restore_from_seed_placeholder": "Vui lòng nhập hoặc dán hạt giống của bạn vào đây", "restore_new_seed": "Hạt giống mới", @@ -610,6 +627,7 @@ "seed_alert_title": "Chú ý", "seed_alert_yes": "Có, tôi đã ghi lại", "seed_choose": "Chọn ngôn ngữ hạt giống", + "seed_display_path": "Menu -> Bảo mật và Sao lưu -> Hiển thị khóa/Hạt giống", "seed_hex_form": "Hạt giống ví (dạng hex)", "seed_key": "Khóa hạt giống", "seed_language": "Ngôn ngữ hạt giống", @@ -628,9 +646,13 @@ "seed_language_russian": "Tiếng Nga", "seed_language_spanish": "Tiếng Tây Ban Nha", "seed_phrase_length": "Độ dài cụm từ hạt giống", + "seed_position_question_one": "Cái gì là gì", + "seed_position_question_two": "Lời của cụm từ hạt giống của bạn?", "seed_reminder": "Vui lòng ghi lại những điều này phòng khi bạn mất hoặc xóa điện thoại của mình", "seed_share": "Chia sẻ hạt giống", "seed_title": "Hạt giống", + "seed_verified": "Hạt giống được xác minh", + "seed_verified_subtext": "Bạn có thể sử dụng hạt giống đã lưu của mình sau này để khôi phục ví này trong trường hợp tham nhũng hoặc mất thiết bị của mình. \n\n Bạn có thể xem lại hạt giống này từ", "seedtype": "Loại hạt giống", "seedtype_alert_content": "Chia sẻ hạt giống với ví khác chỉ có thể với BIP39 SeedType.", "seedtype_alert_title": "Cảnh báo hạt giống", @@ -669,6 +691,7 @@ "sent": "Đã gửi", "service_health_disabled": "Thông báo sức khỏe dịch vụ bị vô hiệu hóa", "service_health_disabled_message": "Đây là trang thông báo sức khỏe dịch vụ, bạn có thể kích hoạt trang này trong Cài đặt -> Quyền riêng tư", + "set_a_pin": "Đặt một pin", "settings": "Cài đặt", "settings_all": "TẤT CẢ", "settings_allow_biometrical_authentication": "Cho phép xác thực sinh trắc học", @@ -704,6 +727,7 @@ "share_address": "Chia sẻ địa chỉ", "shared_seed_wallet_groups": "Nhóm ví hạt được chia sẻ", "show": "Trình diễn", + "show_address_book_popup": "Hiển thị cửa sổ bật lên 'Thêm vào sổ địa chỉ' sau khi gửi", "show_details": "Hiển thị chi tiết", "show_keys": "Hiển thị hạt giống/khóa", "show_market_place": "Hiển thị Thị trường", @@ -731,6 +755,10 @@ "silent_payments_settings": "Cài đặt thanh toán im lặng", "single_seed_wallets_group": "Ví hạt đơn", "slidable": "Có thể kéo", + "solana_create_associated_token_account_exception": "Lỗi Tạo tài khoản mã thông báo liên quan cho địa chỉ biên lai.", + "solana_no_associated_token_account_exception": "Không có tài khoản mã thông báo liên quan cho địa chỉ này.", + "solana_sign_native_transaction_rent_exception": "Giao dịch không thể được hoàn thành. Không đủ Sol còn lại cho thuê sau khi giao dịch. Vui lòng tăng số dư Sol của bạn hoặc giảm số lượng sol bạn đang gửi.", + "solana_sign_spl_token_transaction_rent_exception": "Giao dịch không thể được hoàn thành. Không đủ Sol còn lại cho thuê sau khi giao dịch. Vui lòng lên cân bằng sol của bạn.", "sort_by": "Sắp xếp theo", "spend_key_private": "Khóa chi tiêu (riêng tư)", "spend_key_public": "Khóa chi tiêu (công khai)", @@ -743,7 +771,7 @@ "support_description_guides": "Tài liệu và hỗ trợ cho các vấn đề phổ biến", "support_description_live_chat": "Miễn phí và nhanh chóng! Các đại diện hỗ trợ được đào tạo sẵn sàng hỗ trợ", "support_description_other_links": "Tham gia cộng đồng của chúng tôi hoặc liên hệ với chúng tôi hoặc các đối tác của chúng tôi qua các phương pháp khác", - "support_title_guides": "Hướng dẫn Cake Wallet", + "support_title_guides": "Cake Wallet Docs", "support_title_live_chat": "Hỗ trợ trực tiếp", "support_title_other_links": "Liên kết hỗ trợ khác", "sweeping_wallet": "Quét ví", @@ -822,6 +850,7 @@ "trade_state_underpaid": "Thanh toán chưa đủ", "trade_state_unpaid": "Chưa thanh toán", "trades": "Giao dịch", + "transaction_cost": "Chi phí giao dịch", "transaction_details_amount": "Số tiền", "transaction_details_copied": "${title} đã được sao chép vào clipboard", "transaction_details_date": "Ngày", @@ -881,6 +910,7 @@ "variable_pair_not_supported": "Cặp biến này không được hỗ trợ với các sàn giao dịch đã chọn", "verification": "Xác minh", "verify_message": "Xác minh tin nhắn", + "verify_seed": "Xác minh hạt giống", "verify_with_2fa": "Xác minh với Cake 2FA", "version": "Phiên bản ${currentVersion}", "view_all": "Xem tất cả", @@ -890,6 +920,7 @@ "view_transaction_on": "Xem giao dịch trên", "voting_weight": "Trọng số bỏ phiếu", "waitFewSecondForTxUpdate": "Vui lòng đợi vài giây để giao dịch được phản ánh trong lịch sử giao dịch", + "wallet": "Cái ví", "wallet_group": "Nhóm ví", "wallet_group_description_four": "Để tạo ra một ví với một hạt giống hoàn toàn mới.", "wallet_group_description_one": "Trong ví bánh, bạn có thể tạo", @@ -922,6 +953,8 @@ "wallets": "Các ví", "warning": "Cảnh báo", "welcome": "Chào mừng đến với", + "welcome_subtitle_new_wallet": "Nếu bạn muốn bắt đầu mới, hãy nhấn Tạo ví mới bên dưới và bạn sẽ rời khỏi các cuộc đua.", + "welcome_subtitle_restore_wallet": "Nếu bạn có một ví hiện có mà bạn muốn mang vào bánh, chỉ cần chọn khôi phục ví hiện có và chúng tôi sẽ hướng dẫn bạn qua quá trình này.", "welcome_to_cakepay": "Chào mừng đến với Cake Pay!", "what_is_silent_payments": "Thanh toán im lặng là gì?", "widgets_address": "Địa chỉ", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 74e7a798d..f026cada7 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -38,6 +38,7 @@ "agree_to": "Tẹ́ ẹ bá dá àkáǹtì ẹ jọ rò ", "alert_notice": "Akiyesi", "all": "Gbogbo", + "all_coins": "Gbogbo awọn owó", "all_trades": "Gbogbo àwọn pàṣípààrọ̀", "all_transactions": "Gbogbo àwọn àránṣẹ́", "alphabetical": "Labidibi", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "Ra awọn kaadi ti a san ni agbaye ati awọn kaadi ẹbun", "cake_pay_web_cards_subtitle": "Ra àwọn káàdì ìrajà t'á lò nínú ìtajà kan àti àwọn káàdì náà t'á lè lò níbikíbi", "cake_pay_web_cards_title": "Àwọn káàdì wẹ́ẹ̀bù ti Cake Pay", + "cake_seeds_save_disclaimer": "Jọwọ fi awọn ọrọ wọnyi pamọ ni aaye aabo! Iwọ yoo nilo awọn ọrọ wọnyi lati mu pada apamọwọ rẹ sori ẹrọ tuntun.", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "Mo jẹrisi pe Emi ko lo aṣoju tabi VPN", + "cakepay_confirm_purchase": "Jẹrisi rira", + "cakepay_confirm_terms_agreed": "Mo gba si awọn ofin ati ipo ti a ṣafihan nibi:", + "cakepay_confirm_voided_refund": "Mo ye awọn igbiyanju irapada lati orilẹ-ede ihamọ kan yoo di agbapada eyikeyi", + "cakepay_ios_not_available": "Ma binu, kaadi ẹbun yii ko wa lori iOS. O le ra lori Android tabi nipasẹ oju opo wẹẹbu wa dipo.", "cakepay_prepaid_card": "Káàdì ìrajà ti CakePay", "camera_consent": "Kamẹra rẹ yoo ṣee lo lati ya aworan kan fun awọn idi idanimọ nipasẹ ${provider}. Jọwọ ṣayẹwo Ilana Aṣiri wọn fun awọn alaye.", "camera_permission_is_required": "A nilo igbanilaaye kamẹra.\nJọwọ jeki o lati app eto.", @@ -175,6 +182,7 @@ "copy_address": "Ṣẹ̀dà àdírẹ́sì", "copy_id": "Ṣẹ̀dà àmì ìdánimọ̀", "copyWalletConnectLink": "Daakọ ọna asopọ WalletConnect lati dApp ki o si lẹẹmọ nibi", + "corrupted_seed_notice": "Awọn faili fun apamọwọ yii jẹ ibajẹ ati pe ko lagbara lati ṣii. Jọwọ wo ọrọ iseda, fipamọ rẹ, ki o mu apamọwọ naa pada.\n\nTi iye ba ṣofo, lẹhinna irugbin naa ko lagbara lati gba pada ni deede.", "countries": "Awọn orilẹ-ede", "create_account": "Dá àkáǹtì", "create_backup": "Ṣẹ̀dà nípamọ́", @@ -257,7 +265,7 @@ "enterTokenID": "Tẹ ID ami sii", "enterWalletConnectURI": "Tẹ WalletConnect URI sii", "error": "Àṣìṣe", - "error_dialog_content": "Àṣìṣe ti dé.\n\nẸ jọ̀wọ́, fi àkọsílẹ̀ àṣìṣe ránṣẹ́ sí ẹgbẹ́ ìranlọ́wọ́ wa kí áàpù wa bá túbọ̀ dára.", + "error_dialog_content": "Oops, a ni aṣiṣe diẹ.\n\nJọwọ fi aṣiṣe naa ranṣẹ si ẹgbẹ atilẹyin wa lati jẹ ki ohun elo naa dara julọ.", "error_text_account_name": "Orúkọ àkáǹtì lè ni nìkan nínú ẹyọ ọ̀rọ̀ àti òǹkà\nGígun rẹ̀ kò gbọ́dọ̀ kéré ju oókan. Gígun rẹ̀ sì kò gbọ́dọ̀ tóbi ju márùndínlógún.", "error_text_address": "Àdírẹ́sì àpamọ́wọ́ gbọ́dọ̀ báramu irú owó", "error_text_amount": "Iye lè ni nìkan nínú àwọn òǹkà", @@ -324,6 +332,7 @@ "frequently_asked_questions": "Àwọn ìbéèrè la máa ń béèrè", "frozen": "Ó l'a tì pa", "full_balance": "Ìyókù owó kíkún", + "gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.", "generate_name": "Ṣẹda Orukọ", "generating_gift_card": "À ń dá káàdì ìrajà t'á lò nínú irú kan ìtajà", "get_a": "Gba ", @@ -351,13 +360,17 @@ "how_to_use": "Bawo ni lati lo", "how_to_use_card": "Báyìí ni wọ́n ṣe ń lo káàdì yìí.", "id": "Àmì Ìdánimọ̀: ", + "if_you_dont_see_your_device": "Ti o ko ba ri ẹrọ rẹ loke, jọwọ rii daju pe a le jiji rẹ ati ṣiṣi!", "ignor": "Ṣàìfiyèsí", "import": "gbe wọle", "importNFTs": "Gbe awọn NFT wọle", "in_store": "A níyí", "incoming": "Wọ́n tó ń bọ̀", "incorrect_seed": "Ọ̀rọ̀ tí a tẹ̀ kì í ṣe èyí.", + "incorrect_seed_option": "Ti ko tọ. Jọwọ gbiyanju lẹẹkansi", + "incorrect_seed_option_back": "Ti ko tọ. Jọwọ rii daju pe irugbin rẹ wa ni fipamọ ni deede ki o tun gbiyanju lẹẹkan si.", "inputs": "Igbewọle", + "insufficient_funds_for_tx": "Awọn owo ti ko to lati ṣe idunadura ni ifijišẹ.", "insufficient_lamport_for_tx": "O ko ni sosi to lati bo idunadura ati idiyele iṣowo rẹ. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku sodo naa ti o \\ 'tun n firanṣẹ.", "insufficient_lamports": "O ko ni sosi to lati bo idunadura ati idiyele iṣowo rẹ. O nilo o kere ju ${solValueNeeded}. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku soso ti o n firanṣẹ", "insufficientFundsForRentError": "O ko ni Sol kan lati bo owo isanwo naa ki o yalo fun iroyin naa. Fi agbara kun Sol diẹ sii si apamọwọ rẹ tabi dinku soso naa ti o \\ 'tun n firanṣẹ", @@ -428,7 +441,7 @@ "nano_pick_new_rep": "Mu aṣoju tuntun kan", "nanogpt_subtitle": "Gbogbo awọn awoṣe tuntun (GPT-4, Claude). \\ Nno alabapin kan, sanwo pẹlu Crypto.", "narrow": "Taara", - "new_first_wallet_text": "Ni rọọrun jẹ ki o jẹ ki o jẹ ki o jẹ ki a mu", + "new_first_wallet_text": "Tọju ẹrọ ti o ni aabo rẹ jẹ nkan ti akara oyinbo kan", "new_node_testing": "A ń dán apẹka títun wò", "new_subaddress_create": "Ṣe é", "new_subaddress_label_name": "Orúkọ", @@ -465,6 +478,7 @@ "online": "Lórí ayélujára", "onramper_option_description": "Ni kiakia Ra Crypto pẹlu ọpọlọpọ awọn ọna isanwo. Wa ni ọpọlọpọ awọn orilẹ-ede. Itankale ati awọn idiyele yatọ.", "open_gift_card": "Ṣí káàdí ìrajà t'á lò nínú irú kan ìtajà", + "open_wallet": "Ṣii apamọwọ", "optional_description": "Ṣeto ẹru iye", "optional_email_hint": "Ṣeto imọ-ẹrọ iye fun owo ti o gbọdọjọ", "optional_name": "Ṣeto orukọ ti o ni", @@ -478,6 +492,7 @@ "outdated_electrum_wallet_receive_warning": "Ẹ KÒ FI BITCOIN SÍ ÀPAMỌ́WỌ́ YÌÍ t'á ti dá a nínú Cake Wallet àti àpamọ́wọ́ yìí ni hóró ti ọ̀rọ̀ méjìlá. A lè pàdánù BTC t'á ránṣẹ́ sí àpamọ́wọ́ yìí. Ẹ dá àpamọ́wọ́ títun tó ni hóró tó ni ọ̀rọ̀ mẹ́rinlélógún (Ẹ tẹ àkọsílẹ̀ tó wa l’ókè l'ọ́tún nígbàna, ẹ sì yan àwọn àpamọ́wọ́ nígbàna, ẹ sì yan Dá Àpamọ́wọ́ Títun nígbàna, ẹ sì yan Bitcoin) àti sún Bitcoin yín síbẹ̀ ní sinsìn yẹn. Àwọn àpamọ́wọ́ títun (hóró ni ọ̀rọ̀ mẹ́rinlélógún) láti Cake Wallet wa láìléwu.", "outgoing": "Wọ́n tó ń jáde", "outputs": "Awọn iṣan", + "overshot": "Overshot", "overwrite_amount": "Pààrọ̀ iye owó", "pairingInvalidEvent": "Pipọpọ Iṣẹlẹ Ti ko tọ", "passphrase": "Ọrọ kukuru (iyan)", @@ -532,6 +547,7 @@ "recipient_address": "Àdírẹ́sì olùgbà", "reconnect": "Ṣe àtúnse", "reconnect_alert_text": "Ṣó dá ẹ lójú pé ẹ fẹ́ ṣe àtúnse?", + "reconnect_your_hardware_wallet": "Ṣe atunṣe apamọwọ ohun elo rẹ", "reconnection": "Àtúnṣe", "red_dark_theme": "Akọle dudu pupa", "red_light_theme": "Akori ina pupa", @@ -571,6 +587,7 @@ "restore_description_from_keys": "Mú àpamọ́wọ́ yín padà láti àwọn àtẹ̀ nípamọ́ láti àwọn kọ́kọ́rọ́ àdáni yín", "restore_description_from_seed": "Ẹ mú àpamọ́wọ́ yín padà láti àkànpọ̀ ọlọ́rọ̀ ẹ̀ẹ̀marùndínlọgbọ̀n tàbí ti mẹ́talá.", "restore_description_from_seed_keys": "Mú àpamọ́wọ́ yín padà láti hóró/kọ́kọ́rọ́ t'ẹ́ ti pamọ́ sí ibi láìléwu", + "restore_existing_wallet": "Mu pada apamọwọ to wa tẹlẹ", "restore_from_date_or_blockheight": "Ẹ jọ̀wọ́, tẹ̀ ìgbà ọjọ́ díẹ̀ k'ẹ́ tó ti dá àpamọ́wọ́ yìí. Tàbí ẹ lè tẹ̀ ẹ́ t'ẹ́ bá mọ gíga àkójọpọ̀.", "restore_from_seed_placeholder": "Ẹ jọ̀wọ́ tẹ̀ hóró yín tàbí fikún ẹ̀dà hóró ḿbí.", "restore_new_seed": "Hóró títun", @@ -612,6 +629,7 @@ "seed_alert_title": "Ẹ wo", "seed_alert_yes": "Mo ti kọ ọ́", "seed_choose": "Yan èdè hóró", + "seed_display_path": "Aṣayan -> Aabo ati afẹyinti -> Fiwe bọtini / Awọn irugbin", "seed_hex_form": "Irú Opamọwọ apamọwọ (HOX)", "seed_key": "Bọtini Ose", "seed_language": "Ewu ọmọ", @@ -630,9 +648,13 @@ "seed_language_russian": "Èdè Rọ́síà", "seed_language_spanish": "Èdè Sípéènì", "seed_phrase_length": "Gigun gbolohun irugbin", + "seed_position_question_one": "Kini awọn", + "seed_position_question_two": "Ọrọ ti gbolohun irubò rẹ?", "seed_reminder": "Ẹ jọ̀wọ́, kọ wọnyí sílẹ̀ k'ẹ́ tó pàdánù ẹ̀rọ ìbánisọ̀rọ̀ yín", "seed_share": "Pín hóró", "seed_title": "Hóró", + "seed_verified": "Irugbin ijẹrisi", + "seed_verified_subtext": "O le lo irugbin ti o fipamọ nigbamii lati mu apamọwọ yii pada sinu iṣẹlẹ ti ibajẹ tabi padanu ẹrọ rẹ. \n\n O le wo irugbin yii lẹẹkansi lati", "seedtype": "Irugbin-seetypu", "seedtype_alert_content": "Pinpin awọn irugbin pẹlu awọn gedo miiran ṣee ṣe pẹlu Bip39 irugbin.", "seedtype_alert_title": "Ṣajọpọ Seeytype", @@ -671,6 +693,7 @@ "sent": "Owó t'á ti ránṣẹ́", "service_health_disabled": "IPỌRỌ IWE TI AGBARA TI O LE RẸ", "service_health_disabled_message": "Eyi ni oju-iwe Iwe itẹlera Iṣẹ Ile-iṣẹ Iṣẹ: O le mu oju-iwe yii ṣiṣẹ labẹ Eto -> Asiri", + "set_a_pin": "Ṣeto PIN kan", "settings": "Awọn aseṣe", "settings_all": "Gbogbo", "settings_allow_biometrical_authentication": "Fi àyè gba ìfẹ̀rílàdí biometrical", @@ -706,6 +729,7 @@ "share_address": "Pín àdírẹ́sì", "shared_seed_wallet_groups": "Awọn ẹgbẹ ti a pin irugbin", "show": "Fihan", + "show_address_book_popup": "Fihan 'ṣafikun si Agbejade Iwe' Lẹhin fifiranṣẹ", "show_details": "Fi ìsọfúnni kékeré hàn", "show_keys": "Wo hóró / àwọn kọ́kọ́rọ́", "show_market_place": "Wa Sopọ Pataki", @@ -733,6 +757,10 @@ "silent_payments_settings": "Awọn eto isanwo ti o dakẹ", "single_seed_wallets_group": "Awọn Wowei Awọn gige", "slidable": "Slidable", + "solana_create_associated_token_account_exception": "Aṣiṣe ṣiṣẹda akọọlẹ token ti o ni ibatan fun adirẹsi gbigba.", + "solana_no_associated_token_account_exception": "Ko si iroyin token ti o ni ibatan fun adirẹsi yii.", + "solana_sign_native_transaction_rent_exception": "Idunadura ko le pari. Solusi ti ko to ju fun iyalo lẹhin idunadura. Jowo oke iwọntunwọnsi rẹ tabi dinku iye sol ti o firanṣẹ.", + "solana_sign_spl_token_transaction_rent_exception": "Idunadura ko le pari. Solusi ti ko to ju fun iyalo lẹhin idunadura. Sanra si oke ni iwọntunwọnsi Sol rẹ.", "sort_by": "Sa pelu", "spend_key_private": "Kọ́kọ́rọ́ sísan (àdáni)", "spend_key_public": "Kọ́kọ́rọ́ sísan (kò àdáni)", @@ -745,7 +773,7 @@ "support_description_guides": "Iwe ati atilẹyin fun awọn ọran ti o wọpọ", "support_description_live_chat": "Free ati sare! Ti oṣiṣẹ awọn aṣoju wa lati ṣe iranlọwọ", "support_description_other_links": "Darapọ mọ awọn agbegbe wa tabi de wa awọn alabaṣepọ wa nipasẹ awọn ọna miiran", - "support_title_guides": "Akara oyinbo Awọn Itọsọna Awọki oyinbo", + "support_title_guides": "Awọn iwe apamọwọ oyinbo akara oyinbo", "support_title_live_chat": "Atilẹyin ifiwe", "support_title_other_links": "Awọn ọna asopọ atilẹyin miiran", "sweeping_wallet": "Fi owo iwe iwe wofo", @@ -824,6 +852,7 @@ "trade_state_underpaid": "Ti san iye tó kéré jù", "trade_state_unpaid": "Kò tíì san", "trades": "Àwọn pàṣípààrọ̀", + "transaction_cost": "Oniruuru idiyele", "transaction_details_amount": "Iye owó", "transaction_details_copied": "A ṣeda ${title} sí àkọsílẹ̀", "transaction_details_date": "Ìgbà", @@ -883,6 +912,7 @@ "variable_pair_not_supported": "A kì í ṣe k'á fi àwọn ilé pàṣípààrọ̀ yìí ṣe pàṣípààrọ̀ irú owó méji yìí", "verification": "Ìjẹ́rìísí", "verify_message": "Daju ifiranṣẹ", + "verify_seed": "Dajudaju irugbin", "verify_with_2fa": "Ṣeẹda pẹlu Cake 2FA", "version": "Àtúnse ${currentVersion}", "view_all": "Wo gbogbo nǹkan kan", @@ -892,6 +922,7 @@ "view_transaction_on": "Wo pàṣípààrọ̀ lórí ", "voting_weight": "Idibo iwuwo", "waitFewSecondForTxUpdate": "Fi inurere duro fun awọn iṣeju diẹ fun idunadura lati ṣe afihan ninu itan-akọọlẹ iṣowo", + "wallet": "Ohun apamọwọwọ", "wallet_group": "Ẹgbẹ apamọwọ", "wallet_group_description_four": "Lati ṣẹda apamọwọ kan pẹlu irugbin tuntun tuntun.", "wallet_group_description_one": "Ni apamọwọ akara oyinbo, o le ṣẹda a", @@ -924,6 +955,8 @@ "wallets": "Àwọn àpamọ́wọ́", "warning": "Ikilo", "welcome": "Ẹ káàbọ sí", + "welcome_subtitle_new_wallet": "Ti o ba fẹ bẹrẹ alabapade, tẹ Ṣẹda apamọwọ tuntun ni isalẹ iwọ yoo wa ni pipa si awọn ere-ije.", + "welcome_subtitle_restore_wallet": "Ti o ba ni apamọwọ ti o wa tẹlẹ ti o fẹ lati mu wa sinu akara oyinbo, yan omi apamọwọ wa tẹlẹ ati pe a yoo rin ọ nipasẹ ilana naa.", "welcome_to_cakepay": "Ẹ káàbọ̀ sí Cake Pay!", "what_is_silent_payments": "Kini awọn sisanwo ipalọlọ?", "widgets_address": "Àdírẹ́sì", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index a524302bb..a2221ae48 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -38,6 +38,7 @@ "agree_to": "创建账户即表示您同意 ", "alert_notice": "注意", "all": "全部", + "all_coins": "所有硬币", "all_trades": "所有的变化", "all_transactions": "所有交易", "alphabetical": "按字母顺序", @@ -100,7 +101,13 @@ "cake_pay_subtitle": "购买全球预付费卡和礼品卡", "cake_pay_web_cards_subtitle": "购买全球预付卡和礼品卡", "cake_pay_web_cards_title": "蛋糕支付网络卡", + "cake_seeds_save_disclaimer": "请在安全的地方保存这些单词!您将需要这些单词来恢复新设备上的钱包。", "cake_wallet": "Cake Wallet", + "cakepay_confirm_no_vpn": "我确认我不使用代理或VPN", + "cakepay_confirm_purchase": "确认购买", + "cakepay_confirm_terms_agreed": "我同意此处介绍的条款和条件:", + "cakepay_confirm_voided_refund": "我了解限制国家的赎回尝试将使任何退款无效", + "cakepay_ios_not_available": "抱歉,这张礼品卡在iOS上不可用。您可以在Android或通过我们的网站上购买它。", "cakepay_prepaid_card": "CakePay 预付借记卡", "camera_consent": "${provider} 将使用您的相机拍摄图像以供识别之用。请查看他们的隐私政策了解详情。", "camera_permission_is_required": "需要相机许可。\n请从应用程序设置中启用它。", @@ -175,6 +182,7 @@ "copy_address": "复制地址", "copy_id": "复制ID", "copyWalletConnectLink": "从 dApp 复制 WalletConnect 链接并粘贴到此处", + "corrupted_seed_notice": "该钱包的文件被损坏,无法打开。请查看种子短语,保存并恢复钱包。\n\n如果该值为空,则种子无法正确恢复。", "countries": "国家", "create_account": "创建账户", "create_backup": "创建备份", @@ -256,7 +264,7 @@ "enterTokenID": "输入令牌 ID", "enterWalletConnectURI": "输入 WalletConnect URI", "error": "错误", - "error_dialog_content": "糟糕,我们遇到了一些错误。\n\n请将崩溃报告发送给我们的支持团队,以改进应用程序。", + "error_dialog_content": "糟糕,我们有一些错误。\n\n请将错误报告发送给我们的支持团队,以使应用程序更好。", "error_text_account_name": "帐户名称只能包含字母数字\n且必须介于1到15个字符之间", "error_text_address": "钱包地址必须与类型对应\n加密货币", "error_text_amount": "金额只能包含数字", @@ -323,6 +331,7 @@ "frequently_asked_questions": "常见问题", "frozen": "凍結的", "full_balance": "全部余额", + "gas_exceeds_allowance": "交易要求的气体超出了津贴。", "generate_name": "生成名称", "generating_gift_card": "生成礼品卡", "get_a": "得到一个", @@ -350,13 +359,17 @@ "how_to_use": "如何使用", "how_to_use_card": "如何使用这张卡", "id": "ID: ", + "if_you_dont_see_your_device": "如果您在上面看不到设备,请确保您的分类帐已经清醒并解锁!", "ignor": "忽视", "import": "进口", "importNFTs": "导入 NFT", "in_store": "店内", "incoming": "收到", "incorrect_seed": "输入的文字无效。", + "incorrect_seed_option": "不正确。请重试", + "incorrect_seed_option_back": "不正确。请确保您的种子可以正确保存,然后重试。", "inputs": "输入", + "insufficient_funds_for_tx": "资金不足无法成功执行交易。", "insufficient_lamport_for_tx": "您没有足够的溶胶来支付交易及其交易费用。请在您的钱包中添加更多溶胶或减少您发送的溶胶量。", "insufficient_lamports": "您没有足够的溶胶来支付交易及其交易费用。您至少需要${solValueNeeded} sol。请在您的钱包中添加更多溶胶或减少您发送的溶胶量", "insufficientFundsForRentError": "您没有足够的溶胶来支付该帐户的交易费和租金。请在钱包中添加更多溶胶或减少您发送的溶胶量", @@ -427,7 +440,7 @@ "nano_pick_new_rep": "选择新代表", "nanogpt_subtitle": "所有最新型号(GPT-4,Claude)。\\ nno订阅,用加密货币付款。", "narrow": "狭窄的", - "new_first_wallet_text": "轻松确保您的加密货币安全", + "new_first_wallet_text": "保持加密货币是一件小菜一碟", "new_node_testing": "新节点测试", "new_subaddress_create": "创建", "new_subaddress_label_name": "标签名称", @@ -464,6 +477,7 @@ "online": "在线", "onramper_option_description": "快速使用许多付款方式购买加密货币。在大多数国家 /地区可用。利差和费用各不相同。", "open_gift_card": "打开礼品卡", + "open_wallet": "打开钱包", "optional_description": "可选说明", "optional_email_hint": "可选的收款人通知电子邮件", "optional_name": "可选收件人姓名", @@ -477,6 +491,7 @@ "outdated_electrum_wallet_receive_warning": "如果这个钱包有一个 12 字的种子并且是在 Cake 中创建的,不要将比特币存入这个钱包。 任何转移到此钱包的 BTC 都可能丢失。 创建一个新的 24 字钱包(点击右上角的菜单,选择钱包,选择创建新钱包,然后选择比特币)并立即将您的 BTC 移到那里。 Cake 的新(24 字)BTC 钱包是安全的", "outgoing": "发送", "outputs": "输出", + "overshot": "超越", "overwrite_amount": "Overwrite amount", "pairingInvalidEvent": "配对无效事件", "passphrase": "密码(可选)", @@ -531,6 +546,7 @@ "recipient_address": "收件人地址", "reconnect": "重新连接", "reconnect_alert_text": "您确定要重新连接吗?", + "reconnect_your_hardware_wallet": "重新连接您的硬件钱包", "reconnection": "重新连接", "red_dark_theme": "红色的黑暗主题", "red_light_theme": "红灯主题", @@ -570,6 +586,7 @@ "restore_description_from_keys": "使用私钥恢复钱包", "restore_description_from_seed": "从25个字中恢复您的钱包或13个字的组合码", "restore_description_from_seed_keys": "从保存到安全地方的种子/钥匙取回钱包", + "restore_existing_wallet": "恢复现有的钱包", "restore_from_date_or_blockheight": "请输入您创建这个钱包前几天的日期。或者如果您知道区块高度,请输入区块高度", "restore_from_seed_placeholder": "请在此处输入或粘贴您的代码短语", "restore_new_seed": "新种子", @@ -611,6 +628,7 @@ "seed_alert_title": "注意", "seed_alert_yes": "确定", "seed_choose": "选择种子语言", + "seed_display_path": "菜单 - >安全性和备份 - >显示键/种子", "seed_hex_form": "钱包种子(十六进制形式)", "seed_key": "种子钥匙", "seed_language": "种子语言", @@ -629,9 +647,13 @@ "seed_language_russian": "俄文", "seed_language_spanish": "西班牙文", "seed_phrase_length": "种子短语长度", + "seed_position_question_one": "什么是", + "seed_position_question_two": "你的种子短语的话?", "seed_reminder": "请记下这些内容,以防丟失或数据损坏", "seed_share": "分享种子", "seed_title": "种子", + "seed_verified": "种子经过验证", + "seed_verified_subtext": "您可以在以后使用保存的种子在发生损坏或丢失设备的情况下还原该钱包。\n\n您可以从", "seedtype": "籽粒", "seedtype_alert_content": "只有BIP39籽粒可以与其他钱包共享种子。", "seedtype_alert_title": "籽粒警报", @@ -670,6 +692,7 @@ "sent": "已发送", "service_health_disabled": "服务健康公告被禁用", "service_health_disabled_message": "这是服务健康公告页面,您可以在设置 - >隐私下启用此页面", + "set_a_pin": "设置一个别针", "settings": "设置", "settings_all": "全部", "settings_allow_biometrical_authentication": "允许生物识别认证", @@ -705,6 +728,7 @@ "share_address": "分享地址", "shared_seed_wallet_groups": "共享种子钱包组", "show": "展示", + "show_address_book_popup": "发送后显示“添加到通讯簿”弹出窗口", "show_details": "显示详细信息", "show_keys": "显示种子/密钥", "show_market_place": "显示市场", @@ -732,6 +756,10 @@ "silent_payments_settings": "无声付款设置", "single_seed_wallets_group": "单个种子钱包", "slidable": "可滑动", + "solana_create_associated_token_account_exception": "错误创建有关接收地址的关联令牌帐户。", + "solana_no_associated_token_account_exception": "该地址没有关联的令牌帐户。", + "solana_sign_native_transaction_rent_exception": "交易无法完成。交易后剩下的溶胶不足。请增强您的溶胶余额或减少您发送的SOL的量。", + "solana_sign_spl_token_transaction_rent_exception": "交易无法完成。交易后剩下的溶胶不足。请增强您的溶液余额。", "sort_by": "排序方式", "spend_key_private": "Spend 密钥 (私钥)", "spend_key_public": "Spend 密钥 (公钥)", @@ -744,7 +772,7 @@ "support_description_guides": "对常见问题的文档和支持", "support_description_live_chat": "免费快速!训练有素的支持代表可以协助", "support_description_other_links": "加入我们的社区或通过其他方法与我们联系我们的合作伙伴", - "support_title_guides": "蛋糕钱包指南", + "support_title_guides": "蛋糕钱包文档", "support_title_live_chat": "实时支持", "support_title_other_links": "其他支持链接", "sweeping_wallet": "扫一扫钱包", @@ -823,6 +851,7 @@ "trade_state_underpaid": "支付不足", "trade_state_unpaid": "未付", "trades": "交易", + "transaction_cost": "交易成本", "transaction_details_amount": "金额", "transaction_details_copied": "${title} 复制到剪切板", "transaction_details_date": "日期", @@ -882,6 +911,7 @@ "variable_pair_not_supported": "所选交易所不支持此变量对", "verification": "验证", "verify_message": "验证消息", + "verify_seed": "验证种子", "verify_with_2fa": "用 Cake 2FA 验证", "version": "版本 ${currentVersion}", "view_all": "查看全部", @@ -891,6 +921,7 @@ "view_transaction_on": "View Transaction on ", "voting_weight": "投票权重", "waitFewSecondForTxUpdate": "请等待几秒钟,交易才会反映在交易历史记录中", + "wallet": "钱包", "wallet_group": "钱包组", "wallet_group_description_four": "创建一个带有全新种子的钱包。", "wallet_group_description_one": "在蛋糕钱包中,您可以创建一个", @@ -923,6 +954,8 @@ "wallets": "钱包", "warning": "警告", "welcome": "欢迎使用", + "welcome_subtitle_new_wallet": "如果您想开始新鲜,请点击下面的创建新钱包,您将参加比赛。", + "welcome_subtitle_restore_wallet": "如果您有一个现有的钱包要把蛋糕带入蛋糕,只需选择还原现有的钱包,我们将带您完成整个过程。", "welcome_to_cakepay": "欢迎来到 Cake Pay!", "what_is_silent_payments": "什么是无声付款?", "widgets_address": "地址", diff --git a/run-android.sh b/run-android.sh index 880d86b6f..cb0c34038 100755 --- a/run-android.sh +++ b/run-android.sh @@ -1,5 +1,5 @@ #!/bin/bash - +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/universal_sed.sh" # Get the current git branch get_current_branch() { if git rev-parse --git-dir > /dev/null 2>&1; then @@ -15,9 +15,8 @@ get_current_branch() { update_app_properties() { local branch=$1 local file_path="./android/app.properties" - - sed -i "s/^id=.*/id=com.cakewallet.$branch/" "$file_path" - sed -i "s/^name=.*/name=$branch-Cake Wallet/" "$file_path" + universal_sed "s/^id=.*/id=com.cakewallet.$branch/" "$file_path" + universal_sed "s/^name=.*/name=$branch-Cake Wallet/" "$file_path" } # only update app.properties if getting the current branch was successful diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 7eee6d6ae..385414f24 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -15,15 +15,15 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_ANDROID_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.18.0" -MONERO_COM_BUILD_NUMBER=105 +MONERO_COM_VERSION="1.19.0" +MONERO_COM_BUILD_NUMBER=109 MONERO_COM_BUNDLE_ID="com.monero.app" MONERO_COM_PACKAGE="com.monero.app" MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.21.0" -CAKEWALLET_BUILD_NUMBER=236 +CAKEWALLET_VERSION="4.22.0" +CAKEWALLET_BUILD_NUMBER=240 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/android/inject_app_details.sh b/scripts/android/inject_app_details.sh index 2957b91e3..7b0d74798 100755 --- a/scripts/android/inject_app_details.sh +++ b/scripts/android/inject_app_details.sh @@ -1,5 +1,5 @@ #!/bin/bash - +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/universal_sed.sh" if [ -z "$APP_ANDROID_TYPE" ]; then echo "Please set APP_ANDROID_TYPE" exit 1 @@ -7,9 +7,9 @@ fi cd ../.. set -x -sed -i "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml -sed -i "0,/version:/{s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/}" ./android/app/src/main/AndroidManifest.xml -sed -i "0,/__APP_SCHEME__/s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/" ./android/app/src/main/AndroidManifest.xml -sed -i "0,/version:/{s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/}" ./android/app/src/main/AndroidManifest.xml -sed -i "0,/version:/{s/__versionName__/${APP_ANDROID_VERSION}/}" ./android/app/src/main/AndroidManifest.xml +universal_sed "1,/version:/ {s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/;}" ./pubspec.yaml +universal_sed "1,/version:/ {s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/;}" ./android/app/src/main/AndroidManifest.xml +universal_sed "1,/__APP_SCHEME__/ {s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/;}" ./android/app/src/main/AndroidManifest.xml +universal_sed "1,/version:/ {s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/;}" ./android/app/src/main/AndroidManifest.xml +universal_sed "1,/version:/ {s/__versionName__/${APP_ANDROID_VERSION}/;}" ./android/app/src/main/AndroidManifest.xml cd scripts/android diff --git a/scripts/android/pubspec_gen.sh b/scripts/android/pubspec_gen.sh index 468f548f3..febc4f9e9 100755 --- a/scripts/android/pubspec_gen.sh +++ b/scripts/android/pubspec_gen.sh @@ -23,7 +23,7 @@ esac cd ../.. cp -rf pubspec_description.yaml pubspec.yaml flutter pub get -flutter pub run tool/generate_pubspec.dart +dart run tool/generate_pubspec.dart flutter pub get -flutter packages pub run tool/configure.dart $CONFIG_ARGS +dart run tool/configure.dart $CONFIG_ARGS cd scripts/android \ No newline at end of file diff --git a/scripts/ios/app_config.sh b/scripts/ios/app_config.sh index 2232491a6..396ccd7f0 100755 --- a/scripts/ios/app_config.sh +++ b/scripts/ios/app_config.sh @@ -1,5 +1,6 @@ #!/bin/bash - +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/universal_sed.sh" +set -x -e MONERO_COM="monero.com" CAKEWALLET="cakewallet" HAVEN="haven" @@ -22,7 +23,7 @@ cp -rf ./ios/Runner/InfoBase.plist ./ios/Runner/Info.plist /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLName string ${APP_IOS_TYPE}" ./ios/Runner/Info.plist /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLSchemes array" ./ios/Runner/Info.plist /usr/libexec/PlistBuddy -c "Add :CFBundleURLTypes:1:CFBundleURLSchemes: string ${APP_IOS_TYPE}" ./ios/Runner/Info.plist -sed -i '' "s/PRODUCT_BUNDLE_IDENTIFIER = .*;/PRODUCT_BUNDLE_IDENTIFIER = $APP_IOS_BUNDLE_ID;/g" ./ios/Runner.xcodeproj/project.pbxproj +universal_sed "s/PRODUCT_BUNDLE_IDENTIFIER = .*;/PRODUCT_BUNDLE_IDENTIFIER = $APP_IOS_BUNDLE_ID;/g" ./ios/Runner.xcodeproj/project.pbxproj CONFIG_ARGS="" @@ -45,8 +46,8 @@ esac cp -rf pubspec_description.yaml pubspec.yaml flutter pub get -flutter pub run tool/generate_pubspec.dart +dart run tool/generate_pubspec.dart flutter pub get -flutter packages pub run tool/configure.dart $CONFIG_ARGS +dart run tool/configure.dart $CONFIG_ARGS cd $DIR $DIR/app_icon.sh diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index fe18758c8..580adad8e 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN) APP_IOS_TYPE=$1 MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.18.0" -MONERO_COM_BUILD_NUMBER=103 +MONERO_COM_VERSION="1.19.0" +MONERO_COM_BUILD_NUMBER=106 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="4.21.0" -CAKEWALLET_BUILD_NUMBER=281 +CAKEWALLET_VERSION="4.22.0" +CAKEWALLET_BUILD_NUMBER=287 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/linux/app_config.sh b/scripts/linux/app_config.sh index b4ca1423c..0fc41bd0f 100755 --- a/scripts/linux/app_config.sh +++ b/scripts/linux/app_config.sh @@ -1,5 +1,5 @@ #!/bin/bash - +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/universal_sed.sh" CAKEWALLET="cakewallet" DIR=`pwd` @@ -18,8 +18,8 @@ esac cp -rf pubspec_description.yaml pubspec.yaml flutter pub get -flutter pub run tool/generate_pubspec.dart +dart run tool/generate_pubspec.dart flutter pub get -flutter packages pub run tool/configure.dart $CONFIG_ARGS -sed -i '0,/version: 0.0.0/s//version: '"${APP_LINUX_VERSION}"'+'"${APP_LINUX_BUILD_NUMBER}"'/' pubspec.yaml +dart run tool/configure.dart $CONFIG_ARGS +universal_sed '0,/version: 0.0.0/s//version: '"${APP_LINUX_VERSION}"'+'"${APP_LINUX_BUILD_NUMBER}"'/' pubspec.yaml cd $DIR diff --git a/scripts/linux/app_env.sh b/scripts/linux/app_env.sh index 1cdb43ced..6d8557d6c 100755 --- a/scripts/linux/app_env.sh +++ b/scripts/linux/app_env.sh @@ -14,8 +14,8 @@ if [ -n "$1" ]; then fi CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.11.0" -CAKEWALLET_BUILD_NUMBER=38 +CAKEWALLET_VERSION="1.12.0" +CAKEWALLET_BUILD_NUMBER=41 if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then echo "Wrong app type." diff --git a/scripts/macos/app_config.sh b/scripts/macos/app_config.sh index 92a8636bd..452205dd9 100755 --- a/scripts/macos/app_config.sh +++ b/scripts/macos/app_config.sh @@ -1,4 +1,5 @@ #!/bin/bash +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/universal_sed.sh" MONERO_COM="monero.com" CAKEWALLET="cakewallet" @@ -24,11 +25,11 @@ cp -rf ./macos/Runner/DebugProfileBase.entitlements ./macos/Runner/DebugProfile. cp -rf ./macos/Runner/ReleaseBase.entitlements ./macos/Runner/Release.entitlements cp -rf ./macos/Runner/RunnerBase.entitlements ./macos/Runner/Runner.entitlements cp -rf ./macos/Runner/Configs/AppInfoBase.xcconfig ./macos/Runner/Configs/AppInfo.xcconfig -sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/DebugProfile.entitlements -sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Release.entitlements -sed -i '' "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Runner.entitlements -sed -i '' "s/\${PRODUCT_NAME}/${APP_MACOS_NAME}/g" ./macos/Runner/Configs/AppInfo.xcconfig -sed -i '' "s/PRODUCT_BUNDLE_IDENTIFIER = .*;/PRODUCT_BUNDLE_IDENTIFIER = $APP_MACOS_BUNDLE_ID;/g" ./macos/Runner/Configs/AppInfo.xcconfig +universal_sed "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/DebugProfile.entitlements +universal_sed "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Release.entitlements +universal_sed "s/\${BUNDLE_ID}/${APP_MACOS_BUNDLE_ID}/g" ./macos/Runner/Runner.entitlements +universal_sed "s/\${PRODUCT_NAME}/${APP_MACOS_NAME}/g" ./macos/Runner/Configs/AppInfo.xcconfig +universal_sed "s/PRODUCT_BUNDLE_IDENTIFIER = .*;/PRODUCT_BUNDLE_IDENTIFIER = $APP_MACOS_BUNDLE_ID;/g" ./macos/Runner/Configs/AppInfo.xcconfig CONFIG_ARGS="" case $APP_MACOS_TYPE in @@ -40,8 +41,8 @@ esac cp -rf pubspec_description.yaml pubspec.yaml flutter pub get -flutter pub run tool/generate_pubspec.dart +dart run tool/generate_pubspec.dart flutter pub get -flutter packages pub run tool/configure.dart $CONFIG_ARGS +dart run tool/configure.dart $CONFIG_ARGS cd $DIR $DIR/app_icon.sh diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index 8f3b68ab5..37e7890c4 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -16,13 +16,13 @@ if [ -n "$1" ]; then fi MONERO_COM_NAME="Monero.com" -MONERO_COM_VERSION="1.8.0" -MONERO_COM_BUILD_NUMBER=36 +MONERO_COM_VERSION="1.9.0" +MONERO_COM_BUILD_NUMBER=39 MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" -CAKEWALLET_VERSION="1.14.0" -CAKEWALLET_BUILD_NUMBER=95 +CAKEWALLET_VERSION="1.15.0" +CAKEWALLET_BUILD_NUMBER=99 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then diff --git a/scripts/macos/gen_common.sh b/scripts/macos/gen_common.sh index d75ac919e..d1d40edc9 100755 --- a/scripts/macos/gen_common.sh +++ b/scripts/macos/gen_common.sh @@ -1,5 +1,5 @@ #!/bin/sh - +source "$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/universal_sed.sh" gen_podspec() { ARCH=$1 CW_PLUGIN_DIR="`pwd`/../../cw_monero/macos" @@ -9,7 +9,7 @@ gen_podspec() { DEFAULT_FILE_PATH="${CW_PLUGIN_DIR}/${DEFAULT_FILENAME}" rm -f $DEFAULT_FILE_PATH cp $BASE_FILE_PATH $DEFAULT_FILE_PATH - gsed -i "s/#___VALID_ARCHS___#/${ARCH}/g" $DEFAULT_FILE_PATH + universal_sed "s/#___VALID_ARCHS___#/${ARCH}/g" $DEFAULT_FILE_PATH } gen_project() { @@ -17,7 +17,7 @@ gen_project() { CW_DIR="`pwd`/../../macos/Runner.xcodeproj" DEFAULT_FILENAME="project.pbxproj" DEFAULT_FILE_PATH="${CW_DIR}/${DEFAULT_FILENAME}" - gsed -i "s/ARCHS =.*/ARCHS = \"${ARCH}\";/g" $DEFAULT_FILE_PATH + universal_sed "s/ARCHS =.*/ARCHS = \"${ARCH}\";/g" $DEFAULT_FILE_PATH } gen() { diff --git a/scripts/prepare_moneroc.sh b/scripts/prepare_moneroc.sh index 3596bd18b..c345408dd 100755 --- a/scripts/prepare_moneroc.sh +++ b/scripts/prepare_moneroc.sh @@ -8,7 +8,7 @@ if [[ ! -d "monero_c" ]]; then git clone https://github.com/mrcyjanek/monero_c --branch master cd monero_c - git checkout d72c15f4339791a7bbdf17e9d827b7b56ca144e4 + git checkout af5277f96073917185864d3596e82b67bee54e78 git reset --hard git submodule update --init --force --recursive ./apply_patches.sh monero diff --git a/scripts/universal_sed.sh b/scripts/universal_sed.sh new file mode 100644 index 000000000..d8a95684e --- /dev/null +++ b/scripts/universal_sed.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +detect_sed() { + if sed --version 2>/dev/null | grep -q "GNU"; then + SED_TYPE="GNU" + else + SED_TYPE="BSD" + fi +} + +universal_sed() { + local expression=$1 + local file=$2 + + if [[ "$SED_TYPE" == "GNU" ]]; then + sed -i "$expression" "$file" + else + sed -i '' "$expression" "$file" + fi +} + +detect_sed diff --git a/scripts/windows/build_exe_installer.iss b/scripts/windows/build_exe_installer.iss index 25f94cb1f..155e65005 100644 --- a/scripts/windows/build_exe_installer.iss +++ b/scripts/windows/build_exe_installer.iss @@ -1,5 +1,5 @@ #define MyAppName "Cake Wallet" -#define MyAppVersion "0.2.0" +#define MyAppVersion "0.3.0" #define MyAppPublisher "Cake Labs LLC" #define MyAppURL "https://cakewallet.com/" #define MyAppExeName "CakeWallet.exe" diff --git a/tool/append_translation.dart b/tool/append_translation.dart index d196421e9..8ef646502 100644 --- a/tool/append_translation.dart +++ b/tool/append_translation.dart @@ -1,8 +1,10 @@ +import 'package:cw_core/utils/print_verbose.dart'; + import 'utils/translation/arb_file_utils.dart'; import 'utils/translation/translation_constants.dart'; import 'utils/translation/translation_utils.dart'; -/// flutter packages pub run tool/append_translation.dart "hello_world" "Hello World!" +/// dart run tool/append_translation.dart "hello_world" "Hello World!" void main(List args) async { if (args.length < 2) { @@ -14,7 +16,7 @@ void main(List args) async { final text = args[1]; final force = args.last == "--force"; - print('Appending "$name": "$text"'); + printV('Appending "$name": "$text"'); // add translation to all languages: for (var lang in langs) { @@ -24,12 +26,12 @@ void main(List args) async { appendStringToArbFile(fileName, name, translation, force: force); } - print('Alphabetizing all files...'); + printV('Alphabetizing all files...'); for (var lang in langs) { final fileName = getArbFileName(lang); alphabetizeArbFile(fileName); } - print('Done!'); + printV('Done!'); } \ No newline at end of file diff --git a/tool/configure.dart b/tool/configure.dart index d50edb8bc..c46f7eb35 100644 --- a/tool/configure.dart +++ b/tool/configure.dart @@ -95,6 +95,7 @@ import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/get_height_by_date.dart'; import 'package:hive/hive.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger; @@ -656,7 +657,14 @@ import 'package:cw_core/output_info.dart'; import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cw_core/wallet_service.dart'; import 'package:hive/hive.dart'; -import 'package:cw_core/crypto_currency.dart';"""; +import 'package:cw_core/crypto_currency.dart'; +import 'package:cake_wallet/core/key_service.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; +import 'package:cake_wallet/entities/haven_seed_store.dart'; +import 'package:cw_core/cake_hive.dart'; +import 'package:cw_core/wallet_info.dart'; +import 'package:cw_core/wallet_type.dart'; +"""; const havenCWHeaders = """ import 'package:cw_core/get_height_by_date.dart'; import 'package:cw_core/monero_amount_format.dart'; @@ -679,6 +687,7 @@ import 'package:cw_haven/mnemonics/french.dart'; import 'package:cw_haven/mnemonics/italian.dart'; import 'package:cw_haven/haven_transaction_creation_credentials.dart'; import 'package:cw_haven/api/balance_list.dart'; +import 'package:cw_haven/haven_wallet_service.dart'; """; const havenCwPart = "part 'cw_haven.dart';"; const havenContent = """ @@ -779,6 +788,7 @@ abstract class Haven { void onStartup(); int getTransactionInfoAccountId(TransactionInfo tx); WalletService createHavenWalletService(Box walletInfoSource); + Future backupHavenSeeds(Box havenSeedStore); CryptoCurrency assetOfTransaction(TransactionInfo tx); List getAssetRate(); } @@ -835,6 +845,7 @@ import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:hive/hive.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger; import 'package:web3dart/web3dart.dart'; @@ -939,6 +950,7 @@ import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_credentials.dart'; import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_service.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:hive/hive.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart' as ledger; import 'package:web3dart/web3dart.dart'; @@ -1101,6 +1113,7 @@ import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/output_info.dart'; import 'package:cw_core/nano_account_info_response.dart'; import 'package:cw_core/n2_node.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:mobx/mobx.dart'; import 'package:hive/hive.dart'; import 'package:cake_wallet/view_model/send/output.dart'; @@ -1425,8 +1438,7 @@ Future generatePubspec({ git: url: https://github.com/cake-tech/flutter_secure_storage.git path: flutter_secure_storage - ref: cake-8.1.0 - version: 8.1.0 + ref: ca897a08677edb443b366352dd7412735e098e7b """; const cwEthereum = """ cw_ethereum: diff --git a/tool/download_moneroc_prebuilds.dart b/tool/download_moneroc_prebuilds.dart index 9df0b4e7b..5169ea687 100644 --- a/tool/download_moneroc_prebuilds.dart +++ b/tool/download_moneroc_prebuilds.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:dio/dio.dart'; import 'package:archive/archive_io.dart'; @@ -29,7 +30,7 @@ Future main() async { final resp = await _dio.get("https://api.github.com/repos/mrcyjanek/monero_c/releases"); final data = resp.data[0]; final tagName = data['tag_name']; - print("Downloading artifacts for: ${tagName}"); + printV("Downloading artifacts for: ${tagName}"); final assets = data['assets'] as List; for (var i = 0; i < assets.length; i++) { for (var triplet in triplets) { @@ -40,9 +41,9 @@ Future main() async { String localFilename = filename.replaceAll("${coin}_${triplet}_", ""); localFilename = "scripts/monero_c/release/${coin}/${triplet}_${localFilename}"; final url = asset["browser_download_url"] as String; - print("- downloading $localFilename"); + printV("- downloading $localFilename"); await _dio.download(url, localFilename); - print(" extracting $localFilename"); + printV(" extracting $localFilename"); final inputStream = InputFileStream(localFilename); final archive = XZDecoder().decodeBuffer(inputStream); final outputStream = OutputFileStream(localFilename.replaceAll(".xz", "")); @@ -50,11 +51,11 @@ Future main() async { } } if (Platform.isMacOS) { - print("Generating ios framework"); + printV("Generating ios framework"); final result = Process.runSync("bash", [ "-c", "cd scripts/ios && ./gen_framework.sh && cd ../.." ]); - print((result.stdout+result.stderr).toString().trim()); + printV((result.stdout+result.stderr).toString().trim()); } } \ No newline at end of file diff --git a/tool/generate_localization.dart b/tool/generate_localization.dart index 530b316ac..0f9af8366 100644 --- a/tool/generate_localization.dart +++ b/tool/generate_localization.dart @@ -1,5 +1,7 @@ import 'dart:io'; import 'dart:convert'; +import 'package:cw_core/utils/print_verbose.dart'; + import 'localization/localization_constants.dart'; import 'utils/utils.dart'; @@ -35,7 +37,7 @@ Future main(List args) async { extraInfo.forEach((key, dynamic value) async { if (key != srcDir) { - print('Wrong key: $key'); + printV('Wrong key: $key'); return; } @@ -43,7 +45,7 @@ Future main(List args) async { final dir = Directory(dirPath); if (!await dir.exists()) { - print('Wrong directory path: $dirPath'); + printV('Wrong directory path: $dirPath'); return; } @@ -53,12 +55,12 @@ Future main(List args) async { final shortLocale = element.path.split('_',)[1].split('.')[0]; localePath[shortLocale] = element.path; } catch (e) { - print('Wrong file: ${element.path}'); + printV('Wrong file: ${element.path}'); } }); if (!localePath.keys.contains(defaultLocale)) { - print("Locale list doesn't contain $defaultLocale"); + printV("Locale list doesn't contain $defaultLocale"); return; } @@ -115,7 +117,7 @@ Future main(List args) async { await File(outputPath + localeListFileName).writeAsString(locales); } catch (e) { - print(e.toString()); + printV(e.toString()); } }); } diff --git a/tool/translation_add_lang.dart b/tool/translation_add_lang.dart index 8b392df6e..96f22158d 100644 --- a/tool/translation_add_lang.dart +++ b/tool/translation_add_lang.dart @@ -1,5 +1,7 @@ import 'dart:io'; +import 'package:cw_core/utils/print_verbose.dart'; + import 'utils/translation/arb_file_utils.dart'; import 'utils/translation/translation_constants.dart'; import 'utils/translation/translation_utils.dart'; @@ -32,5 +34,5 @@ void main(List args) async { } appendStringsToArbFile(targetFileName, translations); - print("Success! Please add your Language Code to lib/entities/language_service.dart"); + printV("Success! Please add your Language Code to lib/entities/language_service.dart"); } diff --git a/tool/translation_consistence.dart b/tool/translation_consistence.dart index 7f3ac130e..df24cce15 100644 --- a/tool/translation_consistence.dart +++ b/tool/translation_consistence.dart @@ -1,18 +1,20 @@ import 'dart:io'; +import 'package:cw_core/utils/print_verbose.dart'; + import 'utils/translation/arb_file_utils.dart'; import 'utils/translation/translation_constants.dart'; import 'utils/translation/translation_utils.dart'; void main(List args) async { - print('Checking Consistency of all arb-files. Default: $defaultLang'); + printV('Checking Consistency of all arb-files. Default: $defaultLang'); final doFix = args.contains("--fix"); if (doFix) - print('Auto fixing enabled!\n'); + printV('Auto fixing enabled!\n'); else - print('Auto fixing disabled!\nRun with arg "--fix" to enable autofix\n'); + printV('Auto fixing disabled!\nRun with arg "--fix" to enable autofix\n'); final fileName = getArbFileName(defaultLang); final file = File(fileName); @@ -25,7 +27,7 @@ void main(List args) async { final missingDefaults = {}; missingKeys.forEach((key) { - print('Missing in "$lang": "$key"'); + printV('Missing in "$lang": "$key"'); if (doFix) missingDefaults[key] = arbObj[key] as String; }); diff --git a/tool/utils/secret_key.dart b/tool/utils/secret_key.dart index affe4017c..e17a509d7 100644 --- a/tool/utils/secret_key.dart +++ b/tool/utils/secret_key.dart @@ -62,7 +62,7 @@ class SecretKey { SecretKey('bitcoinTestWalletReceiveAddress', () => ''), SecretKey('ethereumTestWalletReceiveAddress', () => ''), SecretKey('litecoinTestWalletReceiveAddress', () => ''), - SecretKey('bitco inCashTestWalletReceiveAddress', () => ''), + SecretKey('bitcoinCashTestWalletReceiveAddress', () => ''), SecretKey('polygonTestWalletReceiveAddress', () => ''), SecretKey('solanaTestWalletReceiveAddress', () => ''), SecretKey('tronTestWalletReceiveAddress', () => ''), @@ -81,6 +81,7 @@ class SecretKey { SecretKey('etherScanApiKey', () => ''), SecretKey('polygonScanApiKey', () => ''), SecretKey('moralisApiKey', () => ''), + SecretKey('nowNodesApiKey ', () => ''), ]; static final solanaSecrets = [ diff --git a/tool/utils/translation/arb_file_utils.dart b/tool/utils/translation/arb_file_utils.dart index 414d318dd..0fe31d85d 100644 --- a/tool/utils/translation/arb_file_utils.dart +++ b/tool/utils/translation/arb_file_utils.dart @@ -1,12 +1,14 @@ import 'dart:convert'; import 'dart:io'; +import 'package:cw_core/utils/print_verbose.dart'; + void appendStringToArbFile(String fileName, String name, String text, {bool force = false}) { final file = File(fileName); final arbObj = readArbFile(file); if (arbObj.containsKey(name) && !force) { - print("String $name already exists in $fileName!"); + printV("String $name already exists in $fileName!"); return; } diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ad540a359..4deae3420 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -17,6 +18,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { ConnectivityPlusWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin")); + FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi")); FlutterLocalAuthenticationPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("FlutterLocalAuthenticationPluginCApi")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 92431a6fb..e0f2c11c0 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST connectivity_plus + flutter_inappwebview_windows flutter_local_authentication flutter_secure_storage_windows permission_handler_windows