mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-22 02:34:59 +00:00
Merge branch 'v4.12.0_v1.9.0' of https://github.com/cake-tech/cake_wallet into cw_linux_direct_input_password
Conflicts: assets/text/Monerocom_Release_Notes.txt assets/text/Release_Notes.txt cw_bitcoin/pubspec.lock cw_core/lib/node.dart cw_core/pubspec.lock cw_core/pubspec.yaml cw_ethereum/lib/ethereum_wallet.dart cw_monero/example/pubspec.lock cw_monero/ios/Classes/monero_api.cpp cw_monero/pubspec.lock cw_polygon/lib/polygon_wallet.dart lib/di.dart lib/router.dart lib/src/screens/restore/wallet_restore_from_seed_form.dart lib/src/screens/wallet_list/wallet_list_page.dart lib/store/settings_store.dart scripts/android/app_env.sh scripts/android/pubspec_gen.sh scripts/ios/app_env.sh scripts/macos/app_env.sh
This commit is contained in:
commit
f747773f3a
123 changed files with 10611 additions and 711 deletions
29
.github/workflows/pr_test_build.yml
vendored
29
.github/workflows/pr_test_build.yml
vendored
|
@ -3,6 +3,12 @@ name: PR Test Build
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
branch:
|
||||||
|
description: 'Branch name to build'
|
||||||
|
required: true
|
||||||
|
default: 'main'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
PR_test_build:
|
PR_test_build:
|
||||||
|
@ -12,6 +18,14 @@ jobs:
|
||||||
KEY_PASS: test@cake_wallet
|
KEY_PASS: test@cake_wallet
|
||||||
|
|
||||||
steps:
|
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 Up GitHub Actions Ubuntu Runner Disk Space
|
- name: Free Up GitHub Actions Ubuntu Runner Disk Space
|
||||||
run: |
|
run: |
|
||||||
sudo rm -rf /usr/share/dotnet
|
sudo rm -rf /usr/share/dotnet
|
||||||
|
@ -40,7 +54,7 @@ jobs:
|
||||||
cd /opt/android
|
cd /opt/android
|
||||||
-y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
-y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
cargo install cargo-ndk
|
cargo install cargo-ndk
|
||||||
git clone https://github.com/cake-tech/cake_wallet.git --branch $GITHUB_HEAD_REF
|
git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
|
||||||
cd cake_wallet/scripts/android/
|
cd cake_wallet/scripts/android/
|
||||||
./install_ndk.sh
|
./install_ndk.sh
|
||||||
source ./app_env.sh cakewallet
|
source ./app_env.sh cakewallet
|
||||||
|
@ -105,6 +119,7 @@ jobs:
|
||||||
cd /opt/android/cake_wallet
|
cd /opt/android/cake_wallet
|
||||||
touch lib/.secrets.g.dart
|
touch lib/.secrets.g.dart
|
||||||
touch cw_ethereum/lib/.secrets.g.dart
|
touch cw_ethereum/lib/.secrets.g.dart
|
||||||
|
touch cw_polygon/lib/.secrets.g.dart
|
||||||
echo "const salt = '${{ secrets.SALT }}';" > 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 keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
|
||||||
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
|
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
@ -132,16 +147,16 @@ jobs:
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> 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 payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
||||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
|
||||||
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> 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 exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
|
||||||
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
|
||||||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> 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 moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
|
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
|
||||||
|
|
||||||
- name: Rename app
|
- name: Rename app
|
||||||
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties
|
run: echo -e "id=com.cakewallet.test\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
|
@ -156,7 +171,7 @@ jobs:
|
||||||
# appcenter distribute release \
|
# appcenter distribute release \
|
||||||
# --group "Testers" \
|
# --group "Testers" \
|
||||||
# --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
|
# --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
|
||||||
# --release-notes ${GITHUB_HEAD_REF} \
|
# --release-notes ${{ env.BRANCH_NAME }} \
|
||||||
# --app Cake-Labs/Cake-Wallet \
|
# --app Cake-Labs/Cake-Wallet \
|
||||||
# --token ${{ secrets.APP_CENTER_TOKEN }} \
|
# --token ${{ secrets.APP_CENTER_TOKEN }} \
|
||||||
# --quiet
|
# --quiet
|
||||||
|
@ -165,7 +180,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
cd /opt/android/cake_wallet/build/app/outputs/apk/release
|
cd /opt/android/cake_wallet/build/app/outputs/apk/release
|
||||||
mkdir test-apk
|
mkdir test-apk
|
||||||
cp app-release.apk test-apk/$GITHUB_HEAD_REF.apk
|
cp app-release.apk test-apk/${{env.BRANCH_NAME}}.apk
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: kittaakos/upload-artifact-as-is@v0
|
uses: kittaakos/upload-artifact-as-is@v0
|
||||||
|
@ -179,6 +194,6 @@ jobs:
|
||||||
token: ${{ secrets.SLACK_APP_TOKEN }}
|
token: ${{ secrets.SLACK_APP_TOKEN }}
|
||||||
path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
|
path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
|
||||||
channel: ${{ secrets.SLACK_APK_CHANNEL }}
|
channel: ${{ secrets.SLACK_APK_CHANNEL }}
|
||||||
title: "${{github.head_ref}}.apk"
|
title: "${{ env.BRANCH_NAME }}.apk"
|
||||||
filename: ${{github.head_ref}}.apk
|
filename: ${{ env.BRANCH_NAME }}.apk
|
||||||
initial_comment: ${{ github.event.head_commit.message }}
|
initial_comment: ${{ github.event.head_commit.message }}
|
||||||
|
|
BIN
assets/images/dfx_dark.png
Normal file
BIN
assets/images/dfx_dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
BIN
assets/images/dfx_light.png
Normal file
BIN
assets/images/dfx_light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
|
@ -1,6 +1,6 @@
|
||||||
-
|
|
||||||
uri: polygon-bor.publicnode.com
|
|
||||||
-
|
-
|
||||||
uri: polygon-rpc.com
|
uri: polygon-rpc.com
|
||||||
|
-
|
||||||
|
uri: polygon-bor.publicnode.com
|
||||||
-
|
-
|
||||||
uri: polygon.llamarpc.com
|
uri: polygon.llamarpc.com
|
|
@ -1,2 +1,4 @@
|
||||||
Monero Polyseed support, create and restore from a 16 words phrase and without the need to remember the wallet creation date
|
Polyseed enhancements
|
||||||
Bug fixes and enhancements
|
New on-ramp provider DFX
|
||||||
|
Usability enhancements
|
||||||
|
Bug fixes
|
|
@ -1,3 +1,6 @@
|
||||||
Monero Polyseed support, create and restore from a 16 words phrase and without the need to remember the wallet creation date
|
Add Polygon (Matic) wallet
|
||||||
Add NFTs tab to see all of your purchased NFTs on Ethereum
|
Polyseed enhancements
|
||||||
Bug fixes and enhancements
|
New on-ramp provider DFX
|
||||||
|
Usability enhancements
|
||||||
|
Bitcoin enhancements
|
||||||
|
Bug fixes
|
8717
assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt
Normal file
8717
assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt
Normal file
File diff suppressed because it is too large
Load diff
|
@ -4,7 +4,10 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
|
|
||||||
class ElectrumBalance extends Balance {
|
class ElectrumBalance extends Balance {
|
||||||
const ElectrumBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
|
const ElectrumBalance(
|
||||||
|
{required this.confirmed,
|
||||||
|
required this.unconfirmed,
|
||||||
|
required this.frozen})
|
||||||
: super(confirmed, unconfirmed);
|
: super(confirmed, unconfirmed);
|
||||||
|
|
||||||
static ElectrumBalance? fromJSON(String? jsonSource) {
|
static ElectrumBalance? fromJSON(String? jsonSource) {
|
||||||
|
@ -25,16 +28,19 @@ class ElectrumBalance extends Balance {
|
||||||
final int frozen;
|
final int frozen;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
|
String get formattedAvailableBalance =>
|
||||||
|
bitcoinAmountToString(amount: confirmed - unconfirmed.abs() - frozen);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
|
String get formattedAdditionalBalance =>
|
||||||
|
bitcoinAmountToString(amount: unconfirmed);
|
||||||
|
|
||||||
String get formattedFrozenBalance {
|
@override
|
||||||
|
String get formattedUnAvailableBalance {
|
||||||
final frozenFormatted = bitcoinAmountToString(amount: frozen);
|
final frozenFormatted = bitcoinAmountToString(amount: frozen);
|
||||||
return frozenFormatted == '0.0' ? '' : frozenFormatted;
|
return frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||||
}
|
}
|
||||||
|
|
||||||
String toJSON() =>
|
String toJSON() => json.encode(
|
||||||
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
|
{'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ abstract class ElectrumWalletBase
|
||||||
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/0");
|
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/0");
|
||||||
|
|
||||||
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
|
||||||
inputsCount * 146 + outputsCounts * 33 + 8;
|
inputsCount * 68 + outputsCounts * 34 + 10;
|
||||||
|
|
||||||
final bitcoin.HDWallet hd;
|
final bitcoin.HDWallet hd;
|
||||||
final String mnemonic;
|
final String mnemonic;
|
||||||
|
@ -735,8 +735,7 @@ abstract class ElectrumWalletBase
|
||||||
final index = address != null
|
final index = address != null
|
||||||
? walletAddresses.addresses.firstWhere((element) => element.address == address).index
|
? walletAddresses.addresses.firstWhere((element) => element.address == address).index
|
||||||
: null;
|
: null;
|
||||||
return index == null
|
final HD = index == null ? hd : hd.derive(index);
|
||||||
? base64Encode(hd.sign(message))
|
return base64Encode(HD.signMessage(message));
|
||||||
: base64Encode(hd.derive(index).sign(message));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,11 +79,11 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
resolved-ref: df9204144011ed9419eff7d9ef3143102a40252d
|
resolved-ref: e19ffb7e7977278a75b27e0479b3c6f4034223b3
|
||||||
url: "https://github.com/cake-tech/bitcoin_flutter.git"
|
url: "https://github.com/cake-tech/bitcoin_flutter.git"
|
||||||
source: git
|
source: git
|
||||||
version: "2.0.2"
|
version: "2.1.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -164,15 +164,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.4.3"
|
version: "8.4.3"
|
||||||
cake_backup:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
|
||||||
url: "https://github.com/cake-tech/cake_backup.git"
|
|
||||||
source: git
|
|
||||||
version: "1.0.0+1"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -237,14 +228,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.5"
|
version: "2.0.5"
|
||||||
cupertino_icons:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.6"
|
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -261,7 +244,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.4"
|
version: "2.2.4"
|
||||||
encrypt:
|
encrypt:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: encrypt
|
name: encrypt
|
||||||
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
|
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
|
||||||
|
@ -715,23 +698,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
tor:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
|
||||||
url: "https://github.com/cake-tech/tor.git"
|
|
||||||
source: git
|
|
||||||
version: "0.0.1"
|
|
||||||
tuple:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: tuple
|
|
||||||
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.2"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -22,7 +22,7 @@ dependencies:
|
||||||
bitcoin_flutter:
|
bitcoin_flutter:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
url: https://github.com/cake-tech/bitcoin_flutter.git
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
bitbox:
|
bitbox:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
|
|
|
@ -309,10 +309,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
||||||
final index = address != null
|
final index = address != null
|
||||||
? walletAddresses.addresses
|
? walletAddresses.addresses
|
||||||
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
|
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
|
||||||
.index
|
.index : null;
|
||||||
: null;
|
final HD = index == null ? hd : hd.derive(index);
|
||||||
return index == null
|
return base64Encode(HD.signMessage(message));
|
||||||
? base64Encode(hd.sign(message))
|
|
||||||
: base64Encode(hd.derive(index).sign(message));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ dependencies:
|
||||||
bitcoin_flutter:
|
bitcoin_flutter:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
url: https://github.com/cake-tech/bitcoin_flutter.git
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
bitbox:
|
bitbox:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||||
|
|
|
@ -93,6 +93,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
CryptoCurrency.dydx,
|
CryptoCurrency.dydx,
|
||||||
CryptoCurrency.steth,
|
CryptoCurrency.steth,
|
||||||
CryptoCurrency.banano,
|
CryptoCurrency.banano,
|
||||||
|
CryptoCurrency.usdtPoly,
|
||||||
|
CryptoCurrency.usdcEPoly,
|
||||||
];
|
];
|
||||||
|
|
||||||
static const havenCurrencies = [
|
static const havenCurrencies = [
|
||||||
|
@ -202,6 +204,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18);
|
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18);
|
||||||
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png', decimals: 18);
|
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png', decimals: 18);
|
||||||
static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29);
|
static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29);
|
||||||
|
static const usdtPoly = CryptoCurrency(title: 'USDT', tag: 'POLY', fullName: 'Tether USD (PoS)', raw: 87, name: 'usdtpoly', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
|
||||||
|
static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POLY', fullName: 'USD Coin (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
|
||||||
|
|
||||||
|
|
||||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||||
|
|
|
@ -18,6 +18,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
||||||
bool _enabled;
|
bool _enabled;
|
||||||
@HiveField(5)
|
@HiveField(5)
|
||||||
final String? iconPath;
|
final String? iconPath;
|
||||||
|
@HiveField(6)
|
||||||
|
final String? tag;
|
||||||
|
|
||||||
bool get enabled => _enabled;
|
bool get enabled => _enabled;
|
||||||
|
|
||||||
|
@ -30,30 +32,31 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
||||||
required this.decimal,
|
required this.decimal,
|
||||||
bool enabled = true,
|
bool enabled = true,
|
||||||
this.iconPath,
|
this.iconPath,
|
||||||
|
this.tag,
|
||||||
}) : _enabled = enabled,
|
}) : _enabled = enabled,
|
||||||
super(
|
super(
|
||||||
name: symbol.toLowerCase(),
|
name: symbol.toLowerCase(),
|
||||||
title: symbol.toUpperCase(),
|
title: symbol.toUpperCase(),
|
||||||
fullName: name,
|
fullName: name,
|
||||||
tag: "ETH",
|
tag: tag,
|
||||||
iconPath: iconPath,
|
iconPath: iconPath,
|
||||||
decimals: decimal
|
decimals: decimal);
|
||||||
);
|
|
||||||
|
|
||||||
Erc20Token.copyWith(Erc20Token other, String? icon)
|
Erc20Token.copyWith(Erc20Token other, String? icon, String? tag)
|
||||||
: this.name = other.name,
|
: this.name = other.name,
|
||||||
this.symbol = other.symbol,
|
this.symbol = other.symbol,
|
||||||
this.contractAddress = other.contractAddress,
|
this.contractAddress = other.contractAddress,
|
||||||
this.decimal = other.decimal,
|
this.decimal = other.decimal,
|
||||||
this._enabled = other.enabled,
|
this._enabled = other.enabled,
|
||||||
|
this.tag = tag,
|
||||||
this.iconPath = icon,
|
this.iconPath = icon,
|
||||||
super(
|
super(
|
||||||
name: other.name,
|
name: other.name,
|
||||||
title: other.symbol.toUpperCase(),
|
title: other.symbol.toUpperCase(),
|
||||||
fullName: other.name,
|
fullName: other.name,
|
||||||
tag: "ETH",
|
tag: tag,
|
||||||
iconPath: icon,
|
iconPath: icon,
|
||||||
decimals: other.decimal
|
decimals: other.decimal,
|
||||||
);
|
);
|
||||||
|
|
||||||
static const typeId = ERC20_TOKEN_TYPE_ID;
|
static const typeId = ERC20_TOKEN_TYPE_ID;
|
||||||
|
@ -61,7 +64,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
||||||
static const polygonBoxName = ' PolygonErc20Tokens';
|
static const polygonBoxName = ' PolygonErc20Tokens';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(other) => (other is Erc20Token && other.contractAddress == contractAddress) ||
|
bool operator ==(other) =>
|
||||||
|
(other is Erc20Token && other.contractAddress == contractAddress) ||
|
||||||
(other is CryptoCurrency && other.title == title);
|
(other is CryptoCurrency && other.title == title);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -113,15 +113,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.4.3"
|
version: "8.4.3"
|
||||||
cake_backup:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
|
||||||
url: "https://github.com/cake-tech/cake_backup.git"
|
|
||||||
source: git
|
|
||||||
version: "1.0.0+1"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -178,22 +169,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
cryptography:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cryptography
|
|
||||||
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
cupertino_icons:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.6"
|
|
||||||
dart_style:
|
dart_style:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -641,23 +616,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
tor:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
|
||||||
url: "https://github.com/cake-tech/tor.git"
|
|
||||||
source: git
|
|
||||||
version: "0.0.1"
|
|
||||||
tuple:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: tuple
|
|
||||||
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.2"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -300,10 +300,6 @@ class DefaultErc20Tokens {
|
||||||
.iconPath;
|
.iconPath;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
if (iconPath != null) {
|
return Erc20Token.copyWith(token, iconPath, 'ETH');
|
||||||
return Erc20Token.copyWith(token, iconPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
|
@ -78,19 +78,18 @@ class EthereumClient {
|
||||||
currency == CryptoCurrency.maticpoly ||
|
currency == CryptoCurrency.maticpoly ||
|
||||||
contractAddress != null);
|
contractAddress != null);
|
||||||
|
|
||||||
bool _isEVMCompatibleChain = currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
|
bool _isEVMCompatibleChain =
|
||||||
|
currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
|
||||||
|
|
||||||
final price = _client!.getGasPrice();
|
final price = _client!.getGasPrice();
|
||||||
|
|
||||||
final Transaction transaction = Transaction(
|
final Transaction transaction = createTransaction(
|
||||||
from: privateKey.address,
|
from: privateKey.address,
|
||||||
to: EthereumAddress.fromHex(toAddress),
|
to: EthereumAddress.fromHex(toAddress),
|
||||||
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
|
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
|
||||||
value: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
|
amount: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
|
||||||
);
|
);
|
||||||
|
|
||||||
final chainId = _getChainIdForCurrency(currency);
|
|
||||||
|
|
||||||
final signedTransaction =
|
final signedTransaction =
|
||||||
await _client!.signTransaction(privateKey, transaction, chainId: chainId);
|
await _client!.signTransaction(privateKey, transaction, chainId: chainId);
|
||||||
|
|
||||||
|
@ -124,18 +123,27 @@ class EthereumClient {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _getChainIdForCurrency(CryptoCurrency currency) {
|
int get chainId => 1;
|
||||||
switch (currency) {
|
|
||||||
case CryptoCurrency.maticpoly:
|
Transaction createTransaction({
|
||||||
return 137;
|
required EthereumAddress from,
|
||||||
case CryptoCurrency.eth:
|
required EthereumAddress to,
|
||||||
default:
|
required EtherAmount amount,
|
||||||
return 1;
|
EtherAmount? maxPriorityFeePerGas,
|
||||||
}
|
}) {
|
||||||
|
return Transaction(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
maxPriorityFeePerGas: maxPriorityFeePerGas,
|
||||||
|
value: amount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> sendTransaction(Uint8List signedTransaction) async =>
|
Future<String> sendTransaction(Uint8List signedTransaction) async =>
|
||||||
await _client!.sendRawTransaction(prependTransactionType(0x02, signedTransaction));
|
await _client!.sendRawTransaction(prepareSignedTransactionForSending(signedTransaction));
|
||||||
|
|
||||||
|
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) =>
|
||||||
|
prependTransactionType(0x02, signedTransaction);
|
||||||
|
|
||||||
Future getTransactionDetails(String transactionHash) async {
|
Future getTransactionDetails(String transactionHash) async {
|
||||||
// Wait for the transaction receipt to become available
|
// Wait for the transaction receipt to become available
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/wallet_addresses.dart';
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_ethereum/default_ethereum_erc20_tokens.dart';
|
||||||
import 'package:cw_ethereum/default_erc20_tokens.dart';
|
import 'package:cw_ethereum/default_erc20_tokens.dart';
|
||||||
import 'package:cw_core/encryption_file_utils.dart';
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
import 'package:cw_ethereum/erc20_balance.dart';
|
import 'package:cw_ethereum/erc20_balance.dart';
|
||||||
|
@ -439,6 +440,7 @@ abstract class EthereumWalletBase
|
||||||
contractAddress: token.contractAddress,
|
contractAddress: token.contractAddress,
|
||||||
decimal: token.decimal,
|
decimal: token.decimal,
|
||||||
enabled: token.enabled,
|
enabled: token.enabled,
|
||||||
|
tag: token.tag ?? "ETH",
|
||||||
iconPath: iconPath,
|
iconPath: iconPath,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -502,7 +504,7 @@ abstract class EthereumWalletBase
|
||||||
_transactionsUpdateTimer!.cancel();
|
_transactionsUpdateTimer!.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) {
|
_transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 10), (_) {
|
||||||
_updateTransactions();
|
_updateTransactions();
|
||||||
_updateBalance();
|
_updateBalance();
|
||||||
});
|
});
|
||||||
|
@ -521,7 +523,7 @@ abstract class EthereumWalletBase
|
||||||
String get password => _password;
|
String get password => _password;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String signMessage(String message, {String? address = null}) =>
|
String signMessage(String message, {String? address}) =>
|
||||||
bytesToHex(_ethPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
|
bytesToHex(_ethPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
|
||||||
|
|
||||||
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
||||||
|
|
|
@ -33,15 +33,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
cake_backup:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
|
||||||
url: "https://github.com/cake-tech/cake_backup.git"
|
|
||||||
source: git
|
|
||||||
version: "1.0.0+1"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -82,14 +73,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
cryptography:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cryptography
|
|
||||||
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -170,6 +153,22 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
hashlib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hashlib
|
||||||
|
sha256: "71bf102329ddb8e50c8a995ee4645ae7f1728bb65e575c17196b4d8262121a96"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.12.0"
|
||||||
|
hashlib_codecs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hashlib_codecs
|
||||||
|
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -325,12 +324,11 @@ packages:
|
||||||
polyseed:
|
polyseed:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
path: "."
|
name: polyseed
|
||||||
ref: HEAD
|
sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
|
||||||
resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7"
|
url: "https://pub.dev"
|
||||||
url: "https://github.com/cake-tech/polyseed_dart.git"
|
source: hosted
|
||||||
source: git
|
version: "0.0.2"
|
||||||
version: "0.0.1"
|
|
||||||
process:
|
process:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -400,23 +398,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.5.1"
|
||||||
tor:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
|
||||||
url: "https://github.com/cake-tech/tor.git"
|
|
||||||
source: git
|
|
||||||
version: "0.0.1"
|
|
||||||
tuple:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: tuple
|
|
||||||
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.2"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -988,6 +988,8 @@ extern "C"
|
||||||
return m_wallet->trustedDaemon();
|
return m_wallet->trustedDaemon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Coin Control //
|
||||||
|
|
||||||
FUNCTION_VISABILITY_ATTRIBUTE
|
FUNCTION_VISABILITY_ATTRIBUTE
|
||||||
CoinsInfoRow* coin(int index)
|
CoinsInfoRow* coin(int index)
|
||||||
{
|
{
|
||||||
|
@ -1085,6 +1087,13 @@ extern "C"
|
||||||
m_coins->thaw(index);
|
m_coins->thaw(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign Messages //
|
||||||
|
|
||||||
|
char *sign_message(char *message, char *address = "")
|
||||||
|
{
|
||||||
|
return strdup(get_current_wallet()->signMessage(std::string(message), std::string(address)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@ void store(char *path);
|
||||||
|
|
||||||
void set_trusted_daemon(bool arg);
|
void set_trusted_daemon(bool arg);
|
||||||
bool trusted_daemon();
|
bool trusted_daemon();
|
||||||
|
char *sign_message(char *message, char *address);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,3 +149,5 @@ typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
|
||||||
typedef freeze_coin = Void Function(Int32 index);
|
typedef freeze_coin = Void Function(Int32 index);
|
||||||
|
|
||||||
typedef thaw_coin = Void Function(Int32 index);
|
typedef thaw_coin = Void Function(Int32 index);
|
||||||
|
|
||||||
|
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);
|
||||||
|
|
|
@ -149,3 +149,5 @@ typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
|
||||||
typedef FreezeCoin = void Function(int);
|
typedef FreezeCoin = void Function(int);
|
||||||
|
|
||||||
typedef ThawCoin = void Function(int);
|
typedef ThawCoin = void Function(int);
|
||||||
|
|
||||||
|
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);
|
||||||
|
|
|
@ -8,7 +8,6 @@ import 'package:cw_monero/api/types.dart';
|
||||||
import 'package:cw_monero/api/monero_api.dart';
|
import 'package:cw_monero/api/monero_api.dart';
|
||||||
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
|
|
||||||
int _boolToInt(bool value) => value ? 1 : 0;
|
int _boolToInt(bool value) => value ? 1 : 0;
|
||||||
|
|
||||||
|
@ -128,6 +127,10 @@ final trustedDaemonNative = moneroApi
|
||||||
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
|
||||||
.asFunction<TrustedDaemon>();
|
.asFunction<TrustedDaemon>();
|
||||||
|
|
||||||
|
final signMessageNative = moneroApi
|
||||||
|
.lookup<NativeFunction<sign_message>>('sign_message')
|
||||||
|
.asFunction<SignMessage>();
|
||||||
|
|
||||||
int getSyncingHeight() => getSyncingHeightNative();
|
int getSyncingHeight() => getSyncingHeightNative();
|
||||||
|
|
||||||
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
|
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
|
||||||
|
@ -296,7 +299,7 @@ class SyncListener {
|
||||||
|
|
||||||
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
|
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
|
||||||
|
|
||||||
if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
|
if (_lastKnownBlockHeight == syncHeight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +314,7 @@ class SyncListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
|
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
|
||||||
onNewBlock?.call(syncHeight, left, ptc);
|
onNewBlock.call(syncHeight, left, ptc);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,3 +386,14 @@ String getSubaddressLabel(int accountIndex, int addressIndex) {
|
||||||
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
|
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
|
||||||
|
|
||||||
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
|
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
|
||||||
|
|
||||||
|
String signMessage(String message, {String address = ""}) {
|
||||||
|
final messagePointer = message.toNativeUtf8();
|
||||||
|
final addressPointer = address.toNativeUtf8();
|
||||||
|
|
||||||
|
final signature = convertUTF8ToString(pointer: signMessageNative(messagePointer, addressPointer));
|
||||||
|
calloc.free(messagePointer);
|
||||||
|
calloc.free(addressPointer);
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
|
@ -662,4 +662,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => _onError = onError;
|
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => _onError = onError;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String signMessage(String message, {String? address}) {
|
||||||
|
final useAddress = address ?? "";
|
||||||
|
return monero_wallet.signMessage(message, address: useAddress);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
||||||
import 'package:cw_monero/monero_wallet.dart';
|
import 'package:cw_monero/monero_wallet.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:polyseed/polyseed.dart';
|
import 'package:polyseed/polyseed.dart';
|
||||||
import 'package:polyseed/src/utils/key_utils.dart';
|
|
||||||
|
|
||||||
class MoneroNewWalletCredentials extends WalletCredentials {
|
class MoneroNewWalletCredentials extends WalletCredentials {
|
||||||
MoneroNewWalletCredentials({required String name, required this.language, required this.isPolyseed, String? password})
|
MoneroNewWalletCredentials({required String name, required this.language, required this.isPolyseed, String? password})
|
||||||
|
@ -287,7 +286,7 @@ class MoneroWalletService extends WalletService<
|
||||||
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
|
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
|
||||||
final height = overrideHeight ?? getMoneroHeigthByDate(
|
final height = overrideHeight ?? getMoneroHeigthByDate(
|
||||||
date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
|
date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
|
||||||
final spendKey = keyToHexString(polyseed.generateKey(coin, 32));
|
final spendKey = polyseed.generateKey(coin, 32).toHexString();
|
||||||
final seed = polyseed.encode(lang, coin);
|
final seed = polyseed.encode(lang, coin);
|
||||||
|
|
||||||
walletInfo.isRecovery = true;
|
walletInfo.isRecovery = true;
|
||||||
|
|
|
@ -1019,6 +1019,13 @@ extern "C"
|
||||||
m_coins->thaw(index);
|
m_coins->thaw(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sign Messages //
|
||||||
|
|
||||||
|
char *sign_message(char *message, char *address = "")
|
||||||
|
{
|
||||||
|
return strdup(get_current_wallet()->signMessage(std::string(message), std::string(address)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -32,6 +32,7 @@ void store(char *path);
|
||||||
|
|
||||||
void set_trusted_daemon(bool arg);
|
void set_trusted_daemon(bool arg);
|
||||||
bool trusted_daemon();
|
bool trusted_daemon();
|
||||||
|
char *sign_message(char *message, char *address);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,15 +113,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.4.3"
|
version: "8.4.3"
|
||||||
cake_backup:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
|
||||||
url: "https://github.com/cake-tech/cake_backup.git"
|
|
||||||
source: git
|
|
||||||
version: "1.0.0+1"
|
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -178,22 +169,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.2"
|
||||||
cryptography:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cryptography
|
|
||||||
sha256: df156c5109286340817d21fa7b62f9140f17915077127dd70f8bd7a2a0997a35
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
cupertino_icons:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: cupertino_icons
|
|
||||||
sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.6"
|
|
||||||
cw_core:
|
cw_core:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -291,6 +266,22 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.0"
|
version: "2.2.0"
|
||||||
|
hashlib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hashlib
|
||||||
|
sha256: "71bf102329ddb8e50c8a995ee4645ae7f1728bb65e575c17196b4d8262121a96"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.12.0"
|
||||||
|
hashlib_codecs:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hashlib_codecs
|
||||||
|
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.0"
|
||||||
hive:
|
hive:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -510,12 +501,11 @@ packages:
|
||||||
polyseed:
|
polyseed:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
name: polyseed
|
||||||
ref: HEAD
|
sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
|
||||||
resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7"
|
url: "https://pub.dev"
|
||||||
url: "https://github.com/cake-tech/polyseed_dart.git"
|
source: hosted
|
||||||
source: git
|
version: "0.0.2"
|
||||||
version: "0.0.1"
|
|
||||||
pool:
|
pool:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -657,23 +647,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
tor:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
path: "."
|
|
||||||
ref: main
|
|
||||||
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
|
|
||||||
url: "https://github.com/cake-tech/tor.git"
|
|
||||||
source: git
|
|
||||||
version: "0.0.1"
|
|
||||||
tuple:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: tuple
|
|
||||||
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.2"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -19,9 +19,7 @@ dependencies:
|
||||||
flutter_mobx: ^2.0.6+1
|
flutter_mobx: ^2.0.6+1
|
||||||
intl: ^0.18.0
|
intl: ^0.18.0
|
||||||
encrypt: ^5.0.1
|
encrypt: ^5.0.1
|
||||||
polyseed:
|
polyseed: ^0.0.2
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/polyseed_dart.git
|
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class DefaultPolygonErc20Tokens {
|
||||||
symbol: "USDC.e",
|
symbol: "USDC.e",
|
||||||
contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
|
contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
|
||||||
decimal: 6,
|
decimal: 6,
|
||||||
enabled: false,
|
enabled: true,
|
||||||
),
|
),
|
||||||
Erc20Token(
|
Erc20Token(
|
||||||
name: "Avalanche Token",
|
name: "Avalanche Token",
|
||||||
|
@ -73,14 +73,10 @@ class DefaultPolygonErc20Tokens {
|
||||||
try {
|
try {
|
||||||
iconPath = CryptoCurrency.all
|
iconPath = CryptoCurrency.all
|
||||||
.firstWhere((element) =>
|
.firstWhere((element) =>
|
||||||
element.title.toUpperCase() == token.symbol.toUpperCase())
|
element.title.toUpperCase() == token.symbol.split(".").first.toUpperCase())
|
||||||
.iconPath;
|
.iconPath;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
if (iconPath != null) {
|
return Erc20Token.copyWith(token, iconPath, 'POLY');
|
||||||
return Erc20Token.copyWith(token, iconPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
return token;
|
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
|
@ -3,8 +3,30 @@ import 'dart:convert';
|
||||||
import 'package:cw_ethereum/ethereum_client.dart';
|
import 'package:cw_ethereum/ethereum_client.dart';
|
||||||
import 'package:cw_polygon/polygon_transaction_model.dart';
|
import 'package:cw_polygon/polygon_transaction_model.dart';
|
||||||
import 'package:cw_ethereum/.secrets.g.dart' as secrets;
|
import 'package:cw_ethereum/.secrets.g.dart' as secrets;
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:web3dart/web3dart.dart';
|
||||||
|
|
||||||
class PolygonClient extends EthereumClient {
|
class PolygonClient extends EthereumClient {
|
||||||
|
@override
|
||||||
|
Transaction createTransaction({
|
||||||
|
required EthereumAddress from,
|
||||||
|
required EthereumAddress to,
|
||||||
|
required EtherAmount amount,
|
||||||
|
EtherAmount? maxPriorityFeePerGas,
|
||||||
|
}) {
|
||||||
|
return Transaction(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
value: amount,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) => signedTransaction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get chainId => 137;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<PolygonTransactionModel>> fetchTransactions(String address,
|
Future<List<PolygonTransactionModel>> fetchTransactions(String address,
|
||||||
{String? contractAddress}) async {
|
{String? contractAddress}) async {
|
||||||
|
@ -27,7 +49,6 @@ class PolygonClient extends EthereumClient {
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e);
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,9 +17,9 @@ import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_ethereum/erc20_balance.dart';
|
import 'package:cw_ethereum/erc20_balance.dart';
|
||||||
import 'package:cw_ethereum/ethereum_formatter.dart';
|
import 'package:cw_ethereum/ethereum_formatter.dart';
|
||||||
import 'package:cw_ethereum/ethereum_transaction_model.dart';
|
import 'package:cw_ethereum/file.dart';
|
||||||
import 'package:cw_core/erc20_token.dart';
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_polygon/default_erc20_tokens.dart';
|
import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
|
||||||
import 'package:cw_polygon/polygon_client.dart';
|
import 'package:cw_polygon/polygon_client.dart';
|
||||||
import 'package:cw_polygon/polygon_exceptions.dart';
|
import 'package:cw_polygon/polygon_exceptions.dart';
|
||||||
import 'package:cw_polygon/polygon_formatter.dart';
|
import 'package:cw_polygon/polygon_formatter.dart';
|
||||||
|
@ -42,28 +42,26 @@ part 'polygon_wallet.g.dart';
|
||||||
|
|
||||||
class PolygonWallet = PolygonWalletBase with _$PolygonWallet;
|
class PolygonWallet = PolygonWalletBase with _$PolygonWallet;
|
||||||
|
|
||||||
abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
abstract class PolygonWalletBase
|
||||||
PolygonTransactionHistory, PolygonTransactionInfo> with Store {
|
extends WalletBase<ERC20Balance, PolygonTransactionHistory, PolygonTransactionInfo> with Store {
|
||||||
PolygonWalletBase({
|
PolygonWalletBase({
|
||||||
required WalletInfo walletInfo,
|
required WalletInfo walletInfo,
|
||||||
String? mnemonic,
|
String? mnemonic,
|
||||||
String? privateKey,
|
String? privateKey,
|
||||||
required String password,
|
required String password,
|
||||||
ERC20Balance? initialBalance,
|
ERC20Balance? initialBalance,
|
||||||
}) : syncStatus = NotConnectedSyncStatus(),
|
}) : syncStatus = const NotConnectedSyncStatus(),
|
||||||
_password = password,
|
_password = password,
|
||||||
_mnemonic = mnemonic,
|
_mnemonic = mnemonic,
|
||||||
_hexPrivateKey = privateKey,
|
_hexPrivateKey = privateKey,
|
||||||
_isTransactionUpdating = false,
|
_isTransactionUpdating = false,
|
||||||
_client = PolygonClient(),
|
_client = PolygonClient(),
|
||||||
walletAddresses = PolygonWalletAddresses(walletInfo),
|
walletAddresses = PolygonWalletAddresses(walletInfo),
|
||||||
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of({
|
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of(
|
||||||
CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero)
|
{CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero)}),
|
||||||
}),
|
|
||||||
super(walletInfo) {
|
super(walletInfo) {
|
||||||
this.walletInfo = walletInfo;
|
this.walletInfo = walletInfo;
|
||||||
transactionHistory =
|
transactionHistory = PolygonTransactionHistory(walletInfo: walletInfo, password: password);
|
||||||
PolygonTransactionHistory(walletInfo: walletInfo, password: password);
|
|
||||||
|
|
||||||
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
||||||
CakeHive.registerAdapter(Erc20TokenAdapter());
|
CakeHive.registerAdapter(Erc20TokenAdapter());
|
||||||
|
@ -80,9 +78,9 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
|
|
||||||
late final EthPrivateKey _polygonPrivateKey;
|
late final EthPrivateKey _polygonPrivateKey;
|
||||||
|
|
||||||
EthPrivateKey get polygonPrivateKey => _polygonPrivateKey;
|
late final PolygonClient _client;
|
||||||
|
|
||||||
late PolygonClient _client;
|
EthPrivateKey get polygonPrivateKey => _polygonPrivateKey;
|
||||||
|
|
||||||
int? _gasPrice;
|
int? _gasPrice;
|
||||||
int? _estimatedGas;
|
int? _estimatedGas;
|
||||||
|
@ -102,11 +100,11 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
@observable
|
@observable
|
||||||
late ObservableMap<CryptoCurrency, ERC20Balance> balance;
|
late ObservableMap<CryptoCurrency, ERC20Balance> balance;
|
||||||
|
|
||||||
Completer<SharedPreferences> _sharedPrefs = Completer();
|
final Completer<SharedPreferences> _sharedPrefs = Completer();
|
||||||
|
|
||||||
Future<void> init() async {
|
Future<void> init() async {
|
||||||
polygonErc20TokensBox =
|
polygonErc20TokensBox = await CakeHive.openBox<Erc20Token>(
|
||||||
await CakeHive.openBox<Erc20Token>(Erc20Token.polygonBoxName);
|
"${walletInfo.name.replaceAll(" ", "_")}_${Erc20Token.polygonBoxName}");
|
||||||
await walletAddresses.init();
|
await walletAddresses.init();
|
||||||
await transactionHistory.init();
|
await transactionHistory.init();
|
||||||
_polygonPrivateKey = await getPrivateKey(
|
_polygonPrivateKey = await getPrivateKey(
|
||||||
|
@ -122,8 +120,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
||||||
try {
|
try {
|
||||||
if (priority is PolygonTransactionPriority) {
|
if (priority is PolygonTransactionPriority) {
|
||||||
final priorityFee =
|
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||||
EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
|
||||||
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
|
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,33 +165,29 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||||
final _credentials = credentials as PolygonTransactionCredentials;
|
final credentials0 = credentials as PolygonTransactionCredentials;
|
||||||
final outputs = _credentials.outputs;
|
final outputs = credentials0.outputs;
|
||||||
final hasMultiDestination = outputs.length > 1;
|
final hasMultiDestination = outputs.length > 1;
|
||||||
|
|
||||||
final CryptoCurrency transactionCurrency = balance.keys
|
final CryptoCurrency transactionCurrency =
|
||||||
.firstWhere((element) => element.title == _credentials.currency.title);
|
balance.keys.firstWhere((element) => element.title == credentials0.currency.title);
|
||||||
|
|
||||||
final _erc20Balance = balance[transactionCurrency]!;
|
final erc20Balance = balance[transactionCurrency]!;
|
||||||
BigInt totalAmount = BigInt.zero;
|
BigInt totalAmount = BigInt.zero;
|
||||||
int exponent =
|
int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
|
||||||
transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
|
|
||||||
num amountToPolygonMultiplier = pow(10, exponent);
|
num amountToPolygonMultiplier = pow(10, exponent);
|
||||||
|
|
||||||
// so far this can not be made with Polygon as Polygon does not support multiple recipients
|
// so far this can not be made with Polygon as Polygon does not support multiple recipients
|
||||||
if (hasMultiDestination) {
|
if (hasMultiDestination) {
|
||||||
if (outputs.any(
|
if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
|
||||||
(item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
|
|
||||||
throw PolygonTransactionCreationException(transactionCurrency);
|
throw PolygonTransactionCreationException(transactionCurrency);
|
||||||
}
|
}
|
||||||
|
|
||||||
final totalOriginalAmount = PolygonFormatter.parsePolygonAmountToDouble(
|
final totalOriginalAmount = PolygonFormatter.parsePolygonAmountToDouble(
|
||||||
outputs.fold(
|
outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
|
||||||
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
|
totalAmount = BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
|
||||||
totalAmount =
|
|
||||||
BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
|
|
||||||
|
|
||||||
if (_erc20Balance.balance < totalAmount) {
|
if (erc20Balance.balance < totalAmount) {
|
||||||
throw PolygonTransactionCreationException(transactionCurrency);
|
throw PolygonTransactionCreationException(transactionCurrency);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,35 +196,33 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
// then no need to subtract the fees from the amount if send all
|
// then no need to subtract the fees from the amount if send all
|
||||||
final BigInt allAmount;
|
final BigInt allAmount;
|
||||||
if (transactionCurrency is Erc20Token) {
|
if (transactionCurrency is Erc20Token) {
|
||||||
allAmount = _erc20Balance.balance;
|
allAmount = erc20Balance.balance;
|
||||||
} else {
|
} else {
|
||||||
allAmount = _erc20Balance.balance -
|
allAmount =
|
||||||
BigInt.from(calculateEstimatedFee(_credentials.priority!, null));
|
erc20Balance.balance - BigInt.from(calculateEstimatedFee(credentials0.priority!, null));
|
||||||
}
|
}
|
||||||
final totalOriginalAmount = EthereumFormatter.parseEthereumAmountToDouble(
|
final totalOriginalAmount =
|
||||||
output.formattedCryptoAmount ?? 0);
|
EthereumFormatter.parseEthereumAmountToDouble(output.formattedCryptoAmount ?? 0);
|
||||||
totalAmount = output.sendAll
|
totalAmount =
|
||||||
? allAmount
|
output.sendAll ? allAmount : BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
|
||||||
: BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
|
|
||||||
|
|
||||||
if (_erc20Balance.balance < totalAmount) {
|
if (erc20Balance.balance < totalAmount) {
|
||||||
throw PolygonTransactionCreationException(transactionCurrency);
|
throw PolygonTransactionCreationException(transactionCurrency);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final pendingPolygonTransaction = await _client.signTransaction(
|
final pendingPolygonTransaction = await _client.signTransaction(
|
||||||
privateKey: _polygonPrivateKey,
|
privateKey: _polygonPrivateKey,
|
||||||
toAddress: _credentials.outputs.first.isParsedAddress
|
toAddress: credentials0.outputs.first.isParsedAddress
|
||||||
? _credentials.outputs.first.extractedAddress!
|
? credentials0.outputs.first.extractedAddress!
|
||||||
: _credentials.outputs.first.address,
|
: credentials0.outputs.first.address,
|
||||||
amount: totalAmount.toString(),
|
amount: totalAmount.toString(),
|
||||||
gas: _estimatedGas!,
|
gas: _estimatedGas!,
|
||||||
priority: _credentials.priority!,
|
priority: credentials0.priority!,
|
||||||
currency: transactionCurrency,
|
currency: transactionCurrency,
|
||||||
exponent: exponent,
|
exponent: exponent,
|
||||||
contractAddress: transactionCurrency is Erc20Token
|
contractAddress:
|
||||||
? transactionCurrency.contractAddress
|
transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null,
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return pendingPolygonTransaction;
|
return pendingPolygonTransaction;
|
||||||
|
@ -262,15 +253,16 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
final address = _polygonPrivateKey.address.hex;
|
final address = _polygonPrivateKey.address.hex;
|
||||||
final transactions = await _client.fetchTransactions(address);
|
final transactions = await _client.fetchTransactions(address);
|
||||||
|
|
||||||
final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions =
|
final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions = [];
|
||||||
[];
|
|
||||||
|
|
||||||
for (var token in balance.keys) {
|
for (var token in balance.keys) {
|
||||||
if (token is Erc20Token) {
|
if (token is Erc20Token) {
|
||||||
polygonErc20TokensTransactions.add(_client.fetchTransactions(
|
polygonErc20TokensTransactions.add(
|
||||||
|
_client.fetchTransactions(
|
||||||
address,
|
address,
|
||||||
contractAddress: token.contractAddress,
|
contractAddress: token.contractAddress,
|
||||||
) as Future<List<PolygonTransactionModel>>);
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,8 +286,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
isPending: false,
|
isPending: false,
|
||||||
date: transactionModel.date,
|
date: transactionModel.date,
|
||||||
confirmations: transactionModel.confirmations,
|
confirmations: transactionModel.confirmations,
|
||||||
ethFee:
|
ethFee: BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
|
||||||
BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
|
|
||||||
exponent: transactionModel.tokenDecimal ?? 18,
|
exponent: transactionModel.tokenDecimal ?? 18,
|
||||||
tokenSymbol: transactionModel.tokenSymbol ?? "MATIC",
|
tokenSymbol: transactionModel.tokenSymbol ?? "MATIC",
|
||||||
to: transactionModel.to,
|
to: transactionModel.to,
|
||||||
|
@ -337,8 +328,8 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
_gasPrice = await _client.getGasUnitPrice();
|
_gasPrice = await _client.getGasUnitPrice();
|
||||||
_estimatedGas = await _client.getEstimatedGas();
|
_estimatedGas = await _client.getEstimatedGas();
|
||||||
|
|
||||||
Timer.periodic(const Duration(minutes: 1),
|
Timer.periodic(
|
||||||
(timer) async => _gasPrice = await _client.getGasUnitPrice());
|
const Duration(minutes: 1), (timer) async => _gasPrice = await _client.getGasUnitPrice());
|
||||||
Timer.periodic(const Duration(seconds: 10),
|
Timer.periodic(const Duration(seconds: 10),
|
||||||
(timer) async => _estimatedGas = await _client.getEstimatedGas());
|
(timer) async => _estimatedGas = await _client.getEstimatedGas());
|
||||||
|
|
||||||
|
@ -348,8 +339,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> makePath() async =>
|
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||||
pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
|
||||||
|
|
||||||
String toJSON() => json.encode({
|
String toJSON() => json.encode({
|
||||||
'mnemonic': _mnemonic,
|
'mnemonic': _mnemonic,
|
||||||
|
@ -367,8 +357,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
final data = json.decode(jsonSource) as Map;
|
final data = json.decode(jsonSource) as Map;
|
||||||
final mnemonic = data['mnemonic'] as String?;
|
final mnemonic = data['mnemonic'] as String?;
|
||||||
final privateKey = data['private_key'] as String?;
|
final privateKey = data['private_key'] as String?;
|
||||||
final balance = ERC20Balance.fromJSON(data['balance'] as String) ??
|
final balance = ERC20Balance.fromJSON(data['balance'] as String) ?? ERC20Balance(BigInt.zero);
|
||||||
ERC20Balance(BigInt.zero);
|
|
||||||
|
|
||||||
return PolygonWallet(
|
return PolygonWallet(
|
||||||
walletInfo: walletInfo,
|
walletInfo: walletInfo,
|
||||||
|
@ -418,14 +407,14 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
|
|
||||||
final root = bip32.BIP32.fromSeed(seed);
|
final root = bip32.BIP32.fromSeed(seed);
|
||||||
|
|
||||||
const _hdPathPolygon = "m/44'/60'/0'/0";
|
const hdPathPolygon = "m/44'/60'/0'/0";
|
||||||
const index = 0;
|
const index = 0;
|
||||||
final addressAtIndex = root.derivePath("$_hdPathPolygon/$index");
|
final addressAtIndex = root.derivePath("$hdPathPolygon/$index");
|
||||||
|
|
||||||
return EthPrivateKey.fromHex(
|
return EthPrivateKey.fromHex(HEX.encode(addressAtIndex.privateKey as List<int>));
|
||||||
HEX.encode(addressAtIndex.privateKey as List<int>));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<void>? updateBalance() async => await _updateBalance();
|
Future<void>? updateBalance() async => await _updateBalance();
|
||||||
|
|
||||||
List<Erc20Token> get erc20Currencies => polygonErc20TokensBox.values.toList();
|
List<Erc20Token> get erc20Currencies => polygonErc20TokensBox.values.toList();
|
||||||
|
@ -434,29 +423,29 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
String? iconPath;
|
String? iconPath;
|
||||||
try {
|
try {
|
||||||
iconPath = CryptoCurrency.all
|
iconPath = CryptoCurrency.all
|
||||||
.firstWhere((element) =>
|
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
|
||||||
element.title.toUpperCase() == token.symbol.toUpperCase())
|
|
||||||
.iconPath;
|
.iconPath;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
final _token = Erc20Token(
|
final token0 = Erc20Token(
|
||||||
name: token.name,
|
name: token.name,
|
||||||
symbol: token.symbol,
|
symbol: token.symbol,
|
||||||
contractAddress: token.contractAddress,
|
contractAddress: token.contractAddress,
|
||||||
decimal: token.decimal,
|
decimal: token.decimal,
|
||||||
enabled: token.enabled,
|
enabled: token.enabled,
|
||||||
|
tag: token.tag ?? "POLY",
|
||||||
iconPath: iconPath,
|
iconPath: iconPath,
|
||||||
);
|
);
|
||||||
|
|
||||||
await polygonErc20TokensBox.put(_token.contractAddress, _token);
|
await polygonErc20TokensBox.put(token0.contractAddress, token0);
|
||||||
|
|
||||||
if (_token.enabled) {
|
if (token0.enabled) {
|
||||||
balance[_token] = await _client.fetchERC20Balances(
|
balance[token0] = await _client.fetchERC20Balances(
|
||||||
_polygonPrivateKey.address,
|
_polygonPrivateKey.address,
|
||||||
_token.contractAddress,
|
token0.contractAddress,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
balance.remove(_token);
|
balance.remove(token0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,8 +465,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
}
|
}
|
||||||
|
|
||||||
void addInitialTokens() {
|
void addInitialTokens() {
|
||||||
final initialErc20Tokens =
|
final initialErc20Tokens = DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
|
||||||
DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
|
|
||||||
|
|
||||||
for (var token in initialErc20Tokens) {
|
for (var token in initialErc20Tokens) {
|
||||||
polygonErc20TokensBox.put(token.contractAddress, token);
|
polygonErc20TokensBox.put(token.contractAddress, token);
|
||||||
|
@ -486,26 +474,20 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> renameWalletFiles(String newWalletName) async {
|
Future<void> renameWalletFiles(String newWalletName) async {
|
||||||
final currentWalletPath =
|
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
|
||||||
await pathForWallet(name: walletInfo.name, type: type);
|
|
||||||
final currentWalletFile = File(currentWalletPath);
|
final currentWalletFile = File(currentWalletPath);
|
||||||
|
|
||||||
final currentDirPath =
|
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
|
||||||
await pathForWalletDir(name: walletInfo.name, type: type);
|
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
|
||||||
final currentTransactionsFile =
|
|
||||||
File('$currentDirPath/$transactionsHistoryFileName');
|
|
||||||
|
|
||||||
// Copies current wallet files into new wallet name's dir and files
|
// Copies current wallet files into new wallet name's dir and files
|
||||||
if (currentWalletFile.existsSync()) {
|
if (currentWalletFile.existsSync()) {
|
||||||
final newWalletPath =
|
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
|
||||||
await pathForWallet(name: newWalletName, type: type);
|
|
||||||
await currentWalletFile.copy(newWalletPath);
|
await currentWalletFile.copy(newWalletPath);
|
||||||
}
|
}
|
||||||
if (currentTransactionsFile.existsSync()) {
|
if (currentTransactionsFile.existsSync()) {
|
||||||
final newDirPath =
|
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
|
||||||
await pathForWalletDir(name: newWalletName, type: type);
|
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
|
||||||
await currentTransactionsFile
|
|
||||||
.copy('$newDirPath/$transactionsHistoryFileName');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete old name's dir and files
|
// Delete old name's dir and files
|
||||||
|
@ -517,7 +499,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
_transactionsUpdateTimer!.cancel();
|
_transactionsUpdateTimer!.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) {
|
_transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 10), (_) {
|
||||||
_updateTransactions();
|
_updateTransactions();
|
||||||
_updateBalance();
|
_updateBalance();
|
||||||
});
|
});
|
||||||
|
@ -536,8 +518,8 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
|
||||||
String get password => _password;
|
String get password => _password;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String signMessage(String message, {String? address = null}) => bytesToHex(
|
String signMessage(String message, {String? address}) =>
|
||||||
_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
|
bytesToHex(_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
|
||||||
|
|
||||||
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
Web3Client? getWeb3Client() => _client.getWeb3Client();
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,6 +122,8 @@ PODS:
|
||||||
- Flutter
|
- Flutter
|
||||||
- MTBBarcodeScanner (5.0.11)
|
- MTBBarcodeScanner (5.0.11)
|
||||||
- OrderedSet (5.0.0)
|
- OrderedSet (5.0.0)
|
||||||
|
- package_info (0.0.1):
|
||||||
|
- Flutter
|
||||||
- package_info_plus (0.4.5):
|
- package_info_plus (0.4.5):
|
||||||
- Flutter
|
- Flutter
|
||||||
- path_provider_foundation (0.0.1):
|
- path_provider_foundation (0.0.1):
|
||||||
|
@ -143,8 +145,6 @@ PODS:
|
||||||
- SwiftProtobuf (1.22.0)
|
- SwiftProtobuf (1.22.0)
|
||||||
- SwiftyGif (5.4.4)
|
- SwiftyGif (5.4.4)
|
||||||
- Toast (4.0.0)
|
- Toast (4.0.0)
|
||||||
- tor (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- uni_links (0.0.1):
|
- uni_links (0.0.1):
|
||||||
- Flutter
|
- Flutter
|
||||||
- UnstoppableDomainsResolution (4.0.0):
|
- UnstoppableDomainsResolution (4.0.0):
|
||||||
|
@ -175,13 +175,13 @@ DEPENDENCIES:
|
||||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||||
|
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||||
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
|
||||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||||
- tor (from `.symlinks/plugins/tor/ios`)
|
|
||||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||||
|
@ -236,6 +236,8 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/in_app_review/ios"
|
:path: ".symlinks/plugins/in_app_review/ios"
|
||||||
local_auth_ios:
|
local_auth_ios:
|
||||||
:path: ".symlinks/plugins/local_auth_ios/ios"
|
:path: ".symlinks/plugins/local_auth_ios/ios"
|
||||||
|
package_info:
|
||||||
|
:path: ".symlinks/plugins/package_info/ios"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
:path: ".symlinks/plugins/package_info_plus/ios"
|
:path: ".symlinks/plugins/package_info_plus/ios"
|
||||||
path_provider_foundation:
|
path_provider_foundation:
|
||||||
|
@ -248,8 +250,6 @@ EXTERNAL SOURCES:
|
||||||
:path: ".symlinks/plugins/share_plus/ios"
|
:path: ".symlinks/plugins/share_plus/ios"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||||
tor:
|
|
||||||
:path: ".symlinks/plugins/tor/ios"
|
|
||||||
uni_links:
|
uni_links:
|
||||||
:path: ".symlinks/plugins/uni_links/ios"
|
:path: ".symlinks/plugins/uni_links/ios"
|
||||||
url_launcher_ios:
|
url_launcher_ios:
|
||||||
|
@ -282,6 +282,7 @@ SPEC CHECKSUMS:
|
||||||
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
|
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
|
||||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||||
|
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||||
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
|
||||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||||
|
@ -293,7 +294,6 @@ SPEC CHECKSUMS:
|
||||||
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
|
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
|
||||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||||
tor: 662a9f5b980b5c86decb8ba611de9bcd4c8286eb
|
|
||||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||||
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
url_launcher_ios: bf5ce03e0e2088bad9cc378ea97fa0ed5b49673b
|
||||||
|
|
179
lib/buy/dfx/dfx_buy_provider.dart
Normal file
179
lib/buy/dfx/dfx_buy_provider.dart
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
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/device_info.dart';
|
||||||
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
class DFXBuyProvider {
|
||||||
|
DFXBuyProvider({required WalletBase wallet}) : this._wallet = wallet;
|
||||||
|
|
||||||
|
final WalletBase _wallet;
|
||||||
|
|
||||||
|
static const _baseUrl = 'api.dfx.swiss';
|
||||||
|
static const _authPath = '/v1/auth/signMessage';
|
||||||
|
static const _signUpPath = '/v1/auth/signUp';
|
||||||
|
static const _signInPath = '/v1/auth/signIn';
|
||||||
|
static const walletName = 'CakeWallet';
|
||||||
|
|
||||||
|
String get assetOut {
|
||||||
|
switch (_wallet.type) {
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
return 'BTC';
|
||||||
|
case WalletType.bitcoinCash:
|
||||||
|
return 'BCH';
|
||||||
|
case WalletType.litecoin:
|
||||||
|
return 'LTC';
|
||||||
|
case WalletType.monero:
|
||||||
|
return 'XMR';
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return 'ETH';
|
||||||
|
default:
|
||||||
|
throw Exception("WalletType is not available for DFX ${_wallet.type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String get blockchain {
|
||||||
|
switch (_wallet.type) {
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.bitcoinCash:
|
||||||
|
case WalletType.litecoin:
|
||||||
|
return 'Bitcoin';
|
||||||
|
case WalletType.monero:
|
||||||
|
return 'Monero';
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return 'Ethereum';
|
||||||
|
default:
|
||||||
|
throw Exception("WalletType is not available for DFX ${_wallet.type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getSignMessage() async {
|
||||||
|
final walletAddress = _wallet.walletAddresses.address;
|
||||||
|
final uri = Uri.https(_baseUrl, _authPath, {'address': walletAddress});
|
||||||
|
|
||||||
|
var response = await http.get(uri, headers: {'accept': 'application/json'});
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final responseBody = jsonDecode(response.body);
|
||||||
|
return responseBody['message'] as String;
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
'Failed to get sign message. Status: ${response.statusCode} ${response.body}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> signUp() async {
|
||||||
|
final signMessage = getSignature(await getSignMessage());
|
||||||
|
final walletAddress = _wallet.walletAddresses.address;
|
||||||
|
|
||||||
|
final requestBody = jsonEncode({
|
||||||
|
'wallet': walletName,
|
||||||
|
'address': walletAddress,
|
||||||
|
'signature': signMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
final uri = Uri.https(_baseUrl, _signUpPath);
|
||||||
|
var response = await http.post(uri,
|
||||||
|
headers: {'Content-Type': 'application/json'}, body: requestBody);
|
||||||
|
|
||||||
|
if (response.statusCode == 201) {
|
||||||
|
final responseBody = jsonDecode(response.body);
|
||||||
|
return responseBody['accessToken'] as String;
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
'Failed to sign up. Status: ${response.statusCode} ${response.body}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> signIn() async {
|
||||||
|
final signMessage = getSignature(await getSignMessage());
|
||||||
|
final walletAddress = _wallet.walletAddresses.address;
|
||||||
|
|
||||||
|
final requestBody = jsonEncode({
|
||||||
|
'address': walletAddress,
|
||||||
|
'signature': signMessage,
|
||||||
|
});
|
||||||
|
|
||||||
|
final uri = Uri.https(_baseUrl, _signInPath);
|
||||||
|
var response = await http.post(uri,
|
||||||
|
headers: {'Content-Type': 'application/json'}, body: requestBody);
|
||||||
|
|
||||||
|
if (response.statusCode == 201) {
|
||||||
|
final responseBody = jsonDecode(response.body);
|
||||||
|
return responseBody['accessToken'] as String;
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
'Failed to sign in. Status: ${response.statusCode} ${response.body}');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getSignature(String message) {
|
||||||
|
switch (_wallet.type) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return _wallet.signMessage(message);
|
||||||
|
case WalletType.monero:
|
||||||
|
case WalletType.litecoin:
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.bitcoinCash:
|
||||||
|
return _wallet.signMessage(message,
|
||||||
|
address: _wallet.walletAddresses.address);
|
||||||
|
default:
|
||||||
|
throw Exception("WalletType is not available for DFX ${_wallet.type}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> launchProvider(BuildContext context) async {
|
||||||
|
try {
|
||||||
|
final assetOut = this.assetOut;
|
||||||
|
final blockchain = this.blockchain;
|
||||||
|
|
||||||
|
String accessToken;
|
||||||
|
|
||||||
|
try {
|
||||||
|
accessToken = await signUp();
|
||||||
|
} on Exception catch (e) {
|
||||||
|
if (e.toString().contains('409')) {
|
||||||
|
accessToken = await signIn();
|
||||||
|
} else {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final uri = Uri.https('services.dfx.swiss', '/buy', {
|
||||||
|
'session': accessToken,
|
||||||
|
'lang': 'en',
|
||||||
|
'asset-out': assetOut,
|
||||||
|
'blockchain': blockchain,
|
||||||
|
'asset-in': 'EUR',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (await canLaunchUrl(uri)) {
|
||||||
|
if (DeviceInfo.instance.isMobile) {
|
||||||
|
Navigator.of(context).pushNamed(Routes.webViewPage,
|
||||||
|
arguments: [S.of(context).buy, uri]);
|
||||||
|
} else {
|
||||||
|
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Could not launch URL');
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertWithOneAction(
|
||||||
|
alertTitle: "DFX Connect",
|
||||||
|
alertContent: S.of(context).buy_provider_unavailable + ': $e',
|
||||||
|
buttonText: S.of(context).ok,
|
||||||
|
buttonAction: () => Navigator.of(context).pop());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -32,6 +32,8 @@ class AddressValidator extends TextValidator {
|
||||||
return '[0-9a-zA-Z_]';
|
return '[0-9a-zA-Z_]';
|
||||||
case CryptoCurrency.usdc:
|
case CryptoCurrency.usdc:
|
||||||
case CryptoCurrency.usdcpoly:
|
case CryptoCurrency.usdcpoly:
|
||||||
|
case CryptoCurrency.usdtPoly:
|
||||||
|
case CryptoCurrency.usdcEPoly:
|
||||||
case CryptoCurrency.ape:
|
case CryptoCurrency.ape:
|
||||||
case CryptoCurrency.avaxc:
|
case CryptoCurrency.avaxc:
|
||||||
case CryptoCurrency.eth:
|
case CryptoCurrency.eth:
|
||||||
|
@ -141,6 +143,8 @@ class AddressValidator extends TextValidator {
|
||||||
return [42];
|
return [42];
|
||||||
case CryptoCurrency.eth:
|
case CryptoCurrency.eth:
|
||||||
case CryptoCurrency.usdcpoly:
|
case CryptoCurrency.usdcpoly:
|
||||||
|
case CryptoCurrency.usdtPoly:
|
||||||
|
case CryptoCurrency.usdcEPoly:
|
||||||
case CryptoCurrency.mana:
|
case CryptoCurrency.mana:
|
||||||
case CryptoCurrency.matic:
|
case CryptoCurrency.matic:
|
||||||
case CryptoCurrency.maticpoly:
|
case CryptoCurrency.maticpoly:
|
||||||
|
|
|
@ -285,10 +285,12 @@ class EvmChainServiceImpl implements ChainService {
|
||||||
}
|
}
|
||||||
|
|
||||||
String _convertToReadable(Map<String, dynamic> data) {
|
String _convertToReadable(Map<String, dynamic> data) {
|
||||||
|
final tokenName = getTokenNameBasedOnWalletType(appStore.wallet!.type);
|
||||||
String gas = int.parse((data['gas'] as String).substring(2), radix: 16).toString();
|
String gas = int.parse((data['gas'] as String).substring(2), radix: 16).toString();
|
||||||
String value = data['value'] != null
|
String value = data['value'] != null
|
||||||
? (int.parse((data['value'] as String).substring(2), radix: 16) / 1e18).toString() + ' ETH'
|
? (int.parse((data['value'] as String).substring(2), radix: 16) / 1e18).toString() +
|
||||||
: '0 ETH';
|
' $tokenName'
|
||||||
|
: '0 $tokenName';
|
||||||
String from = data['from'] as String;
|
String from = data['from'] as String;
|
||||||
String to = data['to'] as String;
|
String to = data['to'] as String;
|
||||||
|
|
||||||
|
|
27
lib/di.dart
27
lib/di.dart
|
@ -22,7 +22,6 @@ import 'package:cake_wallet/ionia/ionia_anypay.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
import 'package:cake_wallet/ionia/ionia_gift_card.dart';
|
||||||
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
import 'package:cake_wallet/ionia/ionia_tip.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
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/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
import 'package:cake_wallet/src/screens/buy/buy_options_page.dart';
|
||||||
|
@ -100,6 +99,7 @@ import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dar
|
||||||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
|
import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||||
|
@ -243,6 +243,7 @@ import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
|
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_page.dart';
|
||||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||||
|
|
||||||
|
import 'buy/dfx/dfx_buy_provider.dart';
|
||||||
import 'core/totp_request_details.dart';
|
import 'core/totp_request_details.dart';
|
||||||
import 'src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
import 'src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
||||||
|
|
||||||
|
@ -386,7 +387,8 @@ Future<void> setup({
|
||||||
settingsStore: settingsStore,
|
settingsStore: settingsStore,
|
||||||
yatStore: getIt.get<YatStore>(),
|
yatStore: getIt.get<YatStore>(),
|
||||||
ordersStore: getIt.get<OrdersStore>(),
|
ordersStore: getIt.get<OrdersStore>(),
|
||||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>()));
|
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
|
||||||
|
keyService: getIt.get<KeyService>()));
|
||||||
|
|
||||||
getIt.registerFactory<AuthService>(
|
getIt.registerFactory<AuthService>(
|
||||||
() => AuthService(
|
() => AuthService(
|
||||||
|
@ -731,6 +733,8 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
getIt.registerFactory(() => WalletSeedViewModel(getIt.get<AppStore>().wallet!));
|
||||||
|
|
||||||
|
getIt.registerFactory<SeedTypeViewModel>(() => SeedTypeViewModel(getIt.get<AppStore>()));
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
|
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
|
||||||
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
|
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
|
||||||
|
|
||||||
|
@ -761,13 +765,7 @@ Future<void> setup({
|
||||||
return PowNodeListViewModel(_powNodeSource, appStore);
|
return PowNodeListViewModel(_powNodeSource, appStore);
|
||||||
});
|
});
|
||||||
|
|
||||||
getIt.registerFactory(() {
|
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
|
||||||
final wallet = getIt.get<AppStore>().wallet;
|
|
||||||
return ConnectionSyncPage(
|
|
||||||
getIt.get<DashboardViewModel>(),
|
|
||||||
isEVMCompatibleChain(wallet!.type) ? getIt.get<Web3WalletService>() : null,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
getIt.registerFactory(
|
getIt.registerFactory(
|
||||||
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
||||||
|
@ -808,6 +806,9 @@ Future<void> setup({
|
||||||
getIt.registerFactory<RobinhoodBuyProvider>(
|
getIt.registerFactory<RobinhoodBuyProvider>(
|
||||||
() => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
() => RobinhoodBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||||
|
|
||||||
|
getIt
|
||||||
|
.registerFactory<DFXBuyProvider>(() => DFXBuyProvider(wallet: getIt.get<AppStore>().wallet!));
|
||||||
|
|
||||||
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
getIt.registerFactory<OnRamperBuyProvider>(() => OnRamperBuyProvider(
|
||||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||||
wallet: getIt.get<AppStore>().wallet!,
|
wallet: getIt.get<AppStore>().wallet!,
|
||||||
|
@ -893,8 +894,8 @@ Future<void> setup({
|
||||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||||
type: type));
|
type: type));
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>(
|
getIt.registerFactoryParam<WalletRestorePage, WalletType, void>((type, _) => WalletRestorePage(
|
||||||
(type, _) => WalletRestorePage(getIt.get<WalletRestoreViewModel>(param1: type)));
|
getIt.get<WalletRestoreViewModel>(param1: type), getIt.get<SeedTypeViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>(
|
getIt.registerFactoryParam<WalletRestoreChooseDerivationViewModel, List<DerivationInfo>, void>(
|
||||||
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
|
(derivations, _) => WalletRestoreChooseDerivationViewModel(derivationInfos: derivations));
|
||||||
|
@ -925,7 +926,7 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactoryParam<PreSeedPage, WalletType, AdvancedPrivacySettingsViewModel>(
|
getIt.registerFactoryParam<PreSeedPage, WalletType, AdvancedPrivacySettingsViewModel>(
|
||||||
(WalletType type, AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel) =>
|
(WalletType type, AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel) =>
|
||||||
PreSeedPage(type, advancedPrivacySettingsViewModel));
|
PreSeedPage(type, advancedPrivacySettingsViewModel, getIt.get<SeedTypeViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
getIt.registerFactoryParam<TradeDetailsViewModel, Trade, void>((trade, _) =>
|
||||||
TradeDetailsViewModel(
|
TradeDetailsViewModel(
|
||||||
|
@ -958,7 +959,7 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactory(() => BuyAmountViewModel());
|
getIt.registerFactory(() => BuyAmountViewModel());
|
||||||
|
|
||||||
getIt.registerFactory(() => BuyOptionsPage());
|
getIt.registerFactory(() => BuyOptionsPage(getIt.get<DashboardViewModel>()));
|
||||||
|
|
||||||
getIt.registerFactory(() {
|
getIt.registerFactory(() {
|
||||||
final wallet = getIt.get<AppStore>().wallet;
|
final wallet = getIt.get<AppStore>().wallet;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
enum BuyProviderType {
|
enum BuyProviderType {
|
||||||
AskEachTime,
|
AskEachTime,
|
||||||
Robinhood,
|
Robinhood,
|
||||||
Onramper;
|
Onramper,
|
||||||
|
DFX;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
|
@ -14,6 +16,42 @@ enum BuyProviderType {
|
||||||
return "Robinhood";
|
return "Robinhood";
|
||||||
case BuyProviderType.Onramper:
|
case BuyProviderType.Onramper:
|
||||||
return "Onramper";
|
return "Onramper";
|
||||||
|
case BuyProviderType.DFX:
|
||||||
|
return "DFX";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<BuyProviderType> getAvailableProviders(WalletType walletType) {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.nano:
|
||||||
|
case WalletType.banano:
|
||||||
|
return [
|
||||||
|
BuyProviderType.AskEachTime,
|
||||||
|
BuyProviderType.Onramper
|
||||||
|
];
|
||||||
|
case WalletType.monero:
|
||||||
|
return [
|
||||||
|
BuyProviderType.AskEachTime,
|
||||||
|
BuyProviderType.Onramper,
|
||||||
|
BuyProviderType.DFX
|
||||||
|
];
|
||||||
|
case WalletType.bitcoin:
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return [
|
||||||
|
BuyProviderType.AskEachTime,
|
||||||
|
BuyProviderType.Onramper,
|
||||||
|
BuyProviderType.DFX,
|
||||||
|
BuyProviderType.Robinhood
|
||||||
|
];
|
||||||
|
case WalletType.litecoin:
|
||||||
|
case WalletType.bitcoinCash:
|
||||||
|
return [
|
||||||
|
BuyProviderType.AskEachTime,
|
||||||
|
BuyProviderType.Onramper,
|
||||||
|
BuyProviderType.Robinhood
|
||||||
|
];
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,6 @@ Future<void> defaultSettingsMigration(
|
||||||
case 25:
|
case 25:
|
||||||
await rewriteSecureStoragePin(secureStorage: secureStorage);
|
await rewriteSecureStoragePin(secureStorage: secureStorage);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
34
lib/entities/list_order_mode.dart
Normal file
34
lib/entities/list_order_mode.dart
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cw_core/enumerable_item.dart';
|
||||||
|
|
||||||
|
class ListOrderMode extends EnumerableItem<int> with Serializable<int> {
|
||||||
|
const ListOrderMode({required String title, required int raw}) : super(title: title, raw: raw);
|
||||||
|
|
||||||
|
static const all = [ListOrderMode.ascending, ListOrderMode.descending];
|
||||||
|
|
||||||
|
static const ascending = ListOrderMode(raw: 0, title: 'Ascending');
|
||||||
|
static const descending = ListOrderMode(raw: 1, title: 'Descending');
|
||||||
|
|
||||||
|
static ListOrderMode deserialize({required int raw}) {
|
||||||
|
switch (raw) {
|
||||||
|
case 0:
|
||||||
|
return ascending;
|
||||||
|
case 1:
|
||||||
|
return descending;
|
||||||
|
default:
|
||||||
|
throw Exception('Unexpected token: $raw for ListOrderMode deserialize');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (this) {
|
||||||
|
case ListOrderMode.ascending:
|
||||||
|
return S.current.ascending;
|
||||||
|
case ListOrderMode.descending:
|
||||||
|
return S.current.descending;
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||||
|
@ -44,18 +45,22 @@ class MainActions {
|
||||||
isEnabled: (viewModel) => viewModel.isEnabledBuyAction,
|
isEnabled: (viewModel) => viewModel.isEnabledBuyAction,
|
||||||
canShow: (viewModel) => viewModel.hasBuyAction,
|
canShow: (viewModel) => viewModel.hasBuyAction,
|
||||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||||
|
if (!viewModel.isEnabledBuyAction) {
|
||||||
|
await _showErrorDialog(context, S.of(context).unsupported_asset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final defaultBuyProvider = viewModel.defaultBuyProvider;
|
final defaultBuyProvider = viewModel.defaultBuyProvider;
|
||||||
final walletType = viewModel.type;
|
try {
|
||||||
|
await _launchProviderByType(context, defaultBuyProvider);
|
||||||
|
} catch (e) {
|
||||||
|
await _showErrorDialog(context, e.toString());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (!viewModel.isEnabledBuyAction) return;
|
static Future<void> _launchProviderByType(BuildContext context, BuyProviderType providerType) async {
|
||||||
|
switch (providerType) {
|
||||||
switch (walletType) {
|
|
||||||
case WalletType.bitcoin:
|
|
||||||
case WalletType.litecoin:
|
|
||||||
case WalletType.ethereum:
|
|
||||||
case WalletType.polygon:
|
|
||||||
case WalletType.bitcoinCash:
|
|
||||||
switch (defaultBuyProvider) {
|
|
||||||
case BuyProviderType.AskEachTime:
|
case BuyProviderType.AskEachTime:
|
||||||
Navigator.pushNamed(context, Routes.buy);
|
Navigator.pushNamed(context, Routes.buy);
|
||||||
break;
|
break;
|
||||||
|
@ -65,26 +70,28 @@ class MainActions {
|
||||||
case BuyProviderType.Robinhood:
|
case BuyProviderType.Robinhood:
|
||||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context);
|
await getIt.get<RobinhoodBuyProvider>().launchProvider(context);
|
||||||
break;
|
break;
|
||||||
}
|
case BuyProviderType.DFX:
|
||||||
break;
|
await getIt.get<DFXBuyProvider>().launchProvider(context);
|
||||||
case WalletType.nano:
|
|
||||||
case WalletType.banano:
|
|
||||||
case WalletType.monero:
|
|
||||||
await getIt.get<OnRamperBuyProvider>().launchProvider(context);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
throw UnsupportedError('Unsupported buy provider type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Future<void> _showErrorDialog(BuildContext context, String errorMessage) async {
|
||||||
await showPopUp<void>(
|
await showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertWithOneAction(
|
return AlertWithOneAction(
|
||||||
alertTitle: S.of(context).buy,
|
alertTitle: S.of(context).buy,
|
||||||
alertContent: S.of(context).unsupported_asset,
|
alertContent: errorMessage,
|
||||||
buttonText: S.of(context).ok,
|
buttonText: S.of(context).ok,
|
||||||
buttonAction: () => Navigator.of(context).pop());
|
buttonAction: () => Navigator.of(context).pop(),
|
||||||
});
|
);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static MainActions receiveAction = MainActions._(
|
static MainActions receiveAction = MainActions._(
|
||||||
name: (context) => S.of(context).receive,
|
name: (context) => S.of(context).receive,
|
||||||
|
|
|
@ -85,8 +85,7 @@ Future<List<Node>> loadDefaultEthereumNodes() async {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Node>> loadBitcoinCashElectrumServerList() async {
|
Future<List<Node>> loadBitcoinCashElectrumServerList() async {
|
||||||
final serverListRaw =
|
final serverListRaw = await rootBundle.loadString('assets/bitcoin_cash_electrum_server_list.yml');
|
||||||
await rootBundle.loadString('assets/bitcoin_cash_electrum_server_list.yml');
|
|
||||||
final loadedServerList = loadYaml(serverListRaw) as YamlList;
|
final loadedServerList = loadYaml(serverListRaw) as YamlList;
|
||||||
final serverList = <Node>[];
|
final serverList = <Node>[];
|
||||||
|
|
||||||
|
@ -141,6 +140,7 @@ Future<List<Node>> loadDefaultPolygonNodes() async {
|
||||||
for (final raw in loadedNodes) {
|
for (final raw in loadedNodes) {
|
||||||
if (raw is Map) {
|
if (raw is Map) {
|
||||||
final node = Node.fromMap(Map<String, Object>.from(raw));
|
final node = Node.fromMap(Map<String, Object>.from(raw));
|
||||||
|
|
||||||
node.type = WalletType.polygon;
|
node.type = WalletType.polygon;
|
||||||
nodes.add(node);
|
nodes.add(node);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,6 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||||
final nanoNodes = await loadDefaultNanoNodes();
|
final nanoNodes = await loadDefaultNanoNodes();
|
||||||
final polygonNodes = await loadDefaultPolygonNodes();
|
final polygonNodes = await loadDefaultPolygonNodes();
|
||||||
|
|
||||||
|
|
||||||
final nodes = moneroNodes +
|
final nodes = moneroNodes +
|
||||||
bitcoinElectrumServerList +
|
bitcoinElectrumServerList +
|
||||||
litecoinElectrumServerList +
|
litecoinElectrumServerList +
|
||||||
|
|
|
@ -20,6 +20,8 @@ class PreferencesKey {
|
||||||
static const disableBuyKey = 'disable_buy';
|
static const disableBuyKey = 'disable_buy';
|
||||||
static const disableSellKey = 'disable_sell';
|
static const disableSellKey = 'disable_sell';
|
||||||
static const defaultBuyProvider = 'default_buy_provider';
|
static const defaultBuyProvider = 'default_buy_provider';
|
||||||
|
static const walletListOrder = 'wallet_list_order';
|
||||||
|
static const walletListAscending = 'wallet_list_ascending';
|
||||||
static const currentFiatApiModeKey = 'current_fiat_api_mode';
|
static const currentFiatApiModeKey = 'current_fiat_api_mode';
|
||||||
static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication';
|
static const allowBiometricalAuthenticationKey = 'allow_biometrical_authentication';
|
||||||
static const useTOTP2FA = 'use_totp_2fa';
|
static const useTOTP2FA = 'use_totp_2fa';
|
||||||
|
|
|
@ -6,7 +6,7 @@ class SeedType extends EnumerableItem<int> with Serializable<int> {
|
||||||
|
|
||||||
static const all = [SeedType.legacy, SeedType.polyseed];
|
static const all = [SeedType.legacy, SeedType.polyseed];
|
||||||
|
|
||||||
static const defaultSeedType = legacy;
|
static const defaultSeedType = polyseed;
|
||||||
|
|
||||||
static const legacy = SeedType(raw: 0, title: 'Legacy (25 words)');
|
static const legacy = SeedType(raw: 0, title: 'Legacy (25 words)');
|
||||||
static const polyseed = SeedType(raw: 1, title: 'Polyseed (16 words)');
|
static const polyseed = SeedType(raw: 1, title: 'Polyseed (16 words)');
|
||||||
|
|
22
lib/entities/wallet_list_order_types.dart
Normal file
22
lib/entities/wallet_list_order_types.dart
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
|
enum WalletListOrderType {
|
||||||
|
CreationDate,
|
||||||
|
Alphabetical,
|
||||||
|
GroupByType,
|
||||||
|
Custom;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
switch (this) {
|
||||||
|
case WalletListOrderType.CreationDate:
|
||||||
|
return S.current.creation_date;
|
||||||
|
case WalletListOrderType.Alphabetical:
|
||||||
|
return S.current.alphabetical;
|
||||||
|
case WalletListOrderType.GroupByType:
|
||||||
|
return S.current.group_by_type;
|
||||||
|
case WalletListOrderType.Custom:
|
||||||
|
return S.current.custom_drag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -159,8 +159,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
url = apiBaseUrl + orderPath + '/fixed';
|
url = apiBaseUrl + orderPath + '/fixed';
|
||||||
} else {
|
} else {
|
||||||
url = apiBaseUrl + orderPath + '/variable';
|
url = apiBaseUrl + orderPath + '/variable';
|
||||||
body["depositCoin"] = request.fromCurrency.title.toLowerCase();
|
body["depositCoin"] = _normalizeCurrency(request.fromCurrency);
|
||||||
body["settleCoin"] = request.toCurrency.title.toLowerCase();
|
body["settleCoin"] = _normalizeCurrency(request.toCurrency);
|
||||||
body["settleNetwork"] = _networkFor(request.toCurrency);
|
body["settleNetwork"] = _networkFor(request.toCurrency);
|
||||||
body["depositNetwork"] = _networkFor(request.fromCurrency);
|
body["depositNetwork"] = _networkFor(request.fromCurrency);
|
||||||
}
|
}
|
||||||
|
@ -248,8 +248,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
final url = apiBaseUrl + quotePath;
|
final url = apiBaseUrl + quotePath;
|
||||||
final headers = {'Content-Type': 'application/json'};
|
final headers = {'Content-Type': 'application/json'};
|
||||||
final body = {
|
final body = {
|
||||||
'depositCoin': request.fromCurrency.title.toLowerCase(),
|
'depositCoin': _normalizeCurrency(request.fromCurrency),
|
||||||
'settleCoin': request.toCurrency.title.toLowerCase(),
|
'settleCoin': _normalizeCurrency(request.toCurrency),
|
||||||
'affiliateId': affiliateId,
|
'affiliateId': affiliateId,
|
||||||
'settleAmount': request.toAmount,
|
'settleAmount': request.toAmount,
|
||||||
'settleNetwork': _networkFor(request.toCurrency),
|
'settleNetwork': _networkFor(request.toCurrency),
|
||||||
|
@ -274,6 +274,15 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
||||||
return responseJSON['id'] as String;
|
return responseJSON['id'] as String;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String _normalizeCurrency(CryptoCurrency currency) {
|
||||||
|
switch (currency) {
|
||||||
|
case CryptoCurrency.usdcEPoly:
|
||||||
|
return 'usdc';
|
||||||
|
default:
|
||||||
|
return currency.title.toLowerCase();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
String _networkFor(CryptoCurrency currency) =>
|
String _networkFor(CryptoCurrency currency) =>
|
||||||
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';
|
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';
|
||||||
|
|
||||||
|
|
|
@ -222,6 +222,10 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||||
return 'usdttrc20';
|
return 'usdttrc20';
|
||||||
case CryptoCurrency.usdcpoly:
|
case CryptoCurrency.usdcpoly:
|
||||||
return 'usdcpoly';
|
return 'usdcpoly';
|
||||||
|
case CryptoCurrency.usdtPoly:
|
||||||
|
return 'usdtpoly';
|
||||||
|
case CryptoCurrency.usdcEPoly:
|
||||||
|
return 'usdcepoly';
|
||||||
case CryptoCurrency.usdcsol:
|
case CryptoCurrency.usdcsol:
|
||||||
return 'usdcspl';
|
return 'usdcspl';
|
||||||
case CryptoCurrency.matic:
|
case CryptoCurrency.matic:
|
||||||
|
|
|
@ -271,6 +271,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
case CryptoCurrency.maticpoly:
|
case CryptoCurrency.maticpoly:
|
||||||
return 'Mainnet';
|
return 'Mainnet';
|
||||||
case CryptoCurrency.usdcpoly:
|
case CryptoCurrency.usdcpoly:
|
||||||
|
case CryptoCurrency.usdtPoly:
|
||||||
|
case CryptoCurrency.usdcEPoly:
|
||||||
return 'MATIC';
|
return 'MATIC';
|
||||||
case CryptoCurrency.zec:
|
case CryptoCurrency.zec:
|
||||||
return 'Mainnet';
|
return 'Mainnet';
|
||||||
|
@ -283,6 +285,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||||
switch (currency) {
|
switch (currency) {
|
||||||
case CryptoCurrency.zec:
|
case CryptoCurrency.zec:
|
||||||
return 'zec';
|
return 'zec';
|
||||||
|
case CryptoCurrency.usdcEPoly:
|
||||||
|
return 'usdce';
|
||||||
default:
|
default:
|
||||||
return currency.title.toLowerCase();
|
return currency.title.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,3 +44,14 @@ String getChainNameBasedOnWalletType(WalletType walletType) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getTokenNameBasedOnWalletType(WalletType walletType) {
|
||||||
|
switch (walletType) {
|
||||||
|
case WalletType.ethereum:
|
||||||
|
return 'ETH';
|
||||||
|
case WalletType.polygon:
|
||||||
|
return 'MATIC';
|
||||||
|
default:
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -65,6 +65,7 @@ import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
import 'package:cw_core/nano_account.dart';
|
import 'package:cw_core/nano_account.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -158,9 +159,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
case Routes.newWallet:
|
case Routes.newWallet:
|
||||||
final type = settings.arguments as WalletType;
|
final type = settings.arguments as WalletType;
|
||||||
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
|
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
|
||||||
final settingsStore = getIt.get<SettingsStore>();
|
final seedTypeViewModel = getIt.get<SeedTypeViewModel>();
|
||||||
|
|
||||||
return CupertinoPageRoute<void>(builder: (_) => NewWalletPage(walletNewVM, settingsStore));
|
return CupertinoPageRoute<void>(builder: (_) => NewWalletPage(walletNewVM, seedTypeViewModel));
|
||||||
|
|
||||||
case Routes.setupPin:
|
case Routes.setupPin:
|
||||||
Function(PinCodeState<PinCodeWidget>, String)? callback;
|
Function(PinCodeState<PinCodeWidget>, String)? callback;
|
||||||
|
@ -581,7 +582,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||||
builder: (_) => AdvancedPrivacySettingsPage(
|
builder: (_) => AdvancedPrivacySettingsPage(
|
||||||
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
getIt.get<AdvancedPrivacySettingsViewModel>(param1: type),
|
||||||
getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
|
getIt.get<NodeCreateOrEditViewModel>(param1: type, param2: false),
|
||||||
));
|
getIt.get<SeedTypeViewModel>()));
|
||||||
|
|
||||||
case Routes.anonPayInvoicePage:
|
case Routes.anonPayInvoicePage:
|
||||||
final args = settings.arguments as List;
|
final args = settings.arguments as List;
|
||||||
|
|
|
@ -1,18 +1,26 @@
|
||||||
|
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
import 'package:cake_wallet/src/widgets/option_tile.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
import 'package:cake_wallet/themes/extensions/option_tile_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||||
|
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class BuyOptionsPage extends BasePage {
|
class BuyOptionsPage extends BasePage {
|
||||||
|
BuyOptionsPage(this.dashboardViewModel);
|
||||||
|
|
||||||
|
final DashboardViewModel dashboardViewModel;
|
||||||
final iconDarkRobinhood = 'assets/images/robinhood_dark.png';
|
final iconDarkRobinhood = 'assets/images/robinhood_dark.png';
|
||||||
final iconLightRobinhood = 'assets/images/robinhood_light.png';
|
final iconLightRobinhood = 'assets/images/robinhood_light.png';
|
||||||
final iconDarkOnramper = 'assets/images/onramper_dark.png';
|
final iconDarkOnramper = 'assets/images/onramper_dark.png';
|
||||||
final iconLightOnramper = 'assets/images/onramper_light.png';
|
final iconLightOnramper = 'assets/images/onramper_light.png';
|
||||||
|
final iconDarkDFX = 'assets/images/dfx_dark.png';
|
||||||
|
final iconLightDFX = 'assets/images/dfx_light.png';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.buy;
|
String get title => S.current.buy;
|
||||||
|
@ -22,11 +30,19 @@ class BuyOptionsPage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
final isLightMode = Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
|
final isLightMode =
|
||||||
final iconRobinhood =
|
Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
|
||||||
Image.asset(isLightMode ? iconLightRobinhood : iconDarkRobinhood, height: 40, width: 40);
|
final iconRobinhood = Image.asset(
|
||||||
final iconOnramper =
|
isLightMode ? iconLightRobinhood : iconDarkRobinhood,
|
||||||
Image.asset(isLightMode ? iconLightOnramper : iconDarkOnramper, height: 40, width: 40);
|
height: 40,
|
||||||
|
width: 40);
|
||||||
|
final iconOnramper = Image.asset(
|
||||||
|
isLightMode ? iconLightOnramper : iconDarkOnramper,
|
||||||
|
height: 40,
|
||||||
|
width: 40);
|
||||||
|
final iconDFX = Image.asset(isLightMode ? iconLightDFX : iconDarkDFX,
|
||||||
|
height: 40, width: 40);
|
||||||
|
final availableProviders = dashboardViewModel.availableProviders;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
child: Center(
|
child: Center(
|
||||||
|
@ -34,24 +50,40 @@ class BuyOptionsPage extends BasePage {
|
||||||
constraints: BoxConstraints(maxWidth: 330),
|
constraints: BoxConstraints(maxWidth: 330),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
if (availableProviders.contains(BuyProviderType.Onramper))
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: EdgeInsets.only(top: 24),
|
||||||
child: OptionTile(
|
child: OptionTile(
|
||||||
image: iconOnramper,
|
image: iconOnramper,
|
||||||
title: "Onramper",
|
title: "Onramper",
|
||||||
description: S.of(context).onramper_option_description,
|
description: S.of(context).onramper_option_description,
|
||||||
onPressed: () async =>
|
onPressed: () async => await getIt
|
||||||
await getIt.get<OnRamperBuyProvider>().launchProvider(context),
|
.get<OnRamperBuyProvider>()
|
||||||
|
.launchProvider(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (availableProviders.contains(BuyProviderType.Robinhood))
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: EdgeInsets.only(top: 24),
|
||||||
child: OptionTile(
|
child: OptionTile(
|
||||||
image: iconRobinhood,
|
image: iconRobinhood,
|
||||||
title: "Robinhood Connect",
|
title: "Robinhood Connect",
|
||||||
description: S.of(context).robinhood_option_description,
|
description: S.of(context).robinhood_option_description,
|
||||||
onPressed: () async =>
|
onPressed: () async => await getIt
|
||||||
await getIt.get<RobinhoodBuyProvider>().launchProvider(context),
|
.get<RobinhoodBuyProvider>()
|
||||||
|
.launchProvider(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (availableProviders.contains(BuyProviderType.DFX))
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(top: 24),
|
||||||
|
child: OptionTile(
|
||||||
|
image: iconDFX,
|
||||||
|
title: "DFX Connect",
|
||||||
|
description: S.of(context).dfx_option_description,
|
||||||
|
onPressed: () async => await getIt
|
||||||
|
.get<DFXBuyProvider>()
|
||||||
|
.launchProvider(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
|
@ -63,7 +95,9 @@ class BuyOptionsPage extends BasePage {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
color: Theme.of(context)
|
||||||
|
.extension<TransactionTradeTheme>()!
|
||||||
|
.detailsTitlesColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -135,6 +135,7 @@ class ContactListPage extends BasePage {
|
||||||
await showBar<void>(context, S.of(context).copied_to_clipboard);
|
await showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.only(top: 16, bottom: 16, right: 24),
|
padding: const EdgeInsets.only(top: 16, bottom: 16, right: 24),
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sideba
|
||||||
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/pages/market_place_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/bottom_sheet_listener.dart';
|
||||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
import 'package:cake_wallet/utils/device_info.dart';
|
||||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||||
|
@ -60,7 +61,8 @@ class DashboardPage extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (DeviceInfo.instance.isDesktop) {
|
if (DeviceInfo.instance.isDesktop) {
|
||||||
if (responsiveLayoutUtil.screenWidth > ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
if (responsiveLayoutUtil.screenWidth >
|
||||||
|
ResponsiveLayoutUtilBase.kDesktopMaxDashBoardWidthConstraint) {
|
||||||
return getIt.get<DesktopSidebarWrapper>();
|
return getIt.get<DesktopSidebarWrapper>();
|
||||||
} else {
|
} else {
|
||||||
return dashboardPageView;
|
return dashboardPageView;
|
||||||
|
@ -191,7 +193,10 @@ class _DashboardPageView extends BasePage {
|
||||||
radius: 6.0,
|
radius: 6.0,
|
||||||
dotWidth: 6.0,
|
dotWidth: 6.0,
|
||||||
dotHeight: 6.0,
|
dotHeight: 6.0,
|
||||||
dotColor: Theme.of(context).indicatorColor,
|
dotColor: Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.indicatorDotTheme
|
||||||
|
.indicatorColor,
|
||||||
activeDotColor: Theme.of(context)
|
activeDotColor: Theme.of(context)
|
||||||
.extension<DashboardPageTheme>()!
|
.extension<DashboardPageTheme>()!
|
||||||
.indicatorDotTheme
|
.indicatorDotTheme
|
||||||
|
@ -292,6 +297,8 @@ class _DashboardPageView extends BasePage {
|
||||||
|
|
||||||
_showReleaseNotesPopup(context);
|
_showReleaseNotesPopup(context);
|
||||||
|
|
||||||
|
_showVulnerableSeedsPopup(context);
|
||||||
|
|
||||||
var needToPresentYat = false;
|
var needToPresentYat = false;
|
||||||
var isInactive = false;
|
var isInactive = false;
|
||||||
|
|
||||||
|
@ -351,4 +358,22 @@ class _DashboardPageView extends BasePage {
|
||||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showVulnerableSeedsPopup(BuildContext context) async {
|
||||||
|
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
|
||||||
|
|
||||||
|
if (affectedWalletNames.isNotEmpty) {
|
||||||
|
Future<void>.delayed(
|
||||||
|
Duration(seconds: 1),
|
||||||
|
() {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return VulnerableSeedsPopup(affectedWalletNames);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
|
import 'package:cake_wallet/src/screens/release_notes/release_notes_screen.dart';
|
||||||
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
import 'package:cake_wallet/src/screens/yat_emoji_id.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/vulnerable_seeds_popup.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/utils/version_comparator.dart';
|
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -110,5 +111,25 @@ class DesktopDashboardPage extends StatelessWidget {
|
||||||
} else if (isNewInstall!) {
|
} else if (isNewInstall!) {
|
||||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_showVulnerableSeedsPopup(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showVulnerableSeedsPopup(BuildContext context) async {
|
||||||
|
final List<String> affectedWalletNames = await dashboardViewModel.checkAffectedWallets();
|
||||||
|
|
||||||
|
if (affectedWalletNames.isNotEmpty) {
|
||||||
|
Future<void>.delayed(
|
||||||
|
Duration(seconds: 1),
|
||||||
|
() {
|
||||||
|
showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return VulnerableSeedsPopup(affectedWalletNames);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.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_switcher_cell.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/address_theme.dart';
|
import 'package:cake_wallet/themes/extensions/address_theme.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
||||||
|
@ -91,7 +92,7 @@ class HomeSettingsPage extends BasePage {
|
||||||
fillColor: Theme.of(context).cardColor,
|
fillColor: Theme.of(context).cardColor,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.add,
|
Icons.add,
|
||||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
size: 22.0,
|
size: 22.0,
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.all(12),
|
padding: EdgeInsets.all(12),
|
||||||
|
|
|
@ -54,6 +54,24 @@ class BalancePage extends StatelessWidget {
|
||||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
height: 1,
|
height: 1,
|
||||||
),
|
),
|
||||||
|
unselectedLabelStyle: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
|
height: 1,
|
||||||
|
),
|
||||||
|
labelColor:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
|
dividerColor:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
|
indicatorColor:
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||||
|
unselectedLabelColor: Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.pageTitleTextColor
|
||||||
|
.withOpacity(0.5),
|
||||||
tabs: [
|
tabs: [
|
||||||
Tab(text: 'My Crypto'),
|
Tab(text: 'My Crypto'),
|
||||||
Tab(text: 'My NFTs'),
|
Tab(text: 'My NFTs'),
|
||||||
|
|
158
lib/src/screens/dashboard/widgets/filter_list_widget.dart
Normal file
158
lib/src/screens/dashboard/widgets/filter_list_widget.dart
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
import 'package:cake_wallet/entities/list_order_mode.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/settings/widgets/settings_choices_cell.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/section_divider.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||||
|
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||||
|
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
|
||||||
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||||
|
|
||||||
|
class FilterListWidget extends StatefulWidget {
|
||||||
|
FilterListWidget({
|
||||||
|
required this.initalType,
|
||||||
|
required this.initalAscending,
|
||||||
|
required this.onClose,
|
||||||
|
});
|
||||||
|
|
||||||
|
final WalletListOrderType? initalType;
|
||||||
|
final bool initalAscending;
|
||||||
|
final Function(bool, WalletListOrderType) onClose;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FilterListWidgetState createState() => FilterListWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilterListWidgetState extends State<FilterListWidget> {
|
||||||
|
late bool ascending;
|
||||||
|
late WalletListOrderType? type;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
ascending = widget.initalAscending;
|
||||||
|
type = widget.initalType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSelectedOrderType(WalletListOrderType? orderType) {
|
||||||
|
setState(() {
|
||||||
|
type = orderType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
const sectionDivider = const HorizontalSectionDivider();
|
||||||
|
return PickerWrapperWidget(
|
||||||
|
onClose: () {
|
||||||
|
widget.onClose(ascending, type!);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.only(left: 24, right: 24, top: 24),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(24)),
|
||||||
|
child: Container(
|
||||||
|
color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
|
||||||
|
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(24.0),
|
||||||
|
child: Text(
|
||||||
|
S.of(context).order_by,
|
||||||
|
style: TextStyle(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (type != WalletListOrderType.Custom) ...[
|
||||||
|
sectionDivider,
|
||||||
|
SettingsChoicesCell(
|
||||||
|
ChoicesListItem<ListOrderMode>(
|
||||||
|
title: "",
|
||||||
|
items: ListOrderMode.all,
|
||||||
|
selectedItem: ascending ? ListOrderMode.ascending : ListOrderMode.descending,
|
||||||
|
onItemSelected: (ListOrderMode listOrderMode) {
|
||||||
|
setState(() {
|
||||||
|
ascending = listOrderMode == ListOrderMode.ascending;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
sectionDivider,
|
||||||
|
RadioListTile(
|
||||||
|
value: WalletListOrderType.CreationDate,
|
||||||
|
groupValue: type,
|
||||||
|
title: Text(
|
||||||
|
WalletListOrderType.CreationDate.toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
),
|
||||||
|
onChanged: setSelectedOrderType,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
value: WalletListOrderType.Alphabetical,
|
||||||
|
groupValue: type,
|
||||||
|
title: Text(
|
||||||
|
WalletListOrderType.Alphabetical.toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
),
|
||||||
|
onChanged: setSelectedOrderType,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
value: WalletListOrderType.GroupByType,
|
||||||
|
groupValue: type,
|
||||||
|
title: Text(
|
||||||
|
WalletListOrderType.GroupByType.toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
),
|
||||||
|
onChanged: setSelectedOrderType,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
RadioListTile(
|
||||||
|
value: WalletListOrderType.Custom,
|
||||||
|
groupValue: type,
|
||||||
|
title: Text(
|
||||||
|
WalletListOrderType.Custom.toString(),
|
||||||
|
style: TextStyle(
|
||||||
|
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||||
|
fontSize: 16,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
decoration: TextDecoration.none),
|
||||||
|
),
|
||||||
|
onChanged: setSelectedOrderType,
|
||||||
|
activeColor: Theme.of(context).primaryColor,
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ class HomeScreenAccountWidget extends StatelessWidget {
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => getIt.get<MoneroAccountListPage>());
|
builder: (_) => getIt.get<MoneroAccountListPage>());
|
||||||
},
|
},
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 100.0,
|
height: 100.0,
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|
|
@ -411,10 +411,6 @@ class ExchangePage extends BasePage {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => exchangeViewModel.isReceiveAddressEnabled, (bool isEnabled) {
|
|
||||||
receiveKey.currentState!.isAddressEditable(isEditable: isEnabled);
|
|
||||||
});
|
|
||||||
|
|
||||||
reaction((_) => exchangeViewModel.isReceiveAmountEditable, (bool isReceiveAmountEditable) {
|
reaction((_) => exchangeViewModel.isReceiveAmountEditable, (bool isReceiveAmountEditable) {
|
||||||
receiveKey.currentState!.isAmountEditable(isEditable: isReceiveAmountEditable);
|
receiveKey.currentState!.isAmountEditable(isEditable: isReceiveAmountEditable);
|
||||||
});
|
});
|
||||||
|
@ -670,7 +666,6 @@ class ExchangePage extends BasePage {
|
||||||
? exchangeViewModel.wallet.walletAddresses.address
|
? exchangeViewModel.wallet.walletAddresses.address
|
||||||
: exchangeViewModel.receiveAddress,
|
: exchangeViewModel.receiveAddress,
|
||||||
initialIsAmountEditable: exchangeViewModel.isReceiveAmountEditable,
|
initialIsAmountEditable: exchangeViewModel.isReceiveAmountEditable,
|
||||||
initialIsAddressEditable: exchangeViewModel.isReceiveAddressEnabled,
|
|
||||||
isAmountEstimated: true,
|
isAmountEstimated: true,
|
||||||
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
||||||
currencies: exchangeViewModel.receiveCurrencies,
|
currencies: exchangeViewModel.receiveCurrencies,
|
||||||
|
|
|
@ -174,8 +174,6 @@ class ExchangeTemplatePage extends BasePage {
|
||||||
? exchangeViewModel.wallet.walletAddresses.address
|
? exchangeViewModel.wallet.walletAddresses.address
|
||||||
: exchangeViewModel.receiveAddress,
|
: exchangeViewModel.receiveAddress,
|
||||||
initialIsAmountEditable: false,
|
initialIsAmountEditable: false,
|
||||||
initialIsAddressEditable:
|
|
||||||
exchangeViewModel.isReceiveAddressEnabled,
|
|
||||||
isAmountEstimated: true,
|
isAmountEstimated: true,
|
||||||
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
||||||
currencies: exchangeViewModel.receiveCurrencies,
|
currencies: exchangeViewModel.receiveCurrencies,
|
||||||
|
@ -328,11 +326,6 @@ class ExchangeTemplatePage extends BasePage {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => exchangeViewModel.isReceiveAddressEnabled,
|
|
||||||
(bool isEnabled) {
|
|
||||||
receiveKey.currentState!.isAddressEditable(isEditable: isEnabled);
|
|
||||||
});
|
|
||||||
|
|
||||||
reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) {
|
reaction((_) => exchangeViewModel.provider, (ExchangeProvider? provider) {
|
||||||
receiveKey.currentState!.isAmountEditable(isEditable: false);
|
receiveKey.currentState!.isAmountEditable(isEditable: false);
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,7 +23,6 @@ class ExchangeCard extends StatefulWidget {
|
||||||
required this.initialAddress,
|
required this.initialAddress,
|
||||||
required this.initialWalletName,
|
required this.initialWalletName,
|
||||||
required this.initialIsAmountEditable,
|
required this.initialIsAmountEditable,
|
||||||
required this.initialIsAddressEditable,
|
|
||||||
required this.isAmountEstimated,
|
required this.isAmountEstimated,
|
||||||
required this.currencies,
|
required this.currencies,
|
||||||
required this.onCurrencySelected,
|
required this.onCurrencySelected,
|
||||||
|
@ -31,6 +30,7 @@ class ExchangeCard extends StatefulWidget {
|
||||||
this.currencyValueValidator,
|
this.currencyValueValidator,
|
||||||
this.addressTextFieldValidator,
|
this.addressTextFieldValidator,
|
||||||
this.title = '',
|
this.title = '',
|
||||||
|
this.initialIsAddressEditable = true,
|
||||||
this.hasRefundAddress = false,
|
this.hasRefundAddress = false,
|
||||||
this.isMoneroWallet = false,
|
this.isMoneroWallet = false,
|
||||||
this.currencyButtonColor = Colors.transparent,
|
this.currencyButtonColor = Colors.transparent,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.
|
||||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||||
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
import 'package:cake_wallet/view_model/settings/choices_list_item.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -18,25 +19,30 @@ 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/scollable_with_bottom_section.dart';
|
||||||
|
|
||||||
class AdvancedPrivacySettingsPage extends BasePage {
|
class AdvancedPrivacySettingsPage extends BasePage {
|
||||||
AdvancedPrivacySettingsPage(this.advancedPrivacySettingsViewModel, this.nodeViewModel);
|
AdvancedPrivacySettingsPage(
|
||||||
|
this.advancedPrivacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel);
|
||||||
|
|
||||||
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
||||||
final NodeCreateOrEditViewModel nodeViewModel;
|
final NodeCreateOrEditViewModel nodeViewModel;
|
||||||
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.privacy_settings;
|
String get title => S.current.privacy_settings;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) =>
|
Widget body(BuildContext context) => AdvancedPrivacySettingsBody(
|
||||||
AdvancedPrivacySettingsBody(advancedPrivacySettingsViewModel, nodeViewModel);
|
advancedPrivacySettingsViewModel, nodeViewModel, seedTypeViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AdvancedPrivacySettingsBody extends StatefulWidget {
|
class AdvancedPrivacySettingsBody extends StatefulWidget {
|
||||||
const AdvancedPrivacySettingsBody(this.privacySettingsViewModel, this.nodeViewModel, {Key? key})
|
const AdvancedPrivacySettingsBody(
|
||||||
|
this.privacySettingsViewModel, this.nodeViewModel, this.seedTypeViewModel,
|
||||||
|
{Key? key})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
|
final AdvancedPrivacySettingsViewModel privacySettingsViewModel;
|
||||||
final NodeCreateOrEditViewModel nodeViewModel;
|
final NodeCreateOrEditViewModel nodeViewModel;
|
||||||
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
|
_AdvancedPrivacySettingsBodyState createState() => _AdvancedPrivacySettingsBodyState();
|
||||||
|
@ -59,7 +65,7 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
||||||
Observer(builder: (_) {
|
Observer(builder: (_) {
|
||||||
return SettingsChoicesCell(
|
return SettingsChoicesCell(
|
||||||
ChoicesListItem<FiatApiMode>(
|
ChoicesListItem<FiatApiMode>(
|
||||||
title: S.current.disable_fiat,
|
title: S.current.fiat_api,
|
||||||
items: FiatApiMode.all,
|
items: FiatApiMode.all,
|
||||||
selectedItem: widget.privacySettingsViewModel.fiatApiMode,
|
selectedItem: widget.privacySettingsViewModel.fiatApiMode,
|
||||||
onItemSelected: (FiatApiMode mode) =>
|
onItemSelected: (FiatApiMode mode) =>
|
||||||
|
@ -114,8 +120,8 @@ class _AdvancedPrivacySettingsBodyState extends State<AdvancedPrivacySettingsBod
|
||||||
ChoicesListItem<SeedType>(
|
ChoicesListItem<SeedType>(
|
||||||
title: S.current.seedtype,
|
title: S.current.seedtype,
|
||||||
items: SeedType.all,
|
items: SeedType.all,
|
||||||
selectedItem: widget.privacySettingsViewModel.seedType,
|
selectedItem: widget.seedTypeViewModel.moneroSeedType,
|
||||||
onItemSelected: widget.privacySettingsViewModel.setSeedType,
|
onItemSelected: widget.seedTypeViewModel.setMoneroSeedType,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/themes/theme_base.dart';
|
import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -23,13 +24,12 @@ import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
import 'package:cake_wallet/themes/extensions/new_wallet_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
import 'package:cake_wallet/entities/seed_type.dart';
|
import 'package:cake_wallet/entities/seed_type.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
|
||||||
|
|
||||||
class NewWalletPage extends BasePage {
|
class NewWalletPage extends BasePage {
|
||||||
NewWalletPage(this._walletNewVM, this._settingsStore);
|
NewWalletPage(this._walletNewVM, this._seedTypeViewModel);
|
||||||
|
|
||||||
final WalletNewVM _walletNewVM;
|
final WalletNewVM _walletNewVM;
|
||||||
final SettingsStore _settingsStore;
|
final SeedTypeViewModel _seedTypeViewModel;
|
||||||
|
|
||||||
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
||||||
|
|
||||||
|
@ -40,15 +40,15 @@ class NewWalletPage extends BasePage {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => WalletNameForm(
|
Widget body(BuildContext context) => WalletNameForm(
|
||||||
_walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _settingsStore);
|
_walletNewVM, currentTheme.type == ThemeType.dark ? walletNameImage : walletNameLightImage, _seedTypeViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletNameForm extends StatefulWidget {
|
class WalletNameForm extends StatefulWidget {
|
||||||
WalletNameForm(this._walletNewVM, this.walletImage, this._settingsStore);
|
WalletNameForm(this._walletNewVM, this.walletImage, this._seedTypeViewModel);
|
||||||
|
|
||||||
final WalletNewVM _walletNewVM;
|
final WalletNewVM _walletNewVM;
|
||||||
final Image walletImage;
|
final Image walletImage;
|
||||||
final SettingsStore _settingsStore;
|
final SeedTypeViewModel _seedTypeViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_WalletNameFormState createState() => _WalletNameFormState(_walletNewVM);
|
_WalletNameFormState createState() => _WalletNameFormState(_walletNewVM);
|
||||||
|
@ -272,7 +272,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
builder: (BuildContext build) => Padding(
|
builder: (BuildContext build) => Padding(
|
||||||
padding: EdgeInsets.only(top: 24),
|
padding: EdgeInsets.only(top: 24),
|
||||||
child: SelectButton(
|
child: SelectButton(
|
||||||
text: widget._settingsStore.moneroSeedType.title,
|
text: widget._seedTypeViewModel.moneroSeedType.title,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await showPopUp<void>(
|
await showPopUp<void>(
|
||||||
context: context,
|
context: context,
|
||||||
|
@ -295,7 +295,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
key: _languageSelectorKey,
|
key: _languageSelectorKey,
|
||||||
initialSelected: defaultSeedLanguage,
|
initialSelected: defaultSeedLanguage,
|
||||||
seedType: _walletNewVM.hasSeedType
|
seedType: _walletNewVM.hasSeedType
|
||||||
? widget._settingsStore.moneroSeedType
|
? widget._seedTypeViewModel.moneroSeedType
|
||||||
: SeedType.legacy,
|
: SeedType.legacy,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -355,10 +355,10 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool get isPolyseed => widget._settingsStore.moneroSeedType == SeedType.polyseed;
|
bool get isPolyseed => widget._seedTypeViewModel.moneroSeedType == SeedType.polyseed;
|
||||||
|
|
||||||
void _setSeedType(SeedType item) {
|
void _setSeedType(SeedType item) {
|
||||||
widget._settingsStore.moneroSeedType = item;
|
widget._seedTypeViewModel.setMoneroSeedType(item);
|
||||||
_languageSelectorKey.currentState?.selected = defaultSeedLanguage; // Reset Seed language
|
_languageSelectorKey.currentState?.selected = defaultSeedLanguage; // Reset Seed language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,10 @@ import 'package:cake_wallet/src/widgets/seed_language_picker.dart';
|
||||||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:polyseed/polyseed.dart';
|
import 'package:polyseed/polyseed.dart';
|
||||||
|
|
||||||
class WalletRestoreFromSeedForm extends StatefulWidget {
|
class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||||
|
@ -20,6 +22,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||||
required this.displayBlockHeightSelector,
|
required this.displayBlockHeightSelector,
|
||||||
required this.type,
|
required this.type,
|
||||||
required this.displayWalletPassword,
|
required this.displayWalletPassword,
|
||||||
|
required this.seedTypeViewModel,
|
||||||
this.blockHeightFocusNode,
|
this.blockHeightFocusNode,
|
||||||
this.onHeightOrDateEntered,
|
this.onHeightOrDateEntered,
|
||||||
this.onSeedChange,
|
this.onSeedChange,
|
||||||
|
@ -32,6 +35,7 @@ class WalletRestoreFromSeedForm extends StatefulWidget {
|
||||||
final bool displayLanguageSelector;
|
final bool displayLanguageSelector;
|
||||||
final bool displayBlockHeightSelector;
|
final bool displayBlockHeightSelector;
|
||||||
final bool displayWalletPassword;
|
final bool displayWalletPassword;
|
||||||
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
final FocusNode? blockHeightFocusNode;
|
final FocusNode? blockHeightFocusNode;
|
||||||
final Function(bool)? onHeightOrDateEntered;
|
final Function(bool)? onHeightOrDateEntered;
|
||||||
final void Function(String)? onSeedChange;
|
final void Function(String)? onSeedChange;
|
||||||
|
@ -63,15 +67,15 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
final TextEditingController? repeatedPasswordTextEditingController;
|
final TextEditingController? repeatedPasswordTextEditingController;
|
||||||
final TextEditingController seedTypeController;
|
final TextEditingController seedTypeController;
|
||||||
final GlobalKey<FormState> formKey;
|
final GlobalKey<FormState> formKey;
|
||||||
|
late ReactionDisposer moneroSeedTypeReaction;
|
||||||
String language;
|
String language;
|
||||||
void Function()? passwordListener;
|
void Function()? passwordListener;
|
||||||
void Function()? repeatedPasswordListener;
|
void Function()? repeatedPasswordListener;
|
||||||
bool isPolyseed = false;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
_setSeedType(widget.seedTypeViewModel.moneroSeedType);
|
||||||
_setLanguageLabel(language);
|
_setLanguageLabel(language);
|
||||||
_setSeedType(SeedType.defaultSeedType);
|
|
||||||
|
|
||||||
if (passwordTextEditingController != null) {
|
if (passwordTextEditingController != null) {
|
||||||
passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text);
|
passwordListener = () => widget.onPasswordChange?.call(passwordTextEditingController!.text);
|
||||||
|
@ -82,9 +86,21 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
|
repeatedPasswordListener = () => widget.onRepeatedPasswordChange?.call(repeatedPasswordTextEditingController!.text);
|
||||||
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
|
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
|
||||||
}
|
}
|
||||||
|
moneroSeedTypeReaction =
|
||||||
|
reaction((_) => widget.seedTypeViewModel.moneroSeedType, (SeedType item) {
|
||||||
|
_setSeedType(item);
|
||||||
|
_changeLanguage('English');
|
||||||
|
});
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
moneroSeedTypeReaction();
|
||||||
|
}
|
||||||
|
|
||||||
void onSeedChange(String seed) {
|
void onSeedChange(String seed) {
|
||||||
if (widget.type == WalletType.monero && Polyseed.isValidSeed(seed)) {
|
if (widget.type == WalletType.monero && Polyseed.isValidSeed(seed)) {
|
||||||
final lang = PolyseedLang.getByPhrase(seed);
|
final lang = PolyseedLang.getByPhrase(seed);
|
||||||
|
@ -225,6 +241,8 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool get isPolyseed => widget.seedTypeViewModel.moneroSeedType == SeedType.polyseed;
|
||||||
|
|
||||||
Widget get expandIcon => Container(
|
Widget get expandIcon => Container(
|
||||||
padding: EdgeInsets.all(18),
|
padding: EdgeInsets.all(18),
|
||||||
width: 24,
|
width: 24,
|
||||||
|
@ -252,10 +270,10 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
|
||||||
void _changeSeedType(SeedType item) {
|
void _changeSeedType(SeedType item) {
|
||||||
_setSeedType(item);
|
_setSeedType(item);
|
||||||
_changeLanguage('English');
|
_changeLanguage('English');
|
||||||
|
widget.seedTypeViewModel.setMoneroSeedType(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setSeedType(SeedType item) {
|
void _setSeedType(SeedType item) {
|
||||||
setState(() => isPolyseed = item == SeedType.polyseed);
|
|
||||||
seedTypeController.text = item.toString();
|
seedTypeController.text = item.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||||
import 'package:cw_core/nano_account_info_response.dart';
|
import 'package:cw_core/nano_account_info_response.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -27,7 +28,7 @@ import 'package:polyseed/polyseed.dart';
|
||||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||||
|
|
||||||
class WalletRestorePage extends BasePage {
|
class WalletRestorePage extends BasePage {
|
||||||
WalletRestorePage(this.walletRestoreViewModel)
|
WalletRestorePage(this.walletRestoreViewModel, this.seedTypeViewModel)
|
||||||
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
: walletRestoreFromSeedFormKey = GlobalKey<WalletRestoreFromSeedFormState>(),
|
||||||
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
walletRestoreFromKeysFormKey = GlobalKey<WalletRestoreFromKeysFromState>(),
|
||||||
_pages = [],
|
_pages = [],
|
||||||
|
@ -37,6 +38,7 @@ class WalletRestorePage extends BasePage {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case WalletRestoreMode.seed:
|
case WalletRestoreMode.seed:
|
||||||
_pages.add(WalletRestoreFromSeedForm(
|
_pages.add(WalletRestoreFromSeedForm(
|
||||||
|
seedTypeViewModel: seedTypeViewModel,
|
||||||
displayBlockHeightSelector:
|
displayBlockHeightSelector:
|
||||||
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
|
||||||
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
displayLanguageSelector: walletRestoreViewModel.hasSeedLanguageSelector,
|
||||||
|
@ -97,6 +99,7 @@ class WalletRestorePage extends BasePage {
|
||||||
));
|
));
|
||||||
|
|
||||||
final WalletRestoreViewModel walletRestoreViewModel;
|
final WalletRestoreViewModel walletRestoreViewModel;
|
||||||
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
final PageController _controller;
|
final PageController _controller;
|
||||||
final List<Widget> _pages;
|
final List<Widget> _pages;
|
||||||
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
final GlobalKey<WalletRestoreFromSeedFormState> walletRestoreFromSeedFormKey;
|
||||||
|
|
|
@ -177,7 +177,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
);
|
);
|
||||||
launchUri = null;
|
launchUri = null;
|
||||||
} else {
|
} else {
|
||||||
_nonETHWalletErrorToast(S.current.switchToETHWallet);
|
_nonETHWalletErrorToast(S.current.switchToEVMCompatibleWallet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +207,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
String? _getRouteToGo() {
|
String? _getRouteToGo() {
|
||||||
if (isWalletConnectLink) {
|
if (isWalletConnectLink) {
|
||||||
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
|
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
|
||||||
_nonETHWalletErrorToast(S.current.switchToETHWallet);
|
_nonETHWalletErrorToast(S.current.switchToEVMCompatibleWallet);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return Routes.walletConnectConnectionsListing;
|
return Routes.walletConnectConnectionsListing;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import 'package:cake_wallet/entities/seed_type.dart';
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
|
||||||
|
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
@ -10,19 +12,21 @@ import 'package:cake_wallet/themes/theme_base.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class PreSeedPage extends BasePage {
|
class PreSeedPage extends BasePage {
|
||||||
PreSeedPage(this.type, this.advancedPrivacySettingsViewModel)
|
PreSeedPage(this.type, this.advancedPrivacySettingsViewModel, this.seedTypeViewModel)
|
||||||
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
|
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
|
||||||
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
|
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
|
||||||
seedPhraseLength =
|
seedPhraseLength = advancedPrivacySettingsViewModel.seedPhraseLength.value,
|
||||||
advancedPrivacySettingsViewModel.seedPhraseLength.value {
|
moneroSeedType = seedTypeViewModel.moneroSeedType {
|
||||||
wordsCount = _wordsCount(type, seedPhraseLength);
|
wordsCount = _wordsCount(type, seedPhraseLength, moneroSeedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Image imageDark;
|
final Image imageDark;
|
||||||
final Image imageLight;
|
final Image imageLight;
|
||||||
final WalletType type;
|
final WalletType type;
|
||||||
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
final AdvancedPrivacySettingsViewModel advancedPrivacySettingsViewModel;
|
||||||
|
final SeedTypeViewModel seedTypeViewModel;
|
||||||
final int seedPhraseLength;
|
final int seedPhraseLength;
|
||||||
|
final SeedType moneroSeedType;
|
||||||
late final int wordsCount;
|
late final int wordsCount;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -76,9 +80,11 @@ class PreSeedPage extends BasePage {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _wordsCount(WalletType type, int seedPhraseLength) {
|
static int _wordsCount(WalletType type, int seedPhraseLength, SeedType moneroSeedType) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
|
if (moneroSeedType == SeedType.polyseed)
|
||||||
|
return 16;
|
||||||
return 25;
|
return 25;
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
|
|
||||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.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_picker_cell.dart';
|
||||||
|
@ -18,12 +17,11 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
||||||
class ConnectionSyncPage extends BasePage {
|
class ConnectionSyncPage extends BasePage {
|
||||||
ConnectionSyncPage(this.dashboardViewModel, this.web3walletService);
|
ConnectionSyncPage(this.dashboardViewModel);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get title => S.current.connection_sync;
|
String get title => S.current.connection_sync;
|
||||||
|
|
||||||
final Web3WalletService? web3walletService;
|
|
||||||
final DashboardViewModel dashboardViewModel;
|
final DashboardViewModel dashboardViewModel;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -76,7 +76,7 @@ class DisplaySettingsPage extends BasePage {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile)
|
if (responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile)
|
||||||
SettingsThemeChoicesCell(_displaySettingsViewModel),
|
Semantics(label: S.current.color_theme, child: SettingsThemeChoicesCell(_displaySettingsViewModel)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
|
||||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
|
||||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
@ -42,9 +40,10 @@ class OtherSettingsPage extends BasePage {
|
||||||
handler: (BuildContext context) =>
|
handler: (BuildContext context) =>
|
||||||
Navigator.of(context).pushNamed(Routes.changeRep),
|
Navigator.of(context).pushNamed(Routes.changeRep),
|
||||||
),
|
),
|
||||||
|
if(_otherSettingsViewModel.isEnabledBuyAction)
|
||||||
SettingsPickerCell(
|
SettingsPickerCell(
|
||||||
title: S.current.default_buy_provider,
|
title: S.current.default_buy_provider,
|
||||||
items: BuyProviderType.values,
|
items: _otherSettingsViewModel.availableBuyProviders,
|
||||||
displayItem: _otherSettingsViewModel.getBuyProviderType,
|
displayItem: _otherSettingsViewModel.getBuyProviderType,
|
||||||
selectedItem: _otherSettingsViewModel.buyProviderType,
|
selectedItem: _otherSettingsViewModel.buyProviderType,
|
||||||
onItemSelected: _otherSettingsViewModel.onBuyProviderTypeSelected,
|
onItemSelected: _otherSettingsViewModel.onBuyProviderTypeSelected,
|
||||||
|
|
|
@ -17,6 +17,7 @@ class SettingsChoicesCell extends StatelessWidget {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
if (choicesListItem.title.isNotEmpty) ...[
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
|
@ -30,9 +31,8 @@ class SettingsChoicesCell extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
|
],
|
||||||
Center(
|
Center(
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.horizontal,
|
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(30),
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
@ -42,18 +42,18 @@ class SettingsChoicesCell extends StatelessWidget {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: choicesListItem.items.map((dynamic e) {
|
children: choicesListItem.items.map((dynamic e) {
|
||||||
final isSelected = choicesListItem.selectedItem == e;
|
final isSelected = choicesListItem.selectedItem == e;
|
||||||
return GestureDetector(
|
return Expanded(
|
||||||
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
choicesListItem.onItemSelected.call(e);
|
choicesListItem.onItemSelected.call(e);
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(horizontal: 32, vertical: 8),
|
padding: EdgeInsets.symmetric(vertical: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(30),
|
borderRadius: BorderRadius.circular(30),
|
||||||
color: isSelected
|
color: isSelected ? Theme.of(context).primaryColor : null,
|
||||||
? Theme.of(context).primaryColor
|
|
||||||
: null,
|
|
||||||
),
|
),
|
||||||
|
child: Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
choicesListItem.displayItem.call(e),
|
choicesListItem.displayItem.call(e),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
@ -64,12 +64,13 @@ class SettingsChoicesCell extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -54,6 +54,9 @@ class SettingsThemeChoicesCell extends StatelessWidget {
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: EdgeInsets.all(5),
|
padding: EdgeInsets.all(5),
|
||||||
|
child: Semantics(
|
||||||
|
label: e.toString(),
|
||||||
|
selected: isSelected,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
_displaySettingsViewModel.setTheme(e);
|
_displaySettingsViewModel.setTheme(e);
|
||||||
|
@ -108,6 +111,7 @@ class SettingsThemeChoicesCell extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
39
lib/src/screens/wallet_list/filtered_list.dart
Normal file
39
lib/src/screens/wallet_list/filtered_list.dart
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
class FilteredList extends StatefulWidget {
|
||||||
|
FilteredList({
|
||||||
|
required this.list,
|
||||||
|
required this.itemBuilder,
|
||||||
|
required this.updateFunction,
|
||||||
|
});
|
||||||
|
|
||||||
|
final ObservableList<dynamic> list;
|
||||||
|
final Widget Function(BuildContext, int) itemBuilder;
|
||||||
|
final Function updateFunction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FilteredListState createState() => FilteredListState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilteredListState extends State<FilteredList> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Observer(
|
||||||
|
builder: (_) => ReorderableListView.builder(
|
||||||
|
physics: const BouncingScrollPhysics(),
|
||||||
|
itemBuilder: widget.itemBuilder,
|
||||||
|
itemCount: widget.list.length,
|
||||||
|
onReorder: (int oldIndex, int newIndex) {
|
||||||
|
if (oldIndex < newIndex) {
|
||||||
|
newIndex -= 1;
|
||||||
|
}
|
||||||
|
final dynamic item = widget.list.removeAt(oldIndex);
|
||||||
|
widget.list.insert(newIndex, item);
|
||||||
|
widget.updateFunction();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,16 @@
|
||||||
|
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_widget.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||||
import 'package:cake_wallet/main.dart';
|
import 'package:cake_wallet/main.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/filter_theme.dart';
|
||||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
|
||||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||||
import 'package:cake_wallet/utils/show_bar.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';
|
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||||
import 'package:another_flushbar/flushbar.dart';
|
import 'package:another_flushbar/flushbar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -33,6 +36,53 @@ class WalletListPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) =>
|
Widget body(BuildContext context) =>
|
||||||
WalletListBody(walletListViewModel: walletListViewModel, authService: authService);
|
WalletListBody(walletListViewModel: walletListViewModel, authService: authService);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget trailing(BuildContext context) {
|
||||||
|
final filterIcon = Image.asset('assets/images/filter_icon.png',
|
||||||
|
color: Theme.of(context).extension<FilterTheme>()!.iconColor);
|
||||||
|
return MergeSemantics(
|
||||||
|
child: SizedBox(
|
||||||
|
height: 37,
|
||||||
|
width: 37,
|
||||||
|
child: ButtonTheme(
|
||||||
|
minWidth: double.minPositive,
|
||||||
|
child: Semantics(
|
||||||
|
container: true,
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () async {
|
||||||
|
await showPopUp<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => FilterListWidget(
|
||||||
|
initalType: walletListViewModel.orderType,
|
||||||
|
initalAscending: walletListViewModel.ascending,
|
||||||
|
onClose: (bool ascending, WalletListOrderType type) async {
|
||||||
|
walletListViewModel.setAscending(ascending);
|
||||||
|
await walletListViewModel.setOrderType(type);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Semantics(
|
||||||
|
label: 'Transaction Filter',
|
||||||
|
button: true,
|
||||||
|
enabled: true,
|
||||||
|
child: Container(
|
||||||
|
height: 36,
|
||||||
|
width: 36,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
color: Theme.of(context).extension<FilterTheme>()!.buttonColor,
|
||||||
|
),
|
||||||
|
child: filterIcon,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletListBody extends StatefulWidget {
|
class WalletListBody extends StatefulWidget {
|
||||||
|
@ -75,11 +125,9 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
child: Observer(
|
child: Observer(
|
||||||
builder: (_) => ListView.separated(
|
builder: (_) => FilteredList(
|
||||||
physics: const BouncingScrollPhysics(),
|
list: widget.walletListViewModel.wallets,
|
||||||
separatorBuilder: (_, index) =>
|
updateFunction: widget.walletListViewModel.reorderAccordingToWalletList,
|
||||||
Divider(color: Theme.of(context).colorScheme.background, height: 32),
|
|
||||||
itemCount: widget.walletListViewModel.wallets.length,
|
|
||||||
itemBuilder: (__, index) {
|
itemBuilder: (__, index) {
|
||||||
final wallet = widget.walletListViewModel.wallets[index];
|
final wallet = widget.walletListViewModel.wallets[index];
|
||||||
final currentColor = wallet.isCurrent
|
final currentColor = wallet.isCurrent
|
||||||
|
@ -88,6 +136,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
.createNewWalletButtonBackgroundColor
|
.createNewWalletButtonBackgroundColor
|
||||||
: Theme.of(context).colorScheme.background;
|
: Theme.of(context).colorScheme.background;
|
||||||
final row = GestureDetector(
|
final row = GestureDetector(
|
||||||
|
key: ValueKey(wallet.name),
|
||||||
onTap: () => wallet.isCurrent ? null : _loadWallet(wallet),
|
onTap: () => wallet.isCurrent ? null : _loadWallet(wallet),
|
||||||
child: Container(
|
child: Container(
|
||||||
height: tileHeight,
|
height: tileHeight,
|
||||||
|
@ -122,7 +171,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
maxLines: null,
|
maxLines: null,
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 22,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.extension<CakeTextTheme>()!
|
.extension<CakeTextTheme>()!
|
||||||
|
@ -142,13 +191,15 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
return wallet.isCurrent
|
return wallet.isCurrent
|
||||||
? row
|
? row
|
||||||
: Row(
|
: Row(
|
||||||
|
key: ValueKey(wallet.name),
|
||||||
children: [
|
children: [
|
||||||
Expanded(child: row),
|
Expanded(child: row),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => Navigator.of(context).pushNamed(Routes.walletEdit,
|
onTap: () => Navigator.of(context).pushNamed(Routes.walletEdit,
|
||||||
arguments: [widget.walletListViewModel, wallet]),
|
arguments: [widget.walletListViewModel, wallet]),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.only(right: 20),
|
padding: EdgeInsets.only(
|
||||||
|
right: DeviceInfo.instance.isMobile ? 20 : 40),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Container(
|
child: Container(
|
||||||
height: 40,
|
height: 40,
|
||||||
|
|
|
@ -4,10 +4,11 @@ import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||||
|
|
||||||
class PickerWrapperWidget extends StatelessWidget {
|
class PickerWrapperWidget extends StatelessWidget {
|
||||||
PickerWrapperWidget({required this.children, this.hasTitle = false});
|
PickerWrapperWidget({required this.children, this.hasTitle = false, this.onClose});
|
||||||
|
|
||||||
final List<Widget> children;
|
final List<Widget> children;
|
||||||
final bool hasTitle;
|
final bool hasTitle;
|
||||||
|
final Function()? onClose;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -45,7 +46,7 @@ class PickerWrapperWidget extends StatelessWidget {
|
||||||
children: children,
|
children: children,
|
||||||
),
|
),
|
||||||
SizedBox(height: ResponsiveLayoutUtilBase.kPopupSpaceHeight),
|
SizedBox(height: ResponsiveLayoutUtilBase.kPopupSpaceHeight),
|
||||||
AlertCloseButton(bottom: closeButtonBottom),
|
AlertCloseButton(bottom: closeButtonBottom, onTap: onClose),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,7 +14,10 @@ class StandardSwitch extends StatefulWidget {
|
||||||
class StandardSwitchState extends State<StandardSwitch> {
|
class StandardSwitchState extends State<StandardSwitch> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return GestureDetector(
|
|
||||||
|
return Semantics(
|
||||||
|
toggled: widget.value,
|
||||||
|
child: GestureDetector(
|
||||||
onTap: widget.onTaped,
|
onTap: widget.onTaped,
|
||||||
child: AnimatedContainer(
|
child: AnimatedContainer(
|
||||||
padding: EdgeInsets.only(left: 2.0, right: 2.0),
|
padding: EdgeInsets.only(left: 2.0, right: 2.0),
|
||||||
|
@ -35,6 +38,7 @@ class StandardSwitchState extends State<StandardSwitch> {
|
||||||
shape: BoxShape.circle),
|
shape: BoxShape.circle),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
91
lib/src/widgets/vulnerable_seeds_popup.dart
Normal file
91
lib/src/widgets/vulnerable_seeds_popup.dart
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||||
|
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||||
|
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class VulnerableSeedsPopup extends StatelessWidget {
|
||||||
|
final List<String> affectedWalletNames;
|
||||||
|
|
||||||
|
const VulnerableSeedsPopup(this.affectedWalletNames, {Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
children: [
|
||||||
|
AlertBackground(
|
||||||
|
child: AlertDialog(
|
||||||
|
insetPadding: EdgeInsets.only(left: 16, right: 16, bottom: 48),
|
||||||
|
elevation: 0.0,
|
||||||
|
contentPadding: EdgeInsets.zero,
|
||||||
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(30))),
|
||||||
|
content: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(30.0),
|
||||||
|
gradient: LinearGradient(colors: [
|
||||||
|
Theme.of(context).extension<DashboardPageTheme>()!.firstGradientBackgroundColor,
|
||||||
|
Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.secondGradientBackgroundColor,
|
||||||
|
], begin: Alignment.centerLeft, end: Alignment.centerRight)),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 24.0),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 16.0),
|
||||||
|
child: Container(
|
||||||
|
alignment: Alignment.bottomCenter,
|
||||||
|
child: DefaultTextStyle(
|
||||||
|
style: TextStyle(
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
fontSize: 24.0,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||||
|
),
|
||||||
|
child: Text("Emergency Notice"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(top: 48, bottom: 16),
|
||||||
|
child: Container(
|
||||||
|
width: double.maxFinite,
|
||||||
|
child: Column(
|
||||||
|
children: <Widget>[
|
||||||
|
ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
maxHeight: MediaQuery.of(context).size.height * 0.7,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
"Your Bitcoin wallet(s) below use a legacy seed format that is vulnerable, which MAY result in you losing money from these wallet(s) if no action is taken.\nWe recommend that you IMMEDIATELY create wallet(s) in Cake Wallet and immediately transfer the funds to these wallet(s).\nVulnerable wallet name(s):\n\n[${affectedWalletNames.join(", ")}]\n\nFor assistance, please use the in-app support or email support@cakewallet.com",
|
||||||
|
style: TextStyle(
|
||||||
|
decoration: TextDecoration.none,
|
||||||
|
fontSize: 16.0,
|
||||||
|
fontFamily: 'Lato',
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<DashboardPageTheme>()!
|
||||||
|
.textColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
AlertCloseButton(bottom: 30)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||||
import 'package:cake_wallet/entities/seed_type.dart';
|
import 'package:cake_wallet/entities/seed_type.dart';
|
||||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||||
|
@ -36,8 +37,6 @@ import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
import 'package:cake_wallet/entities/action_list_display_mode.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
import 'package:cw_core/set_app_secure_native.dart';
|
import 'package:cw_core/set_app_secure_native.dart';
|
||||||
import 'package:cake_wallet/utils/device_info.dart';
|
|
||||||
|
|
||||||
part 'settings_store.g.dart';
|
part 'settings_store.g.dart';
|
||||||
|
|
||||||
class SettingsStore = SettingsStoreBase with _$SettingsStore;
|
class SettingsStore = SettingsStoreBase with _$SettingsStore;
|
||||||
|
@ -55,7 +54,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
required bool initialAppSecure,
|
required bool initialAppSecure,
|
||||||
required bool initialDisableBuy,
|
required bool initialDisableBuy,
|
||||||
required bool initialDisableSell,
|
required bool initialDisableSell,
|
||||||
required BuyProviderType initialDefaultBuyProvider,
|
required WalletListOrderType initialWalletListOrder,
|
||||||
|
required bool initialWalletListAscending,
|
||||||
required FiatApiMode initialFiatMode,
|
required FiatApiMode initialFiatMode,
|
||||||
required bool initialAllowBiometricalAuthentication,
|
required bool initialAllowBiometricalAuthentication,
|
||||||
required String initialTotpSecretKey,
|
required String initialTotpSecretKey,
|
||||||
|
@ -124,7 +124,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
isAppSecure = initialAppSecure,
|
isAppSecure = initialAppSecure,
|
||||||
disableBuy = initialDisableBuy,
|
disableBuy = initialDisableBuy,
|
||||||
disableSell = initialDisableSell,
|
disableSell = initialDisableSell,
|
||||||
defaultBuyProvider = initialDefaultBuyProvider,
|
walletListOrder = initialWalletListOrder,
|
||||||
|
walletListAscending = initialWalletListAscending,
|
||||||
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
|
shouldShowMarketPlaceInDashboard = initialShouldShowMarketPlaceInDashboard,
|
||||||
exchangeStatus = initialExchangeStatus,
|
exchangeStatus = initialExchangeStatus,
|
||||||
currentTheme = initialTheme,
|
currentTheme = initialTheme,
|
||||||
|
@ -179,6 +180,12 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
initializeTrocadorProviderStates();
|
initializeTrocadorProviderStates();
|
||||||
|
|
||||||
|
WalletType.values.forEach((walletType) {
|
||||||
|
final key = 'defaultBuyProvider_${walletType.toString()}';
|
||||||
|
final providerIndex = sharedPreferences.getInt(key);
|
||||||
|
defaultBuyProviders[walletType] = providerIndex != null ? BuyProviderType.values[providerIndex] : BuyProviderType.AskEachTime;
|
||||||
|
});
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => fiatCurrency,
|
(_) => fiatCurrency,
|
||||||
(FiatCurrency fiatCurrency) => sharedPreferences.setString(
|
(FiatCurrency fiatCurrency) => sharedPreferences.setString(
|
||||||
|
@ -245,9 +252,24 @@ abstract class SettingsStoreBase with Store {
|
||||||
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
|
sharedPreferences.setBool(PreferencesKey.disableSellKey, disableSell));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => defaultBuyProvider,
|
(_) => defaultBuyProviders.asObservable(),
|
||||||
(BuyProviderType defaultBuyProvider) =>
|
(ObservableMap<WalletType, BuyProviderType> providers) {
|
||||||
sharedPreferences.setInt(PreferencesKey.defaultBuyProvider, defaultBuyProvider.index));
|
providers.forEach((walletType, provider) {
|
||||||
|
final key = 'defaultBuyProvider_${walletType.toString()}';
|
||||||
|
sharedPreferences.setInt(key, provider.index);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
(_) => walletListOrder,
|
||||||
|
(WalletListOrderType walletListOrder) =>
|
||||||
|
sharedPreferences.setInt(PreferencesKey.walletListOrder, walletListOrder.index));
|
||||||
|
|
||||||
|
reaction(
|
||||||
|
(_) => walletListAscending,
|
||||||
|
(bool walletListAscending) =>
|
||||||
|
sharedPreferences.setBool(PreferencesKey.walletListAscending, walletListAscending));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => autoGenerateSubaddressStatus,
|
(_) => autoGenerateSubaddressStatus,
|
||||||
|
@ -334,6 +356,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
|
|
||||||
reaction((_) => totpSecretKey,
|
reaction((_) => totpSecretKey,
|
||||||
(String totpKey) => sharedPreferences.setString(PreferencesKey.totpSecretKey, totpKey));
|
(String totpKey) => sharedPreferences.setString(PreferencesKey.totpSecretKey, totpKey));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => numberOfFailedTokenTrials,
|
(_) => numberOfFailedTokenTrials,
|
||||||
(int failedTokenTrail) =>
|
(int failedTokenTrail) =>
|
||||||
|
@ -497,7 +520,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
bool disableSell;
|
bool disableSell;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
BuyProviderType defaultBuyProvider;
|
WalletListOrderType walletListOrder;
|
||||||
|
|
||||||
|
@observable
|
||||||
|
bool walletListAscending;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool allowBiometricalAuthentication;
|
bool allowBiometricalAuthentication;
|
||||||
|
@ -568,6 +594,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
|
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
|
||||||
|
|
||||||
|
@observable
|
||||||
|
ObservableMap<WalletType, BuyProviderType> defaultBuyProviders = ObservableMap<WalletType, BuyProviderType>();
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
SortBalanceBy sortBalanceBy;
|
SortBalanceBy sortBalanceBy;
|
||||||
|
|
||||||
|
@ -709,8 +738,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
final isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
|
final isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? false;
|
||||||
final disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
|
final disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? false;
|
||||||
final disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
|
final disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? false;
|
||||||
final defaultBuyProvider =
|
final walletListOrder =
|
||||||
BuyProviderType.values[sharedPreferences.getInt(PreferencesKey.defaultBuyProvider) ?? 0];
|
WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0];
|
||||||
|
final walletListAscending =
|
||||||
|
sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true;
|
||||||
final currentFiatApiMode = FiatApiMode.deserialize(
|
final currentFiatApiMode = FiatApiMode.deserialize(
|
||||||
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
|
raw: sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ??
|
||||||
FiatApiMode.enabled.raw);
|
FiatApiMode.enabled.raw);
|
||||||
|
@ -869,7 +900,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
final savedSyncMode = SyncMode.all.firstWhere((element) {
|
final savedSyncMode = SyncMode.all.firstWhere((element) {
|
||||||
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 1);
|
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 0);
|
||||||
});
|
});
|
||||||
final savedSyncAll = sharedPreferences.getBool(PreferencesKey.syncAllKey) ?? true;
|
final savedSyncAll = sharedPreferences.getBool(PreferencesKey.syncAllKey) ?? true;
|
||||||
|
|
||||||
|
@ -889,7 +920,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
initialAppSecure: isAppSecure,
|
initialAppSecure: isAppSecure,
|
||||||
initialDisableBuy: disableBuy,
|
initialDisableBuy: disableBuy,
|
||||||
initialDisableSell: disableSell,
|
initialDisableSell: disableSell,
|
||||||
initialDefaultBuyProvider: defaultBuyProvider,
|
initialWalletListOrder: walletListOrder,
|
||||||
|
initialWalletListAscending: walletListAscending,
|
||||||
initialFiatMode: currentFiatApiMode,
|
initialFiatMode: currentFiatApiMode,
|
||||||
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||||
initialCake2FAPresetOptions: selectedCake2FAPreset,
|
initialCake2FAPresetOptions: selectedCake2FAPreset,
|
||||||
|
@ -1005,8 +1037,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
|
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
|
||||||
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
|
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
|
||||||
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
|
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
|
||||||
defaultBuyProvider =
|
walletListOrder =
|
||||||
BuyProviderType.values[sharedPreferences.getInt(PreferencesKey.defaultBuyProvider) ?? 0];
|
WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0];
|
||||||
|
walletListAscending = sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true;
|
||||||
allowBiometricalAuthentication =
|
allowBiometricalAuthentication =
|
||||||
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
sharedPreferences.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
|
||||||
allowBiometricalAuthentication;
|
allowBiometricalAuthentication;
|
||||||
|
|
|
@ -78,7 +78,7 @@ class BrightTheme extends LightTheme {
|
||||||
FilterTheme get filterTheme => super.filterTheme.copyWith(
|
FilterTheme get filterTheme => super.filterTheme.copyWith(
|
||||||
checkboxSecondGradientColor: Palette.pinkFlamingo,
|
checkboxSecondGradientColor: Palette.pinkFlamingo,
|
||||||
checkboxBackgroundColor: Colors.white,
|
checkboxBackgroundColor: Colors.white,
|
||||||
buttonColor: Colors.white.withOpacity(0.2),
|
buttonColor: Palette.darkGray.withOpacity(0.2),
|
||||||
iconColor: Colors.white);
|
iconColor: Colors.white);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
import 'package:cake_wallet/entities/seed_phrase_length.dart';
|
||||||
import 'package:cake_wallet/entities/seed_type.dart';
|
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
@ -20,9 +19,6 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||||
@computed
|
@computed
|
||||||
FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode;
|
FiatApiMode get fiatApiMode => _settingsStore.fiatApiMode;
|
||||||
|
|
||||||
@computed
|
|
||||||
SeedType get seedType => _settingsStore.moneroSeedType;
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool _addCustomNode = false;
|
bool _addCustomNode = false;
|
||||||
|
|
||||||
|
@ -44,9 +40,6 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||||
@action
|
@action
|
||||||
void setFiatApiMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode;
|
void setFiatApiMode(FiatApiMode fiatApiMode) => _settingsStore.fiatApiMode = fiatApiMode;
|
||||||
|
|
||||||
@action
|
|
||||||
void setSeedType(SeedType seedType) => _settingsStore.moneroSeedType = seedType;
|
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value;
|
void setExchangeApiMode(ExchangeApiMode value) => _settingsStore.exchangeStatus = value;
|
||||||
|
|
||||||
|
|
|
@ -91,6 +91,9 @@ abstract class ContactListViewModelBase with Store {
|
||||||
walletContacts.where((element) => _isValidForCurrency(element)).toList();
|
walletContacts.where((element) => _isValidForCurrency(element)).toList();
|
||||||
|
|
||||||
bool _isValidForCurrency(ContactBase element) {
|
bool _isValidForCurrency(ContactBase element) {
|
||||||
return _currency == null || element.type == _currency || element.type.title == _currency!.tag;
|
return _currency == null ||
|
||||||
|
element.type == _currency ||
|
||||||
|
element.type.title == _currency!.tag ||
|
||||||
|
element.type.tag == _currency!.tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:cake_wallet/core/key_service.dart';
|
||||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||||
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
import 'package:cake_wallet/entities/buy_provider_types.dart';
|
||||||
|
@ -24,12 +27,19 @@ import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||||
|
import 'package:cryptography/cryptography.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
|
import 'package:cw_core/cake_hive.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
import 'package:cw_core/sync_status.dart';
|
import 'package:cw_core/sync_status.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
import 'package:cw_core/utils/file.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:eth_sig_util/util/utils.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
part 'dashboard_view_model.g.dart';
|
part 'dashboard_view_model.g.dart';
|
||||||
|
@ -46,7 +56,8 @@ abstract class DashboardViewModelBase with Store {
|
||||||
required this.settingsStore,
|
required this.settingsStore,
|
||||||
required this.yatStore,
|
required this.yatStore,
|
||||||
required this.ordersStore,
|
required this.ordersStore,
|
||||||
required this.anonpayTransactionsStore})
|
required this.anonpayTransactionsStore,
|
||||||
|
required this.keyService})
|
||||||
: hasSellAction = false,
|
: hasSellAction = false,
|
||||||
hasBuyAction = false,
|
hasBuyAction = false,
|
||||||
hasExchangeAction = false,
|
hasExchangeAction = false,
|
||||||
|
@ -262,6 +273,8 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
|
bool get hasRescan => wallet.type == WalletType.monero || wallet.type == WalletType.haven;
|
||||||
|
|
||||||
|
final KeyService keyService;
|
||||||
|
|
||||||
BalanceViewModel balanceViewModel;
|
BalanceViewModel balanceViewModel;
|
||||||
|
|
||||||
AppStore appStore;
|
AppStore appStore;
|
||||||
|
@ -282,10 +295,14 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
Map<String, List<FilterItem>> filterItems;
|
Map<String, List<FilterItem>> filterItems;
|
||||||
|
|
||||||
BuyProviderType get defaultBuyProvider => settingsStore.defaultBuyProvider;
|
BuyProviderType get defaultBuyProvider =>
|
||||||
|
settingsStore.defaultBuyProviders[wallet.type] ?? BuyProviderType.AskEachTime;
|
||||||
|
|
||||||
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
|
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
|
||||||
|
|
||||||
|
List<BuyProviderType> get availableProviders =>
|
||||||
|
BuyProviderType.getAvailableProviders(wallet.type);
|
||||||
|
|
||||||
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
|
bool get shouldShowYatPopup => settingsStore.shouldShowYatPopup;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -429,4 +446,32 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
|
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
|
||||||
|
|
||||||
|
Future<List<String>> checkAffectedWallets() async {
|
||||||
|
// await load file
|
||||||
|
final vulnerableSeedsString = await rootBundle.loadString('assets/text/cakewallet_weak_bitcoin_seeds_hashed_sorted_version1.txt');
|
||||||
|
final vulnerableSeeds = vulnerableSeedsString.split("\n");
|
||||||
|
|
||||||
|
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||||
|
|
||||||
|
List<String> affectedWallets = [];
|
||||||
|
for (var walletInfo in walletInfoSource.values) {
|
||||||
|
if (walletInfo.type == WalletType.bitcoin) {
|
||||||
|
final password = await keyService.getWalletPassword(walletName: walletInfo.name);
|
||||||
|
final path = await pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
final jsonSource = await read(path: path, password: password);
|
||||||
|
final data = json.decode(jsonSource) as Map;
|
||||||
|
final mnemonic = data['mnemonic'] as String;
|
||||||
|
|
||||||
|
final hash = await Cryptography.instance.sha256().hash(utf8.encode(mnemonic));
|
||||||
|
final seedSha = bytesToHex(hash.bytes);
|
||||||
|
|
||||||
|
if (vulnerableSeeds.contains(seedSha)) {
|
||||||
|
affectedWallets.add(walletInfo.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return affectedWallets;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
receiveAddress = '',
|
receiveAddress = '',
|
||||||
depositAddress = '',
|
depositAddress = '',
|
||||||
isDepositAddressEnabled = false,
|
isDepositAddressEnabled = false,
|
||||||
isReceiveAddressEnabled = false,
|
|
||||||
isReceiveAmountEditable = false,
|
isReceiveAmountEditable = false,
|
||||||
_useTorOnly = false,
|
_useTorOnly = false,
|
||||||
receiveCurrencies = <CryptoCurrency>[],
|
receiveCurrencies = <CryptoCurrency>[],
|
||||||
|
@ -108,7 +107,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
|
bestRateSync = Timer.periodic(Duration(seconds: 10), (timer) => _calculateBestRate());
|
||||||
|
|
||||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
|
||||||
depositAmount = '';
|
depositAmount = '';
|
||||||
receiveAmount = '';
|
receiveAmount = '';
|
||||||
receiveAddress = '';
|
receiveAddress = '';
|
||||||
|
@ -201,9 +199,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
@observable
|
@observable
|
||||||
bool isDepositAddressEnabled;
|
bool isDepositAddressEnabled;
|
||||||
|
|
||||||
@observable
|
|
||||||
bool isReceiveAddressEnabled;
|
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
bool isReceiveAmountEntered;
|
bool isReceiveAmountEntered;
|
||||||
|
|
||||||
|
@ -315,7 +310,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
isFixedRateMode = false;
|
isFixedRateMode = false;
|
||||||
_onPairChange();
|
_onPairChange();
|
||||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -324,7 +318,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
isFixedRateMode = false;
|
isFixedRateMode = false;
|
||||||
_onPairChange();
|
_onPairChange();
|
||||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -535,7 +528,6 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
depositAddress = depositCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
||||||
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
receiveAddress = receiveCurrency == wallet.currency ? wallet.walletAddresses.address : '';
|
||||||
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
isDepositAddressEnabled = !(depositCurrency == wallet.currency);
|
||||||
isReceiveAddressEnabled = !(receiveCurrency == wallet.currency);
|
|
||||||
isFixedRateMode = false;
|
isFixedRateMode = false;
|
||||||
_onPairChange();
|
_onPairChange();
|
||||||
}
|
}
|
||||||
|
|
19
lib/view_model/seed_type_view_model.dart
Normal file
19
lib/view_model/seed_type_view_model.dart
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import 'package:cake_wallet/entities/seed_type.dart';
|
||||||
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
|
||||||
|
part 'seed_type_view_model.g.dart';
|
||||||
|
|
||||||
|
class SeedTypeViewModel = SeedTypeViewModelBase with _$SeedTypeViewModel;
|
||||||
|
|
||||||
|
abstract class SeedTypeViewModelBase with Store {
|
||||||
|
SeedTypeViewModelBase(this._appStore);
|
||||||
|
|
||||||
|
@computed
|
||||||
|
SeedType get moneroSeedType => _appStore.settingsStore.moneroSeedType;
|
||||||
|
|
||||||
|
@action
|
||||||
|
void setMoneroSeedType(SeedType seedType) => _appStore.settingsStore.moneroSeedType = seedType;
|
||||||
|
|
||||||
|
final AppStore _appStore;
|
||||||
|
}
|
|
@ -13,14 +13,15 @@ import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
part 'other_settings_view_model.g.dart';
|
part 'other_settings_view_model.g.dart';
|
||||||
|
|
||||||
class OtherSettingsViewModel = OtherSettingsViewModelBase with _$OtherSettingsViewModel;
|
class OtherSettingsViewModel = OtherSettingsViewModelBase
|
||||||
|
with _$OtherSettingsViewModel;
|
||||||
|
|
||||||
abstract class OtherSettingsViewModelBase with Store {
|
abstract class OtherSettingsViewModelBase with Store {
|
||||||
OtherSettingsViewModelBase(this._settingsStore, this._wallet)
|
OtherSettingsViewModelBase(this._settingsStore, this._wallet)
|
||||||
: walletType = _wallet.type,
|
: walletType = _wallet.type,
|
||||||
currentVersion = '' {
|
currentVersion = '' {
|
||||||
PackageInfo.fromPlatform()
|
PackageInfo.fromPlatform().then(
|
||||||
.then((PackageInfo packageInfo) => currentVersion = packageInfo.version);
|
(PackageInfo packageInfo) => currentVersion = packageInfo.version);
|
||||||
|
|
||||||
final priority = _settingsStore.priority[_wallet.type];
|
final priority = _settingsStore.priority[_wallet.type];
|
||||||
final priorities = priorityForWalletType(_wallet.type);
|
final priorities = priorityForWalletType(_wallet.type);
|
||||||
|
@ -31,7 +32,8 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
final WalletType walletType;
|
final WalletType walletType;
|
||||||
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> _wallet;
|
final WalletBase<Balance, TransactionHistoryBase<TransactionInfo>,
|
||||||
|
TransactionInfo> _wallet;
|
||||||
|
|
||||||
@observable
|
@observable
|
||||||
String currentVersion;
|
String currentVersion;
|
||||||
|
@ -50,15 +52,19 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get changeRepresentativeEnabled {
|
bool get changeRepresentativeEnabled =>
|
||||||
if (_wallet.type == WalletType.nano || _wallet.type == WalletType.banano) {
|
_wallet.type == WalletType.nano || _wallet.type == WalletType.banano;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
@computed
|
||||||
}
|
bool get isEnabledBuyAction =>
|
||||||
|
!_settingsStore.disableBuy && _wallet.type != WalletType.haven;
|
||||||
|
|
||||||
BuyProviderType get buyProviderType { return _settingsStore.defaultBuyProvider; }
|
List<BuyProviderType> get availableBuyProviders =>
|
||||||
|
BuyProviderType.getAvailableProviders(walletType);
|
||||||
|
|
||||||
|
BuyProviderType get buyProviderType =>
|
||||||
|
_settingsStore.defaultBuyProviders[walletType] ??
|
||||||
|
BuyProviderType.AskEachTime;
|
||||||
|
|
||||||
String getDisplayPriority(dynamic priority) {
|
String getDisplayPriority(dynamic priority) {
|
||||||
final _priority = priority as TransactionPriority;
|
final _priority = priority as TransactionPriority;
|
||||||
|
@ -83,6 +89,5 @@ abstract class OtherSettingsViewModelBase with Store {
|
||||||
_settingsStore.priority[_wallet.type] = priority;
|
_settingsStore.priority[_wallet.type] = priority;
|
||||||
|
|
||||||
void onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
|
void onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
|
||||||
_settingsStore.defaultBuyProvider = buyProviderType;
|
_settingsStore.defaultBuyProviders[walletType] = buyProviderType;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/haven/haven.dart';
|
import 'package:cake_wallet/haven/haven.dart';
|
||||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
||||||
|
import 'package:polyseed/polyseed.dart';
|
||||||
|
|
||||||
part 'wallet_keys_view_model.g.dart';
|
part 'wallet_keys_view_model.g.dart';
|
||||||
|
|
||||||
|
@ -74,6 +75,15 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
|
StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
|
||||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
|
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
if (_appStore.wallet?.seed != null && Polyseed.isValidSeed(_appStore.wallet!.seed!)) {
|
||||||
|
final lang = PolyseedLang.getByPhrase(_appStore.wallet!.seed!);
|
||||||
|
final legacyLang = _getLegacySeedLang(lang);
|
||||||
|
final legacySeed =
|
||||||
|
Polyseed.decode(_appStore.wallet!.seed!, lang, PolyseedCoin.POLYSEED_MONERO)
|
||||||
|
.toLegacySeed(legacyLang);
|
||||||
|
items.add(StandartListItem(title: S.current.wallet_seed_legacy, value: legacySeed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_appStore.wallet!.type == WalletType.haven) {
|
if (_appStore.wallet!.type == WalletType.haven) {
|
||||||
|
@ -207,4 +217,23 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
String getRoundedRestoreHeight(int height) => ((height / 1000).floor() * 1000).toString();
|
String getRoundedRestoreHeight(int height) => ((height / 1000).floor() * 1000).toString();
|
||||||
|
|
||||||
|
LegacySeedLang _getLegacySeedLang(PolyseedLang lang) {
|
||||||
|
switch (lang.nameEnglish) {
|
||||||
|
case "Spanish":
|
||||||
|
return LegacySeedLang.getByEnglishName("Spanish");
|
||||||
|
case "French":
|
||||||
|
return LegacySeedLang.getByEnglishName("French");
|
||||||
|
case "Italian":
|
||||||
|
return LegacySeedLang.getByEnglishName("Italian");
|
||||||
|
case "Japanese":
|
||||||
|
return LegacySeedLang.getByEnglishName("Japanese");
|
||||||
|
case "Portuguese":
|
||||||
|
return LegacySeedLang.getByEnglishName("Portuguese");
|
||||||
|
case "Chinese (Simplified)":
|
||||||
|
return LegacySeedLang.getByEnglishName("Chinese (simplified)");
|
||||||
|
default:
|
||||||
|
return LegacySeedLang.getByEnglishName("English");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
|
@ -19,7 +20,7 @@ abstract class WalletListViewModelBase with Store {
|
||||||
this._walletLoadingService,
|
this._walletLoadingService,
|
||||||
this._authService,
|
this._authService,
|
||||||
) : wallets = ObservableList<WalletListItem>() {
|
) : wallets = ObservableList<WalletListItem>() {
|
||||||
updateList();
|
setOrderType(_appStore.settingsStore.walletListOrder);
|
||||||
reaction((_) => _appStore.wallet, (_) => updateList());
|
reaction((_) => _appStore.wallet, (_) => updateList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,11 +44,14 @@ abstract class WalletListViewModelBase with Store {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> loadWallet(WalletListItem walletItem) async {
|
Future<void> loadWallet(WalletListItem walletItem) async {
|
||||||
final wallet =
|
final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name);
|
||||||
await _walletLoadingService.load(walletItem.type, walletItem.name);
|
|
||||||
_appStore.changeCurrentWallet(wallet);
|
_appStore.changeCurrentWallet(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WalletListOrderType? get orderType => _appStore.settingsStore.walletListOrder;
|
||||||
|
|
||||||
|
bool get ascending => _appStore.settingsStore.walletListAscending;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
void updateList() {
|
void updateList() {
|
||||||
wallets.clear();
|
wallets.clear();
|
||||||
|
@ -57,14 +61,105 @@ abstract class WalletListViewModelBase with Store {
|
||||||
name: info.name,
|
name: info.name,
|
||||||
type: info.type,
|
type: info.type,
|
||||||
key: info.key,
|
key: info.key,
|
||||||
isCurrent: info.name == _appStore.wallet?.name &&
|
isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
|
||||||
info.type == _appStore.wallet?.type,
|
|
||||||
isEnabled: availableWalletTypes.contains(info.type),
|
isEnabled: availableWalletTypes.contains(info.type),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> reorderAccordingToWalletList() async {
|
||||||
|
if (wallets.isEmpty) {
|
||||||
|
updateList();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_appStore.settingsStore.walletListOrder = WalletListOrderType.Custom;
|
||||||
|
|
||||||
|
// make a copy of the walletInfoSource:
|
||||||
|
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
|
||||||
|
// delete all wallets from walletInfoSource:
|
||||||
|
await _walletInfoSource.clear();
|
||||||
|
|
||||||
|
// add wallets from wallets list in order of wallets list, by name:
|
||||||
|
for (WalletListItem wallet in wallets) {
|
||||||
|
for (int i = 0; i < walletInfoSourceCopy.length; i++) {
|
||||||
|
if (walletInfoSourceCopy[i].name == wallet.name) {
|
||||||
|
await _walletInfoSource.add(walletInfoSourceCopy[i]);
|
||||||
|
walletInfoSourceCopy.removeAt(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> sortGroupByType() async {
|
||||||
|
// sort the wallets by type:
|
||||||
|
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
|
||||||
|
await _walletInfoSource.clear();
|
||||||
|
if (ascending) {
|
||||||
|
walletInfoSourceCopy.sort((a, b) => a.type.toString().compareTo(b.type.toString()));
|
||||||
|
} else {
|
||||||
|
walletInfoSourceCopy.sort((a, b) => b.type.toString().compareTo(a.type.toString()));
|
||||||
|
}
|
||||||
|
await _walletInfoSource.addAll(walletInfoSourceCopy);
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> sortAlphabetically() async {
|
||||||
|
// sort the wallets alphabetically:
|
||||||
|
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
|
||||||
|
await _walletInfoSource.clear();
|
||||||
|
if (ascending) {
|
||||||
|
walletInfoSourceCopy.sort((a, b) => a.name.compareTo(b.name));
|
||||||
|
} else {
|
||||||
|
walletInfoSourceCopy.sort((a, b) => b.name.compareTo(a.name));
|
||||||
|
}
|
||||||
|
await _walletInfoSource.addAll(walletInfoSourceCopy);
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> sortByCreationDate() async {
|
||||||
|
// sort the wallets by creation date:
|
||||||
|
List<WalletInfo> walletInfoSourceCopy = _walletInfoSource.values.toList();
|
||||||
|
await _walletInfoSource.clear();
|
||||||
|
if (ascending) {
|
||||||
|
walletInfoSourceCopy.sort((a, b) => a.date.compareTo(b.date));
|
||||||
|
} else {
|
||||||
|
walletInfoSourceCopy.sort((a, b) => b.date.compareTo(a.date));
|
||||||
|
}
|
||||||
|
await _walletInfoSource.addAll(walletInfoSourceCopy);
|
||||||
|
updateList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setAscending(bool ascending) {
|
||||||
|
_appStore.settingsStore.walletListAscending = ascending;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setOrderType(WalletListOrderType? type) async {
|
||||||
|
if (type == null) return;
|
||||||
|
|
||||||
|
_appStore.settingsStore.walletListOrder = type;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case WalletListOrderType.CreationDate:
|
||||||
|
await sortByCreationDate();
|
||||||
|
break;
|
||||||
|
case WalletListOrderType.Alphabetical:
|
||||||
|
await sortAlphabetically();
|
||||||
|
break;
|
||||||
|
case WalletListOrderType.GroupByType:
|
||||||
|
await sortGroupByType();
|
||||||
|
break;
|
||||||
|
case WalletListOrderType.Custom:
|
||||||
|
default:
|
||||||
|
await reorderAccordingToWalletList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool checkIfAuthRequired() {
|
bool checkIfAuthRequired() {
|
||||||
return _authService.requireAuth();
|
return _authService.requireAuth();
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,7 @@ dependencies:
|
||||||
bitcoin_flutter:
|
bitcoin_flutter:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
url: https://github.com/cake-tech/bitcoin_flutter.git
|
||||||
ref: cake-update-v3
|
ref: cake-update-v4
|
||||||
fluttertoast: 8.1.4
|
fluttertoast: 8.1.4
|
||||||
# tor:
|
# tor:
|
||||||
# git:
|
# git:
|
||||||
|
@ -97,9 +97,7 @@ dependencies:
|
||||||
# ref: main
|
# ref: main
|
||||||
socks5_proxy: ^1.0.4
|
socks5_proxy: ^1.0.4
|
||||||
flutter_svg: ^2.0.9
|
flutter_svg: ^2.0.9
|
||||||
polyseed:
|
polyseed: ^0.0.2
|
||||||
git:
|
|
||||||
url: https://github.com/cake-tech/polyseed_dart.git
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
@ -733,6 +733,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "ﺔﻴﺟﺭﺎﺧ ﻆﻓﺎﺤﻣ ﻰﻟﺇ ﺕﻻﺩﺎﺒﺘﻟﺍ ﺐﻠﻄﺘﺗ",
|
"require_for_exchanges_to_external_wallets": "ﺔﻴﺟﺭﺎﺧ ﻆﻓﺎﺤﻣ ﻰﻟﺇ ﺕﻻﺩﺎﺒﺘﻟﺍ ﺐﻠﻄﺘﺗ",
|
||||||
"camera_permission_is_required": ".ﺍﺮﻴﻣﺎﻜﻟﺍ ﻥﺫﺇ ﺏﻮﻠﻄﻣ",
|
"camera_permission_is_required": ".ﺍﺮﻴﻣﺎﻜﻟﺍ ﻥﺫﺇ ﺏﻮﻠﻄﻣ",
|
||||||
"switchToETHWallet": "ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ Ethereum ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ",
|
"switchToETHWallet": "ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ Ethereum ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ",
|
||||||
|
"order_by": "ترتيب حسب",
|
||||||
|
"creation_date": "تاريخ الإنشاء",
|
||||||
|
"group_by_type": "مجموعة حسب النوع",
|
||||||
"importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ",
|
"importNFTs": "NFTs ﺩﺍﺮﻴﺘﺳﺍ",
|
||||||
"noNFTYet": "ﻥﻵﺍ ﻰﺘﺣ NFTs ﺪﺟﻮﻳ ﻻ",
|
"noNFTYet": "ﻥﻵﺍ ﻰﺘﺣ NFTs ﺪﺟﻮﻳ ﻻ",
|
||||||
"address": " ﻥﺍﻮﻨﻋ",
|
"address": " ﻥﺍﻮﻨﻋ",
|
||||||
|
@ -752,5 +755,11 @@
|
||||||
"seed_language_czech": "التشيكية",
|
"seed_language_czech": "التشيكية",
|
||||||
"seed_language_korean": "الكورية",
|
"seed_language_korean": "الكورية",
|
||||||
"seed_language_chinese_traditional": "تقاليد صينية)",
|
"seed_language_chinese_traditional": "تقاليد صينية)",
|
||||||
"polygonscan_history": "ﻥﺎﻜﺴﻧﻮﺠﻴﻟﻮﺑ ﺦﻳﺭﺎﺗ"
|
"ascending": "تصاعدي",
|
||||||
|
"descending": "النزول",
|
||||||
|
"dfx_option_description": "ﺎﺑﻭﺭﻭﺃ ﻲﻓ ﺕﺎﻛﺮﺸﻟﺍﻭ ﺔﺋﺰﺠﺘﻟﺍ ءﻼﻤﻌﻟ .ﻲﻓﺎﺿﺇ KYC ﻥﻭﺪﺑ ﻭﺭﻮﻳ 990 ﻰﻟﺇ ﻞﺼﻳ ﺎﻣ .ﻱﺮﺴﻳﻮﺴﻟﺍ",
|
||||||
|
"polygonscan_history": "ﻥﺎﻜﺴﻧﻮﺠﻴﻟﻮﺑ ﺦﻳﺭﺎﺗ",
|
||||||
|
"wallet_seed_legacy": "بذرة محفظة قديمة",
|
||||||
|
"custom_drag": "مخصص (عقد وسحب)",
|
||||||
|
"switchToEVMCompatibleWallet": " (Ethereum، Polygon) ﻯﺮﺧﺃ ﺓﺮﻣ ﺔﻟﻭﺎﺤﻤﻟﺍﻭ EVM ﻊﻣ ﺔﻘﻓﺍﻮﺘﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻰﺟﺮﻳ"
|
||||||
}
|
}
|
||||||
|
|
|
@ -729,6 +729,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Изискване за обмен към външни портфейли",
|
"require_for_exchanges_to_external_wallets": "Изискване за обмен към външни портфейли",
|
||||||
"camera_permission_is_required": "Изисква се разрешение за камерата.\nМоля, активирайте го от настройките на приложението.",
|
"camera_permission_is_required": "Изисква се разрешение за камерата.\nМоля, активирайте го от настройките на приложението.",
|
||||||
"switchToETHWallet": "Моля, преминете към портфейл Ethereum и опитайте отново",
|
"switchToETHWallet": "Моля, преминете към портфейл Ethereum и опитайте отново",
|
||||||
|
"order_by": "Подредени по",
|
||||||
|
"creation_date": "Дата на създаване",
|
||||||
|
"group_by_type": "Група по вид",
|
||||||
"importNFTs": "Импортирайте NFT",
|
"importNFTs": "Импортирайте NFT",
|
||||||
"noNFTYet": "Все още няма NFT",
|
"noNFTYet": "Все още няма NFT",
|
||||||
"address": "Адрес",
|
"address": "Адрес",
|
||||||
|
@ -748,5 +751,11 @@
|
||||||
"seed_language_czech": "Чех",
|
"seed_language_czech": "Чех",
|
||||||
"seed_language_korean": "Корейски",
|
"seed_language_korean": "Корейски",
|
||||||
"seed_language_chinese_traditional": "Традиционен китайски)",
|
"seed_language_chinese_traditional": "Традиционен китайски)",
|
||||||
"polygonscan_history": "История на PolygonScan"
|
"ascending": "Възходящ",
|
||||||
|
"descending": "Низходящ",
|
||||||
|
"dfx_option_description": "Купете крипто с EUR и CHF. До 990 € без допълнителен KYC. За клиенти на дребно и корпоративни клиенти в Европа",
|
||||||
|
"polygonscan_history": "История на PolygonScan",
|
||||||
|
"wallet_seed_legacy": "Наследено портфейл семе",
|
||||||
|
"custom_drag": "Персонализиране (задръжте и плъзнете)",
|
||||||
|
"switchToEVMCompatibleWallet": "Моля, превключете към портфейл, съвместим с EVM, и опитайте отново (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -729,6 +729,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Vyžadovat pro výměny do externích peněženek",
|
"require_for_exchanges_to_external_wallets": "Vyžadovat pro výměny do externích peněženek",
|
||||||
"camera_permission_is_required": "Vyžaduje se povolení fotoaparátu.\nPovolte jej v nastavení aplikace.",
|
"camera_permission_is_required": "Vyžaduje se povolení fotoaparátu.\nPovolte jej v nastavení aplikace.",
|
||||||
"switchToETHWallet": "Přejděte na peněženku Ethereum a zkuste to znovu",
|
"switchToETHWallet": "Přejděte na peněženku Ethereum a zkuste to znovu",
|
||||||
|
"order_by": "Seřadit podle",
|
||||||
|
"creation_date": "Datum vzniku",
|
||||||
|
"group_by_type": "Skupina podle typu",
|
||||||
"importNFTs": "Importujte NFT",
|
"importNFTs": "Importujte NFT",
|
||||||
"noNFTYet": "Zatím žádné NFT",
|
"noNFTYet": "Zatím žádné NFT",
|
||||||
"address": "Adresa",
|
"address": "Adresa",
|
||||||
|
@ -748,5 +751,11 @@
|
||||||
"seed_language_czech": "čeština",
|
"seed_language_czech": "čeština",
|
||||||
"seed_language_korean": "korejština",
|
"seed_language_korean": "korejština",
|
||||||
"seed_language_chinese_traditional": "Číňan (tradiční)",
|
"seed_language_chinese_traditional": "Číňan (tradiční)",
|
||||||
"polygonscan_history": "Historie PolygonScan"
|
"ascending": "Vzestupné",
|
||||||
|
"descending": "Klesající",
|
||||||
|
"dfx_option_description": "Nakupujte kryptoměny za EUR a CHF. Až 990 € bez dalších KYC. Pro maloobchodní a firemní zákazníky v Evropě",
|
||||||
|
"polygonscan_history": "Historie PolygonScan",
|
||||||
|
"wallet_seed_legacy": "Starší semeno peněženky",
|
||||||
|
"custom_drag": "Custom (Hold and Drag)",
|
||||||
|
"switchToEVMCompatibleWallet": "Přepněte na peněženku kompatibilní s EVM a zkuste to znovu (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,6 +737,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Erforderlich für den Umtausch in externe Wallets",
|
"require_for_exchanges_to_external_wallets": "Erforderlich für den Umtausch in externe Wallets",
|
||||||
"camera_permission_is_required": "Eine Kameraerlaubnis ist erforderlich.\nBitte aktivieren Sie es in den App-Einstellungen.",
|
"camera_permission_is_required": "Eine Kameraerlaubnis ist erforderlich.\nBitte aktivieren Sie es in den App-Einstellungen.",
|
||||||
"switchToETHWallet": "Bitte wechseln Sie zu einem Ethereum-Wallet und versuchen Sie es erneut",
|
"switchToETHWallet": "Bitte wechseln Sie zu einem Ethereum-Wallet und versuchen Sie es erneut",
|
||||||
|
"order_by": "Sortieren nach",
|
||||||
|
"creation_date": "Erstellungsdatum",
|
||||||
|
"group_by_type": "Gruppe nach Typ",
|
||||||
"importNFTs": "NFTs importieren",
|
"importNFTs": "NFTs importieren",
|
||||||
"noNFTYet": "Noch keine NFTs",
|
"noNFTYet": "Noch keine NFTs",
|
||||||
"address": "Adresse",
|
"address": "Adresse",
|
||||||
|
@ -756,5 +759,11 @@
|
||||||
"seed_language_czech": "Tschechisch",
|
"seed_language_czech": "Tschechisch",
|
||||||
"seed_language_korean": "Koreanisch",
|
"seed_language_korean": "Koreanisch",
|
||||||
"seed_language_chinese_traditional": "Chinesisch (Traditionell)",
|
"seed_language_chinese_traditional": "Chinesisch (Traditionell)",
|
||||||
"polygonscan_history": "PolygonScan-Verlauf"
|
"ascending": "Aufsteigend",
|
||||||
|
"descending": "Absteigend",
|
||||||
|
"dfx_option_description": "Krypto mit EUR und CHF kaufen. Bis zu 990€ ohne zusätzliches KYC. Für Privat- und Firmenkunden in Europa",
|
||||||
|
"polygonscan_history": "PolygonScan-Verlauf",
|
||||||
|
"wallet_seed_legacy": "Legacy Wallet Seed",
|
||||||
|
"custom_drag": "Custom (Hold and Drag)",
|
||||||
|
"switchToEVMCompatibleWallet": "Bitte wechseln Sie zu einem EVM-kompatiblen Wallet und versuchen Sie es erneut (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -498,7 +498,7 @@
|
||||||
"bill_amount": "Bill Amount",
|
"bill_amount": "Bill Amount",
|
||||||
"you_pay": "You Pay",
|
"you_pay": "You Pay",
|
||||||
"tip": "Tip:",
|
"tip": "Tip:",
|
||||||
"custom": "custom",
|
"custom": "Custom",
|
||||||
"by_cake_pay": "by Cake Pay",
|
"by_cake_pay": "by Cake Pay",
|
||||||
"expires": "Expires",
|
"expires": "Expires",
|
||||||
"mm": "MM",
|
"mm": "MM",
|
||||||
|
@ -738,6 +738,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Require for exchanges to external wallets",
|
"require_for_exchanges_to_external_wallets": "Require for exchanges to external wallets",
|
||||||
"camera_permission_is_required": "Camera permission is required. \nPlease enable it from app settings.",
|
"camera_permission_is_required": "Camera permission is required. \nPlease enable it from app settings.",
|
||||||
"switchToETHWallet": "Please switch to an Ethereum wallet and try again",
|
"switchToETHWallet": "Please switch to an Ethereum wallet and try again",
|
||||||
|
"order_by": "Order by",
|
||||||
|
"creation_date": "Creation Date",
|
||||||
|
"group_by_type": "Group by type",
|
||||||
"importNFTs": "Import NFTs",
|
"importNFTs": "Import NFTs",
|
||||||
"noNFTYet": "No NFTs yet",
|
"noNFTYet": "No NFTs yet",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
|
@ -757,5 +760,11 @@
|
||||||
"seed_language_czech": "Czech",
|
"seed_language_czech": "Czech",
|
||||||
"seed_language_korean": "Korean",
|
"seed_language_korean": "Korean",
|
||||||
"seed_language_chinese_traditional": "Chinese (Traditional)",
|
"seed_language_chinese_traditional": "Chinese (Traditional)",
|
||||||
"polygonscan_history": "PolygonScan history"
|
"ascending": "Ascending",
|
||||||
|
"descending": "Descending",
|
||||||
|
"dfx_option_description": "Buy crypto with EUR & CHF. Up to 990€ without additional KYC. For retail and corporate customers in Europe",
|
||||||
|
"polygonscan_history": "PolygonScan history",
|
||||||
|
"wallet_seed_legacy": "Legacy wallet seed",
|
||||||
|
"custom_drag": "Custom (Hold and Drag)",
|
||||||
|
"switchToEVMCompatibleWallet": "Please switch to an EVM compatible wallet and try again (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,6 +737,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Requerido para intercambios a billeteras externas",
|
"require_for_exchanges_to_external_wallets": "Requerido para intercambios a billeteras externas",
|
||||||
"camera_permission_is_required": "Se requiere permiso de la cámara.\nHabilítelo desde la configuración de la aplicación.",
|
"camera_permission_is_required": "Se requiere permiso de la cámara.\nHabilítelo desde la configuración de la aplicación.",
|
||||||
"switchToETHWallet": "Cambie a una billetera Ethereum e inténtelo nuevamente.",
|
"switchToETHWallet": "Cambie a una billetera Ethereum e inténtelo nuevamente.",
|
||||||
|
"order_by": "Ordenar",
|
||||||
|
"creation_date": "Fecha de creación",
|
||||||
|
"group_by_type": "Grupo por tipo",
|
||||||
"importNFTs": "Importar NFT",
|
"importNFTs": "Importar NFT",
|
||||||
"noNFTYet": "Aún no hay NFT",
|
"noNFTYet": "Aún no hay NFT",
|
||||||
"address": "DIRECCIÓN",
|
"address": "DIRECCIÓN",
|
||||||
|
@ -755,6 +758,12 @@
|
||||||
"seedtype_polyseed": "Polieta (16 palabras)",
|
"seedtype_polyseed": "Polieta (16 palabras)",
|
||||||
"seed_language_czech": "checo",
|
"seed_language_czech": "checo",
|
||||||
"seed_language_korean": "coreano",
|
"seed_language_korean": "coreano",
|
||||||
|
"ascending": "Ascendente",
|
||||||
|
"descending": "Descendente",
|
||||||
"seed_language_chinese_traditional": "Chino (tradicional)",
|
"seed_language_chinese_traditional": "Chino (tradicional)",
|
||||||
"polygonscan_history": "Historial de PolygonScan"
|
"dfx_option_description": "Compre criptomonedas con EUR y CHF. Hasta 990€ sin KYC adicional. Para clientes minoristas y corporativos en Europa",
|
||||||
|
"polygonscan_history": "Historial de PolygonScan",
|
||||||
|
"wallet_seed_legacy": "Semilla de billetera heredada",
|
||||||
|
"custom_drag": "Custom (mantenía y arrastre)",
|
||||||
|
"switchToEVMCompatibleWallet": "Cambie a una billetera compatible con EVM e inténtelo nuevamente (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -736,7 +736,6 @@
|
||||||
"domain_looks_up": "Résolution de nom",
|
"domain_looks_up": "Résolution de nom",
|
||||||
"require_for_exchanges_to_external_wallets": "Exiger pour les échanges vers des portefeuilles externes",
|
"require_for_exchanges_to_external_wallets": "Exiger pour les échanges vers des portefeuilles externes",
|
||||||
"camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.",
|
"camera_permission_is_required": "L'autorisation de la caméra est requise.\nVeuillez l'activer à partir des paramètres de l'application.",
|
||||||
"switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer",
|
|
||||||
"importNFTs": "Importer des NFT",
|
"importNFTs": "Importer des NFT",
|
||||||
"noNFTYet": "Pas encore de NFT",
|
"noNFTYet": "Pas encore de NFT",
|
||||||
"address": "Adresse",
|
"address": "Adresse",
|
||||||
|
@ -747,7 +746,11 @@
|
||||||
"seed_phrase_length": "Longueur de la phrase de départ",
|
"seed_phrase_length": "Longueur de la phrase de départ",
|
||||||
"unavailable_balance": "Solde indisponible",
|
"unavailable_balance": "Solde indisponible",
|
||||||
"unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
|
"unavailable_balance_description": "Solde indisponible : ce total comprend les fonds bloqués dans les transactions en attente et ceux que vous avez activement gelés dans vos paramètres de contrôle des pièces. Les soldes bloqués deviendront disponibles une fois leurs transactions respectives terminées, tandis que les soldes gelés resteront inaccessibles aux transactions jusqu'à ce que vous décidiez de les débloquer.",
|
||||||
|
"switchToETHWallet": "Veuillez passer à un portefeuille (wallet) Ethereum et réessayer",
|
||||||
"unspent_change": "Changement",
|
"unspent_change": "Changement",
|
||||||
|
"order_by": "Commandé par",
|
||||||
|
"creation_date": "Date de création",
|
||||||
|
"group_by_type": "Groupe par type",
|
||||||
"tor_connection": "Connexion Tor",
|
"tor_connection": "Connexion Tor",
|
||||||
"seed_hex_form": "Graine du portefeuille (forme hexagonale)",
|
"seed_hex_form": "Graine du portefeuille (forme hexagonale)",
|
||||||
"seedtype": "Type de type graine",
|
"seedtype": "Type de type graine",
|
||||||
|
@ -756,5 +759,11 @@
|
||||||
"seed_language_czech": "tchèque",
|
"seed_language_czech": "tchèque",
|
||||||
"seed_language_korean": "coréen",
|
"seed_language_korean": "coréen",
|
||||||
"seed_language_chinese_traditional": "Chinois (Traditionnel)",
|
"seed_language_chinese_traditional": "Chinois (Traditionnel)",
|
||||||
"polygonscan_history": "Historique de PolygonScan"
|
"ascending": "Ascendant",
|
||||||
|
"descending": "Descendant",
|
||||||
|
"dfx_option_description": "Achetez des crypto-monnaies avec EUR et CHF. Jusqu'à 990€ sans KYC supplémentaire. Pour les clients particuliers et entreprises en Europe",
|
||||||
|
"polygonscan_history": "Historique de PolygonScan",
|
||||||
|
"wallet_seed_legacy": "Graine de portefeuille hérité",
|
||||||
|
"custom_drag": "Custom (maintenir et traîner)",
|
||||||
|
"switchToEVMCompatibleWallet": "Veuillez passer à un portefeuille compatible EVM et réessayer (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -715,6 +715,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Bukatar musanya zuwa wallet na waje",
|
"require_for_exchanges_to_external_wallets": "Bukatar musanya zuwa wallet na waje",
|
||||||
"camera_permission_is_required": "Ana buƙatar izinin kyamara.\nDa fatan za a kunna shi daga saitunan app.",
|
"camera_permission_is_required": "Ana buƙatar izinin kyamara.\nDa fatan za a kunna shi daga saitunan app.",
|
||||||
"switchToETHWallet": "Da fatan za a canza zuwa walat ɗin Ethereum kuma a sake gwadawa",
|
"switchToETHWallet": "Da fatan za a canza zuwa walat ɗin Ethereum kuma a sake gwadawa",
|
||||||
|
"order_by": "Oda ta",
|
||||||
|
"creation_date": "Ranar halitta",
|
||||||
|
"group_by_type": "Rukuni ta nau'in",
|
||||||
"importNFTs": "Shigo da NFTs",
|
"importNFTs": "Shigo da NFTs",
|
||||||
"noNFTYet": "Babu NFTs tukuna",
|
"noNFTYet": "Babu NFTs tukuna",
|
||||||
"address": "Adireshi",
|
"address": "Adireshi",
|
||||||
|
@ -734,5 +737,11 @@
|
||||||
"seed_language_czech": "Czech",
|
"seed_language_czech": "Czech",
|
||||||
"seed_language_korean": "Yaren Koriya",
|
"seed_language_korean": "Yaren Koriya",
|
||||||
"seed_language_chinese_traditional": "Sinanci (na gargajiya)",
|
"seed_language_chinese_traditional": "Sinanci (na gargajiya)",
|
||||||
"polygonscan_history": "PolygonScan tarihin kowane zamani"
|
"ascending": "Hau",
|
||||||
|
"descending": "Saukowa",
|
||||||
|
"dfx_option_description": "Sayi crypto tare da EUR & CHF. Har zuwa € 990 ba tare da ƙarin KYC ba. Don 'yan kasuwa da abokan ciniki na kamfanoni a Turai",
|
||||||
|
"polygonscan_history": "PolygonScan tarihin kowane zamani",
|
||||||
|
"wallet_seed_legacy": "Tallarin walat walat",
|
||||||
|
"custom_drag": "Al'ada (riƙe da ja)",
|
||||||
|
"switchToEVMCompatibleWallet": "Da fatan za a canza zuwa walat ɗin EVM mai jituwa kuma a sake gwadawa (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -737,6 +737,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "बाहरी वॉलेट में एक्सचेंज की आवश्यकता है",
|
"require_for_exchanges_to_external_wallets": "बाहरी वॉलेट में एक्सचेंज की आवश्यकता है",
|
||||||
"camera_permission_is_required": "कैमरे की अनुमति आवश्यक है.\nकृपया इसे ऐप सेटिंग से सक्षम करें।",
|
"camera_permission_is_required": "कैमरे की अनुमति आवश्यक है.\nकृपया इसे ऐप सेटिंग से सक्षम करें।",
|
||||||
"switchToETHWallet": "कृपया एथेरियम वॉलेट पर स्विच करें और पुनः प्रयास करें",
|
"switchToETHWallet": "कृपया एथेरियम वॉलेट पर स्विच करें और पुनः प्रयास करें",
|
||||||
|
"order_by": "द्वारा आदेश",
|
||||||
|
"creation_date": "निर्माण तिथि",
|
||||||
|
"group_by_type": "प्रकार द्वारा समूह",
|
||||||
"importNFTs": "एनएफटी आयात करें",
|
"importNFTs": "एनएफटी आयात करें",
|
||||||
"noNFTYet": "अभी तक कोई एनएफटी नहीं",
|
"noNFTYet": "अभी तक कोई एनएफटी नहीं",
|
||||||
"address": "पता",
|
"address": "पता",
|
||||||
|
@ -756,5 +759,11 @@
|
||||||
"seed_language_czech": "चेक",
|
"seed_language_czech": "चेक",
|
||||||
"seed_language_korean": "कोरियाई",
|
"seed_language_korean": "कोरियाई",
|
||||||
"seed_language_chinese_traditional": "चीनी पारंपरिक)",
|
"seed_language_chinese_traditional": "चीनी पारंपरिक)",
|
||||||
"polygonscan_history": "पॉलीगॉनस्कैन इतिहास"
|
"ascending": "आरोही",
|
||||||
|
"descending": "अवरोही",
|
||||||
|
"dfx_option_description": "EUR और CHF के साथ क्रिप्टो खरीदें। अतिरिक्त केवाईसी के बिना 990€ तक। यूरोप में खुदरा और कॉर्पोरेट ग्राहकों के लिए",
|
||||||
|
"polygonscan_history": "पॉलीगॉनस्कैन इतिहास",
|
||||||
|
"wallet_seed_legacy": "विरासत बटुए बीज",
|
||||||
|
"custom_drag": "कस्टम (पकड़ और खींचें)",
|
||||||
|
"switchToEVMCompatibleWallet": "कृपया ईवीएम संगत वॉलेट पर स्विच करें और पुनः प्रयास करें (एथेरियम, पॉलीगॉन)"
|
||||||
}
|
}
|
||||||
|
|
|
@ -735,6 +735,9 @@
|
||||||
"require_for_exchanges_to_external_wallets": "Zahtijeva razmjene na vanjske novčanike",
|
"require_for_exchanges_to_external_wallets": "Zahtijeva razmjene na vanjske novčanike",
|
||||||
"camera_permission_is_required": "Potrebno je dopuštenje kamere.\nOmogućite ga u postavkama aplikacije.",
|
"camera_permission_is_required": "Potrebno je dopuštenje kamere.\nOmogućite ga u postavkama aplikacije.",
|
||||||
"switchToETHWallet": "Prijeđite na Ethereum novčanik i pokušajte ponovno",
|
"switchToETHWallet": "Prijeđite na Ethereum novčanik i pokušajte ponovno",
|
||||||
|
"order_by": "Narediti",
|
||||||
|
"creation_date": "Datum stvaranja",
|
||||||
|
"group_by_type": "Grupirati",
|
||||||
"importNFTs": "Uvoz NFT-ova",
|
"importNFTs": "Uvoz NFT-ova",
|
||||||
"noNFTYet": "Još nema NFT-ova",
|
"noNFTYet": "Još nema NFT-ova",
|
||||||
"address": "Adresa",
|
"address": "Adresa",
|
||||||
|
@ -753,6 +756,12 @@
|
||||||
"seedtype_polyseed": "Poliseed (16 riječi)",
|
"seedtype_polyseed": "Poliseed (16 riječi)",
|
||||||
"seed_language_czech": "češki",
|
"seed_language_czech": "češki",
|
||||||
"seed_language_korean": "korejski",
|
"seed_language_korean": "korejski",
|
||||||
|
"ascending": "Uzlazni",
|
||||||
|
"descending": "Silazni",
|
||||||
"seed_language_chinese_traditional": "Kinesko (tradicionalno)",
|
"seed_language_chinese_traditional": "Kinesko (tradicionalno)",
|
||||||
"polygonscan_history": "Povijest PolygonScan"
|
"dfx_option_description": "Kupujte kripto s EUR i CHF. Do 990 € bez dodatnog KYC-a. Za maloprodajne i poslovne korisnike u Europi",
|
||||||
|
"polygonscan_history": "Povijest PolygonScan",
|
||||||
|
"wallet_seed_legacy": "Sjeme naslijeđenog novčanika",
|
||||||
|
"custom_drag": "Prilagođeni (držite i povucite)",
|
||||||
|
"switchToEVMCompatibleWallet": "Prijeđite na novčanik kompatibilan s EVM-om i pokušajte ponovno (Ethereum, Polygon)"
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue