Reformat the whole codebase with 100 line width (#3403)

This commit is contained in:
Omar Hatem
2026-07-15 01:20:33 +03:00
committed by GitHub
parent 1241b28bec
commit 16ddc0837a
801 changed files with 17517 additions and 17091 deletions
+107 -107
View File
@@ -6,110 +6,110 @@ defaults:
run: run:
shell: bash shell: bash
jobs: jobs:
lint: # lint:
runs-on: [Linux, amd64, android] # runs-on: [Linux, amd64, android]
container: # container:
image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly # image: ghcr.io/cake-tech/cake_wallet:debian13-flutter3.41.9-ndkr28-go1.24.1-ruststablenightly
env: # env:
STORE_PASS: test@cake_wallet # STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet # KEY_PASS: test@cake_wallet
MONEROC_CACHE_DIR_ROOT: /opt/generic_cache # MONEROC_CACHE_DIR_ROOT: /opt/generic_cache
BRANCH_NAME: ${{ github.head_ref || github.ref_name }} # BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
ANDROID_AVD_HOME: /root/.android/avd # ANDROID_AVD_HOME: /root/.android/avd
volumes: # volumes:
- /opt/cw_cache_android/root/.cache:/root/.cache # - /opt/cw_cache_android/root/.cache:/root/.cache
- /opt/cw_cache_android/root/.android/avd/:/root/.android/avd # - /opt/cw_cache_android/root/.android/avd/:/root/.android/avd
- /opt/cw_cache_android/root/.ccache:/root/.ccache # - /opt/cw_cache_android/root/.ccache:/root/.ccache
- /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache # - /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache
- /opt/cw_cache_android/root/.gradle/:/root/.gradle # - /opt/cw_cache_android/root/.gradle/:/root/.gradle
- /opt/cw_cache_android/root/.android/:/root/.android # - /opt/cw_cache_android/root/.android/:/root/.android
- /opt/cw_cache_android/root/go/pkg:/root/go/pkg # - /opt/cw_cache_android/root/go/pkg:/root/go/pkg
- /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache # - /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache
- /dev/kvm:/dev/kvm # - /dev/kvm:/dev/kvm
- /var/run/docker.sock:/var/run/docker.sock # - /var/run/docker.sock:/var/run/docker.sock
strategy: # strategy:
matrix: # matrix:
api-level: [ 29 ] # api-level: [ 29 ]
#
steps: # steps:
- name: Fix github actions messing up $HOME... # - name: Fix github actions messing up $HOME...
run: "echo HOME=/root | sudo tee -a $GITHUB_ENV" # run: "echo HOME=/root | sudo tee -a $GITHUB_ENV"
- uses: actions/checkout@v4 # - uses: actions/checkout@v4
with: # with:
ref: ${{ inputs.ref }} # ref: ${{ inputs.ref }}
#
- name: configure git # - name: configure git
run: | # run: |
git config --global --add safe.directory '*' # git config --global --add safe.directory '*'
git config --global user.email "ci@cakewallet.com" # git config --global user.email "ci@cakewallet.com"
git config --global user.name "CakeWallet CI" # git config --global user.name "CakeWallet CI"
#
- name: Fetch prebuilt Torch # - name: Fetch prebuilt Torch
run: | # run: |
set -x -e # set -x -e
pushd scripts # pushd scripts
wget https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz -O torch_dart.tar.gz # wget https://github.com/MrCyjaneK/torch_dart/releases/download/v1.0.17/torch_dart-v1.0.17.tar.gz -O torch_dart.tar.gz
rm -rf torch_dart # rm -rf torch_dart
mkdir torch_dart # mkdir torch_dart
pushd torch_dart # pushd torch_dart
tar -xzf ../torch_dart.tar.gz # tar -xzf ../torch_dart.tar.gz
popd # popd
rm ./torch_dart.tar.gz # rm ./torch_dart.tar.gz
popd # popd
#
- name: Fetch prebuilt Reown # - name: Fetch prebuilt Reown
run: | # run: |
set -x -e # set -x -e
pushd scripts # pushd scripts
# cleaning # # cleaning
rm -rf reown_flutter # rm -rf reown_flutter
rm -f reown_flutter.tar.gz # rm -f reown_flutter.tar.gz
#
wget https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz -O reown_flutter.tar.gz # wget https://github.com/cake-tech/reown_flutter/releases/download/v0.0.4/reown_flutter-v0.0.4.tar.gz -O reown_flutter.tar.gz
mkdir reown_flutter # mkdir reown_flutter
pushd reown_flutter # pushd reown_flutter
tar -xzf ../reown_flutter.tar.gz # tar -xzf ../reown_flutter.tar.gz
popd # popd
rm ./reown_flutter.tar.gz # rm ./reown_flutter.tar.gz
popd # popd
#
- name: Build Bitbox Flutter # - name: Build Bitbox Flutter
run: | # run: |
set -x -e # set -x -e
pushd scripts # pushd scripts
./build_bitbox_flutter.sh # ./build_bitbox_flutter.sh
popd # popd
#
- name: Prepare Zcash # - name: Prepare Zcash
run: | # run: |
set -x -e # set -x -e
scripts/prepare_zcash.sh # scripts/prepare_zcash.sh
#
- name: Execute Build and Setup Commands # - name: Execute Build and Setup Commands
run: | # run: |
pushd scripts/android # pushd scripts/android
source ./app_env.sh cakewallet # source ./app_env.sh cakewallet
export GITHUB_HUH=yeah # export GITHUB_HUH=yeah
./app_config.sh # ./app_config.sh
popd # popd
#
- name: Install Flutter dependencies # - name: Install Flutter dependencies
run: | # run: |
flutter pub get # flutter pub get
#
- name: Build generated code # - name: Build generated code
run: | # run: |
flutter --version # flutter --version
flutter clean # flutter clean
rm -rf .dart_tool # rm -rf .dart_tool
rm pubspec.lock # rm pubspec.lock
flutter pub get # flutter pub get
./model_generator.sh async # ./model_generator.sh async
#
- name: Generate localization # - name: Generate localization
run: | # run: |
dart run tool/generate_localization.dart # dart run tool/generate_localization.dart
#
- name: Lint # - name: Lint
run: | # run: |
ABORT_ON_CHANGE=yeah scripts/lint.sh # ABORT_ON_CHANGE=yeah scripts/lint.sh
+5 -10
View File
@@ -17,21 +17,16 @@ BitcoinBaseAddress addressFromScript(Script script,
switch (addressType) { switch (addressType) {
case P2pkhAddressType.p2pkh: case P2pkhAddressType.p2pkh:
return P2pkhAddress.fromScriptPubkey( return P2pkhAddress.fromScriptPubkey(script: script, network: BitcoinNetwork.mainnet);
script: script, network: BitcoinNetwork.mainnet);
case P2shAddressType.p2pkhInP2sh: case P2shAddressType.p2pkhInP2sh:
case P2shAddressType.p2pkInP2sh: case P2shAddressType.p2pkInP2sh:
return P2shAddress.fromScriptPubkey( return P2shAddress.fromScriptPubkey(script: script, network: BitcoinNetwork.mainnet);
script: script, network: BitcoinNetwork.mainnet);
case SegwitAddresType.p2wpkh: case SegwitAddresType.p2wpkh:
return P2wpkhAddress.fromScriptPubkey( return P2wpkhAddress.fromScriptPubkey(script: script, network: BitcoinNetwork.mainnet);
script: script, network: BitcoinNetwork.mainnet);
case SegwitAddresType.p2wsh: case SegwitAddresType.p2wsh:
return P2wshAddress.fromScriptPubkey( return P2wshAddress.fromScriptPubkey(script: script, network: BitcoinNetwork.mainnet);
script: script, network: BitcoinNetwork.mainnet);
case SegwitAddresType.p2tr: case SegwitAddresType.p2tr:
return P2trAddress.fromScriptPubkey( return P2trAddress.fromScriptPubkey(script: script, network: BitcoinNetwork.mainnet);
script: script, network: BitcoinNetwork.mainnet);
} }
throw ArgumentError("Invalid script"); throw ArgumentError("Invalid script");
+3 -5
View File
@@ -79,10 +79,9 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
} catch (e) { } catch (e) {
printV(e); printV(e);
} }
} }
static bool _legacyDefaultForType(BitcoinAddressType type) { static bool _legacyDefaultForType(BitcoinAddressType type) {
// Some address types (p2wpkh, p2wsh) were historically derived from the same account/path as our new standard // Some address types (p2wpkh, p2wsh) were historically derived from the same account/path as our new standard
// but using legacy formats. For these, we default to legacy = false. // but using legacy formats. For these, we default to legacy = false.
if (type == SegwitAddresType.p2wpkh || type == SegwitAddresType.p2wsh) return false; if (type == SegwitAddresType.p2wpkh || type == SegwitAddresType.p2wsh) return false;
@@ -154,6 +153,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
} }
return scriptHash!; return scriptHash!;
} }
@override @override
String get derivationPath { String get derivationPath {
if (type == SegwitAddresType.mweb) { if (type == SegwitAddresType.mweb) {
@@ -162,9 +162,7 @@ class BitcoinAddressRecord extends BaseBitcoinAddressRecord {
final coinType = _coinTypeForNetwork(); final coinType = _coinTypeForNetwork();
final purpose = _purposeForType(type); final purpose = _purposeForType(type);
final accountPath = isLegacyDerivation final accountPath = isLegacyDerivation ? electrum_path : "m/$purpose'/$coinType'/0'";
? electrum_path
: "m/$purpose'/$coinType'/0'";
final chain = isHidden ? 1 : 0; final chain = isHidden ? 1 : 0;
return "$accountPath/$chain/$index"; return "$accountPath/$chain/$index";
+2 -2
View File
@@ -7,8 +7,8 @@ final bitcoinAmountFormat = NumberFormat()
..maximumFractionDigits = bitcoinAmountLength ..maximumFractionDigits = bitcoinAmountLength
..minimumFractionDigits = 1; ..minimumFractionDigits = 1;
String bitcoinAmountToString({required int amount}) => bitcoinAmountFormat.format( String bitcoinAmountToString({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider)); bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
double bitcoinAmountToDouble({required int amount}) => double bitcoinAmountToDouble({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider); cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
@@ -5,4 +5,3 @@ class BitcoinCommitTransactionException implements Exception {
@override @override
String toString() => errorMessage; String toString() => errorMessage;
} }
@@ -2,7 +2,8 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
class BitcoinTransactionPriority extends TransactionPriority { class BitcoinTransactionPriority extends TransactionPriority {
const BitcoinTransactionPriority({required String title, required int raw, String? description, String? hint}) const BitcoinTransactionPriority(
{required String title, required int raw, String? description, String? hint})
: super(title: title, raw: raw, description: description, hint: hint); : super(title: title, raw: raw, description: description, hint: hint);
static const List<BitcoinTransactionPriority> all = [fast, medium, slow, custom]; static const List<BitcoinTransactionPriority> all = [fast, medium, slow, custom];
@@ -10,8 +11,8 @@ class BitcoinTransactionPriority extends TransactionPriority {
BitcoinTransactionPriority(title: 'Slow', description: "2 sat/byte", hint: "~ 24 h", raw: 0); BitcoinTransactionPriority(title: 'Slow', description: "2 sat/byte", hint: "~ 24 h", raw: 0);
static const BitcoinTransactionPriority medium = static const BitcoinTransactionPriority medium =
BitcoinTransactionPriority(title: 'Medium', description: "3 sat/byte", hint: "~ 1 h", raw: 1); BitcoinTransactionPriority(title: 'Medium', description: "3 sat/byte", hint: "~ 1 h", raw: 1);
static const BitcoinTransactionPriority fast = static const BitcoinTransactionPriority fast = BitcoinTransactionPriority(
BitcoinTransactionPriority(title: 'Fast', description: "4 sat/byte", hint: "~ 30 min", raw: 2); title: 'Fast', description: "4 sat/byte", hint: "~ 30 min", raw: 2);
static const BitcoinTransactionPriority custom = static const BitcoinTransactionPriority custom =
BitcoinTransactionPriority(title: 'Custom', raw: 3); BitcoinTransactionPriority(title: 'Custom', raw: 3);
@@ -116,8 +117,8 @@ class LitecoinTransactionPriority extends BitcoinTransactionPriority {
return label; return label;
} }
} }
class BitcoinCashTransactionPriority extends BitcoinTransactionPriority { class BitcoinCashTransactionPriority extends BitcoinTransactionPriority {
const BitcoinCashTransactionPriority({required String title, required int raw}) const BitcoinCashTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw); : super(title: title, raw: raw);
@@ -170,4 +171,3 @@ class BitcoinCashTransactionPriority extends BitcoinTransactionPriority {
return label; return label;
} }
} }
+5 -3
View File
@@ -494,7 +494,9 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
@override @override
Future<PendingTransaction> createTransaction(Object credentials) async { Future<PendingTransaction> createTransaction(Object credentials) async {
credentials = credentials as BitcoinTransactionCredentials; credentials = credentials as BitcoinTransactionCredentials;
final lnAddr = credentials.outputs.first.isParsedAddress ? credentials.outputs.first.extractedAddress! : credentials.outputs.first.address; final lnAddr = credentials.outputs.first.isParsedAddress
? credentials.outputs.first.extractedAddress!
: credentials.outputs.first.address;
final isLNCompatible = await lightningWallet?.isCompatible(lnAddr); final isLNCompatible = await lightningWallet?.isCompatible(lnAddr);
if ((credentials.coinTypeToSpendFrom == UnspentCoinType.lightning && lightningWallet != null) || if ((credentials.coinTypeToSpendFrom == UnspentCoinType.lightning && lightningWallet != null) ||
@@ -506,12 +508,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
amount = credentials.outputs.first.cryptoAmount; amount = credentials.outputs.first.cryptoAmount;
} }
return lightningWallet!.createTransaction( return lightningWallet!.createTransaction(
lnAddr, lnAddr,
amount.amount > BigInt.zero ? amount.amount : null, amount.amount > BigInt.zero ? amount.amount : null,
credentials.priority, credentials.priority,
credentials.outputs.first.sendAll,); credentials.outputs.first.sendAll,
);
} }
final tx = (await super.createTransaction(credentials)) as PendingBitcoinTransaction; final tx = (await super.createTransaction(credentials)) as PendingBitcoinTransaction;
+3 -5
View File
@@ -137,7 +137,8 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
} }
@override @override
bool containsAddress(String address) => super.containsAddress(address) || address == lightningAddress; bool containsAddress(String address) =>
super.containsAddress(address) || address == lightningAddress;
@override @override
String get addressForBuy { String get addressForBuy {
@@ -153,12 +154,9 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
@override @override
String get addressForExchange { String get addressForExchange {
final current = getFreshAddress(); final current = getFreshAddress();
final availableReceiveAddresses = receiveAddresses.where((element) => final availableReceiveAddresses = receiveAddresses.where((element) =>
!element.isUsed && !element.isUsed && !element.isHidden && !hiddenAddresses.contains(element.address));
!element.isHidden &&
!hiddenAddresses.contains(element.address));
final bool isSilentPaymentsPage = addressPageType == SilentPaymentsAddresType.p2sp; final bool isSilentPaymentsPage = addressPageType == SilentPaymentsAddresType.p2sp;
final bool isLightningPage = addressPageType == LightningAddressType.p2l; final bool isLightningPage = addressPageType == LightningAddressType.p2l;
@@ -59,27 +59,27 @@ class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials {
} }
class BitcoinWalletFromKeysCredentials extends WalletCredentials { class BitcoinWalletFromKeysCredentials extends WalletCredentials {
BitcoinWalletFromKeysCredentials({ BitcoinWalletFromKeysCredentials(
required String name, {required String name,
required String password, required String password,
required this.xpub, required this.xpub,
WalletInfo? walletInfo, WalletInfo? walletInfo,
super.hardwareWalletType super.hardwareWalletType})
}) : super(name: name, password: password, walletInfo: walletInfo); : super(name: name, password: password, walletInfo: walletInfo);
final String xpub; final String xpub;
} }
class LitecoinWalletFromKeysCredentials extends WalletCredentials { class LitecoinWalletFromKeysCredentials extends WalletCredentials {
LitecoinWalletFromKeysCredentials({ LitecoinWalletFromKeysCredentials(
required String name, {required String name,
required String password, required String password,
required this.xpub, required this.xpub,
required this.scanSecret, required this.scanSecret,
required this.spendPubkey, required this.spendPubkey,
WalletInfo? walletInfo, WalletInfo? walletInfo,
super.hardwareWalletType super.hardwareWalletType})
}) : super(name: name, password: password, walletInfo: walletInfo); : super(name: name, password: password, walletInfo: walletInfo);
final String xpub; final String xpub;
final String scanSecret; final String scanSecret;
+4 -7
View File
@@ -1,15 +1,12 @@
class BitcoinWalletKeys { class BitcoinWalletKeys {
const BitcoinWalletKeys({required this.wif, required this.privateKey, required this.publicKey, required this.xpub}); const BitcoinWalletKeys(
{required this.wif, required this.privateKey, required this.publicKey, required this.xpub});
final String wif; final String wif;
final String privateKey; final String privateKey;
final String publicKey; final String publicKey;
final String xpub; final String xpub;
Map<String, String> toJson() => { Map<String, String> toJson() =>
'wif': wif, {'wif': wif, 'privateKey': privateKey, 'publicKey': publicKey, 'xpub': xpub};
'privateKey': privateKey,
'publicKey': publicKey,
'xpub': xpub
};
} }
+11 -9
View File
@@ -21,8 +21,7 @@ class BitcoinWalletService extends WalletService<
BitcoinRestoreWalletFromSeedCredentials, BitcoinRestoreWalletFromSeedCredentials,
BitcoinWalletFromKeysCredentials, BitcoinWalletFromKeysCredentials,
BitcoinRestoreWalletFromHardware> { BitcoinRestoreWalletFromHardware> {
BitcoinWalletService(this.unspentCoinsInfoSource, BitcoinWalletService(this.unspentCoinsInfoSource, this.payjoinSessionSource, this.isDirect);
this.payjoinSessionSource, this.isDirect);
final Box<UnspentCoinsInfo> unspentCoinsInfoSource; final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
final Box<PayjoinSession> payjoinSessionSource; final Box<PayjoinSession> payjoinSessionSource;
@@ -38,9 +37,12 @@ class BitcoinWalletService extends WalletService<
final String mnemonic; final String mnemonic;
final derivationInfo = await credentials.walletInfo!.getDerivationInfo(); final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
derivationInfo.derivationType = credentials.derivationInfo?.derivationType ?? derivationInfo.derivationType; derivationInfo.derivationType =
derivationInfo.derivationPath = credentials.derivationInfo?.derivationPath ?? derivationInfo.derivationPath; credentials.derivationInfo?.derivationType ?? derivationInfo.derivationType;
derivationInfo.description = credentials.derivationInfo?.description ?? derivationInfo.description; derivationInfo.derivationPath =
credentials.derivationInfo?.derivationPath ?? derivationInfo.derivationPath;
derivationInfo.description =
credentials.derivationInfo?.description ?? derivationInfo.description;
derivationInfo.scriptType = credentials.derivationInfo?.scriptType ?? derivationInfo.scriptType; derivationInfo.scriptType = credentials.derivationInfo?.scriptType ?? derivationInfo.scriptType;
await derivationInfo.save(); await derivationInfo.save();
switch (derivationInfo.derivationType) { switch (derivationInfo.derivationType) {
@@ -119,8 +121,9 @@ class BitcoinWalletService extends WalletService<
} }
await WalletInfo.delete(walletInfo); await WalletInfo.delete(walletInfo);
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where( final unspentCoinsToDelete = unspentCoinsInfoSource.values
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList(); .where((unspentCoin) => unspentCoin.walletId == walletInfo.id)
.toList();
final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList(); final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList();
@@ -135,8 +138,7 @@ class BitcoinWalletService extends WalletService<
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet; final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
credentials.walletInfo?.network = network.value; credentials.walletInfo?.network = network.value;
final derivationInfo = await credentials.walletInfo!.getDerivationInfo(); final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
derivationInfo.derivationPath = derivationInfo.derivationPath = credentials.hwAccountData.derivationPath;
credentials.hwAccountData.derivationPath;
final xpub = convertAnyToXpub(credentials.hwAccountData.xpub!); final xpub = convertAnyToXpub(credentials.hwAccountData.xpub!);
+2 -7
View File
@@ -483,12 +483,8 @@ class ElectrumClient {
// Build the Batch Array // Build the Batch Array
final List<Map<String, dynamic>> batchPayload = []; final List<Map<String, dynamic>> batchPayload = [];
for (int i = 0; i < paramsList.length; i++) { for (int i = 0; i < paramsList.length; i++) {
batchPayload.add({ batchPayload.add(
"jsonrpc": "2.0", {"jsonrpc": "2.0", "method": method, "params": paramsList[i], "id": "$batchBaseId-$i"});
"method": method,
"params": paramsList[i],
"id": "$batchBaseId-$i"
});
} }
// Register the task // Register the task
@@ -775,7 +771,6 @@ class ElectrumClient {
} }
void _handleResponse(dynamic response) { void _handleResponse(dynamic response) {
// Handle batch response // Handle batch response
if (response is List) { if (response is List) {
if (response.isEmpty) return; if (response.isEmpty) return;
@@ -1,6 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cw_bitcoin/electrum_transaction_info.dart'; import 'package:cw_bitcoin/electrum_transaction_info.dart';
import 'package:cw_core/encryption_file_utils.dart'; import 'package:cw_core/encryption_file_utils.dart';
import 'package:cw_core/pathForWallet.dart'; import 'package:cw_core/pathForWallet.dart';
@@ -184,15 +184,13 @@ class ElectrumTransactionInfo extends TransactionInfo {
// MWEB HogEx // MWEB HogEx
final isHogExTx = (BtcTransaction tx) { final isHogExTx = (BtcTransaction tx) {
if (tx.inputs.isEmpty || tx.inputs.first.txIndex > 0 || tx.outputs.isEmpty) if (tx.inputs.isEmpty || tx.inputs.first.txIndex > 0 || tx.outputs.isEmpty) return false;
return false;
final b = tx.outputs.first.scriptPubKey.toBytes(); final b = tx.outputs.first.scriptPubKey.toBytes();
return b.length == 34 && b[0] == 88 && b[1] == 32; return b.length == 34 && b[0] == 88 && b[1] == 32;
}; };
final firstInput = bundle.ins.isNotEmpty ? bundle.ins.first : null; final firstInput = bundle.ins.isNotEmpty ? bundle.ins.first : null;
final isHogEx = firstInput != null && final isHogEx =
isHogExTx(bundle.originalTransaction) && firstInput != null && isHogExTx(bundle.originalTransaction) && isHogExTx(firstInput);
isHogExTx(firstInput);
final fee = hasMissingInputTx ? null : inputAmount - totalOutAmount; final fee = hasMissingInputTx ? null : inputAmount - totalOutAmount;
final walletCurrency = walletTypeToCryptoCurrency(type); final walletCurrency = walletTypeToCryptoCurrency(type);
+37 -70
View File
@@ -156,7 +156,6 @@ abstract class ElectrumWalletBase
sideHdByType[type] = sideHd; sideHdByType[type] = sideHd;
} }
} }
} }
int _purposeForType(BitcoinAddressType type) { int _purposeForType(BitcoinAddressType type) {
@@ -195,7 +194,6 @@ abstract class ElectrumWalletBase
/// For LEGACY addresses, returns the wallet's legacy derivation base (derivationInfo.derivationPath) /// For LEGACY addresses, returns the wallet's legacy derivation base (derivationInfo.derivationPath)
/// which is already the account path used historically (e.g. m/0' or m/84'/0'/0'). /// which is already the account path used historically (e.g. m/0' or m/84'/0'/0').
String _accountDerivationPathForRecord(BaseBitcoinAddressRecord record) { String _accountDerivationPathForRecord(BaseBitcoinAddressRecord record) {
if (derivationInfo.derivationType == DerivationType.electrum) { if (derivationInfo.derivationType == DerivationType.electrum) {
return derivationInfo.derivationPath ?? electrum_path; // m/0' return derivationInfo.derivationPath ?? electrum_path; // m/0'
} }
@@ -873,7 +871,8 @@ abstract class ElectrumWalletBase
BigInt get networkDustAmount => BigInt.from(546); BigInt get networkDustAmount => BigInt.from(546);
bool _isBelowDust(BigInt amount) => amount <= networkDustAmount && network != BitcoinNetwork.testnet; bool _isBelowDust(BigInt amount) =>
amount <= networkDustAmount && network != BitcoinNetwork.testnet;
UtxoDetails _createUTXOS({ UtxoDetails _createUTXOS({
required bool sendAll, required bool sendAll,
@@ -961,8 +960,7 @@ abstract class ElectrumWalletBase
final baseDerivationPath = _accountDerivationPathForRecord(utx.bitcoinAddressRecord); final baseDerivationPath = _accountDerivationPathForRecord(utx.bitcoinAddressRecord);
final derivationPath = final derivationPath = "${_hardenedDerivationPath(baseDerivationPath)}"
"${_hardenedDerivationPath(baseDerivationPath)}"
"/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}" "/${utx.bitcoinAddressRecord.isHidden ? "1" : "0"}"
"/${utx.bitcoinAddressRecord.index}"; "/${utx.bitcoinAddressRecord.index}";
publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath); publicKeys[address.pubKeyHash()] = PublicKeyWithDerivationPath(pubKeyHex, derivationPath);
@@ -1139,7 +1137,8 @@ abstract class ElectrumWalletBase
utxoDetails.utxos.length == utxoDetails.utxos.length ==
utxoDetails.availableInputs.length - utxoDetails.unconfirmedCoins.length; utxoDetails.availableInputs.length - utxoDetails.unconfirmedCoins.length;
final amountLeftForChangeAndFee = utxoDetails.allInputsAmount - credentialsAmount.amount.toInt(); final amountLeftForChangeAndFee =
utxoDetails.allInputsAmount - credentialsAmount.amount.toInt();
if (amountLeftForChangeAndFee <= 0) { if (amountLeftForChangeAndFee <= 0) {
if (!spendingAllCoins) { if (!spendingAllCoins) {
@@ -1175,11 +1174,9 @@ abstract class ElectrumWalletBase
isChange: true, isChange: true,
)); ));
// Must match the address' account root (purpose/coinType) and legacy derivation when applicable. // Must match the address' account root (purpose/coinType) and legacy derivation when applicable.
final changeBaseDerivationPath = _accountDerivationPathForRecord(changeAddress); final changeBaseDerivationPath = _accountDerivationPathForRecord(changeAddress);
final changeDerivationPath = final changeDerivationPath = "${_hardenedDerivationPath(changeBaseDerivationPath)}"
"${_hardenedDerivationPath(changeBaseDerivationPath)}"
"/${changeAddress.isHidden ? "1" : "0"}" "/${changeAddress.isHidden ? "1" : "0"}"
"/${changeAddress.index}"; "/${changeAddress.index}";
utxoDetails.publicKeys[address.pubKeyHash()] = utxoDetails.publicKeys[address.pubKeyHash()] =
@@ -1242,7 +1239,8 @@ abstract class ElectrumWalletBase
inputPrivKeyInfos: utxoDetails.inputPrivKeyInfos, inputPrivKeyInfos: utxoDetails.inputPrivKeyInfos,
vinOutpoints: utxoDetails.vinOutpoints, vinOutpoints: utxoDetails.vinOutpoints,
); );
final leftover = utxoDetails.allInputsAmount - credentialsAmount.amount.toInt() - feeNoChange; final leftover =
utxoDetails.allInputsAmount - credentialsAmount.amount.toInt() - feeNoChange;
if (leftover >= 0) { if (leftover >= 0) {
final finalFee = feeNoChange + leftover; // absorb tiny remainder final finalFee = feeNoChange + leftover; // absorb tiny remainder
@@ -1833,7 +1831,6 @@ abstract class ElectrumWalletBase
return Future.wait(addressFutures); return Future.wait(addressFutures);
} }
Future<List<List<BitcoinUnspent>?>> _fetchUnspentsBatch( Future<List<List<BitcoinUnspent>?>> _fetchUnspentsBatch(
List<BitcoinAddressRecord> addresses, List<BitcoinAddressRecord> addresses,
) async { ) async {
@@ -2131,10 +2128,7 @@ abstract class ElectrumWalletBase
final hd = _hdFor(record: addressRecord); final hd = _hdFor(record: addressRecord);
final privkey = generateECPrivate( final privkey = generateECPrivate(hd: hd, index: addressRecord.index, network: network);
hd: hd,
index: addressRecord.index,
network: network);
privateKeys.add(privkey); privateKeys.add(privkey);
@@ -2197,8 +2191,7 @@ abstract class ElectrumWalletBase
final deduction = (outputAmount - networkDustAmount >= remainingFee) final deduction = (outputAmount - networkDustAmount >= remainingFee)
? remainingFee ? remainingFee
: outputAmount - networkDustAmount; : outputAmount - networkDustAmount;
outputs[i] = BitcoinOutput( outputs[i] = BitcoinOutput(address: output.address, value: outputAmount - deduction);
address: output.address, value: outputAmount - deduction);
remainingFee -= deduction; remainingFee -= deduction;
if (remainingFee <= BigInt.zero) break; if (remainingFee <= BigInt.zero) break;
@@ -2464,7 +2457,8 @@ abstract class ElectrumWalletBase
@override @override
Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async { Future<Map<String, ElectrumTransactionInfo>> fetchTransactions() async {
try { try {
final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};; final Map<String, ElectrumTransactionInfo> historiesWithDetails = {};
;
printV('[BATCH_TEST] Fetching transactions with batch: $shouldUseBatchFetching'); printV('[BATCH_TEST] Fetching transactions with batch: $shouldUseBatchFetching');
@@ -2473,19 +2467,16 @@ abstract class ElectrumWalletBase
? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type) ? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type)
: fetchTransactionsForAddressType(historiesWithDetails, type))); : fetchTransactionsForAddressType(historiesWithDetails, type)));
} else if (type == WalletType.bitcoinCash) { } else if (type == WalletType.bitcoinCash) {
await Future.wait(BITCOIN_CASH_ADDRESS_TYPES await Future.wait(BITCOIN_CASH_ADDRESS_TYPES.map((type) => shouldUseBatchFetching
.map((type) => shouldUseBatchFetching
? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type) ? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type)
: fetchTransactionsForAddressType(historiesWithDetails, type))); : fetchTransactionsForAddressType(historiesWithDetails, type)));
} else if (type == WalletType.litecoin) { } else if (type == WalletType.litecoin) {
await Future.wait(LITECOIN_ADDRESS_TYPES await Future.wait(LITECOIN_ADDRESS_TYPES.where((type) => type != SegwitAddresType.mweb).map(
.where((type) => type != SegwitAddresType.mweb) (type) => shouldUseBatchFetching
.map((type) => shouldUseBatchFetching
? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type) ? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type)
: fetchTransactionsForAddressType(historiesWithDetails, type))); : fetchTransactionsForAddressType(historiesWithDetails, type)));
} else if (type == WalletType.dogecoin) { } else if (type == WalletType.dogecoin) {
await Future.wait(DOGECOIN_ADDRESS_TYPES await Future.wait(DOGECOIN_ADDRESS_TYPES.map((type) => shouldUseBatchFetching
.map((type) => shouldUseBatchFetching
? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type) ? fetchTransactionsForAddressTypeBatch(historiesWithDetails, type)
: fetchTransactionsForAddressType(historiesWithDetails, type))); : fetchTransactionsForAddressType(historiesWithDetails, type)));
} }
@@ -2633,8 +2624,7 @@ abstract class ElectrumWalletBase
} }
Future<void> fetchTransactionsForAddressTypeBatch( Future<void> fetchTransactionsForAddressTypeBatch(
Map<String, ElectrumTransactionInfo> historiesWithDetails, Map<String, ElectrumTransactionInfo> historiesWithDetails, BitcoinAddressType type) async {
BitcoinAddressType type) async {
final addressesByType = final addressesByType =
walletAddresses.allAddresses.where((addr) => addr.type == type).toList(); walletAddresses.allAddresses.where((addr) => addr.type == type).toList();
final receiveAddresses = addressesByType.where((addr) => !addr.isHidden).toList(); final receiveAddresses = addressesByType.where((addr) => !addr.isHidden).toList();
@@ -2676,7 +2666,6 @@ abstract class ElectrumWalletBase
); );
} }
Future<void> fetchTransactionsForAddressesBranchBatch( Future<void> fetchTransactionsForAddressesBranchBatch(
Map<String, ElectrumTransactionInfo> historiesWithDetails, Map<String, ElectrumTransactionInfo> historiesWithDetails,
BitcoinAddressType type, BitcoinAddressType type,
@@ -2714,7 +2703,6 @@ abstract class ElectrumWalletBase
if (!shouldDiscover) return; if (!shouldDiscover) return;
final newAddresses = await walletAddresses.discoverAddressesBatch( final newAddresses = await walletAddresses.discoverAddressesBatch(
currentBranch, currentBranch,
isHidden, isHidden,
@@ -2756,9 +2744,7 @@ abstract class ElectrumWalletBase
} }
Future<Map<String, ElectrumTransactionInfo>> _fetchBatchAddressHistory( Future<Map<String, ElectrumTransactionInfo>> _fetchBatchAddressHistory(
List<BitcoinAddressRecord> addressRecords, List<BitcoinAddressRecord> addressRecords, int? currentHeight, int historyChunkSize) async {
int? currentHeight,
int historyChunkSize) async {
String lastTxId = ''; String lastTxId = '';
bool didUpdateHistory = false; bool didUpdateHistory = false;
@@ -2770,10 +2756,7 @@ abstract class ElectrumWalletBase
final historyByScriptHash = final historyByScriptHash =
await _processChunksToMap<String, String, List<Map<String, dynamic>>>( await _processChunksToMap<String, String, List<Map<String, dynamic>>>(
items: scriptHashes, items: scriptHashes, chunkSize: historyChunkSize, processChunk: _getHistoryBatch);
chunkSize: historyChunkSize,
processChunk: _getHistoryBatch
);
// Map scriptHash -> addressRecord // Map scriptHash -> addressRecord
final byScriptHash = <String, BitcoinAddressRecord>{}; final byScriptHash = <String, BitcoinAddressRecord>{};
@@ -2869,8 +2852,7 @@ abstract class ElectrumWalletBase
.toList(growable: false); .toList(growable: false);
final heightsByHash = <String, int?>{ final heightsByHash = <String, int?>{
for (final e in chunkHistory) for (final e in chunkHistory) (e['tx_hash'] as String): (e['height'] as int?),
(e['tx_hash'] as String): (e['height'] as int?),
}; };
final infosByHash = await fetchTransactionInfoBatch( final infosByHash = await fetchTransactionInfoBatch(
@@ -2909,40 +2891,35 @@ abstract class ElectrumWalletBase
} }
} }
Future<Map<String, Map<String, dynamic>>> _getTransactionVerboseBatch( Future<Map<String, Map<String, dynamic>>> _getTransactionVerboseBatch(List<String> hashes) {
List<String> hashes) {
return electrumClient.getBatchTransactionVerbose( return electrumClient.getBatchTransactionVerbose(
hashes, hashes,
timeout: transactionBatchTimeoutMs, timeout: transactionBatchTimeoutMs,
); );
} }
Future<Map<String, String?>> _getTransactionHexBatch( Future<Map<String, String?>> _getTransactionHexBatch(List<String> hashes) {
List<String> hashes) {
return electrumClient.getBatchTransactionHex( return electrumClient.getBatchTransactionHex(
hashes, hashes,
timeout: transactionBatchTimeoutMs, timeout: transactionBatchTimeoutMs,
); );
} }
Future<Map<String, List<Map<String, dynamic>>>> _getHistoryBatch( Future<Map<String, List<Map<String, dynamic>>>> _getHistoryBatch(List<String> scriptHashes) {
List<String> scriptHashes) {
return electrumClient.getBatchHistory( return electrumClient.getBatchHistory(
scriptHashes, scriptHashes,
timeout: transactionBatchTimeoutMs, timeout: transactionBatchTimeoutMs,
); );
} }
Future<Map<String, List<Map<String, dynamic>>>> _getListUnspentBatch( Future<Map<String, List<Map<String, dynamic>>>> _getListUnspentBatch(List<String> scriptHashes) {
List<String> scriptHashes) {
return electrumClient.getBatchUnspent( return electrumClient.getBatchUnspent(
scriptHashes, scriptHashes,
timeout: transactionBatchTimeoutMs, timeout: transactionBatchTimeoutMs,
); );
} }
Future<Map<String, Map<String, dynamic>>> _getBalanceBatch( Future<Map<String, Map<String, dynamic>>> _getBalanceBatch(List<String> scriptHashes) {
List<String> scriptHashes) {
return electrumClient.getBatchBalance( return electrumClient.getBatchBalance(
scriptHashes, scriptHashes,
timeout: transactionBatchTimeoutMs, timeout: transactionBatchTimeoutMs,
@@ -2956,8 +2933,7 @@ abstract class ElectrumWalletBase
Duration retryDelay = const Duration(seconds: 2), Duration retryDelay = const Duration(seconds: 2),
}) async { }) async {
final result = <String, ElectrumTransactionInfo?>{}; final result = <String, ElectrumTransactionInfo?>{};
final uniqueHashes = final uniqueHashes = hashes.map((h) => h.trim()).where((h) => h.isNotEmpty).toSet().toList();
hashes.map((h) => h.trim()).where((h) => h.isNotEmpty).toSet().toList();
if (uniqueHashes.isEmpty) return result; if (uniqueHashes.isEmpty) return result;
@@ -2990,9 +2966,8 @@ abstract class ElectrumWalletBase
required Map<String, int?>? heightsByHash, required Map<String, int?>? heightsByHash,
}) async { }) async {
for (var i = 0; i < txIds.length; i += transactionChunkSize) { for (var i = 0; i < txIds.length; i += transactionChunkSize) {
final end = (i + transactionChunkSize < txIds.length) final end =
? i + transactionChunkSize (i + transactionChunkSize < txIds.length) ? i + transactionChunkSize : txIds.length;
: txIds.length;
final chunk = txIds.sublist(i, end); final chunk = txIds.sublist(i, end);
final bundlesByHash = await getTransactionExpandedBatch( final bundlesByHash = await getTransactionExpandedBatch(
@@ -3024,9 +2999,8 @@ abstract class ElectrumWalletBase
} }
} }
Future<Map<String, ElectrumTransactionBundle>> getTransactionExpandedBatch({ Future<Map<String, ElectrumTransactionBundle>> getTransactionExpandedBatch(
required List<String> hashes, {required List<String> hashes, Map<String, int?>? heightsByHash}) async {
Map<String, int?>? heightsByHash}) async {
final bundles = <String, ElectrumTransactionBundle>{}; final bundles = <String, ElectrumTransactionBundle>{};
if (hashes.isEmpty) return bundles; if (hashes.isEmpty) return bundles;
@@ -3062,8 +3036,8 @@ abstract class ElectrumWalletBase
Future<Map<String, Map<String, dynamic>>> _fetchTransactionVerboseBatch( Future<Map<String, Map<String, dynamic>>> _fetchTransactionVerboseBatch(
List<String> txIds) async { List<String> txIds) async {
final verboseTransactionByHash =
final verboseTransactionByHash = await _processChunksToMap<String, String, Map<String, dynamic>>( await _processChunksToMap<String, String, Map<String, dynamic>>(
items: txIds, items: txIds,
chunkSize: transactionChunkSize, chunkSize: transactionChunkSize,
processChunk: _getTransactionVerboseBatch, processChunk: _getTransactionVerboseBatch,
@@ -3116,7 +3090,6 @@ abstract class ElectrumWalletBase
return result; return result;
} }
Map<String, List<String>> _collectInputTxIdsByHash( Map<String, List<String>> _collectInputTxIdsByHash(
Map<String, BtcTransaction> originalByHash, Map<String, BtcTransaction> originalByHash,
) { ) {
@@ -3276,7 +3249,6 @@ abstract class ElectrumWalletBase
return result; return result;
} }
Future<void> updateTransactions() async { Future<void> updateTransactions() async {
printV("updateTransactions() called!"); printV("updateTransactions() called!");
try { try {
@@ -3368,8 +3340,7 @@ abstract class ElectrumWalletBase
} }
try { try {
final balancesByScriptHash = final balancesByScriptHash = await _processChunksToMap<String, String, Map<String, dynamic>>(
await _processChunksToMap<String, String, Map<String, dynamic>>(
items: scriptHashes, items: scriptHashes,
chunkSize: addressHistoryChunkSize, chunkSize: addressHistoryChunkSize,
processChunk: _getBalanceBatch, processChunk: _getBalanceBatch,
@@ -3415,7 +3386,8 @@ abstract class ElectrumWalletBase
? await fetchBalancesBatch(addresses) ? await fetchBalancesBatch(addresses)
: await fetchBalancesRegular(addresses); : await fetchBalancesRegular(addresses);
printV('Fetched balances for ${addresses.length} addresses. Batch fetching: $shouldUseBatchFetching'); printV(
'Fetched balances for ${addresses.length} addresses. Batch fetching: $shouldUseBatchFetching');
var totalFrozen = 0; var totalFrozen = 0;
var totalConfirmed = 0; var totalConfirmed = 0;
@@ -3545,16 +3517,13 @@ abstract class ElectrumWalletBase
for (final tx2 in transactionHistory.transactions.values) { for (final tx2 in transactionHistory.transactions.values) {
final heightDiff = ((tx2.height ?? 0) - (tx.height ?? 0)).abs(); final heightDiff = ((tx2.height ?? 0) - (tx.height ?? 0)).abs();
// this isn't a perfect matching algorithm since we don't have the right input/output information from these transaction models (the addresses are in different formats), but this should be more than good enough for now as it's extremely unlikely a user receives the EXACT same amount from 2 different sources and one of them is a peg out and the other isn't WITHIN 5 blocks of each other // this isn't a perfect matching algorithm since we don't have the right input/output information from these transaction models (the addresses are in different formats), but this should be more than good enough for now as it's extremely unlikely a user receives the EXACT same amount from 2 different sources and one of them is a peg out and the other isn't WITHIN 5 blocks of each other
if (tx2.additionalInfo["isPegOut"] == true && if (tx2.additionalInfo["isPegOut"] == true && tx2.amount == tx.amount && heightDiff <= 5) {
tx2.amount == tx.amount &&
heightDiff <= 5) {
tx.additionalInfo["fromPegOut"] = true; tx.additionalInfo["fromPegOut"] = true;
} }
} }
} }
Future<void> checkIfBatchSupported() async { Future<void> checkIfBatchSupported() async {
if (_isBatchSupported != null) { if (_isBatchSupported != null) {
printV('[BATCH_TEST] Already checked: $_isBatchSupported'); printV('[BATCH_TEST] Already checked: $_isBatchSupported');
return; return;
@@ -3580,9 +3549,7 @@ abstract class ElectrumWalletBase
); );
final hasError = result.any((item) => final hasError = result.any((item) =>
item is Map<String, dynamic> && item is Map<String, dynamic> && item.containsKey('error') && item['error'] != null);
item.containsKey('error') &&
item['error'] != null);
if (hasError) { if (hasError) {
_isBatchSupported = false; _isBatchSupported = false;
+29 -23
View File
@@ -199,9 +199,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
"Error: Unable to fetch your Lightning address, please check your network connection."; "Error: Unable to fetch your Lightning address, please check your network connection.";
} }
final typeMatchingAddressesAll = _addresses final typeMatchingAddressesAll =
.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)) _addresses.where((addr) => !addr.isHidden && _isAddressPageTypeMatch(addr)).toList();
.toList();
// Prefer standard derivation addresses for the current/active address, // Prefer standard derivation addresses for the current/active address,
// but keep legacy addresses present in the overall address lists. // but keep legacy addresses present in the overall address lists.
@@ -210,8 +209,9 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
...typeMatchingAddressesAll.where((a) => a.isLegacyDerivation), ...typeMatchingAddressesAll.where((a) => a.isLegacyDerivation),
]; ];
final typeMatchingReceiveAddressesAll = final typeMatchingReceiveAddressesAll = typeMatchingAddressesAll
typeMatchingAddressesAll.where((addr) => !addr.isUsed && !hiddenAddresses.contains(addr.address)).toList(); .where((addr) => !addr.isUsed && !hiddenAddresses.contains(addr.address))
.toList();
final typeMatchingReceiveAddresses = <BitcoinAddressRecord>[ final typeMatchingReceiveAddresses = <BitcoinAddressRecord>[
...typeMatchingReceiveAddressesAll.where((a) => !a.isLegacyDerivation), ...typeMatchingReceiveAddressesAll.where((a) => !a.isLegacyDerivation),
...typeMatchingReceiveAddressesAll.where((a) => a.isLegacyDerivation), ...typeMatchingReceiveAddressesAll.where((a) => a.isLegacyDerivation),
@@ -372,7 +372,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh, isLegacyDerivation: true); await _generateInitialAddresses(type: P2pkhAddressType.p2pkh, isLegacyDerivation: true);
await _generateInitialAddresses(type: P2pkhAddressType.p2pkh); await _generateInitialAddresses(type: P2pkhAddressType.p2pkh);
await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh, isLegacyDerivation: true); await _generateInitialAddresses(
type: P2shAddressType.p2wpkhInP2sh, isLegacyDerivation: true);
await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh); await _generateInitialAddresses(type: P2shAddressType.p2wpkhInP2sh);
await _generateInitialAddresses(type: SegwitAddresType.p2tr, isLegacyDerivation: true); await _generateInitialAddresses(type: SegwitAddresType.p2tr, isLegacyDerivation: true);
@@ -680,9 +681,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
@action @action
void updateReceiveAddresses() { void updateReceiveAddresses() {
receiveAddresses.removeRange(0, receiveAddresses.length); receiveAddresses.removeRange(0, receiveAddresses.length);
final newAddresses = _addresses.where((addressRecord) => final newAddresses =
!addressRecord.isHidden && _addresses.where((addressRecord) => !addressRecord.isHidden && !addressRecord.isUsed);
!addressRecord.isUsed);
receiveAddresses.addAll(newAddresses); receiveAddresses.addAll(newAddresses);
} }
@@ -716,8 +716,7 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
addAddresses(newAddresses); addAddresses(newAddresses);
addressList.addAll(newAddresses); addressList.addAll(newAddresses);
final addressesWithHistory = final addressesWithHistory = await Future.wait(newAddresses.map(getAddressHistory));
await Future.wait(newAddresses.map(getAddressHistory));
final isLastAddressUsed = addressesWithHistory.last != null; final isLastAddressUsed = addressesWithHistory.last != null;
if (isLastAddressUsed) { if (isLastAddressUsed) {
@@ -750,8 +749,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
final usedAddresses = await getUsedAddresses(newAddresses); final usedAddresses = await getUsedAddresses(newAddresses);
final hasUsedAddressInGap = newAddresses.any( final hasUsedAddressInGap =
(addressRecord) => usedAddresses.contains(addressRecord.address)); newAddresses.any((addressRecord) => usedAddresses.contains(addressRecord.address));
if (!hasUsedAddressInGap) { if (!hasUsedAddressInGap) {
return newAddresses; return newAddresses;
@@ -770,11 +769,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
return [...newAddresses, ...moreNewAddresses]; return [...newAddresses, ...moreNewAddresses];
} }
Future<void> _generateInitialAddresses( Future<void> _generateInitialAddresses(
{BitcoinAddressType type = SegwitAddresType.p2wpkh, {BitcoinAddressType type = SegwitAddresType.p2wpkh, bool isLegacyDerivation = false}) async {
bool isLegacyDerivation = false }) async {
// Legacy derivation produces the same addresses as standard for these types. // Legacy derivation produces the same addresses as standard for these types.
// Don't generate a legacy set to avoid duplicates. // Don't generate a legacy set to avoid duplicates.
if (isLegacyDerivation && (type == SegwitAddresType.p2wpkh || type == SegwitAddresType.p2wsh)) { if (isLegacyDerivation && (type == SegwitAddresType.p2wpkh || type == SegwitAddresType.p2wsh)) {
@@ -797,24 +793,32 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
if (countOfReceiveAddresses < defaultReceiveAddressesCount) { if (countOfReceiveAddresses < defaultReceiveAddressesCount) {
final addressesCount = defaultReceiveAddressesCount - countOfReceiveAddresses; final addressesCount = defaultReceiveAddressesCount - countOfReceiveAddresses;
final newAddresses = await _createNewAddresses(addressesCount, final newAddresses = await _createNewAddresses(addressesCount,
startIndex: countOfReceiveAddresses, isHidden: false, type: type, isLegacyDerivation: isLegacyDerivation); startIndex: countOfReceiveAddresses,
isHidden: false,
type: type,
isLegacyDerivation: isLegacyDerivation);
addAddresses(newAddresses); addAddresses(newAddresses);
} }
if (countOfHiddenAddresses < defaultChangeAddressesCount) { if (countOfHiddenAddresses < defaultChangeAddressesCount) {
final addressesCount = defaultChangeAddressesCount - countOfHiddenAddresses; final addressesCount = defaultChangeAddressesCount - countOfHiddenAddresses;
final newAddresses = await _createNewAddresses(addressesCount, final newAddresses = await _createNewAddresses(addressesCount,
startIndex: countOfHiddenAddresses, isHidden: true, type: type, isLegacyDerivation: isLegacyDerivation); startIndex: countOfHiddenAddresses,
isHidden: true,
type: type,
isLegacyDerivation: isLegacyDerivation);
addAddresses(newAddresses); addAddresses(newAddresses);
} }
} }
Future<List<BitcoinAddressRecord>> _createNewAddresses(int count, Future<List<BitcoinAddressRecord>> _createNewAddresses(int count,
{int startIndex = 0, bool isHidden = false, BitcoinAddressType? type, bool isLegacyDerivation = false}) async { {int startIndex = 0,
bool isHidden = false,
BitcoinAddressType? type,
bool isLegacyDerivation = false}) async {
final list = <BitcoinAddressRecord>[]; final list = <BitcoinAddressRecord>[];
for (var i = startIndex; i < count + startIndex; i++) { for (var i = startIndex; i < count + startIndex; i++) {
final addrType = type ?? addressPageType; final addrType = type ?? addressPageType;
final hd = _hdFor(isHidden: isHidden, type: addrType, isLegacyDerivation: isLegacyDerivation); final hd = _hdFor(isHidden: isHidden, type: addrType, isLegacyDerivation: isLegacyDerivation);
@@ -868,8 +872,10 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
return; return;
} }
final mainHd = _hdFor(isHidden: false, type: element.type, isLegacyDerivation: element.isLegacyDerivation); final mainHd = _hdFor(
final sideHd = _hdFor(isHidden: true, type: element.type, isLegacyDerivation: element.isLegacyDerivation); isHidden: false, type: element.type, isLegacyDerivation: element.isLegacyDerivation);
final sideHd = _hdFor(
isHidden: true, type: element.type, isLegacyDerivation: element.isLegacyDerivation);
if (!element.isHidden && if (!element.isHidden &&
element.address != element.address !=
await getAddressAsync(index: element.index, hd: mainHd, addressType: element.type)) { await getAddressAsync(index: element.index, hd: mainHd, addressType: element.type)) {
+1 -1
View File
@@ -30,7 +30,7 @@ class BitcoinTransactionCommitFailed extends TransactionCommitFailed {
@override @override
String toString() { String toString() {
return errorMessage??"unknown error"; return errorMessage ?? "unknown error";
} }
} }
+2 -1
View File
@@ -67,7 +67,8 @@ class BitcoinBitboxService extends HardwareWalletService with BitcoinHardwareWal
Future<Uint8List> getMasterFingerprint() => manager.getMasterFingerprint(); Future<Uint8List> getMasterFingerprint() => manager.getMasterFingerprint();
} }
class LitecoinBitboxService extends HardwareWalletService with BitcoinHardwareWalletService, LitecoinHardwareWalletService { class LitecoinBitboxService extends HardwareWalletService
with BitcoinHardwareWalletService, LitecoinHardwareWalletService {
LitecoinBitboxService(this.manager); LitecoinBitboxService(this.manager);
final BitboxManager manager; final BitboxManager manager;
@@ -12,7 +12,8 @@ import 'package:cw_core/hardware/hardware_wallet_service.dart';
import 'package:ledger_flutter_plus/ledger_flutter_plus.dart'; import 'package:ledger_flutter_plus/ledger_flutter_plus.dart';
import 'package:ledger_litecoin/ledger_litecoin.dart'; import 'package:ledger_litecoin/ledger_litecoin.dart';
class LitecoinLedgerService extends HardwareWalletService with BitcoinHardwareWalletService, LitecoinHardwareWalletService { class LitecoinLedgerService extends HardwareWalletService
with BitcoinHardwareWalletService, LitecoinHardwareWalletService {
LitecoinLedgerService(this.ledgerConnection) LitecoinLedgerService(this.ledgerConnection)
: litecoinLedgerApp = LitecoinLedgerApp(ledgerConnection); : litecoinLedgerApp = LitecoinLedgerApp(ledgerConnection);
@@ -53,7 +54,6 @@ class LitecoinLedgerService extends HardwareWalletService with BitcoinHardwareWa
required List<PSBTReadyUtxoWithAddress> inputs, required List<PSBTReadyUtxoWithAddress> inputs,
required Map<String, PublicKeyWithDerivationPath> publicKeys, required Map<String, PublicKeyWithDerivationPath> publicKeys,
}) { }) {
final readyInputs = <LedgerTransaction>[]; final readyInputs = <LedgerTransaction>[];
for (final utxo in inputs) { for (final utxo in inputs) {
final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!; final publicKeyAndDerivationPath = publicKeys[utxo.ownerDetails.address.pubKeyHash()]!;
+13 -11
View File
@@ -90,8 +90,7 @@ class LightningWallet {
lnurlDomain: lnurlDomain, lnurlDomain: lnurlDomain,
apiKey: apiKey, apiKey: apiKey,
privateEnabledDefault: true, privateEnabledDefault: true,
maxDepositClaimFee: MaxFee.rate(satPerVbyte: BigInt.from(5)) maxDepositClaimFee: MaxFee.rate(satPerVbyte: BigInt.from(5)));
);
final connectRequest = ConnectRequest( final connectRequest = ConnectRequest(
config: config, config: config,
@@ -105,8 +104,7 @@ class LightningWallet {
_logStream ??= initLogging().asBroadcastStream(); _logStream ??= initLogging().asBroadcastStream();
try { try {
final logFile = File("$appPath/lightning.log") final logFile = File("$appPath/lightning.log")..createSync();
..createSync();
_subscribeToLogStream(logFile); _subscribeToLogStream(logFile);
} catch (e) { } catch (e) {
printV(e); printV(e);
@@ -198,15 +196,17 @@ class LightningWallet {
} }
} }
Future<PendingLightningTransaction> createTransaction( Future<PendingLightningTransaction> createTransaction(String address, BigInt? amountSats,
String address, BigInt? amountSats, BitcoinTransactionPriority? priority, bool feesIncluded) async { BitcoinTransactionPriority? priority, bool feesIncluded) async {
final inputType = await sdk.parse(input: address); final inputType = await sdk.parse(input: address);
final feePolicy = feesIncluded ? FeePolicy.feesIncluded : FeePolicy.feesExcluded; final feePolicy = feesIncluded ? FeePolicy.feesIncluded : FeePolicy.feesExcluded;
if (inputType is InputType_Bolt11Invoice) { if (inputType is InputType_Bolt11Invoice) {
final request = PrepareSendPaymentRequest( final request = PrepareSendPaymentRequest(
paymentRequest: inputType.field0.invoice.bolt11, amount: amountSats, feePolicy: feePolicy); paymentRequest: inputType.field0.invoice.bolt11,
amount: amountSats,
feePolicy: feePolicy);
final prepareResponse = await sdk.prepareSendPayment(request: request); final prepareResponse = await sdk.prepareSendPayment(request: request);
final paymentMethod = prepareResponse.paymentMethod; final paymentMethod = prepareResponse.paymentMethod;
@@ -392,14 +392,16 @@ class LightningWallet {
return _getElectrumTransactionInfoFromPayment(response.payment); return _getElectrumTransactionInfoFromPayment(response.payment);
} }
Future<String> refundDeposit(String txId, int vout, String destinationAddress, Future<String> refundDeposit(
BigInt feeRate) async { String txId, int vout, String destinationAddress, BigInt feeRate) async {
final response = await sdk.refundDeposit(request: RefundDepositRequest( final response = await sdk.refundDeposit(
request: RefundDepositRequest(
txid: txId, txid: txId,
vout: vout, vout: vout,
destinationAddress: destinationAddress, destinationAddress: destinationAddress,
fee: Fee.rate(satPerVbyte: feeRate), fee: Fee.rate(satPerVbyte: feeRate),
),); ),
);
return response.txHex; return response.txHex;
} }
@@ -10,10 +10,9 @@ class PendingLightningTransaction with PendingTransaction {
required this.commitOverride, required this.commitOverride,
}); });
final bool isSendAll; final bool isSendAll;
Future<String> Function() commitOverride; Future<String> Function() commitOverride;
final List<void Function()> _listeners =[]; final List<void Function()> _listeners = [];
@override @override
String id; String id;
+17 -13
View File
@@ -175,7 +175,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
@override @override
bool get hasRescan => true; bool get hasRescan => true;
final String? scanSecretOverride; final String? scanSecretOverride;
final String? spendPubkeyOverride; final String? spendPubkeyOverride;
List<int> get scanSecret => (scanSecretOverride != null && scanSecretOverride?.isNotEmpty == true) List<int> get scanSecret => (scanSecretOverride != null && scanSecretOverride?.isNotEmpty == true)
@@ -232,8 +231,12 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
@override @override
WalletKeysData get walletKeysData => WalletKeysData get walletKeysData => WalletKeysData(
WalletKeysData(mnemonic: seed, xPub: xpub, passphrase: passphrase, scanSecret: scanSecretOverride, spendPubkey: spendPubkeyOverride); mnemonic: seed,
xPub: xpub,
passphrase: passphrase,
scanSecret: scanSecretOverride,
spendPubkey: spendPubkeyOverride);
static Future<LitecoinWallet> open({ static Future<LitecoinWallet> open({
required String name, required String name,
@@ -1106,12 +1109,15 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
for (final utxo in transaction.utxos) { for (final utxo in transaction.utxos) {
if (utxo.utxo.scriptType != SegwitAddresType.mweb) { if (utxo.utxo.scriptType != SegwitAddresType.mweb) {
inputs.add(utxo.utxo.toInput()); inputs.add(utxo.utxo.toInput());
txouts.add(TxOut(value: Int64(utxo.utxo.value.toInt()), txouts.add(TxOut(
value: Int64(utxo.utxo.value.toInt()),
pkScript: utxo.ownerDetails.address.toScriptPubKey().toBytes())); pkScript: utxo.ownerDetails.address.toScriptPubKey().toBytes()));
} }
} }
var resp = await CwMweb.psbtCreate(PsbtCreateRequest( var resp = await CwMweb.psbtCreate(PsbtCreateRequest(
rawTx: inputs.isEmpty ? null : BtcTransaction( rawTx: inputs.isEmpty
? null
: BtcTransaction(
inputs: inputs, inputs: inputs,
outputs: isMweb ? [] : transaction.outputs, outputs: isMweb ? [] : transaction.outputs,
).toBytes(), ).toBytes(),
@@ -1127,7 +1133,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
)); ));
} }
} }
if (isMweb) for (final output in transaction.outputs) { if (isMweb)
for (final output in transaction.outputs) {
var address = addressFromOutputScript(output.scriptPubKey, LitecoinNetwork.mainnet); var address = addressFromOutputScript(output.scriptPubKey, LitecoinNetwork.mainnet);
if (output.scriptPubKey.getAddressType() == SegwitAddresType.mweb) { if (output.scriptPubKey.getAddressType() == SegwitAddresType.mweb) {
address = SegwitBech32Encoder.encode("ltcmweb", 0, output.scriptPubKey.toBytes()); address = SegwitBech32Encoder.encode("ltcmweb", 0, output.scriptPubKey.toBytes());
@@ -1203,7 +1210,6 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
for (final utxo in tx.utxos) { for (final utxo in tx.utxos) {
if (utxo.utxo.scriptType == SegwitAddresType.mweb) { if (utxo.utxo.scriptType == SegwitAddresType.mweb) {
hasMwebInput = true; hasMwebInput = true;
} else { } else {
// check if any of the inputs of this transaction are hog-ex: // check if any of the inputs of this transaction are hog-ex:
// this list is only non-mweb inputs: // this list is only non-mweb inputs:
@@ -1256,9 +1262,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
final utxo = unspentCoins final utxo = unspentCoins
.firstWhere((utxo) => utxo.hash == e.value.txId && utxo.vout == e.value.txIndex); .firstWhere((utxo) => utxo.hash == e.value.txId && utxo.vout == e.value.txIndex);
final key = generateECPrivate( final key = generateECPrivate(
hd: utxo.bitcoinAddressRecord.isHidden hd: utxo.bitcoinAddressRecord.isHidden ? sideHd : mainHd,
? sideHd
: mainHd,
index: utxo.bitcoinAddressRecord.index, index: utxo.bitcoinAddressRecord.index,
network: network); network: network);
final digest = tx2.getTransactionSegwitDigit( final digest = tx2.getTransactionSegwitDigit(
@@ -1284,8 +1288,8 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
} }
} }
void addTransactionListener(PendingBitcoinTransaction tx, void addTransactionListener(
List<String> inputAddresses, bool isPegIn, bool isPegOut) { PendingBitcoinTransaction tx, List<String> inputAddresses, bool isPegIn, bool isPegOut) {
tx.addListener((transaction) async { tx.addListener((transaction) async {
final addresses = <String>{}; final addresses = <String>{};
transaction.inputAddresses?.addAll(inputAddresses); transaction.inputAddresses?.addAll(inputAddresses);
@@ -1575,7 +1579,7 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
rawTx: rawTx, rawTx: rawTx,
ownerDetails: utxo.ownerDetails, ownerDetails: utxo.ownerDetails,
ownerDerivationPath: publicKeyAndDerivationPath.derivationPath, ownerDerivationPath: publicKeyAndDerivationPath.derivationPath,
ownerMasterFingerprint:masterFingerprint, ownerMasterFingerprint: masterFingerprint,
ownerPublicKey: publicKeyAndDerivationPath.publicKey, ownerPublicKey: publicKeyAndDerivationPath.publicKey,
)); ));
} }
+11 -5
View File
@@ -59,9 +59,11 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
? hex.decode(scanSecretOverride!) ? hex.decode(scanSecretOverride!)
: mwebHd?.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw ?? List.filled(32, 0); : mwebHd?.childKey(Bip32KeyIndex(0x80000000)).privateKey.privKey.raw ?? List.filled(32, 0);
List<int> get spendPubkey => (spendPubkeyOverride != null && spendPubkeyOverride?.isNotEmpty == true) List<int> get spendPubkey =>
(spendPubkeyOverride != null && spendPubkeyOverride?.isNotEmpty == true)
? hex.decode(spendPubkeyOverride!) ? hex.decode(spendPubkeyOverride!)
: mwebHd?.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed ?? List.filled(32, 0); : mwebHd?.childKey(Bip32KeyIndex(0x80000001)).publicKey.pubKey.compressed ??
List.filled(32, 0);
@override @override
Future<void> init() async { Future<void> init() async {
@@ -230,12 +232,16 @@ abstract class LitecoinWalletAddressesBase extends ElectrumWalletAddresses with
// don't use mweb addresses for exchange refund address: // don't use mweb addresses for exchange refund address:
final current = getFreshAddress(); final current = getFreshAddress();
final bool isMweb = receiveAddresses final bool isMweb =
.any((e) => e.address == current && e.type == SegwitAddresType.mweb); receiveAddresses.any((e) => e.address == current && e.type == SegwitAddresType.mweb);
if (isMweb) { if (isMweb) {
final segwit = receiveAddresses final segwit = receiveAddresses
.where((e) => e.type == SegwitAddresType.p2wpkh && !e.isUsed && !e.isHidden && !hiddenAddresses.contains(e.address)) .where((e) =>
e.type == SegwitAddresType.p2wpkh &&
!e.isUsed &&
!e.isHidden &&
!hiddenAddresses.contains(e.address))
.map((e) => e.address) .map((e) => e.address)
.toList(); .toList();
+8 -7
View File
@@ -48,7 +48,8 @@ class LitecoinWalletService extends WalletService<
password: credentials.password!, password: credentials.password!,
passphrase: credentials.passphrase, passphrase: credentials.passphrase,
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
derivationInfo: credentials.derivationInfo ?? (await credentials.walletInfo!.getDerivationInfo()), derivationInfo:
credentials.derivationInfo ?? (await credentials.walletInfo!.getDerivationInfo()),
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect), encryptionFileUtils: encryptionFileUtilsFor(isDirect),
); );
@@ -64,7 +65,6 @@ class LitecoinWalletService extends WalletService<
@override @override
Future<LitecoinWallet> openWallet(String name, String password) async { Future<LitecoinWallet> openWallet(String name, String password) async {
final walletInfo = await WalletInfo.get(name, getType()); final walletInfo = await WalletInfo.get(name, getType());
if (walletInfo == null) { if (walletInfo == null) {
throw Exception('Wallet not found'); throw Exception('Wallet not found');
@@ -125,8 +125,9 @@ class LitecoinWalletService extends WalletService<
} }
} }
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where( final unspentCoinsToDelete = unspentCoinsInfoSource.values
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList(); .where((unspentCoin) => unspentCoin.walletId == walletInfo.id)
.toList();
final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList(); final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList();
@@ -150,8 +151,7 @@ class LitecoinWalletService extends WalletService<
final network = isTestnet == true ? LitecoinNetwork.testnet : LitecoinNetwork.mainnet; final network = isTestnet == true ? LitecoinNetwork.testnet : LitecoinNetwork.mainnet;
credentials.walletInfo?.network = network.value; credentials.walletInfo?.network = network.value;
final derivationInfo = await credentials.walletInfo!.getDerivationInfo(); final derivationInfo = await credentials.walletInfo!.getDerivationInfo();
derivationInfo.derivationPath = derivationInfo.derivationPath = credentials.hwAccountData.derivationPath;
credentials.hwAccountData.derivationPath;
await derivationInfo.save(); await derivationInfo.save();
credentials.walletInfo!.save(); credentials.walletInfo!.save();
@@ -202,7 +202,8 @@ class LitecoinWalletService extends WalletService<
passphrase: credentials.passphrase, passphrase: credentials.passphrase,
mnemonic: credentials.mnemonic, mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
derivationInfo: credentials.derivationInfo ?? (await credentials.walletInfo!.getDerivationInfo()), derivationInfo:
credentials.derivationInfo ?? (await credentials.walletInfo!.getDerivationInfo()),
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect), encryptionFileUtils: encryptionFileUtilsFor(isDirect),
); );
+13 -18
View File
@@ -108,16 +108,14 @@ class PayjoinManager {
Future<Sender> initSender( Future<Sender> initSender(
String pjUriString, String originalPsbt, int networkFeesSatPerVb) async { String pjUriString, String originalPsbt, int networkFeesSatPerVb) async {
try { try {
final pjUri = final pjUri = (await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported();
(await PayjoinUri.Uri.fromStr(pjUriString)).checkPjSupported();
final minFeeRateSatPerKwu = BigInt.from(networkFeesSatPerVb * 250); final minFeeRateSatPerKwu = BigInt.from(networkFeesSatPerVb * 250);
final senderBuilder = await SenderBuilder.fromPsbtAndUri( final senderBuilder = await SenderBuilder.fromPsbtAndUri(
psbtBase64: originalPsbt, psbtBase64: originalPsbt,
pjUri: pjUri, pjUri: pjUri,
); );
final persister = PayjoinSenderPersister.impl(); final persister = PayjoinSenderPersister.impl();
final newSender = final newSender = await senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
await senderBuilder.buildRecommended(minFeeRate: minFeeRateSatPerKwu);
final senderToken = await newSender.persist(persister: persister); final senderToken = await newSender.persist(persister: persister);
return Sender.load(token: senderToken, persister: persister); return Sender.load(token: senderToken, persister: persister);
@@ -133,8 +131,7 @@ class PayjoinManager {
bool isTestnet = false, bool isTestnet = false,
}) async { }) async {
final pjUri = Uri.parse(pjUrl).queryParameters['pj']!; final pjUri = Uri.parse(pjUrl).queryParameters['pj']!;
await _payjoinStorage.insertSenderSession( await _payjoinStorage.insertSenderSession(sender, pjUri, _wallet.id, amount);
sender, pjUri, _wallet.id, amount);
return _spawnSender(isTestnet: isTestnet, sender: sender, pjUri: pjUri); return _spawnSender(isTestnet: isTestnet, sender: sender, pjUri: pjUri);
} }
@@ -207,8 +204,7 @@ class PayjoinManager {
return completer.future; return completer.future;
} }
Future<Receiver> getUnusedReceiver(String address, Future<Receiver> getUnusedReceiver(String address, [bool isTestnet = false]) async {
[bool isTestnet = false]) async {
final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id); final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id);
if (session != null) { if (session != null) {
@@ -220,7 +216,8 @@ class PayjoinManager {
return initReceiver(address); return initReceiver(address);
} }
Future<Receiver> initReceiver(String address, [bool isTestnet = false, int retryCount = 0]) async { Future<Receiver> initReceiver(String address,
[bool isTestnet = false, int retryCount = 0]) async {
if (retryCount > 0) writePayjoinLog("Retrying initReceiver ${retryCount + 1} attempt"); if (retryCount > 0) writePayjoinLog("Retrying initReceiver ${retryCount + 1} attempt");
try { try {
@@ -245,7 +242,6 @@ class PayjoinManager {
} catch (e) { } catch (e) {
writePayjoinLog(e.toString()); writePayjoinLog(e.toString());
if (e.toString().contains("error sending request for url") && retryCount < 5) { if (e.toString().contains("error sending request for url") && retryCount < 5) {
return initReceiver(address, isTestnet, ++retryCount); return initReceiver(address, isTestnet, ++retryCount);
} else { } else {
rethrow; rethrow;
@@ -273,13 +269,11 @@ class PayjoinManager {
rawAmount = getOutputAmountFromTx(tx, _wallet); rawAmount = getOutputAmountFromTx(tx, _wallet);
break; break;
case PayjoinReceiverRequestTypes.checkIsOwned: case PayjoinReceiverRequestTypes.checkIsOwned:
(_wallet.walletAddresses as BitcoinWalletAddresses) (_wallet.walletAddresses as BitcoinWalletAddresses).newPayjoinReceiver();
.newPayjoinReceiver();
_payjoinStorage.markReceiverSessionInProgress(receiver.id()); _payjoinStorage.markReceiverSessionInProgress(receiver.id());
final inputScript = message['input_script'] as Uint8List; final inputScript = message['input_script'] as Uint8List;
final isOwned = final isOwned = _wallet.isMine(Script.fromRaw(byteData: inputScript));
_wallet.isMine(Script.fromRaw(byteData: inputScript));
mainToIsolateSendPort?.send({ mainToIsolateSendPort?.send({
'requestId': message['requestId'], 'requestId': message['requestId'],
'result': isOwned, 'result': isOwned,
@@ -288,8 +282,7 @@ class PayjoinManager {
case PayjoinReceiverRequestTypes.checkIsReceiverOutput: case PayjoinReceiverRequestTypes.checkIsReceiverOutput:
final outputScript = message['output_script'] as Uint8List; final outputScript = message['output_script'] as Uint8List;
final isReceiverOutput = final isReceiverOutput = _wallet.isMine(Script.fromRaw(byteData: outputScript));
_wallet.isMine(Script.fromRaw(byteData: outputScript));
mainToIsolateSendPort?.send({ mainToIsolateSendPort?.send({
'requestId': message['requestId'], 'requestId': message['requestId'],
'result': isReceiverOutput, 'result': isReceiverOutput,
@@ -310,7 +303,8 @@ class PayjoinManager {
case PayjoinReceiverRequestTypes.processPsbt: case PayjoinReceiverRequestTypes.processPsbt:
final psbt = message['psbt'] as String; final psbt = message['psbt'] as String;
writePayjoinLog("Receiver(${receiver.id()}) PayjoinReceiverRequestTypes.processPsbt: $psbt"); writePayjoinLog(
"Receiver(${receiver.id()}) PayjoinReceiverRequestTypes.processPsbt: $psbt");
final signedPsbt = await _wallet.signPsbt(psbt, utxos); final signedPsbt = await _wallet.signPsbt(psbt, utxos);
mainToIsolateSendPort?.send({ mainToIsolateSendPort?.send({
@@ -322,7 +316,8 @@ class PayjoinManager {
case PayjoinReceiverRequestTypes.proposalSent: case PayjoinReceiverRequestTypes.proposalSent:
_cleanupSession(receiver.id()); _cleanupSession(receiver.id());
final psbt = message['psbt'] as String; final psbt = message['psbt'] as String;
writePayjoinLog("Receiver(${receiver.id()}) PayjoinReceiverRequestTypes.proposalSent: $psbt"); writePayjoinLog(
"Receiver(${receiver.id()}) PayjoinReceiverRequestTypes.proposalSent: $psbt");
await _payjoinStorage.markReceiverSessionComplete( await _payjoinStorage.markReceiverSessionComplete(
receiver.id(), getTxIdFromPsbtV0(psbt), rawAmount); receiver.id(), getTxIdFromPsbtV0(psbt), rawAmount);
@@ -47,8 +47,7 @@ class PayjoinReceiverWorker {
try { try {
final receiver = Receiver.fromJson(json: receiverJson); final receiver = Receiver.fromJson(json: receiverJson);
final uncheckedProposal = final uncheckedProposal = await worker.receiveUncheckedProposal(receiver);
await worker.receiveUncheckedProposal(receiver);
final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast(); final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast();
sendPort.send({ sendPort.send({
@@ -112,8 +111,7 @@ class PayjoinReceiverWorker {
final httpRequest = await client.post(url, final httpRequest = await client.post(url,
headers: {'Content-Type': request.contentType}, body: request.body); headers: {'Content-Type': request.contentType}, body: request.body);
final proposal = await session.processRes( final proposal = await session.processRes(body: httpRequest.bodyBytes, ctx: extractReq.$2);
body: httpRequest.bodyBytes, ctx: extractReq.$2);
if (proposal != null) return proposal; if (proposal != null) return proposal;
sleep(Duration(seconds: 2)); sleep(Duration(seconds: 2));
} }
@@ -140,8 +138,7 @@ class PayjoinReceiverWorker {
return await finalProposal.psbt(); return await finalProposal.psbt();
} }
Future<PayjoinProposal> processPayjoinProposal( Future<PayjoinProposal> processPayjoinProposal(UncheckedProposal proposal) async {
UncheckedProposal proposal) async {
await proposal.extractTxToScheduleBroadcast(); await proposal.extractTxToScheduleBroadcast();
// TODO Handle this. send to the main port on a timer? // TODO Handle this. send to the main port on a timer?
@@ -174,20 +171,17 @@ class PayjoinReceiverWorker {
); );
final pj5 = await pj4.commitOutputs(); final pj5 = await pj4.commitOutputs();
final listUnspent = final listUnspent = await _sendRequest(PayjoinReceiverRequestTypes.getCandidateInputs);
await _sendRequest(PayjoinReceiverRequestTypes.getCandidateInputs);
final unspent = listUnspent as List<UtxoWithPrivateKey>; final unspent = listUnspent as List<UtxoWithPrivateKey>;
if (unspent.isEmpty) throw RecoverableError('No unspent outputs available'); if (unspent.isEmpty) throw RecoverableError('No unspent outputs available');
final candidateInputs = final candidateInputs = await Future.wait(unspent.map(_inputPairFromUtxo));
await Future.wait(unspent.map(_inputPairFromUtxo));
// Prefer a UTXO that avoids the Unnecessary Input Heuristic (UIH2); // Prefer a UTXO that avoids the Unnecessary Input Heuristic (UIH2);
// fall back to the first candidate if none preserves privacy. // fall back to the first candidate if none preserves privacy.
InputPair selectedUtxo = candidateInputs.first; InputPair selectedUtxo = candidateInputs.first;
try { try {
selectedUtxo = selectedUtxo = await pj5.tryPreservingPrivacy(candidateInputs: candidateInputs);
await pj5.tryPreservingPrivacy(candidateInputs: candidateInputs);
} catch (_) {} } catch (_) {}
final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]); final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]);
@@ -196,8 +190,8 @@ class PayjoinReceiverWorker {
// Finalize proposal // Finalize proposal
final payjoinProposal = await pj7.finalizeProposal( final payjoinProposal = await pj7.finalizeProposal(
processPsbt: (String psbt) async { processPsbt: (String psbt) async {
final result = await _sendRequest( final result =
PayjoinReceiverRequestTypes.processPsbt, {'psbt': psbt}); await _sendRequest(PayjoinReceiverRequestTypes.processPsbt, {'psbt': psbt});
return result as String; return result as String;
}, },
// TODO set maxFeeRateSatPerVb // TODO set maxFeeRateSatPerVb
@@ -213,15 +207,12 @@ class PayjoinReceiverWorker {
Future<InputPair> _inputPairFromUtxo(UtxoWithPrivateKey utxo) async { Future<InputPair> _inputPairFromUtxo(UtxoWithPrivateKey utxo) async {
final txout = TxOut( final txout = TxOut(
value: utxo.utxo.value, value: utxo.utxo.value,
scriptPubkey: Uint8List.fromList( scriptPubkey: Uint8List.fromList(utxo.ownerDetails.address.toScriptPubKey().toBytes()),
utxo.ownerDetails.address.toScriptPubKey().toBytes()),
); );
final psbtin = final psbtin = PsbtInput(witnessUtxo: txout, redeemScript: null, witnessScript: null);
PsbtInput(witnessUtxo: txout, redeemScript: null, witnessScript: null);
final previousOutput = final previousOutput = OutPoint(txid: utxo.utxo.txHash, vout: utxo.utxo.vout);
OutPoint(txid: utxo.utxo.txHash, vout: utxo.utxo.vout);
final txin = TxIn( final txin = TxIn(
previousOutput: previousOutput, previousOutput: previousOutput,
@@ -46,11 +46,11 @@ class PayjoinSenderWorker {
sendPort.send(e); sendPort.send(e);
} }
} }
final client = ProxyWrapper().getHttpIOClient(); final client = ProxyWrapper().getHttpIOClient();
/// Run a payjoin sender (V2 protocol first, fallback to V1). /// Run a payjoin sender (V2 protocol first, fallback to V1).
Future<String> runSender(Sender sender) async { Future<String> runSender(Sender sender) async {
try { try {
return await _runSenderV2(sender); return await _runSenderV2(sender);
} catch (e) { } catch (e) {
@@ -70,13 +70,11 @@ class PayjoinSenderWorker {
Future<String> _runSenderV2(Sender sender) async { Future<String> _runSenderV2(Sender sender) async {
try { try {
final postRequest = await sender.extractV2( final postRequest = await sender.extractV2(
ohttpProxyUrl: ohttpProxyUrl: await pj_uri.Url.fromStr(PayjoinManager.randomOhttpRelayUrl()),
await pj_uri.Url.fromStr(PayjoinManager.randomOhttpRelayUrl()),
); );
final postResult = await _postRequest(postRequest.$1); final postResult = await _postRequest(postRequest.$1);
final getContext = final getContext = await postRequest.$2.processResponse(response: postResult);
await postRequest.$2.processResponse(response: postResult);
sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted, "pj": pjUrl}); sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted, "pj": pjUrl});
+6 -12
View File
@@ -23,16 +23,14 @@ class PayjoinStorage {
), ),
); );
PayjoinSession? getUnusedActiveReceiverSession(String walletId) => PayjoinSession? getUnusedActiveReceiverSession(String walletId) => _payjoinSessionSources.values
_payjoinSessionSources.values
.where((session) => .where((session) =>
session.walletId == walletId && session.walletId == walletId &&
session.status == PayjoinSessionStatus.created.name && session.status == PayjoinSessionStatus.created.name &&
!session.isSenderSession) !session.isSenderSession)
.firstOrNull; .firstOrNull;
Future<void> markReceiverSessionComplete( Future<void> markReceiverSessionComplete(String sessionId, String txId, String amount) async {
String sessionId, String txId, String amount) async {
final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!; final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!;
session.status = PayjoinSessionStatus.success.name; session.status = PayjoinSessionStatus.success.name;
@@ -41,8 +39,7 @@ class PayjoinStorage {
await session.save(); await session.save();
} }
Future<void> markReceiverSessionUnrecoverable( Future<void> markReceiverSessionUnrecoverable(String sessionId, String reason) async {
String sessionId, String reason) async {
final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!; final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!;
session.status = PayjoinSessionStatus.unrecoverable.name; session.status = PayjoinSessionStatus.unrecoverable.name;
@@ -92,13 +89,10 @@ class PayjoinStorage {
await session.save(); await session.save();
} }
List<PayjoinSession> readAllOpenSessions(String walletId) => List<PayjoinSession> readAllOpenSessions(String walletId) => _payjoinSessionSources.values
_payjoinSessionSources.values
.where((session) => .where((session) =>
session.walletId == walletId && session.walletId == walletId &&
![ ![PayjoinSessionStatus.success.name, PayjoinSessionStatus.unrecoverable.name]
PayjoinSessionStatus.success.name, .contains(session.status))
PayjoinSessionStatus.unrecoverable.name
].contains(session.status))
.toList(); .toList();
} }
+19 -38
View File
@@ -40,8 +40,7 @@ extension PsbtSigner on PsbtV2 {
return tx.buffer(); return tx.buffer();
} }
Future<void> signWithUTXO( Future<void> signWithUTXO(List<UtxoWithPrivateKey> utxos, UTXOSignerCallBack signer,
List<UtxoWithPrivateKey> utxos, UTXOSignerCallBack signer,
[UTXOGetterCallBack? getTaprootPair]) async { [UTXOGetterCallBack? getTaprootPair]) async {
final raw = BytesUtils.toHexString(extractUnsignedTX(getSegwit: false)); final raw = BytesUtils.toHexString(extractUnsignedTX(getSegwit: false));
final tx = BtcTransaction.fromRaw(raw); final tx = BtcTransaction.fromRaw(raw);
@@ -53,8 +52,8 @@ extension PsbtSigner on PsbtV2 {
if (utxos.any((e) => e.utxo.isP2tr())) { if (utxos.any((e) => e.utxo.isP2tr())) {
for (final input in tx.inputs) { for (final input in tx.inputs) {
final utxo = utxos.firstWhereOrNull( final utxo = utxos
(u) => u.utxo.txHash == input.txId && u.utxo.vout == input.txIndex); .firstWhereOrNull((u) => u.utxo.txHash == input.txId && u.utxo.vout == input.txIndex);
if (utxo == null) { if (utxo == null) {
final trPair = await getTaprootPair!.call(input.txId, input.txIndex); final trPair = await getTaprootPair!.call(input.txId, input.txIndex);
@@ -81,8 +80,8 @@ extension PsbtSigner on PsbtV2 {
: BitcoinOpCodeConst.SIGHASH_ALL; : BitcoinOpCodeConst.SIGHASH_ALL;
/// We generate transaction digest for current input /// We generate transaction digest for current input
final digest = _generateTransactionDigest( final digest =
script, i, utxo.utxo, tx, taprootAmounts, taprootScripts); _generateTransactionDigest(script, i, utxo.utxo, tx, taprootAmounts, taprootScripts);
/// now we need sign the transaction digest /// now we need sign the transaction digest
final sig = signer(digest, utxo, utxo.privateKey, sighash); final sig = signer(digest, utxo, utxo.privateKey, sighash);
@@ -90,21 +89,14 @@ extension PsbtSigner on PsbtV2 {
if (utxo.utxo.isP2tr()) { if (utxo.utxo.isP2tr()) {
setInputTapKeySig(i, Uint8List.fromList(BytesUtils.fromHexString(sig))); setInputTapKeySig(i, Uint8List.fromList(BytesUtils.fromHexString(sig)));
} else { } else {
setInputPartialSig( setInputPartialSig(i, Uint8List.fromList(BytesUtils.fromHexString(utxo.public().toHex())),
i,
Uint8List.fromList(BytesUtils.fromHexString(utxo.public().toHex())),
Uint8List.fromList(BytesUtils.fromHexString(sig))); Uint8List.fromList(BytesUtils.fromHexString(sig)));
} }
} }
} }
List<int> _generateTransactionDigest( List<int> _generateTransactionDigest(Script scriptPubKeys, int input, BitcoinUtxo utxo,
Script scriptPubKeys, BtcTransaction transaction, List<BigInt> taprootAmounts, List<Script> tapRootPubKeys) {
int input,
BitcoinUtxo utxo,
BtcTransaction transaction,
List<BigInt> taprootAmounts,
List<Script> tapRootPubKeys) {
if (utxo.isSegwit()) { if (utxo.isSegwit()) {
if (utxo.isP2tr()) { if (utxo.isP2tr()) {
return transaction.getTransactionTaprootDigset( return transaction.getTransactionTaprootDigset(
@@ -116,8 +108,7 @@ extension PsbtSigner on PsbtV2 {
return transaction.getTransactionSegwitDigit( return transaction.getTransactionSegwitDigit(
txInIndex: input, script: scriptPubKeys, amount: utxo.value); txInIndex: input, script: scriptPubKeys, amount: utxo.value);
} }
return transaction.getTransactionDigest( return transaction.getTransactionDigest(txInIndex: input, script: scriptPubKeys);
txInIndex: input, script: scriptPubKeys);
} }
Script _findLockingScript(UtxoWithAddress utxo, bool isTaproot) { Script _findLockingScript(UtxoWithAddress utxo, bool isTaproot) {
@@ -172,11 +163,10 @@ extension PsbtSigner on PsbtV2 {
} }
} }
typedef UTXOSignerCallBack = String Function(List<int> trDigest, typedef UTXOSignerCallBack = String Function(
UtxoWithAddress utxo, ECPrivate privateKey, int sighash); List<int> trDigest, UtxoWithAddress utxo, ECPrivate privateKey, int sighash);
typedef UTXOGetterCallBack = Future<TaprootAmountScriptPair> Function( typedef UTXOGetterCallBack = Future<TaprootAmountScriptPair> Function(String txId, int vout);
String txId, int vout);
class TaprootAmountScriptPair { class TaprootAmountScriptPair {
final BigInt value; final BigInt value;
@@ -216,23 +206,17 @@ class UtxoWithPrivateKey extends UtxoWithAddress {
} }
return UtxoWithPrivateKey( return UtxoWithPrivateKey(
utxo: input.utxo, utxo: input.utxo, ownerDetails: input.ownerDetails, privateKey: key.privkey);
ownerDetails: input.ownerDetails,
privateKey: key.privkey);
} }
factory UtxoWithPrivateKey.fromUnspent( factory UtxoWithPrivateKey.fromUnspent(BitcoinUnspent input, BitcoinWalletBase wallet) {
BitcoinUnspent input, BitcoinWalletBase wallet) { final address = RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);
final address =
RegexUtils.addressTypeFromStr(input.address, BitcoinNetwork.mainnet);
final newHd = final newHd = input.bitcoinAddressRecord.isHidden ? wallet.sideHd : wallet.mainHd;
input.bitcoinAddressRecord.isHidden ? wallet.sideHd : wallet.mainHd;
ECPrivate privkey; ECPrivate privkey;
if (input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) { if (input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) {
final unspentAddress = final unspentAddress = input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
input.bitcoinAddressRecord as BitcoinSilentPaymentAddressRecord;
privkey = wallet.walletAddresses.silentAddress!.b_spend.tweakAdd( privkey = wallet.walletAddresses.silentAddress!.b_spend.tweakAdd(
BigintUtils.fromBytes( BigintUtils.fromBytes(
BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!), BytesUtils.fromHexString(unspentAddress.silentPaymentTweak!),
@@ -240,9 +224,7 @@ class UtxoWithPrivateKey extends UtxoWithAddress {
); );
} else { } else {
privkey = generateECPrivate( privkey = generateECPrivate(
hd: newHd, hd: newHd, index: input.bitcoinAddressRecord.index, network: BitcoinNetwork.mainnet);
index: input.bitcoinAddressRecord.index,
network: BitcoinNetwork.mainnet);
} }
return UtxoWithPrivateKey( return UtxoWithPrivateKey(
@@ -251,8 +233,7 @@ class UtxoWithPrivateKey extends UtxoWithAddress {
value: BigInt.from(input.value), value: BigInt.from(input.value),
vout: input.vout, vout: input.vout,
scriptType: input.bitcoinAddressRecord.type, scriptType: input.bitcoinAddressRecord.type,
isSilentPayment: isSilentPayment: input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
input.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord,
), ),
ownerDetails: UtxoAddressDetails( ownerDetails: UtxoAddressDetails(
publicKey: privkey.getPublic().toHex(), publicKey: privkey.getPublic().toHex(),
+10 -13
View File
@@ -11,7 +11,10 @@ class PSBTTransactionBuild {
final PsbtV2 psbt = PsbtV2(); final PsbtV2 psbt = PsbtV2();
PSBTTransactionBuild( PSBTTransactionBuild(
{required List<PSBTReadyUtxoWithAddress> inputs, required List<BitcoinBaseOutput> outputs, required List<OutputInfo> cwOutputs, bool enableRBF = true}) { {required List<PSBTReadyUtxoWithAddress> inputs,
required List<BitcoinBaseOutput> outputs,
required List<OutputInfo> cwOutputs,
bool enableRBF = true}) {
psbt.setGlobalTxVersion(2); psbt.setGlobalTxVersion(2);
psbt.setGlobalInputCount(inputs.length); psbt.setGlobalInputCount(inputs.length);
psbt.setGlobalOutputCount(outputs.length); psbt.setGlobalOutputCount(outputs.length);
@@ -23,11 +26,11 @@ class PSBTTransactionBuild {
printV(input.utxo.isSegwit()); printV(input.utxo.isSegwit());
printV(input.utxo.isP2shSegwit()); printV(input.utxo.isP2shSegwit());
psbt.setInputPreviousTxId(i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList())); psbt.setInputPreviousTxId(
i, Uint8List.fromList(hex.decode(input.utxo.txHash).reversed.toList()));
psbt.setInputOutputIndex(i, input.utxo.vout); psbt.setInputOutputIndex(i, input.utxo.vout);
psbt.setInputSequence(i, enableRBF ? 0xfffffffd : 0xffffffff); psbt.setInputSequence(i, enableRBF ? 0xfffffffd : 0xffffffff);
if (input.utxo.isSegwit()) { if (input.utxo.isSegwit()) {
setInputSegwit(i, input); setInputSegwit(i, input);
} else if (input.utxo.isP2shSegwit()) { } else if (input.utxo.isP2shSegwit()) {
@@ -80,20 +83,14 @@ class PSBTTransactionBuild {
void setInputP2pkh(int i, PSBTReadyUtxoWithAddress input) { void setInputP2pkh(int i, PSBTReadyUtxoWithAddress input) {
psbt.setInputNonWitnessUtxo(i, Uint8List.fromList(hex.decode(input.rawTx))); psbt.setInputNonWitnessUtxo(i, Uint8List.fromList(hex.decode(input.rawTx)));
psbt.setInputBip32Derivation( psbt.setInputBip32Derivation(i, Uint8List.fromList(hex.decode(input.ownerPublicKey)),
i, input.ownerMasterFingerprint, BIPPath.fromString(input.ownerDerivationPath).toPathArray());
Uint8List.fromList(hex.decode(input.ownerPublicKey)),
input.ownerMasterFingerprint,
BIPPath.fromString(input.ownerDerivationPath).toPathArray());
} }
void setInputSegwit(int i, PSBTReadyUtxoWithAddress input) { void setInputSegwit(int i, PSBTReadyUtxoWithAddress input) {
psbt.setInputNonWitnessUtxo(i, Uint8List.fromList(hex.decode(input.rawTx))); psbt.setInputNonWitnessUtxo(i, Uint8List.fromList(hex.decode(input.rawTx)));
psbt.setInputBip32Derivation( psbt.setInputBip32Derivation(i, Uint8List.fromList(hex.decode(input.ownerPublicKey)),
i, input.ownerMasterFingerprint, BIPPath.fromString(input.ownerDerivationPath).toPathArray());
Uint8List.fromList(hex.decode(input.ownerPublicKey)),
input.ownerMasterFingerprint,
BIPPath.fromString(input.ownerDerivationPath).toPathArray());
psbt.setInputWitnessUtxo(i, Uint8List.fromList(bigIntToUint64LE(input.utxo.value)), psbt.setInputWitnessUtxo(i, Uint8List.fromList(bigIntToUint64LE(input.utxo.value)),
Uint8List.fromList(input.ownerDetails.address.toScriptPubKey().toBytes())); Uint8List.fromList(input.ownerDetails.address.toScriptPubKey().toBytes()));
+1 -3
View File
@@ -10,9 +10,7 @@ import 'package:ledger_bitcoin/psbt.dart';
String getTxIdFromPsbtV0(String psbt) { String getTxIdFromPsbtV0(String psbt) {
final psbtV2 = PsbtV2()..deserializeV0(base64.decode(psbt)); final psbtV2 = PsbtV2()..deserializeV0(base64.decode(psbt));
return BtcTransaction.fromRaw( return BtcTransaction.fromRaw(BytesUtils.toHexString(psbtV2.extractUnsignedTX(false))).txId();
BytesUtils.toHexString(psbtV2.extractUnsignedTX(false)))
.txId();
} }
String getOutputAmountFromPsbt(String psbtV0, BitcoinWalletBase wallet) { String getOutputAmountFromPsbt(String psbtV0, BitcoinWalletBase wallet) {
+4 -3
View File
@@ -7,10 +7,10 @@ import 'package:ledger_bitcoin/src/utils/buffer_reader.dart';
import 'package:ledger_bitcoin/src/utils/uint8list_extension.dart' as ext; import 'package:ledger_bitcoin/src/utils/uint8list_extension.dart' as ext;
extension PsbtSigner on PsbtV2 { extension PsbtSigner on PsbtV2 {
void deserializeV0(Uint8List psbt) { void deserializeV0(Uint8List psbt) {
final bufferReader = BufferReader(psbt); final bufferReader = BufferReader(psbt);
if (!listEquals(bufferReader.readSlice(5), Uint8List.fromList([0x70, 0x73, 0x62, 0x74, 0xff]))) { if (!listEquals(
bufferReader.readSlice(5), Uint8List.fromList([0x70, 0x73, 0x62, 0x74, 0xff]))) {
throw Exception("Invalid magic bytes"); throw Exception("Invalid magic bytes");
} }
while (_readKeyPair(globalMap, bufferReader)) {} while (_readKeyPair(globalMap, bufferReader)) {}
@@ -26,7 +26,8 @@ extension PsbtSigner on PsbtV2 {
while (_readKeyPair(inputMaps[i], bufferReader)) {} while (_readKeyPair(inputMaps[i], bufferReader)) {}
final input = tx.inputs[i]; final input = tx.inputs[i];
setInputOutputIndex(i, input.txIndex); setInputOutputIndex(i, input.txIndex);
setInputPreviousTxId(i, Uint8List.fromList(BytesUtils.fromHexString(input.txId).reversed.toList())); setInputPreviousTxId(
i, Uint8List.fromList(BytesUtils.fromHexString(input.txId).reversed.toList()));
setInputSequence(i, Uint8List.fromList(input.sequence).readUint32LE(0)); setInputSequence(i, Uint8List.fromList(input.sequence).readUint32LE(0));
} }
for (var i = 0; i < getGlobalOutputCount(); i++) { for (var i = 0; i < getGlobalOutputCount(); i++) {
+2 -5
View File
@@ -18,7 +18,6 @@ import "package:ledger_bitcoin/src/utils/buffer_writer.dart";
/// through PSBT_IN_PARTIAL_SIG or PSBT_IN_TAP_KEY_SIG /// through PSBT_IN_PARTIAL_SIG or PSBT_IN_TAP_KEY_SIG
extension InputFinalizer on PsbtV2 { extension InputFinalizer on PsbtV2 {
void finalizeV0() { void finalizeV0() {
// First check that each input has a signature // First check that each input has a signature
for (var i = 0; i < getGlobalInputCount(); i++) { for (var i = 0; i < getGlobalInputCount(); i++) {
if (_isFinalized(i)) continue; if (_isFinalized(i)) continue;
@@ -31,8 +30,7 @@ extension InputFinalizer on PsbtV2 {
} }
if (legacyPubkeys.isNotEmpty) { if (legacyPubkeys.isNotEmpty) {
if (legacyPubkeys.length > 1) { if (legacyPubkeys.length > 1) {
throw Exception( throw Exception('Expected exactly one signature, got ${legacyPubkeys.length}');
'Expected exactly one signature, got ${legacyPubkeys.length}');
} }
if (taprootSig != null) { if (taprootSig != null) {
throw Exception('Both taproot and non-taproot signatures present.'); throw Exception('Both taproot and non-taproot signatures present.');
@@ -55,8 +53,7 @@ extension InputFinalizer on PsbtV2 {
setInputFinalScriptwitness(i, witnessBuf.buffer()); setInputFinalScriptwitness(i, witnessBuf.buffer());
if (isWrappedSegwit) { if (isWrappedSegwit) {
if (redeemScript.isEmpty) { if (redeemScript.isEmpty) {
throw Exception( throw Exception("Expected non-empty redeemscript. Can't finalize input $i");
"Expected non-empty redeemscript. Can't finalize input $i");
} }
final scriptSigBuf = BufferWriter() final scriptSigBuf = BufferWriter()
..writeUInt8(redeemScript.length) // Push redeemScript length ..writeUInt8(redeemScript.length) // Push redeemScript length
@@ -87,8 +87,9 @@ class BitcoinCashWalletService extends WalletService<
} }
await WalletInfo.delete(walletInfo); await WalletInfo.delete(walletInfo);
final unspentCoinsToDelete = unspentCoinsInfoSource.values.where( final unspentCoinsToDelete = unspentCoinsInfoSource.values
(unspentCoin) => unspentCoin.walletId == walletInfo.id).toList(); .where((unspentCoin) => unspentCoin.walletId == walletInfo.id)
.toList();
final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList(); final keysToDelete = unspentCoinsToDelete.map((unspentCoin) => unspentCoin.key).toList();
@@ -122,8 +123,7 @@ class BitcoinCashWalletService extends WalletService<
walletInfo: credentials.walletInfo!, walletInfo: credentials.walletInfo!,
unspentCoinsInfo: unspentCoinsInfoSource, unspentCoinsInfo: unspentCoinsInfoSource,
encryptionFileUtils: encryptionFileUtilsFor(isDirect), encryptionFileUtils: encryptionFileUtilsFor(isDirect),
passphrase: credentials.passphrase passphrase: credentials.passphrase);
);
await wallet.save(); await wallet.save();
await wallet.init(); await wallet.init();
return wallet; return wallet;
-1
View File
@@ -1,7 +1,6 @@
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
abstract class AccountList<T> { abstract class AccountList<T> {
ObservableList<T> get accounts; ObservableList<T> get accounts;
void update(); void update();
+1 -3
View File
@@ -41,7 +41,5 @@ class AddressInfoAdapter extends TypeAdapter<AddressInfo> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is AddressInfoAdapter && other is AddressInfoAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
-1
View File
@@ -10,7 +10,6 @@ String _smartAmountSanitizer(String amount) {
return amount.replaceAll(",", "."); return amount.replaceAll(",", ".");
} }
extension SanitizerUserAmounts on String { extension SanitizerUserAmounts on String {
String sanitized() => _smartAmountSanitizer(this); String sanitized() => _smartAmountSanitizer(this);
} }
-1
View File
@@ -21,7 +21,6 @@ class AmountConverter {
return neg ? '-${res.toString()}' : res.toString(); return neg ? '-${res.toString()}' : res.toString();
} }
static String fromBaseUnits(String units, int decimals) { static String fromBaseUnits(String units, int decimals) {
units = units.trim(); units = units.trim();
if (units.isEmpty) return '0'; if (units.isEmpty) return '0';
+5 -9
View File
@@ -59,21 +59,17 @@ class BalanceCardStyleSettings {
int iconStyleIndex = 0, int iconStyleIndex = 0,
int? gradientIndexOverride, int? gradientIndexOverride,
}) { }) {
final int gradientIndex = gradientIndexOverride ?? final int gradientIndex =
CardDesign.allGradients.indexOf(design.gradient); gradientIndexOverride ?? CardDesign.allGradients.indexOf(design.gradient);
return BalanceCardStyleSettings( return BalanceCardStyleSettings(
walletInfoId: walletInfoId, walletInfoId: walletInfoId,
accountIndex: accountIndex, accountIndex: accountIndex,
gradientIndex: gradientIndex, gradientIndex: gradientIndex,
useSpecialDesign: useSpecialDesign: design.backgroundType == CardDesignBackgroundTypes.svgFull,
design.backgroundType == CardDesignBackgroundTypes.svgFull,
backgroundImagePath: backgroundImagePath:
design.backgroundType == CardDesignBackgroundTypes.image design.backgroundType == CardDesignBackgroundTypes.image ? design.imagePath : "",
? design.imagePath
: "",
iconStyleIndex: iconStyleIndex, iconStyleIndex: iconStyleIndex,
isGradientOnly: isGradientOnly: design.backgroundType == CardDesignBackgroundTypes.gradientOnly,
design.backgroundType == CardDesignBackgroundTypes.gradientOnly,
cardOrder: cardOrder, cardOrder: cardOrder,
); );
} }
+112 -99
View File
@@ -18,8 +18,7 @@ class CardColorCombination {
static const light = CardColorCombination( static const light = CardColorCombination(
textColor: Color.fromARGB(200, 255, 255, 255), textColor: Color.fromARGB(200, 255, 255, 255),
textColorSecondary: Colors.white54, textColorSecondary: Colors.white54,
backgroundImageColor: Color.fromARGB(200, 0, 0, 0) backgroundImageColor: Color.fromARGB(200, 0, 0, 0));
);
static const dark = CardColorCombination( static const dark = CardColorCombination(
textColor: Color.fromARGB(200, 0, 0, 0), textColor: Color.fromARGB(200, 0, 0, 0),
@@ -50,7 +49,8 @@ class CardDesign {
const CardDesign( const CardDesign(
{this.backgroundType = CardDesignBackgroundTypes.svgIcon, {this.backgroundType = CardDesignBackgroundTypes.svgIcon,
this.gradient = const LinearGradient(colors: [Colors.black], begin: Alignment.topCenter, end: Alignment.bottomCenter), this.gradient = const LinearGradient(
colors: [Colors.black], begin: Alignment.topCenter, end: Alignment.bottomCenter),
this.imagePath = "assets/new-ui/blank.svg", this.imagePath = "assets/new-ui/blank.svg",
this.colors = CardColorCombination.dark, this.colors = CardColorCombination.dark,
this.preColoredIcon = false}); this.preColoredIcon = false});
@@ -129,71 +129,50 @@ class CardDesign {
static const genericDefault = CardDesign(gradient: gradientBlue); static const genericDefault = CardDesign(gradient: gradientBlue);
static const gradientOnlyDesign = CardDesign( static const gradientOnlyDesign =
backgroundType: CardDesignBackgroundTypes.gradientOnly, CardDesign(backgroundType: CardDesignBackgroundTypes.gradientOnly, gradient: gradientBlue);
gradient: gradientBlue);
static const btc = CardDesign( static const btc = CardDesign(imagePath: "assets/new-ui/balance_card_icons/bitcoin.svg");
imagePath: "assets/new-ui/balance_card_icons/bitcoin.svg");
static const eth = CardDesign( static const eth = CardDesign(imagePath: "assets/new-ui/balance_card_icons/ethereum.svg");
imagePath: "assets/new-ui/balance_card_icons/ethereum.svg");
static const btcln = CardDesign( static const btcln = CardDesign(imagePath: "assets/new-ui/balance_card_icons/lightning.svg");
imagePath: "assets/new-ui/balance_card_icons/lightning.svg");
static const xmr = CardDesign( static const xmr = CardDesign(imagePath: "assets/new-ui/balance_card_icons/monero.svg");
imagePath: "assets/new-ui/balance_card_icons/monero.svg");
static const ltc = CardDesign( static const ltc = CardDesign(imagePath: "assets/new-ui/balance_card_icons/litecoin.svg");
imagePath: "assets/new-ui/balance_card_icons/litecoin.svg");
static const bch = CardDesign( static const bch = CardDesign(imagePath: "assets/new-ui/balance_card_icons/bitcoin_cash.svg");
imagePath: "assets/new-ui/balance_card_icons/bitcoin_cash.svg");
static const doge = CardDesign( static const doge = CardDesign(imagePath: "assets/new-ui/balance_card_icons/dogecoin.svg");
imagePath: "assets/new-ui/balance_card_icons/dogecoin.svg");
static const base = CardDesign( static const base = CardDesign(imagePath: "assets/new-ui/balance_card_icons/base.svg");
imagePath: "assets/new-ui/balance_card_icons/base.svg");
static const pol = CardDesign( static const pol = CardDesign(imagePath: "assets/new-ui/balance_card_icons/polygon.svg");
imagePath: "assets/new-ui/balance_card_icons/polygon.svg");
static const sol = CardDesign( static const sol = CardDesign(imagePath: "assets/new-ui/balance_card_icons/solana.svg");
imagePath: "assets/new-ui/balance_card_icons/solana.svg");
static const tron = CardDesign( static const tron = CardDesign(imagePath: "assets/new-ui/balance_card_icons/tron.svg");
imagePath: "assets/new-ui/balance_card_icons/tron.svg");
static const nano = CardDesign( static const nano = CardDesign(imagePath: "assets/new-ui/balance_card_icons/nano.svg");
imagePath: "assets/new-ui/balance_card_icons/nano.svg");
static const zano = CardDesign( static const zano = CardDesign(imagePath: "assets/new-ui/balance_card_icons/zano.svg");
imagePath: "assets/new-ui/balance_card_icons/zano.svg");
static const wow = CardDesign( static const wow = CardDesign(imagePath: "assets/new-ui/balance_card_icons/wownero.svg");
imagePath: "assets/new-ui/balance_card_icons/wownero.svg");
static const dcr = CardDesign( static const dcr = CardDesign(imagePath: "assets/new-ui/balance_card_icons/decred.svg");
imagePath: "assets/new-ui/balance_card_icons/decred.svg");
static const arbitrum = CardDesign( static const arbitrum = CardDesign(imagePath: "assets/new-ui/balance_card_icons/arbitrum.svg");
imagePath: "assets/new-ui/balance_card_icons/arbitrum.svg");
static const zec = CardDesign(
imagePath: "assets/new-ui/balance_card_icons/zcash.svg");
static const bnb = CardDesign(
imagePath: "assets/new-ui/balance_card_icons/bnb.svg");
static const zec = CardDesign(imagePath: "assets/new-ui/balance_card_icons/zcash.svg");
static const bnb = CardDesign(imagePath: "assets/new-ui/balance_card_icons/bnb.svg");
static const ethSpecial = CardDesign( static const ethSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF6259FF), Color(0xFF3B20E6)], colors: <Color>[Color(0xFF6259FF), Color(0xFF3B20E6)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
colors: CardColorCombination.light, colors: CardColorCombination.light,
imagePath: "assets/new-ui/balance_card_backgrounds/ethereum.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/ethereum.svg");
@@ -201,24 +180,24 @@ class CardDesign {
static const btcSpecial = CardDesign( static const btcSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFFFBF00), Color(0xFFFF6A00)], colors: <Color>[Color(0xFFFFBF00), Color(0xFFFF6A00)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/bitcoin.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/bitcoin.svg");
static const xmrSpecial = CardDesign( static const xmrSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFFF5900), Color(0xFFE62E00)], colors: <Color>[Color(0xFFFF5900), Color(0xFFE62E00)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/monero.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/monero.svg");
static const ltcSpecial = CardDesign( static const ltcSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF2145BF), Color(0xFF072071)], colors: <Color>[Color(0xFF2145BF), Color(0xFF072071)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
colors: CardColorCombination.light, colors: CardColorCombination.light,
imagePath: "assets/new-ui/balance_card_backgrounds/litecoin.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/litecoin.svg");
@@ -226,8 +205,8 @@ class CardDesign {
static const lnSpecial = CardDesign( static const lnSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFFFBF00), Color(0xFFFF6A00)], colors: <Color>[Color(0xFFFFBF00), Color(0xFFFF6A00)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
colors: CardColorCombination.dark, colors: CardColorCombination.dark,
imagePath: "assets/new-ui/balance_card_backgrounds/lightning.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/lightning.svg");
@@ -235,8 +214,8 @@ class CardDesign {
static const tronSpecial = CardDesign( static const tronSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFFF1313), Color(0xFFB40000)], colors: <Color>[Color(0xFFFF1313), Color(0xFFB40000)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
colors: CardColorCombination.light, colors: CardColorCombination.light,
imagePath: "assets/new-ui/balance_card_backgrounds/tron.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/tron.svg");
@@ -244,8 +223,8 @@ class CardDesign {
static const solSpecial = CardDesign( static const solSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF4701AA), Color(0xFF19004B)], colors: <Color>[Color(0xFF4701AA), Color(0xFF19004B)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
colors: CardColorCombination.light, colors: CardColorCombination.light,
imagePath: "assets/new-ui/balance_card_backgrounds/solana.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/solana.svg");
@@ -253,40 +232,40 @@ class CardDesign {
static const bchSpecial = CardDesign( static const bchSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF36DA4C), Color(0xFF008D57)], colors: <Color>[Color(0xFF36DA4C), Color(0xFF008D57)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/bitcoin-cash.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/bitcoin-cash.svg");
static const wowSpecial = CardDesign( static const wowSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFFF6CD3), Color(0xFFF200A9)], colors: <Color>[Color(0xFFFF6CD3), Color(0xFFF200A9)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/wownero.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/wownero.svg");
static const dogeSpecial = CardDesign( static const dogeSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFCBA818), Color(0xFF885D00)], colors: <Color>[Color(0xFFCBA818), Color(0xFF885D00)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/dogecoin.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/dogecoin.svg");
static const nanoSpecial = CardDesign( static const nanoSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF209CE9), Color(0xFF0073CB)], colors: <Color>[Color(0xFF209CE9), Color(0xFF0073CB)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/nano.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/nano.svg");
static const polSpecial = CardDesign( static const polSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF863FE3), Color(0xFF59098E)], colors: <Color>[Color(0xFF863FE3), Color(0xFF59098E)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
colors: CardColorCombination.light, colors: CardColorCombination.light,
imagePath: "assets/new-ui/balance_card_backgrounds/polygon.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/polygon.svg");
@@ -294,8 +273,8 @@ class CardDesign {
static const dcrSpecial = CardDesign( static const dcrSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF2871FF), Color(0xFF0057FF)], colors: <Color>[Color(0xFF2871FF), Color(0xFF0057FF)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
colors: CardColorCombination.light, colors: CardColorCombination.light,
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/decred.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/decred.svg");
@@ -303,8 +282,8 @@ class CardDesign {
static const zanoSpecial = CardDesign( static const zanoSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF0004B4), Color(0xFF170069)], colors: <Color>[Color(0xFF0004B4), Color(0xFF170069)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
colors: CardColorCombination.black, colors: CardColorCombination.black,
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/zano.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/zano.svg");
@@ -312,8 +291,8 @@ class CardDesign {
static const baseSpecial = CardDesign( static const baseSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF003CFF), Color(0xFF000087)], colors: <Color>[Color(0xFF003CFF), Color(0xFF000087)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
colors: CardColorCombination.light, colors: CardColorCombination.light,
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/base.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/base.svg");
@@ -321,8 +300,8 @@ class CardDesign {
static const arbitrumSpecial = CardDesign( static const arbitrumSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF173F76), Color(0xFF031A39)], colors: <Color>[Color(0xFF173F76), Color(0xFF031A39)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
colors: CardColorCombination.light, colors: CardColorCombination.light,
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/arbitrum.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/arbitrum.svg");
@@ -330,16 +309,16 @@ class CardDesign {
static const zecSpecial = CardDesign( static const zecSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFFF6C527), Color(0xFFCD8C00)], colors: <Color>[Color(0xFFF6C527), Color(0xFFCD8C00)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/zcash.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/zcash.svg");
static const bnbSpecial = CardDesign( static const bnbSpecial = CardDesign(
gradient: const LinearGradient( gradient: const LinearGradient(
colors: <Color>[Color(0xFF603000), Color(0xFFF0B90B)], colors: <Color>[Color(0xFF603000), Color(0xFFF0B90B)],
begin: Alignment.topCenter, end: Alignment.bottomCenter begin: Alignment.topCenter,
), end: Alignment.bottomCenter),
colors: CardColorCombination.light, colors: CardColorCombination.light,
backgroundType: CardDesignBackgroundTypes.svgFull, backgroundType: CardDesignBackgroundTypes.svgFull,
imagePath: "assets/new-ui/balance_card_backgrounds/bnb.svg"); imagePath: "assets/new-ui/balance_card_backgrounds/bnb.svg");
@@ -351,7 +330,9 @@ class CardDesign {
backgroundType: backgroundType, backgroundType: backgroundType,
preColoredIcon: preColoredIcon); preColoredIcon: preColoredIcon);
CardDesign withGradientAndColorCombination(Gradient gradient, CardColorCombination cardColorCombination) => CardDesign( CardDesign withGradientAndColorCombination(
Gradient gradient, CardColorCombination cardColorCombination) =>
CardDesign(
gradient: gradient, gradient: gradient,
colors: cardColorCombination, colors: cardColorCombination,
imagePath: imagePath, imagePath: imagePath,
@@ -374,8 +355,10 @@ class CardDesign {
static const Map<CryptoCurrency, _CurrencyIconNames> _iconNames = { static const Map<CryptoCurrency, _CurrencyIconNames> _iconNames = {
CryptoCurrency.arbEth: _CurrencyIconNames(ticker: 'arb', longName: 'arbitrum'), CryptoCurrency.arbEth: _CurrencyIconNames(ticker: 'arb', longName: 'arbitrum'),
CryptoCurrency.baseEth: _CurrencyIconNames(ticker: 'base', longName: 'base', chainFile: 'base_icon'), CryptoCurrency.baseEth:
CryptoCurrency.bch: _CurrencyIconNames(ticker: 'bch', longName: 'bitcoin_cash', chainFile: 'bitcoin-cash'), _CurrencyIconNames(ticker: 'base', longName: 'base', chainFile: 'base_icon'),
CryptoCurrency.bch:
_CurrencyIconNames(ticker: 'bch', longName: 'bitcoin_cash', chainFile: 'bitcoin-cash'),
CryptoCurrency.btc: _CurrencyIconNames(ticker: 'btc', longName: 'bitcoin', outlineFile: 'BTC'), CryptoCurrency.btc: _CurrencyIconNames(ticker: 'btc', longName: 'bitcoin', outlineFile: 'BTC'),
CryptoCurrency.bnb: _CurrencyIconNames(ticker: 'bnb', longName: 'bnb'), CryptoCurrency.bnb: _CurrencyIconNames(ticker: 'bnb', longName: 'bnb'),
CryptoCurrency.dcr: _CurrencyIconNames(ticker: 'dcr', longName: 'decred'), CryptoCurrency.dcr: _CurrencyIconNames(ticker: 'dcr', longName: 'decred'),
@@ -383,13 +366,13 @@ class CardDesign {
CryptoCurrency.eth: _CurrencyIconNames(ticker: 'eth', longName: 'ethereum'), CryptoCurrency.eth: _CurrencyIconNames(ticker: 'eth', longName: 'ethereum'),
CryptoCurrency.btcln: _CurrencyIconNames(ticker: 'ln', longName: 'lightning'), CryptoCurrency.btcln: _CurrencyIconNames(ticker: 'ln', longName: 'lightning'),
CryptoCurrency.ltc: _CurrencyIconNames(ticker: 'ltc', longName: 'litecoin'), CryptoCurrency.ltc: _CurrencyIconNames(ticker: 'ltc', longName: 'litecoin'),
CryptoCurrency.xmr: _CurrencyIconNames( CryptoCurrency.xmr:
ticker: 'xmr', longName: 'monero', ogPath: 'assets/images/xmr-og.webp'), _CurrencyIconNames(ticker: 'xmr', longName: 'monero', ogPath: 'assets/images/xmr-og.webp'),
CryptoCurrency.nano: _CurrencyIconNames(ticker: 'xno', longName: 'nano'), CryptoCurrency.nano: _CurrencyIconNames(ticker: 'xno', longName: 'nano'),
CryptoCurrency.maticpoly: _CurrencyIconNames(ticker: 'pol', longName: 'polygon'), CryptoCurrency.maticpoly: _CurrencyIconNames(ticker: 'pol', longName: 'polygon'),
CryptoCurrency.sol: _CurrencyIconNames(ticker: 'sol', longName: 'solana'), CryptoCurrency.sol: _CurrencyIconNames(ticker: 'sol', longName: 'solana'),
CryptoCurrency.trx: _CurrencyIconNames( CryptoCurrency.trx:
ticker: 'trx', longName: 'tron', ogPath: '$_ogIconPrefix/tron-og.svg'), _CurrencyIconNames(ticker: 'trx', longName: 'tron', ogPath: '$_ogIconPrefix/tron-og.svg'),
CryptoCurrency.zano: _CurrencyIconNames(ticker: 'zano', longName: 'zano'), CryptoCurrency.zano: _CurrencyIconNames(ticker: 'zano', longName: 'zano'),
CryptoCurrency.zec: _CurrencyIconNames(ticker: 'zec', longName: 'zcash'), CryptoCurrency.zec: _CurrencyIconNames(ticker: 'zec', longName: 'zcash'),
}; };
@@ -408,7 +391,40 @@ class CardDesign {
]; ];
} }
static const List<CardDesign> all = [genericDefault, btc, eth, xmr, ltc, eth, pol, doge, base, sol, btcln, tron, zano, dcr, arbitrum, zec, bnb, ethSpecial, btcSpecial, xmrSpecial, ltcSpecial, lnSpecial, tronSpecial, bchSpecial, wowSpecial, dogeSpecial, polSpecial, dcrSpecial, zanoSpecial, arbitrumSpecial, zecSpecial, bnbSpecial]; static const List<CardDesign> all = [
genericDefault,
btc,
eth,
xmr,
ltc,
eth,
pol,
doge,
base,
sol,
btcln,
tron,
zano,
dcr,
arbitrum,
zec,
bnb,
ethSpecial,
btcSpecial,
xmrSpecial,
ltcSpecial,
lnSpecial,
tronSpecial,
bchSpecial,
wowSpecial,
dogeSpecial,
polSpecial,
dcrSpecial,
zanoSpecial,
arbitrumSpecial,
zecSpecial,
bnbSpecial
];
static CardDesign forCurrencySpecial(CryptoCurrency currency) { static CardDesign forCurrencySpecial(CryptoCurrency currency) {
return specialDesignsForCurrencies[currency] ?? genericDefault; return specialDesignsForCurrencies[currency] ?? genericDefault;
@@ -437,7 +453,6 @@ class CardDesign {
CryptoCurrency.zec: zec, CryptoCurrency.zec: zec,
CryptoCurrency.dcr: dcr, CryptoCurrency.dcr: dcr,
CryptoCurrency.bnb: bnb, CryptoCurrency.bnb: bnb,
}; };
static const Map<CryptoCurrency, CardDesign> specialDesignsForCurrencies = { static const Map<CryptoCurrency, CardDesign> specialDesignsForCurrencies = {
@@ -504,9 +519,9 @@ class CardDesign {
if (setting.isGradientOnly) { if (setting.isGradientOnly) {
final gradient = gradientForStoredIndex(setting.gradientIndex, walletCurrency); final gradient = gradientForStoredIndex(setting.gradientIndex, walletCurrency);
final textColors = preferredColorCombinations[gradient] final textColors = preferredColorCombinations[gradient] ??
?? specialDesignsForCurrencies[walletCurrency]?.colors specialDesignsForCurrencies[walletCurrency]?.colors ??
?? gradientOnlyDesign.colors; gradientOnlyDesign.colors;
return gradientOnlyDesign.withGradientAndColorCombination(gradient, textColors); return gradientOnlyDesign.withGradientAndColorCombination(gradient, textColors);
} }
@@ -521,11 +536,9 @@ class CardDesign {
} }
if (!setting.useSpecialDesign && setting.gradientIndex == -1) { if (!setting.useSpecialDesign && setting.gradientIndex == -1) {
final specialColors = final specialColors = specialDesignsForCurrencies[walletCurrency] ?? genericDefault;
specialDesignsForCurrencies[walletCurrency] ?? genericDefault;
final design = CardDesign.forCurrencyIcon(walletCurrency) final design = CardDesign.forCurrencyIcon(walletCurrency)
.withGradientAndColorCombination( .withGradientAndColorCombination(specialColors.gradient, specialColors.colors);
specialColors.gradient, specialColors.colors);
return design.withIconStyleIndex(setting.iconStyleIndex, walletCurrency); return design.withIconStyleIndex(setting.iconStyleIndex, walletCurrency);
} }
if (setting.useSpecialDesign) { if (setting.useSpecialDesign) {
@@ -534,9 +547,9 @@ class CardDesign {
if (setting.gradientIndex != -1) { if (setting.gradientIndex != -1) {
final baseIcon = CardDesign.forCurrencyIcon(walletCurrency); final baseIcon = CardDesign.forCurrencyIcon(walletCurrency);
final gradient = gradientForStoredIndex(setting.gradientIndex, walletCurrency); final gradient = gradientForStoredIndex(setting.gradientIndex, walletCurrency);
final textColors = preferredColorCombinations[gradient] final textColors = preferredColorCombinations[gradient] ??
?? specialDesignsForCurrencies[walletCurrency]?.colors specialDesignsForCurrencies[walletCurrency]?.colors ??
?? baseIcon.colors; baseIcon.colors;
return baseIcon return baseIcon
.withGradientAndColorCombination(gradient, textColors) .withGradientAndColorCombination(gradient, textColors)
.withIconStyleIndex(setting.iconStyleIndex, walletCurrency); .withIconStyleIndex(setting.iconStyleIndex, walletCurrency);
-1
View File
@@ -37,7 +37,6 @@ extension MaxDecimals on String {
return parts.join("."); return parts.join(".");
} }
/// Format a stringified number to a localized representation /// Format a stringified number to a localized representation
/// 1.000.000,00 in de_DE /// 1.000.000,00 in de_DE
/// 1’000’000.00 in de_CH /// 1’000’000.00 in de_CH
+822 -123
View File
@@ -161,139 +161,842 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
// well technically not currencies but since we had them a long time ago and don't want to break // well technically not currencies but since we had them a long time ago and don't want to break
// the app for users who had contacts saved for them // the app for users who had contacts saved for them
static const zcashCurrencies = [ zec, zaddr, tzec ]; static const zcashCurrencies = [zec, zaddr, tzec];
// title, tag (if applicable), fullName (if unique), raw, name, iconPath // title, tag (if applicable), fullName (if unique), raw, name, iconPath
static const xmr = CryptoCurrency(title: 'XMR', fullName: 'Monero', raw: 0, name: 'xmr', iconPath: 'assets/new-ui/crypto_full_icons/monero.svg', decimals: 12, flatIconPath: "assets/new-ui/balance_card_icons/monero.svg"); static const xmr = CryptoCurrency(
static const ada = CryptoCurrency(title: 'ADA', fullName: 'Cardano', raw: 1, name: 'ada', iconPath: 'assets/images/ada_icon.png', decimals: 6); title: 'XMR',
static const bch = CryptoCurrency(title: 'BCH', fullName: 'Bitcoin Cash', raw: 2, name: 'bch', iconPath: 'assets/new-ui/crypto_full_icons/bitcoin-cash.svg', decimals: 8, flatIconPath: "assets/new-ui/balance_card_icons/bitcoin_cash.svg"); fullName: 'Monero',
static const bnb = CryptoCurrency(title: 'BNB', tag: 'BSC', fullName: 'BNB', raw: 3, name: 'bnb', iconPath: 'assets/new-ui/crypto_full_icons/bnb.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/bnb.svg", chainIconPath: "assets/new-ui/chain_badges/bnb.svg"); raw: 0,
static const btc = CryptoCurrency(title: 'BTC', fullName: 'Bitcoin', raw: 4, name: 'btc', iconPath: 'assets/new-ui/crypto_full_icons/bitcoin.svg' ,decimals: 8, flatIconPath: "assets/new-ui/balance_card_icons/bitcoin.svg"); name: 'xmr',
static const dai = CryptoCurrency(title: 'DAI', tag: 'ETH', fullName: 'Dai', raw: 5, name: 'dai', iconPath: 'assets/new-ui/crypto_full_icons/dai.svg', decimals: 18, groups: const {CurrencyGroups.stablecoin}); iconPath: 'assets/new-ui/crypto_full_icons/monero.svg',
static const dash = CryptoCurrency(title: 'DASH', fullName: 'Dash', raw: 6, name: 'dash', iconPath: 'assets/images/dash_icon.png', decimals: 8); decimals: 12,
static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png', decimals: 4); flatIconPath: "assets/new-ui/balance_card_icons/monero.svg");
static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/ethereum.svg", chainIconPath: "assets/new-ui/chain_badges/ethereum.svg"); static const ada = CryptoCurrency(
static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/new-ui/crypto_full_icons/litecoin.svg', decimals: 8, flatIconPath: "assets/new-ui/balance_card_icons/litecoin.svg", chainIconPath: "assets/new-ui/chain_badges/mweb.svg"); title: 'ADA',
static const nano = CryptoCurrency(title: 'XNO', fullName: 'Nano', raw: 10, name: 'xno', iconPath: 'assets/new-ui/crypto_full_icons/nano.svg', decimals: 30, flatIconPath: "assets/new-ui/balance_card_icons/nano.svg"); fullName: 'Cardano',
static const trx = CryptoCurrency(title: 'TRX', fullName: 'TRON', raw: 11, name: 'trx', iconPath: 'assets/new-ui/crypto_full_icons/tron.svg', decimals: 6, flatIconPath: "assets/new-ui/balance_card_icons/tron.svg", chainIconPath: "assets/new-ui/chain_badges/tron.svg"); raw: 1,
static const usdt = CryptoCurrency(title: 'USDT', tag: 'OMNI', fullName: 'Tether', raw: 12, name: 'usdt', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); name: 'ada',
static const usdterc20 = CryptoCurrency(title: 'USDT', tag: 'ETH', fullName: 'Tether', raw: 13, name: 'usdterc20', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); iconPath: 'assets/images/ada_icon.png',
static const xlm = CryptoCurrency(title: 'XLM', fullName: 'Stellar', raw: 14, name: 'xlm', iconPath: 'assets/images/xlm_icon.png', decimals: 7); decimals: 6);
static const xrp = CryptoCurrency(title: 'XRP', fullName: 'Ripple', raw: 15, name: 'xrp', iconPath: 'assets/images/xrp_icon.png', decimals: 6); static const bch = CryptoCurrency(
static const xhv = CryptoCurrency(title: 'XHV', fullName: 'Haven Protocol', raw: 16, name: 'xhv', iconPath: 'assets/images/xhv_logo.png', decimals: 12); title: 'BCH',
fullName: 'Bitcoin Cash',
raw: 2,
name: 'bch',
iconPath: 'assets/new-ui/crypto_full_icons/bitcoin-cash.svg',
decimals: 8,
flatIconPath: "assets/new-ui/balance_card_icons/bitcoin_cash.svg");
static const bnb = CryptoCurrency(
title: 'BNB',
tag: 'BSC',
fullName: 'BNB',
raw: 3,
name: 'bnb',
iconPath: 'assets/new-ui/crypto_full_icons/bnb.svg',
decimals: 18,
flatIconPath: "assets/new-ui/balance_card_icons/bnb.svg",
chainIconPath: "assets/new-ui/chain_badges/bnb.svg");
static const btc = CryptoCurrency(
title: 'BTC',
fullName: 'Bitcoin',
raw: 4,
name: 'btc',
iconPath: 'assets/new-ui/crypto_full_icons/bitcoin.svg',
decimals: 8,
flatIconPath: "assets/new-ui/balance_card_icons/bitcoin.svg");
static const dai = CryptoCurrency(
title: 'DAI',
tag: 'ETH',
fullName: 'Dai',
raw: 5,
name: 'dai',
iconPath: 'assets/new-ui/crypto_full_icons/dai.svg',
decimals: 18,
groups: const {CurrencyGroups.stablecoin});
static const dash = CryptoCurrency(
title: 'DASH',
fullName: 'Dash',
raw: 6,
name: 'dash',
iconPath: 'assets/images/dash_icon.png',
decimals: 8);
static const eos = CryptoCurrency(
title: 'EOS',
fullName: 'EOS',
raw: 7,
name: 'eos',
iconPath: 'assets/images/eos_icon.png',
decimals: 4);
static const eth = CryptoCurrency(
title: 'ETH',
fullName: 'Ethereum',
raw: 8,
name: 'eth',
iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg',
decimals: 18,
flatIconPath: "assets/new-ui/balance_card_icons/ethereum.svg",
chainIconPath: "assets/new-ui/chain_badges/ethereum.svg");
static const ltc = CryptoCurrency(
title: 'LTC',
fullName: 'Litecoin',
raw: 9,
name: 'ltc',
iconPath: 'assets/new-ui/crypto_full_icons/litecoin.svg',
decimals: 8,
flatIconPath: "assets/new-ui/balance_card_icons/litecoin.svg",
chainIconPath: "assets/new-ui/chain_badges/mweb.svg");
static const nano = CryptoCurrency(
title: 'XNO',
fullName: 'Nano',
raw: 10,
name: 'xno',
iconPath: 'assets/new-ui/crypto_full_icons/nano.svg',
decimals: 30,
flatIconPath: "assets/new-ui/balance_card_icons/nano.svg");
static const trx = CryptoCurrency(
title: 'TRX',
fullName: 'TRON',
raw: 11,
name: 'trx',
iconPath: 'assets/new-ui/crypto_full_icons/tron.svg',
decimals: 6,
flatIconPath: "assets/new-ui/balance_card_icons/tron.svg",
chainIconPath: "assets/new-ui/chain_badges/tron.svg");
static const usdt = CryptoCurrency(
title: 'USDT',
tag: 'OMNI',
fullName: 'Tether',
raw: 12,
name: 'usdt',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const usdterc20 = CryptoCurrency(
title: 'USDT',
tag: 'ETH',
fullName: 'Tether',
raw: 13,
name: 'usdterc20',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const xlm = CryptoCurrency(
title: 'XLM',
fullName: 'Stellar',
raw: 14,
name: 'xlm',
iconPath: 'assets/images/xlm_icon.png',
decimals: 7);
static const xrp = CryptoCurrency(
title: 'XRP',
fullName: 'Ripple',
raw: 15,
name: 'xrp',
iconPath: 'assets/images/xrp_icon.png',
decimals: 6);
static const xhv = CryptoCurrency(
title: 'XHV',
fullName: 'Haven Protocol',
raw: 16,
name: 'xhv',
iconPath: 'assets/images/xhv_logo.png',
decimals: 12);
static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag', decimals: 12); static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag', decimals: 12);
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau', decimals: 12); static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau', decimals: 12);
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19, name: 'xaud', decimals: 12); static const xaud =
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20, name: 'xbtc', decimals: 12); CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19, name: 'xaud', decimals: 12);
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21, name: 'xcad', decimals: 12); static const xbtc =
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22, name: 'xchf', decimals: 12); CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20, name: 'xbtc', decimals: 12);
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23, name: 'xcny', decimals: 12); static const xcad =
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24, name: 'xeur', decimals: 12); CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21, name: 'xcad', decimals: 12);
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25, name: 'xgbp', decimals: 12); static const xchf =
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26, name: 'xjpy', decimals: 12); CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22, name: 'xchf', decimals: 12);
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27, name: 'xnok', decimals: 12); static const xcny =
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28, name: 'xnzd', decimals: 12); CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23, name: 'xcny', decimals: 12);
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd', decimals: 12); static const xeur =
CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24, name: 'xeur', decimals: 12);
static const xgbp =
CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25, name: 'xgbp', decimals: 12);
static const xjpy =
CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26, name: 'xjpy', decimals: 12);
static const xnok =
CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27, name: 'xnok', decimals: 12);
static const xnzd =
CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28, name: 'xnzd', decimals: 12);
static const xusd =
CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd', decimals: 12);
static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png', decimals: 18); static const ape = CryptoCurrency(
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'AVAXC', fullName: 'Avalanche', raw: 31, name: 'avaxc', iconPath: 'assets/new-ui/crypto_full_icons/avax.svg', decimals: 9); title: 'APE',
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png', decimals: 18); tag: 'ETH',
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/btt_icon.png', decimals: 18); fullName: 'ApeCoin',
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/new-ui/crypto_full_icons/dogecoin.svg', decimals: 8, flatIconPath: "assets/new-ui/balance_card_icons/dogecoin.svg"); raw: 30,
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png', decimals: 8); name: 'ape',
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); iconPath: 'assets/images/ape_icon.png',
static const hbar = CryptoCurrency(title: 'HBAR', fullName: 'Hedera', raw: 37, name: 'hbar', iconPath: 'assets/images/hbar_icon.png', decimals: 8); decimals: 18);
static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png', decimals: 16); static const avaxc = CryptoCurrency(
static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/new-ui/crypto_full_icons/solana.svg', decimals: 9, flatIconPath: "assets/new-ui/balance_card_icons/solana.svg", chainIconPath: "assets/new-ui/chain_badges/solana.svg"); title: 'AVAX',
static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USDC', raw: 40, name: 'usdc', iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); tag: 'AVAXC',
static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); fullName: 'Avalanche',
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', raw: 42, name: 'zaddr', iconPath: 'assets/new-ui/crypto_full_icons/zcash.svg', decimals: 8); raw: 31,
static const tzec = CryptoCurrency(title: 'tZEC', tag: 'ZEC', fullName: 'Transparent Zcash', raw: 43, name: 'zec', iconPath: 'assets/new-ui/crypto_full_icons/zcash.svg', decimals: 8); name: 'avaxc',
static const zen = CryptoCurrency(title: 'ZEN', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png', decimals: 8); iconPath: 'assets/new-ui/crypto_full_icons/avax.svg',
static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png', decimals: 8); decimals: 9);
static const btt = CryptoCurrency(
title: 'BTT',
tag: 'ETH',
fullName: 'BitTorrent',
raw: 32,
name: 'btt',
iconPath: 'assets/images/btt_icon.png',
decimals: 18);
static const bttc = CryptoCurrency(
title: 'BTTC',
tag: 'TRX',
fullName: 'BitTorrent-NEW',
raw: 33,
name: 'bttc',
iconPath: 'assets/images/btt_icon.png',
decimals: 18);
static const doge = CryptoCurrency(
title: 'DOGE',
fullName: 'Dogecoin',
raw: 34,
name: 'doge',
iconPath: 'assets/new-ui/crypto_full_icons/dogecoin.svg',
decimals: 8,
flatIconPath: "assets/new-ui/balance_card_icons/dogecoin.svg");
static const firo = CryptoCurrency(
title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png', decimals: 8);
static const usdttrc20 = CryptoCurrency(
title: 'USDT',
tag: 'TRX',
fullName: 'Tether',
raw: 36,
name: 'usdttrc20',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const hbar = CryptoCurrency(
title: 'HBAR',
fullName: 'Hedera',
raw: 37,
name: 'hbar',
iconPath: 'assets/images/hbar_icon.png',
decimals: 8);
static const sc = CryptoCurrency(
title: 'SC',
fullName: 'Siacoin',
raw: 38,
name: 'sc',
iconPath: 'assets/images/sc_icon.png',
decimals: 16);
static const sol = CryptoCurrency(
title: 'SOL',
fullName: 'Solana',
raw: 39,
name: 'sol',
iconPath: 'assets/new-ui/crypto_full_icons/solana.svg',
decimals: 9,
flatIconPath: "assets/new-ui/balance_card_icons/solana.svg",
chainIconPath: "assets/new-ui/chain_badges/solana.svg");
static const usdc = CryptoCurrency(
title: 'USDC',
tag: 'ETH',
fullName: 'USDC',
raw: 40,
name: 'usdc',
iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const usdcsol = CryptoCurrency(
title: 'USDC',
tag: 'SOL',
fullName: 'USDC Coin',
raw: 41,
name: 'usdcsol',
iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const zaddr = CryptoCurrency(
title: 'ZZEC',
tag: 'ZEC',
fullName: 'Shielded Zcash',
raw: 42,
name: 'zaddr',
iconPath: 'assets/new-ui/crypto_full_icons/zcash.svg',
decimals: 8);
static const tzec = CryptoCurrency(
title: 'tZEC',
tag: 'ZEC',
fullName: 'Transparent Zcash',
raw: 43,
name: 'zec',
iconPath: 'assets/new-ui/crypto_full_icons/zcash.svg',
decimals: 8);
static const zen = CryptoCurrency(
title: 'ZEN',
fullName: 'Horizen',
raw: 44,
name: 'zen',
iconPath: 'assets/images/zen_icon.png',
decimals: 8);
static const xvg = CryptoCurrency(
title: 'XVG',
fullName: 'Verge',
raw: 45,
name: 'xvg',
iconPath: 'assets/images/xvg_icon.png',
decimals: 8);
static const usdcpoly = CryptoCurrency(title: 'USDC', tag: 'POL', fullName: 'USDC', raw: 46, name: 'usdcpoly', iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); static const usdcpoly = CryptoCurrency(
static const dcr = CryptoCurrency(title: 'DCR', fullName: 'Decred', raw: 47, name: 'dcr', iconPath: 'assets/new-ui/crypto_full_icons/decred.svg', decimals: 8, flatIconPath: "assets/new-ui/balance_card_icons/decred.svg"); title: 'USDC',
static const kmd = CryptoCurrency(title: 'KMD', fullName: 'Komodo', raw: 48, name: 'kmd', iconPath: 'assets/images/kmd_icon.png', decimals: 8); tag: 'POL',
static const mana = CryptoCurrency(title: 'MANA', tag: 'ETH', fullName: 'Decentraland', raw: 49, name: 'mana', iconPath: 'assets/images/mana_icon.png', decimals: 18); fullName: 'USDC',
static const maticpoly = CryptoCurrency(title: 'POL', tag: 'POL', fullName: 'Polygon', raw: 50, name: 'maticpoly', iconPath: 'assets/new-ui/crypto_full_icons/polygon.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/polygon.svg", chainIconPath: "assets/new-ui/chain_badges/polygon.svg"); raw: 46,
static const matic = CryptoCurrency(title: 'MATIC', tag: 'ETH', fullName: 'Polygon', raw: 51, name: 'matic', iconPath: 'assets/new-ui/crypto_full_icons/polygon.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/polygon.svg"); name: 'usdcpoly',
static const mkr = CryptoCurrency(title: 'MKR', tag: 'ETH', fullName: 'Maker', raw: 52, name: 'mkr', iconPath: 'assets/images/mkr_icon.png', decimals: 18); iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg',
static const near = CryptoCurrency(title: 'NEAR', fullName: 'NEAR Protocol', raw: 53, name: 'near', iconPath: 'assets/images/near_icon.png', decimals: 24); decimals: 6,
static const oxt = CryptoCurrency(title: 'OXT', tag: 'ETH', fullName: 'Orchid', raw: 54, name: 'oxt', iconPath: 'assets/images/oxt_icon.png', decimals: 18); groups: const {CurrencyGroups.stablecoin});
static const paxg = CryptoCurrency(title: 'PAXG', tag: 'ETH', fullName: 'Pax Gold', raw: 55, name: 'paxg', iconPath: 'assets/new-ui/crypto_full_icons/paxg.svg', decimals: 18); static const dcr = CryptoCurrency(
static const pivx = CryptoCurrency(title: 'PIVX', raw: 56, name: 'pivx', iconPath: 'assets/images/pivx_icon.png', decimals: 8); title: 'DCR',
static const rune = CryptoCurrency(title: 'RUNE', fullName: 'Thorchain', raw: 57, name: 'rune', iconPath: 'assets/images/rune_icon.png', decimals: 18); fullName: 'Decred',
static const rvn = CryptoCurrency(title: 'RVN', fullName: 'Ravencoin', raw: 58, name: 'rvn', iconPath: 'assets/images/rvn_icon.png', decimals: 8); raw: 47,
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png', decimals: 6); name: 'dcr',
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png', decimals: 18); iconPath: 'assets/new-ui/crypto_full_icons/decred.svg',
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png', decimals: 8); decimals: 8,
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/new-ui/crypto_full_icons/lightning.svg', chainIconPath: "assets/new-ui/chain_badges/lightning.svg", decimals: 8); flatIconPath: "assets/new-ui/balance_card_icons/decred.svg");
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png', decimals: 18); static const kmd = CryptoCurrency(
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png', decimals: 18); title: 'KMD',
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/new-ui/crypto_full_icons/arbitrum.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/arbitrum.svg", chainIconPath: "assets/new-ui/chain_badges/arbitrum.svg"); fullName: 'Komodo',
static const bat = CryptoCurrency(title: 'BAT', tag: 'ETH', fullName: 'Basic Attention Token', raw: 66, name: 'bat', iconPath: 'assets/images/bat_icon.png', decimals: 18); raw: 48,
static const comp = CryptoCurrency(title: 'COMP', tag: 'ETH', fullName: 'Compound', raw: 67, name: 'comp', iconPath: 'assets/images/comp_icon.png', decimals: 18); name: 'kmd',
static const cro = CryptoCurrency(title: 'CRO', tag: 'ETH', fullName: 'Crypto.com Cronos', raw: 68, name: 'cro', iconPath: 'assets/images/cro_icon.png', decimals: 8); iconPath: 'assets/images/kmd_icon.png',
static const ens = CryptoCurrency(title: 'ENS', tag: 'ETH', fullName: 'Ethereum Name Service', raw: 69, name: 'ens', iconPath: 'assets/images/ens_icon.png', decimals: 18); decimals: 8);
static const ftm = CryptoCurrency(title: 'FTM', tag: 'ETH', fullName: 'Fantom', raw: 70, name: 'ftm', iconPath: 'assets/images/ftm_icon.png', decimals: 18); static const mana = CryptoCurrency(
static const frax = CryptoCurrency(title: 'FRAX', tag: 'ETH', fullName: 'Frax', raw: 71, name: 'frax', iconPath: 'assets/images/frax_icon.png', decimals: 18); title: 'MANA',
static const gusd = CryptoCurrency(title: 'GUSD', tag: 'ETH', fullName: 'Gemini USD', raw: 72, name: 'gusd', iconPath: 'assets/images/gusd_icon.png', decimals: 2); tag: 'ETH',
static const gtc = CryptoCurrency(title: 'GTC', tag: 'ETH', fullName: 'Gitcoin', raw: 73, name: 'gtc', iconPath: 'assets/images/gtc_icon.png', decimals: 18); fullName: 'Decentraland',
static const grt = CryptoCurrency(title: 'GRT', tag: 'ETH', fullName: 'The Graph', raw: 74, name: 'grt', iconPath: 'assets/images/grt_icon.png', decimals: 18); raw: 49,
static const ldo = CryptoCurrency(title: 'LDO', tag: 'ETH', fullName: 'Lido DAO', raw: 75, name: 'ldo', iconPath: 'assets/images/ldo_icon.png', decimals: 18); name: 'mana',
static const nexo = CryptoCurrency(title: 'NEXO', tag: 'ETH', fullName: 'Nexo', raw: 76, name: 'nexo', iconPath: 'assets/images/nexo_icon.png', decimals: 18); iconPath: 'assets/images/mana_icon.png',
static const cake = CryptoCurrency(title: 'CAKE', tag: 'BSC', fullName: 'PancakeSwap', raw: 77, name: 'cake', iconPath: 'assets/images/cake_icon.png', decimals: 18); decimals: 18);
static const pepe = CryptoCurrency(title: 'PEPE', tag: 'ETH', fullName: 'Pepe', raw: 78, name: 'pepe', iconPath: 'assets/images/pepe_icon.png', decimals: 18); static const maticpoly = CryptoCurrency(
static const storj = CryptoCurrency(title: 'STORJ', tag: 'ETH', fullName: 'Storj', raw: 79, name: 'storj', iconPath: 'assets/images/storj_icon.png', decimals: 8); title: 'POL',
static const tusd = CryptoCurrency(title: 'TUSD', tag: 'ETH', fullName: 'TrueUSD', raw: 80, name: 'tusd', iconPath: 'assets/images/tusd_icon.png', decimals: 18); tag: 'POL',
static const wbtc = CryptoCurrency(title: 'WBTC', tag: 'ETH', fullName: 'Wrapped Bitcoin', raw: 81, name: 'wbtc', iconPath: 'assets/new-ui/crypto_full_icons/wbtc.svg', decimals: 8); fullName: 'Polygon',
static const weth = CryptoCurrency(title: 'WETH', tag: 'ETH', fullName: 'Wrapped Ethereum', raw: 82, name: 'weth', iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg', decimals: 18); raw: 50,
static const zrx = CryptoCurrency(title: 'ZRX', tag: 'ETH', fullName: '0x Protocol', raw: 83, name: 'zrx', iconPath: 'assets/images/zrx_icon.png', decimals: 18); name: 'maticpoly',
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18); iconPath: 'assets/new-ui/crypto_full_icons/polygon.svg',
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg', decimals: 18); decimals: 18,
static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29,flatIconPath: "assets/new-ui/balance_card_icons/nano.svg"); flatIconPath: "assets/new-ui/balance_card_icons/polygon.svg",
static const usdtPoly = CryptoCurrency(title: 'USDT', tag: 'POL', fullName: 'Tether (PoS)', raw: 87, name: 'usdtpoly', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); chainIconPath: "assets/new-ui/chain_badges/polygon.svg");
static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POL', fullName: 'USDC (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg', decimals: 6); static const matic = CryptoCurrency(
static const kaspa = CryptoCurrency(title: 'KAS', fullName: 'Kaspa', raw: 89, name: 'kas', iconPath: 'assets/images/kaspa_icon.png', decimals: 8); title: 'MATIC',
static const digibyte = CryptoCurrency(title: 'DGB', fullName: 'DigiByte', raw: 90, name: 'dgb', iconPath: 'assets/images/digibyte.png', decimals: 8); tag: 'ETH',
static const usdtSol = CryptoCurrency(title: 'USDT', tag: 'SOL', fullName: 'Tether', raw: 91, name: 'usdtsol', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); fullName: 'Polygon',
static const usdcTrc20 = CryptoCurrency(title: 'USDC', tag: 'TRX', fullName: 'USDC Coin', raw: 92, name: 'usdctrc20', iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); raw: 51,
static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8); name: 'matic',
static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 94, name: 'wow', iconPath: 'assets/images/crypto/wownero.svg', decimals: 11); iconPath: 'assets/new-ui/crypto_full_icons/polygon.svg',
static const ton = CryptoCurrency(title: 'TON', fullName: 'Toncoin', raw: 95, name: 'ton', iconPath: 'assets/new-ui/crypto_full_icons/ton.svg', decimals: 8); decimals: 18,
static const zano = CryptoCurrency(title: 'ZANO', tag: 'ZANO', fullName: 'Zano', raw: 96, name: 'zano', iconPath: 'assets/new-ui/crypto_full_icons/zano.svg', decimals: 12, flatIconPath: "assets/new-ui/balance_card_icons/zano.svg", chainIconPath: "assets/new-ui/chain_badges/zano.svg"); flatIconPath: "assets/new-ui/balance_card_icons/polygon.svg");
static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18); static const mkr = CryptoCurrency(
static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Decentralized Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png',decimals: 18, groups: const {CurrencyGroups.stablecoin}); title: 'MKR',
static const usdtbsc = CryptoCurrency(title: 'USDT', tag: 'BSC', fullName: 'USDT Binance coin', raw: 99, name: 'usdtbsc', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 18, groups: const {CurrencyGroups.stablecoin}); tag: 'ETH',
static const ndeps = CryptoCurrency(title: 'NDEPS', tag: 'ETH', fullName: 'Native Decentralized Euro Protocol Share', raw: 100, name: 'ndeps', iconPath: 'assets/images/ndeps_icon.png', decimals: 18); fullName: 'Maker',
static const deps = CryptoCurrency(title: 'DEPS', tag: 'ETH', fullName: 'Decentralized Euro Protocol Share', raw: 101, name: 'deps', iconPath: 'assets/images/deps_icon.png', decimals: 18); raw: 52,
static const kbtc = CryptoCurrency(title: 'KBTC', tag: 'ETH', fullName: 'Kraken Wrapped Bitcoin', raw: 102, name: 'kbtc', iconPath: 'assets/images/kbtc_icon.png', decimals: 8); name: 'mkr',
static const cbbtc = CryptoCurrency(title: 'CBBTC', tag: 'ETH', fullName: 'Coinbase Wrapped BTC', raw: 103, name: 'cbbtc', iconPath: 'assets/images/cbbtc_icon.png', decimals: 8); iconPath: 'assets/images/mkr_icon.png',
static const baseEth = CryptoCurrency(title: 'ETH', tag: 'BASE', fullName: 'Ethereum', raw: 104, name: 'baseth', iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/base.svg", chainIconPath: "assets/new-ui/chain_badges/base.svg"); decimals: 18);
static const usde = CryptoCurrency(title: 'USDE', tag: 'BASE', fullName: 'Ethena USDE', raw: 105, name: 'usde', iconPath: 'assets/new-ui/crypto_full_icons/usde.svg', decimals: 18); static const near = CryptoCurrency(
static const arbEth = CryptoCurrency(title: 'ETH', tag: 'ARB', fullName: 'Ethereum', raw: 106, name: 'arbeth', iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg', decimals: 18, flatIconPath: "assets/new-ui/balance_card_icons/arbitrum.svg", chainIconPath: "assets/new-ui/chain_badges/arbitrum.svg"); title: 'NEAR',
static const zec = CryptoCurrency(title: 'ZEC', fullName: 'Zcash', raw: 107, name: 'zec', iconPath: 'assets/new-ui/crypto_full_icons/zcash.svg', decimals: 8,flatIconPath: "assets/new-ui/balance_card_icons/zcash.svg"); fullName: 'NEAR Protocol',
static const usdcArb = CryptoCurrency(title: 'USDC', tag: 'ARB', fullName: 'USDC Coin', raw: 108, name: 'usdcarb', iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); raw: 53,
static const usdtArb = CryptoCurrency(title: 'USDT', tag: 'ARB', fullName: 'USDT Tether', raw: 109, name: 'usdtarb', iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg', decimals: 6, groups: const {CurrencyGroups.stablecoin}); name: 'near',
static const ltcmweb = CryptoCurrency(title: 'LTC', fullName: 'Litecoin MWeb', raw: 110, name: 'ltcmweb', iconPath: 'assets/new-ui/crypto_full_icons/litecoin.svg', decimals: 8); iconPath: 'assets/images/near_icon.png',
decimals: 24);
static const oxt = CryptoCurrency(
title: 'OXT',
tag: 'ETH',
fullName: 'Orchid',
raw: 54,
name: 'oxt',
iconPath: 'assets/images/oxt_icon.png',
decimals: 18);
static const paxg = CryptoCurrency(
title: 'PAXG',
tag: 'ETH',
fullName: 'Pax Gold',
raw: 55,
name: 'paxg',
iconPath: 'assets/new-ui/crypto_full_icons/paxg.svg',
decimals: 18);
static const pivx = CryptoCurrency(
title: 'PIVX', raw: 56, name: 'pivx', iconPath: 'assets/images/pivx_icon.png', decimals: 8);
static const rune = CryptoCurrency(
title: 'RUNE',
fullName: 'Thorchain',
raw: 57,
name: 'rune',
iconPath: 'assets/images/rune_icon.png',
decimals: 18);
static const rvn = CryptoCurrency(
title: 'RVN',
fullName: 'Ravencoin',
raw: 58,
name: 'rvn',
iconPath: 'assets/images/rvn_icon.png',
decimals: 8);
static const scrt = CryptoCurrency(
title: 'SCRT',
fullName: 'Secret Network',
raw: 59,
name: 'scrt',
iconPath: 'assets/images/scrt_icon.png',
decimals: 6);
static const uni = CryptoCurrency(
title: 'UNI',
tag: 'ETH',
fullName: 'Uniswap',
raw: 60,
name: 'uni',
iconPath: 'assets/images/uni_icon.png',
decimals: 18);
static const stx = CryptoCurrency(
title: 'STX',
fullName: 'Stacks',
raw: 61,
name: 'stx',
iconPath: 'assets/images/stx_icon.png',
decimals: 8);
static const btcln = CryptoCurrency(
title: 'BTC',
tag: 'LN',
fullName: 'Bitcoin Lightning Network',
raw: 62,
name: 'btcln',
iconPath: 'assets/new-ui/crypto_full_icons/lightning.svg',
chainIconPath: "assets/new-ui/chain_badges/lightning.svg",
decimals: 8);
static const shib = CryptoCurrency(
title: 'SHIB',
tag: 'ETH',
fullName: 'Shiba Inu',
raw: 63,
name: 'shib',
iconPath: 'assets/images/shib_icon.png',
decimals: 18);
static const aave = CryptoCurrency(
title: 'AAVE',
tag: 'ETH',
fullName: 'Aave',
raw: 64,
name: 'aave',
iconPath: 'assets/images/aave_icon.png',
decimals: 18);
static const arb = CryptoCurrency(
title: 'ARB',
fullName: 'Arbitrum',
raw: 65,
name: 'arb',
iconPath: 'assets/new-ui/crypto_full_icons/arbitrum.svg',
decimals: 18,
flatIconPath: "assets/new-ui/balance_card_icons/arbitrum.svg",
chainIconPath: "assets/new-ui/chain_badges/arbitrum.svg");
static const bat = CryptoCurrency(
title: 'BAT',
tag: 'ETH',
fullName: 'Basic Attention Token',
raw: 66,
name: 'bat',
iconPath: 'assets/images/bat_icon.png',
decimals: 18);
static const comp = CryptoCurrency(
title: 'COMP',
tag: 'ETH',
fullName: 'Compound',
raw: 67,
name: 'comp',
iconPath: 'assets/images/comp_icon.png',
decimals: 18);
static const cro = CryptoCurrency(
title: 'CRO',
tag: 'ETH',
fullName: 'Crypto.com Cronos',
raw: 68,
name: 'cro',
iconPath: 'assets/images/cro_icon.png',
decimals: 8);
static const ens = CryptoCurrency(
title: 'ENS',
tag: 'ETH',
fullName: 'Ethereum Name Service',
raw: 69,
name: 'ens',
iconPath: 'assets/images/ens_icon.png',
decimals: 18);
static const ftm = CryptoCurrency(
title: 'FTM',
tag: 'ETH',
fullName: 'Fantom',
raw: 70,
name: 'ftm',
iconPath: 'assets/images/ftm_icon.png',
decimals: 18);
static const frax = CryptoCurrency(
title: 'FRAX',
tag: 'ETH',
fullName: 'Frax',
raw: 71,
name: 'frax',
iconPath: 'assets/images/frax_icon.png',
decimals: 18);
static const gusd = CryptoCurrency(
title: 'GUSD',
tag: 'ETH',
fullName: 'Gemini USD',
raw: 72,
name: 'gusd',
iconPath: 'assets/images/gusd_icon.png',
decimals: 2);
static const gtc = CryptoCurrency(
title: 'GTC',
tag: 'ETH',
fullName: 'Gitcoin',
raw: 73,
name: 'gtc',
iconPath: 'assets/images/gtc_icon.png',
decimals: 18);
static const grt = CryptoCurrency(
title: 'GRT',
tag: 'ETH',
fullName: 'The Graph',
raw: 74,
name: 'grt',
iconPath: 'assets/images/grt_icon.png',
decimals: 18);
static const ldo = CryptoCurrency(
title: 'LDO',
tag: 'ETH',
fullName: 'Lido DAO',
raw: 75,
name: 'ldo',
iconPath: 'assets/images/ldo_icon.png',
decimals: 18);
static const nexo = CryptoCurrency(
title: 'NEXO',
tag: 'ETH',
fullName: 'Nexo',
raw: 76,
name: 'nexo',
iconPath: 'assets/images/nexo_icon.png',
decimals: 18);
static const cake = CryptoCurrency(
title: 'CAKE',
tag: 'BSC',
fullName: 'PancakeSwap',
raw: 77,
name: 'cake',
iconPath: 'assets/images/cake_icon.png',
decimals: 18);
static const pepe = CryptoCurrency(
title: 'PEPE',
tag: 'ETH',
fullName: 'Pepe',
raw: 78,
name: 'pepe',
iconPath: 'assets/images/pepe_icon.png',
decimals: 18);
static const storj = CryptoCurrency(
title: 'STORJ',
tag: 'ETH',
fullName: 'Storj',
raw: 79,
name: 'storj',
iconPath: 'assets/images/storj_icon.png',
decimals: 8);
static const tusd = CryptoCurrency(
title: 'TUSD',
tag: 'ETH',
fullName: 'TrueUSD',
raw: 80,
name: 'tusd',
iconPath: 'assets/images/tusd_icon.png',
decimals: 18);
static const wbtc = CryptoCurrency(
title: 'WBTC',
tag: 'ETH',
fullName: 'Wrapped Bitcoin',
raw: 81,
name: 'wbtc',
iconPath: 'assets/new-ui/crypto_full_icons/wbtc.svg',
decimals: 8);
static const weth = CryptoCurrency(
title: 'WETH',
tag: 'ETH',
fullName: 'Wrapped Ethereum',
raw: 82,
name: 'weth',
iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg',
decimals: 18);
static const zrx = CryptoCurrency(
title: 'ZRX',
tag: 'ETH',
fullName: '0x Protocol',
raw: 83,
name: 'zrx',
iconPath: 'assets/images/zrx_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/new-ui/crypto_full_icons/ethereum.svg',
decimals: 18);
static const banano = CryptoCurrency(
title: 'BAN',
fullName: 'Banano',
raw: 86,
name: 'banano',
iconPath: 'assets/images/nano_icon.png',
decimals: 29,
flatIconPath: "assets/new-ui/balance_card_icons/nano.svg");
static const usdtPoly = CryptoCurrency(
title: 'USDT',
tag: 'POL',
fullName: 'Tether (PoS)',
raw: 87,
name: 'usdtpoly',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const usdcEPoly = CryptoCurrency(
title: 'USDC.E',
tag: 'POL',
fullName: 'USDC (PoS)',
raw: 88,
name: 'usdcepoly',
iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg',
decimals: 6);
static const kaspa = CryptoCurrency(
title: 'KAS',
fullName: 'Kaspa',
raw: 89,
name: 'kas',
iconPath: 'assets/images/kaspa_icon.png',
decimals: 8);
static const digibyte = CryptoCurrency(
title: 'DGB',
fullName: 'DigiByte',
raw: 90,
name: 'dgb',
iconPath: 'assets/images/digibyte.png',
decimals: 8);
static const usdtSol = CryptoCurrency(
title: 'USDT',
tag: 'SOL',
fullName: 'Tether',
raw: 91,
name: 'usdtsol',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const usdcTrc20 = CryptoCurrency(
title: 'USDC',
tag: 'TRX',
fullName: 'USDC Coin',
raw: 92,
name: 'usdctrc20',
iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const tbtc = CryptoCurrency(
title: 'tBTC',
fullName: 'Testnet Bitcoin',
raw: 93,
name: 'tbtc',
iconPath: 'assets/images/tbtc.png',
decimals: 8);
static const wow = CryptoCurrency(
title: 'WOW',
fullName: 'Wownero',
raw: 94,
name: 'wow',
iconPath: 'assets/images/crypto/wownero.svg',
decimals: 11);
static const ton = CryptoCurrency(
title: 'TON',
fullName: 'Toncoin',
raw: 95,
name: 'ton',
iconPath: 'assets/new-ui/crypto_full_icons/ton.svg',
decimals: 8);
static const zano = CryptoCurrency(
title: 'ZANO',
tag: 'ZANO',
fullName: 'Zano',
raw: 96,
name: 'zano',
iconPath: 'assets/new-ui/crypto_full_icons/zano.svg',
decimals: 12,
flatIconPath: "assets/new-ui/balance_card_icons/zano.svg",
chainIconPath: "assets/new-ui/chain_badges/zano.svg");
static const flip = CryptoCurrency(
title: 'FLIP',
tag: 'ETH',
fullName: 'Chainflip',
raw: 97,
name: 'flip',
iconPath: 'assets/images/flip_icon.png',
decimals: 18);
static const deuro = CryptoCurrency(
title: 'DEURO',
tag: 'ETH',
fullName: 'Decentralized Euro',
raw: 98,
name: 'deuro',
iconPath: 'assets/images/deuro_icon.png',
decimals: 18,
groups: const {CurrencyGroups.stablecoin});
static const usdtbsc = CryptoCurrency(
title: 'USDT',
tag: 'BSC',
fullName: 'USDT Binance coin',
raw: 99,
name: 'usdtbsc',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 18,
groups: const {CurrencyGroups.stablecoin});
static const ndeps = CryptoCurrency(
title: 'NDEPS',
tag: 'ETH',
fullName: 'Native Decentralized Euro Protocol Share',
raw: 100,
name: 'ndeps',
iconPath: 'assets/images/ndeps_icon.png',
decimals: 18);
static const deps = CryptoCurrency(
title: 'DEPS',
tag: 'ETH',
fullName: 'Decentralized Euro Protocol Share',
raw: 101,
name: 'deps',
iconPath: 'assets/images/deps_icon.png',
decimals: 18);
static const kbtc = CryptoCurrency(
title: 'KBTC',
tag: 'ETH',
fullName: 'Kraken Wrapped Bitcoin',
raw: 102,
name: 'kbtc',
iconPath: 'assets/images/kbtc_icon.png',
decimals: 8);
static const cbbtc = CryptoCurrency(
title: 'CBBTC',
tag: 'ETH',
fullName: 'Coinbase Wrapped BTC',
raw: 103,
name: 'cbbtc',
iconPath: 'assets/images/cbbtc_icon.png',
decimals: 8);
static const baseEth = CryptoCurrency(
title: 'ETH',
tag: 'BASE',
fullName: 'Ethereum',
raw: 104,
name: 'baseth',
iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg',
decimals: 18,
flatIconPath: "assets/new-ui/balance_card_icons/base.svg",
chainIconPath: "assets/new-ui/chain_badges/base.svg");
static const usde = CryptoCurrency(
title: 'USDE',
tag: 'BASE',
fullName: 'Ethena USDE',
raw: 105,
name: 'usde',
iconPath: 'assets/new-ui/crypto_full_icons/usde.svg',
decimals: 18);
static const arbEth = CryptoCurrency(
title: 'ETH',
tag: 'ARB',
fullName: 'Ethereum',
raw: 106,
name: 'arbeth',
iconPath: 'assets/new-ui/crypto_full_icons/ethereum.svg',
decimals: 18,
flatIconPath: "assets/new-ui/balance_card_icons/arbitrum.svg",
chainIconPath: "assets/new-ui/chain_badges/arbitrum.svg");
static const zec = CryptoCurrency(
title: 'ZEC',
fullName: 'Zcash',
raw: 107,
name: 'zec',
iconPath: 'assets/new-ui/crypto_full_icons/zcash.svg',
decimals: 8,
flatIconPath: "assets/new-ui/balance_card_icons/zcash.svg");
static const usdcArb = CryptoCurrency(
title: 'USDC',
tag: 'ARB',
fullName: 'USDC Coin',
raw: 108,
name: 'usdcarb',
iconPath: 'assets/new-ui/crypto_full_icons/usdc.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const usdtArb = CryptoCurrency(
title: 'USDT',
tag: 'ARB',
fullName: 'USDT Tether',
raw: 109,
name: 'usdtarb',
iconPath: 'assets/new-ui/crypto_full_icons/usdt.svg',
decimals: 6,
groups: const {CurrencyGroups.stablecoin});
static const ltcmweb = CryptoCurrency(
title: 'LTC',
fullName: 'Litecoin MWeb',
raw: 110,
name: 'ltcmweb',
iconPath: 'assets/new-ui/crypto_full_icons/litecoin.svg',
decimals: 8);
static final Map<int, CryptoCurrency> _rawCurrencyMap = static final Map<int, CryptoCurrency> _rawCurrencyMap = [
[...all, ...havenCurrencies, ...zcashCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) { ...all,
...havenCurrencies,
...zcashCurrencies
].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
acc.addAll({item.raw: item}); acc.addAll({item.raw: item});
return acc; return acc;
}); });
static final Map<String, CryptoCurrency> _nameCurrencyMap = static final Map<String, CryptoCurrency> _nameCurrencyMap = [
[...all, ...havenCurrencies, ...zcashCurrencies].fold<Map<String, CryptoCurrency>>(<String, CryptoCurrency>{}, (acc, item) { ...all,
...havenCurrencies,
...zcashCurrencies
].fold<Map<String, CryptoCurrency>>(<String, CryptoCurrency>{}, (acc, item) {
acc.addAll({item.name: item}); acc.addAll({item.name: item});
return acc; return acc;
}); });
static final Map<String, CryptoCurrency> _fullNameCurrencyMap = static final Map<String, CryptoCurrency> _fullNameCurrencyMap = [
[...all, ...havenCurrencies, ...zcashCurrencies].fold<Map<String, CryptoCurrency>>(<String, CryptoCurrency>{}, (acc, item) { ...all,
if(item.fullName != null){ ...havenCurrencies,
...zcashCurrencies
].fold<Map<String, CryptoCurrency>>(<String, CryptoCurrency>{}, (acc, item) {
if (item.fullName != null) {
acc.addAll({item.fullName!.toLowerCase(): item}); acc.addAll({item.fullName!.toLowerCase(): item});
} }
return acc; return acc;
@@ -334,10 +1037,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
return _rawCurrencyMap[raw]; return _rawCurrencyMap[raw];
} }
// TODO: refactor this // TODO: refactor this
static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) { static CryptoCurrency fromString(String name, {CryptoCurrency? walletCurrency}) {
final schemeMatch = _schemeCurrencyMap[name.toLowerCase()]; final schemeMatch = _schemeCurrencyMap[name.toLowerCase()];
if (schemeMatch != null) return schemeMatch; if (schemeMatch != null) return schemeMatch;
@@ -378,7 +1079,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
}) { }) {
if (raw == null || raw.isEmpty) return null; if (raw == null || raw.isEmpty) return null;
if(tag?.toLowerCase() == "lightning") tag = "LN"; if (tag?.toLowerCase() == "lightning") tag = "LN";
if (tag != null && tag.isNotEmpty) { if (tag != null && tag.isNotEmpty) {
final match = CryptoCurrency.all.firstWhereOrNull( final match = CryptoCurrency.all.firstWhereOrNull(
@@ -390,12 +1091,10 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
return null; return null;
} }
// Try for native currency with same title and tag // Try for native currency with same title and tag
if (tag == null || tag.isEmpty) { if (tag == null || tag.isEmpty) {
final match = CryptoCurrency.all.firstWhereOrNull( final match = CryptoCurrency.all.firstWhereOrNull(
(e) => (e) => e.title.toUpperCase() == raw.toUpperCase() && (e.tag == raw.toUpperCase()),
e.title.toUpperCase() == raw.toUpperCase() && (e.tag == raw.toUpperCase()),
); );
if (match != null) return match; if (match != null) return match;
+2 -1
View File
@@ -90,7 +90,8 @@ int? getChainIdByCryptoCurrency(CryptoCurrency currency) {
} }
} }
CryptoCurrency getCryptoCurrencyForWalletListItem(WalletType type, {bool isTestnet = false, int? chainId}) { CryptoCurrency getCryptoCurrencyForWalletListItem(WalletType type,
{bool isTestnet = false, int? chainId}) {
if (type == WalletType.arbitrum) { if (type == WalletType.arbitrum) {
return CryptoCurrency.arb; return CryptoCurrency.arb;
} }
+7 -8
View File
@@ -3,10 +3,8 @@ import 'dart:typed_data';
import 'package:cw_core/utils/file.dart' as file; import 'package:cw_core/utils/file.dart' as file;
import 'package:cake_backup/backup.dart' as cwb; import 'package:cake_backup/backup.dart' as cwb;
EncryptionFileUtils encryptionFileUtilsFor(bool direct) EncryptionFileUtils encryptionFileUtilsFor(bool direct) =>
=> direct direct ? XChaCha20EncryptionFileUtils() : Salsa20EncryhptionFileUtils();
? XChaCha20EncryptionFileUtils()
: Salsa20EncryhptionFileUtils();
abstract class EncryptionFileUtils { abstract class EncryptionFileUtils {
Future<void> write({required String path, required String password, required String data}); Future<void> write({required String path, required String password, required String data});
@@ -16,13 +14,14 @@ abstract class EncryptionFileUtils {
class Salsa20EncryhptionFileUtils extends EncryptionFileUtils { class Salsa20EncryhptionFileUtils extends EncryptionFileUtils {
// Requires legacy complex key + iv as password // Requires legacy complex key + iv as password
@override @override
Future<void> write({required String path, required String password, required String data}) async Future<void> write(
=> await file.write(path: path, password: password, data: data); {required String path, required String password, required String data}) async =>
await file.write(path: path, password: password, data: data);
// Requires legacy complex key + iv as password // Requires legacy complex key + iv as password
@override @override
Future<String> read({required String path, required String password}) async Future<String> read({required String path, required String password}) async =>
=> await file.read(path: path, password: password); await file.read(path: path, password: password);
} }
class XChaCha20EncryptionFileUtils extends EncryptionFileUtils { class XChaCha20EncryptionFileUtils extends EncryptionFileUtils {
+2 -4
View File
@@ -1,4 +1,4 @@
// GENERATED CODE - DO NOT MODIFY BY HAND // GENERATED CODE - DO NOT MODIFY BY HAND
part of 'erc20_token.dart'; part of 'erc20_token.dart';
@@ -55,7 +55,5 @@ class Erc20TokenAdapter extends TypeAdapter<Erc20Token> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is Erc20TokenAdapter && other is Erc20TokenAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+2 -2
View File
@@ -1,7 +1,7 @@
String formatAmount(String amount) { String formatAmount(String amount) {
if ((!amount.contains('.'))&&(!amount.contains(','))) { if ((!amount.contains('.')) && (!amount.contains(','))) {
return amount + '.00'; return amount + '.00';
} else if ((amount.endsWith('.'))||(amount.endsWith(','))) { } else if ((amount.endsWith('.')) || (amount.endsWith(','))) {
return amount + '00'; return amount + '00';
} }
return amount; return amount;
+3 -6
View File
@@ -1,7 +1,6 @@
import 'package:cw_core/parse_fixed.dart'; import 'package:cw_core/parse_fixed.dart';
String formatFixed(BigInt value, int? decimals, String formatFixed(BigInt value, int? decimals, {int? fractionalDigits, bool trimZeros = true}) {
{int? fractionalDigits, bool trimZeros = true}) {
decimals ??= 0; decimals ??= 0;
fractionalDigits ??= decimals; fractionalDigits ??= decimals;
@@ -10,10 +9,8 @@ String formatFixed(BigInt value, int? decimals,
var negative = value.isNegative; var negative = value.isNegative;
if (negative) value = value * BigInt.from(-1); if (negative) value = value * BigInt.from(-1);
var fraction = value var fraction =
.modPow(BigInt.one, BigInt.parse(multiplier)) value.modPow(BigInt.one, BigInt.parse(multiplier)).toString().padLeft(decimals, "0");
.toString()
.padLeft(decimals, "0");
if (fractionalDigits < 0) fractionalDigits = 0; if (fractionalDigits < 0) fractionalDigits = 0;
if (fractionalDigits > decimals) fractionalDigits = decimals; if (fractionalDigits > decimals) fractionalDigits = decimals;
+2 -1
View File
@@ -6,7 +6,8 @@ import 'dart:convert';
// FIXME: Hardcoded values; Works only for monero // FIXME: Hardcoded values; Works only for monero
int getMoneroHeigthByDate({required DateTime date}) => MoneroHeight.getBlockHeightByTime(date..subtract(Duration(days: 1))); int getMoneroHeigthByDate({required DateTime date}) =>
MoneroHeight.getBlockHeightByTime(date..subtract(Duration(days: 1)));
const havenDates = { const havenDates = {
"2023-05": 1352995, "2023-05": 1352995,
-1
View File
@@ -1,4 +1,3 @@
class MoneroHeight { class MoneroHeight {
// for i in $(seq 1 364); do echo "_Checkpoint(_t($(curl https://xmrchain.net/block/${i}0000 | grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' | xargs | sed 's/ /\n/g' | head -5 | tail -1 | tr '()' ' ' | sed 's/ /\n/g' | head -2 | xargs)), ${i}0000),"; done > points.txt // for i in $(seq 1 364); do echo "_Checkpoint(_t($(curl https://xmrchain.net/block/${i}0000 | grep -E '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}' | xargs | sed 's/ /\n/g' | head -5 | tail -1 | tr '()' ' ' | sed 's/ /\n/g' | head -2 | xargs)), ${i}0000),"; done > points.txt
static final List<_Checkpoint> _points = [ static final List<_Checkpoint> _points = [
+2 -1
View File
@@ -16,7 +16,8 @@ List<String> extractKeys(String key) {
return [_key, iv]; return [_key, iv];
} }
Future<String> encode({required encrypt.Key key, required encrypt.IV iv, required String data}) async { Future<String> encode(
{required encrypt.Key key, required encrypt.IV iv, required String data}) async {
final encrypter = encrypt.Encrypter(encrypt.Salsa20(key)); final encrypter = encrypt.Encrypter(encrypt.Salsa20(key));
final encrypted = encrypter.encrypt(data, iv: iv); final encrypted = encrypter.encrypt(data, iv: iv);
+5 -8
View File
@@ -12,12 +12,11 @@ bool isBolt11ZeroInvoice(String invoice) {
try { try {
final request = Bech32Codec().decode(invoice.replaceFirst("lightning:", ""), invoice.length); final request = Bech32Codec().decode(invoice.replaceFirst("lightning:", ""), invoice.length);
final prefix =
final prefix = _BOLT_PREFIXES _BOLT_PREFIXES.firstWhere((prefix) => request.hrp.startsWith(prefix), orElse: () => "");
.firstWhere((prefix) => request.hrp.startsWith(prefix), orElse: () => "");
return request.hrp.length == prefix.length; return request.hrp.length == prefix.length;
} catch(e) { } catch (e) {
return false; return false;
} }
} }
@@ -86,8 +85,7 @@ class LNURL {
final maxSendable = body["maxSendable"] as int?; final maxSendable = body["maxSendable"] as int?;
// if minSendable and maxSendable are the same we assume a specific payment request // if minSendable and maxSendable are the same we assume a specific payment request
if (msat != maxSendable) if (msat != maxSendable) return null;
return null;
if (msat == null || msat % 1000 != 0) return null; if (msat == null || msat % 1000 != 0) return null;
return Money.fromInt(msat ~/ 1000, CryptoCurrency.btcln); return Money.fromInt(msat ~/ 1000, CryptoCurrency.btcln);
@@ -136,8 +134,7 @@ class LNURL {
String _findLnUrl(String input) { String _findLnUrl(String input) {
final res = RegExp(r',*?((lnurl)([0-9]+[a-z0-9]+))').allMatches(input.toLowerCase()); final res = RegExp(r',*?((lnurl)([0-9]+[a-z0-9]+))').allMatches(input.toLowerCase());
if (res.length != 1) if (res.length != 1) throw ArgumentError('Not a valid lnurl string');
throw ArgumentError('Not a valid lnurl string');
return res.first.group(0)!; return res.first.group(0)!;
} }
+1 -3
View File
@@ -50,7 +50,5 @@ class MwebUtxoAdapter extends TypeAdapter<MwebUtxo> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is MwebUtxoAdapter && other is MwebUtxoAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+1 -3
View File
@@ -44,7 +44,5 @@ class NanoAccountAdapter extends TypeAdapter<NanoAccount> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is NanoAccountAdapter && other is NanoAccountAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+19 -23
View File
@@ -25,11 +25,9 @@ Future<void> validateBuiltinNodes() async {
for (final listNode in builtinFromList) { for (final listNode in builtinFromList) {
// preserve proxy settings from user // preserve proxy settings from user
try { try {
final matchedDbNode = builtinFromDb.firstWhere( final matchedDbNode = builtinFromDb.firstWhere((dbNode) => dbNode.uri == listNode.uri);
(dbNode) => dbNode.uri == listNode.uri
);
listNode.socksProxyAddress = matchedDbNode.socksProxyAddress; listNode.socksProxyAddress = matchedDbNode.socksProxyAddress;
} catch(e) {} } catch (e) {}
} }
final dbSet = builtinFromDb.toSet(); final dbSet = builtinFromDb.toSet();
@@ -121,7 +119,7 @@ class Node {
"label": label, "label": label,
'password': password, 'password': password,
"isPow": isPow ? 1 : 0, "isPow": isPow ? 1 : 0,
'useSSL': (useSSL??false) ? 1 : 0, 'useSSL': (useSSL ?? false) ? 1 : 0,
"typeRaw": typeRaw, "typeRaw": typeRaw,
'trusted': trusted ? 1 : 0, 'trusted': trusted ? 1 : 0,
'socksProxyAddress': socksProxyAddress, 'socksProxyAddress': socksProxyAddress,
@@ -165,7 +163,6 @@ class Node {
} }
Future<int> save() async { Future<int> save() async {
final json = toMap(); final json = toMap();
if (json[selfIdColumn] == 0) { if (json[selfIdColumn] == 0) {
json[selfIdColumn] = null; json[selfIdColumn] = null;
@@ -174,9 +171,9 @@ class Node {
return id; return id;
} }
static Future<List<Node>> selectList(String where, List<dynamic> whereArgs,
static Future<List<Node>> selectList(String where, List<dynamic> whereArgs, {String? orderBy}) async { {String? orderBy}) async {
if(orderBy == null) { if (orderBy == null) {
orderBy = selfIdColumn; orderBy = selfIdColumn;
} }
final list = await db!.query( final list = await db!.query(
@@ -189,7 +186,7 @@ class Node {
} }
static Future<Node?> select(String where, List<dynamic> whereArgs, {String? orderBy}) async { static Future<Node?> select(String where, List<dynamic> whereArgs, {String? orderBy}) async {
if(orderBy == null) { if (orderBy == null) {
orderBy = selfIdColumn; orderBy = selfIdColumn;
} }
final list = await db!.query( final list = await db!.query(
@@ -201,7 +198,6 @@ class Node {
return list.isEmpty ? null : Node.fromMap(list.first); return list.isEmpty ? null : Node.fromMap(list.first);
} }
static Future<List<Node>> getAll() async { static Future<List<Node>> getAll() async {
return selectList("isPow = ?", [0]); return selectList("isPow = ?", [0]);
} }
@@ -219,11 +215,15 @@ class Node {
} }
static Future<Node?> getDefaultForWalletType(WalletType type) async { static Future<Node?> getDefaultForWalletType(WalletType type) async {
return (await selectList("typeRaw = ? AND isPow = ? AND isDefault = ?", [serializeToInt(type), 0, 1])).firstOrNull; return (await selectList(
"typeRaw = ? AND isPow = ? AND isDefault = ?", [serializeToInt(type), 0, 1]))
.firstOrNull;
} }
static Future<Node?> getDefaultPowForWalletType(WalletType type) async { static Future<Node?> getDefaultPowForWalletType(WalletType type) async {
return (await selectList("typeRaw = ? AND isPow = ? AND isDefault = ?", [serializeToInt(type), 1, 1])).firstOrNull; return (await selectList(
"typeRaw = ? AND isPow = ? AND isDefault = ?", [serializeToInt(type), 1, 1]))
.firstOrNull;
} }
static Future<List<Node>> getAllForWalletTypePow(WalletType type) async { static Future<List<Node>> getAllForWalletTypePow(WalletType type) async {
@@ -238,7 +238,6 @@ class Node {
return select("${selfIdColumn} = ?", [id]); return select("${selfIdColumn} = ?", [id]);
} }
int id; int id;
late String uriRaw; late String uriRaw;
String? login; String? login;
@@ -262,7 +261,6 @@ class Node {
static String get tableName => "Node"; static String get tableName => "Node";
static String get selfIdColumn => "${tableName}Id"; static String get selfIdColumn => "${tableName}Id";
bool get isSSL => useSSL ?? false; bool get isSSL => useSSL ?? false;
bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty; bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
@@ -333,7 +331,6 @@ class Node {
socksProxyAddress.hashCode ^ socksProxyAddress.hashCode ^
path.hashCode; path.hashCode;
WalletType get type => deserializeFromInt(typeRaw); WalletType get type => deserializeFromInt(typeRaw);
set type(WalletType type) => typeRaw = serializeToInt(type); set type(WalletType type) => typeRaw = serializeToInt(type);
@@ -387,7 +384,6 @@ class Node {
body: jsonBody, body: jsonBody,
); );
final resBody = json.decode(response.body) as Map<String, dynamic>; final resBody = json.decode(response.body) as Map<String, dynamic>;
return resBody['result']['height'] != null; return resBody['result']['height'] != null;
@@ -407,15 +403,13 @@ class Node {
final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName}; final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName};
try { try {
final jsonBody = json.encode(body); final jsonBody = json.encode(body);
final response = await ProxyWrapper().post( final response = await ProxyWrapper().post(
clearnetUri: rpcUri, clearnetUri: rpcUri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: jsonBody, body: jsonBody,
allowMitmMoneroBypassSSLCheck: true allowMitmMoneroBypassSSLCheck: true);
);
// Check if we received a 401 Unauthorized response // Check if we received a 401 Unauthorized response
if (response.statusCode == 401) { if (response.statusCode == 401) {
final daemonRpc = DaemonRpc( final daemonRpc = DaemonRpc(
@@ -494,7 +488,6 @@ class Node {
final ProxySocket socket; final ProxySocket socket;
socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, uri.host, uri.port); socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, uri.host, uri.port);
socket.destroy(); socket.destroy();
return true; return true;
} catch (_) { } catch (_) {
@@ -531,8 +524,11 @@ class Node {
Future<bool> requestEthereumServer() async { Future<bool> requestEthereumServer() async {
try { try {
final req = await ProxyWrapper().getHttpClient() final req = await ProxyWrapper()
.getUrl(uri,) .getHttpClient()
.getUrl(
uri,
)
.timeout(Duration(seconds: 15)); .timeout(Duration(seconds: 15));
final response = await req.close(); final response = await req.close();
+8 -18
View File
@@ -19,17 +19,15 @@ import 'node.dart' as node_new;
part 'node_legacy.part.dart'; part 'node_legacy.part.dart';
Future<void> performNodeHiveMigration() async { Future<void> performNodeHiveMigration() async {
if(!CakeHive.isAdapterRegistered(Node.typeId)) { if (!CakeHive.isAdapterRegistered(Node.typeId)) {
CakeHive.registerAdapter(NodeAdapter()); CakeHive.registerAdapter(NodeAdapter());
} }
final nodeBox = await CakeHive.openBox<Node>(Node.boxName); final nodeBox = await CakeHive.openBox<Node>(Node.boxName);
final powNodeBox = await CakeHive.openBox<Node>(Node.boxName+"pow"); final powNodeBox = await CakeHive.openBox<Node>(Node.boxName + "pow");
final builtinNodes = await loadAllDefaultNodes(); final builtinNodes = await loadAllDefaultNodes();
final builtinPowNodes = await loadDefaultNanoPowNodes(); final builtinPowNodes = await loadDefaultNanoPowNodes();
await Node.migrateAllToSqlite(nodeBox, powNodeBox, builtinNodes, builtinPowNodes); await Node.migrateAllToSqlite(nodeBox, powNodeBox, builtinNodes, builtinPowNodes);
} }
Uri createUriFromElectrumAddress(String address, String path) => Uri createUriFromElectrumAddress(String address, String path) =>
@@ -62,31 +60,26 @@ class Node extends HiveObject with Keyable {
final list = nodeBox.values.toList(); final list = nodeBox.values.toList();
final powList = powNodeBox.values.toList(); final powList = powNodeBox.values.toList();
for (final node in list) { for (final node in list) {
if(defaultNodes.any((item)=>item.uri == node.uri)) { if (defaultNodes.any((item) => item.uri == node.uri)) {
// default nodes will be added by validateBuiltinNodes(), no need to migrate them. // default nodes will be added by validateBuiltinNodes(), no need to migrate them.
await node.delete(); await node.delete();
continue; continue;
} }
await node.migrateToSqlite( await node.migrateToSqlite(isPow: false, isBuiltin: false, isOfficial: false);
isPow: false,
isBuiltin: false,
isOfficial: false);
await node.delete(); await node.delete();
} }
for (final node in powList) { for (final node in powList) {
if(defaultPowNodes.any((item)=>item.uri == node.uri)) { if (defaultPowNodes.any((item) => item.uri == node.uri)) {
await node.delete(); await node.delete();
continue; continue;
} }
await node.migrateToSqlite( await node.migrateToSqlite(isPow: true, isBuiltin: false, isOfficial: false);
isPow: true,
isBuiltin: false,
isOfficial: false);
await node.delete(); await node.delete();
} }
} }
Future<void> migrateToSqlite({required bool isPow, required bool isBuiltin, required bool isOfficial}) async { Future<void> migrateToSqlite(
{required bool isPow, required bool isBuiltin, required bool isOfficial}) async {
final newNode = node_new.Node( final newNode = node_new.Node(
id: key as int, id: key as int,
login: login, login: login,
@@ -106,7 +99,6 @@ class Node extends HiveObject with Keyable {
await newNode.save(); await newNode.save();
} }
Node.fromMap(Map<String, Object?> map) Node.fromMap(Map<String, Object?> map)
: uriRaw = map['uri'] as String? ?? '', : uriRaw = map['uri'] as String? ?? '',
path = map['path'] as String? ?? '', path = map['path'] as String? ?? '',
@@ -241,6 +233,4 @@ class Node extends HiveObject with Keyable {
set type(WalletType type) => typeRaw = serializeToInt(type); set type(WalletType type) => typeRaw = serializeToInt(type);
dynamic _keyIndex; dynamic _keyIndex;
} }
+2 -5
View File
@@ -24,8 +24,7 @@ class NodeAdapter extends TypeAdapter<Node> {
trusted: fields[5] == null ? false : fields[5] as bool, trusted: fields[5] == null ? false : fields[5] as bool,
socksProxyAddress: fields[6] as String?, socksProxyAddress: fields[6] as String?,
path: fields[7] == null ? '' : fields[7] as String?, path: fields[7] == null ? '' : fields[7] as String?,
isEnabledForAutoSwitching: isEnabledForAutoSwitching: fields[11] == null ? false : fields[11] as bool,
fields[11] == null ? false : fields[11] as bool,
) )
..uriRaw = fields[0] == null ? '' : fields[0] as String ..uriRaw = fields[0] == null ? '' : fields[0] as String
..typeRaw = fields[3] == null ? 0 : fields[3] as int ..typeRaw = fields[3] == null ? 0 : fields[3] as int
@@ -72,7 +71,5 @@ class NodeAdapter extends TypeAdapter<Node> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is NodeAdapter && other is NodeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+5 -10
View File
@@ -147,7 +147,6 @@ Future<List<Node>> loadAllDefaultNodes() async {
} }
Future<void> resetToDefault() async { Future<void> resetToDefault() async {
final nodes = await loadAllDefaultNodes(); final nodes = await loadAllDefaultNodes();
final currentNodes = await Node.getAll(); final currentNodes = await Node.getAll();
@@ -160,12 +159,11 @@ Future<void> resetToDefault() async {
(item) => item.uri == node.uri && item.typeRaw == node.typeRaw, (item) => item.uri == node.uri && item.typeRaw == node.typeRaw,
); );
node.id = curr.id; node.id = curr.id;
} catch(e) {} } catch (e) {}
} }
await Node.deleteAll(); await Node.deleteAll();
for(final node in nodes) { for (final node in nodes) {
await node.save(); await node.save();
} }
} }
@@ -173,7 +171,7 @@ Future<void> resetToDefault() async {
Future<void> resetPowToDefault() async { Future<void> resetPowToDefault() async {
final nanoPowNodes = await loadDefaultNanoPowNodes(); final nanoPowNodes = await loadDefaultNanoPowNodes();
await Node.deleteAllPow(); await Node.deleteAllPow();
for(final node in nanoPowNodes) { for (final node in nanoPowNodes) {
node.save(); node.save();
} }
} }
@@ -181,12 +179,9 @@ Future<void> resetPowToDefault() async {
Future<Node> getDefaultNodeFromFiles(WalletType type, {bool isPow = false}) async { Future<Node> getDefaultNodeFromFiles(WalletType type, {bool isPow = false}) async {
final nodes = isPow ? await loadDefaultNanoPowNodes() : await loadDefaultNodes(type); final nodes = isPow ? await loadDefaultNanoPowNodes() : await loadDefaultNodes(type);
try { try {
return nodes.firstWhere((item)=>item.isDefault); return nodes.firstWhere((item) => item.isDefault);
} catch(e) { } catch (e) {
// ideally the yamls would always have a default, but this is better than nothing // ideally the yamls would always have a default, but this is better than nothing
return nodes.first; return nodes.first;
} }
} }
+2 -1
View File
@@ -52,7 +52,8 @@ BigInt parseFixed(String value, int decimals) {
var fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0"); var fraction = (comps.length == 2 ? comps[1] : "0").padRight(decimals, "0");
if (fraction.length > multiplier.length - 1) { if (fraction.length > multiplier.length - 1) {
throw FormatException("fractional component(${fraction.length}) exceeds decimals(${decimals}), underflow, parseFixed"); throw FormatException(
"fractional component(${fraction.length}) exceeds decimals(${decimals}), underflow, parseFixed");
} }
final wholeValue = BigInt.parse(whole); final wholeValue = BigInt.parse(whole);
+1 -2
View File
@@ -28,8 +28,7 @@ Future<String> pathForWalletDir({required String name, required WalletType type}
} }
Future<String> pathForWallet({required String name, required WalletType type}) async => Future<String> pathForWallet({required String name, required WalletType type}) async =>
await pathForWalletDir(name: name, type: type) await pathForWalletDir(name: name, type: type).then((path) => path + '/$name');
.then((path) => path + '/$name');
Future<String> outdatedAndroidPathForWalletDir({required String name}) async { Future<String> outdatedAndroidPathForWalletDir({required String name}) async {
final directory = await getAppDir(); final directory = await getAppDir();
-1
View File
@@ -56,7 +56,6 @@ class PayjoinSession extends HiveObject {
BigInt get amount => BigInt.parse(rawAmount ?? "0"); BigInt get amount => BigInt.parse(rawAmount ?? "0");
set amount(BigInt amount) => rawAmount = amount.toString(); set amount(BigInt amount) => rawAmount = amount.toString();
} }
enum PayjoinSessionStatus { enum PayjoinSessionStatus {
+1 -3
View File
@@ -59,7 +59,5 @@ class PayjoinSessionAdapter extends TypeAdapter<PayjoinSession> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is PayjoinSessionAdapter && other is PayjoinSessionAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
-1
View File
@@ -508,4 +508,3 @@ class LightningPaymentRequest extends PaymentURI {
@override @override
String toString() => bolt11Invoice ?? "lightning:$lnURL"; String toString() => bolt11Invoice ?? "lightning:$lnURL";
} }
+13 -9
View File
@@ -23,8 +23,7 @@ bool get isNonAmnesticTails {
bool showNotice = true; bool showNotice = true;
void setRootDirFromEnv() => void setRootDirFromEnv() => _rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
_rootDirPath = Platform.environment['CAKE_WALLET_DIR'];
void copyDirectory(Directory source, Directory destination) { void copyDirectory(Directory source, Directory destination) {
source.listSync(recursive: false).forEach((var entity) { source.listSync(recursive: false).forEach((var entity) {
@@ -41,7 +40,8 @@ void copyDirectory(Directory source, Directory destination) {
Future<void> linuxSymlinkSharedPreferences() async { Future<void> linuxSymlinkSharedPreferences() async {
if (!Platform.isLinux) return; // nuh-uh if (!Platform.isLinux) return; // nuh-uh
final dataHome = Platform.environment["XDG_DATA_HOME"] ?? p.join(Platform.environment["HOME"] ?? "", ".local", "share"); final dataHome = Platform.environment["XDG_DATA_HOME"] ??
p.join(Platform.environment["HOME"] ?? "", ".local", "share");
var cakeNames = ['com.example.cake_wallet', 'cake_wallet']; var cakeNames = ['com.example.cake_wallet', 'cake_wallet'];
for (String name in cakeNames) { for (String name in cakeNames) {
final oldPath = p.join(dataHome, name); final oldPath = p.join(dataHome, name);
@@ -54,7 +54,7 @@ Future<void> linuxSymlinkSharedPreferences() async {
printV("not creating, link exists"); printV("not creating, link exists");
} else { } else {
if (newDir.existsSync()) { if (newDir.existsSync()) {
newDir.renameSync("${newPath}_${DateTime.now().millisecondsSinceEpoch~/1000}"); newDir.renameSync("${newPath}_${DateTime.now().millisecondsSinceEpoch ~/ 1000}");
} }
copyDirectory(oldDir, newDir); copyDirectory(oldDir, newDir);
oldDir.deleteSync(recursive: true); oldDir.deleteSync(recursive: true);
@@ -94,9 +94,11 @@ Future<Directory> getAppDir() async {
// for storing things that users in general back-up // for storing things that users in general back-up
var linuxAppPath = [ var linuxAppPath = [
if (appDirPath != null) appDirPath, // old preferred if (appDirPath != null) appDirPath, // old preferred
p.join('/home', Platform.environment['USER']??"null", appName), // old fallback p.join('/home', Platform.environment['USER'] ?? "null", appName), // old fallback
if (Platform.environment['HOME'] != null) p.join(Platform.environment['HOME']!, ".$appName"), // old fallback but using HOME if (Platform.environment['HOME'] != null)
if (Platform.environment['HOME'] != null) p.join(Platform.environment['HOME']!, '.config', appName), // old fallback but using HOME p.join(Platform.environment['HOME']!, ".$appName"), // old fallback but using HOME
if (Platform.environment['HOME'] != null)
p.join(Platform.environment['HOME']!, '.config', appName), // old fallback but using HOME
if (isNonAmnesticTails) p.join(_tailsData, ".$appName") // tails (if persistance is enabled) if (isNonAmnesticTails) p.join(_tailsData, ".$appName") // tails (if persistance is enabled)
]; ];
@@ -109,8 +111,10 @@ Future<Directory> getAppDir() async {
if (useThisOne) { if (useThisOne) {
if (showNotice) { if (showNotice) {
showNotice = false; showNotice = false;
printV("Not using $preferredPath because $notSoPreferredPath exists, falling back for backwards compatibility"); printV(
printV("Can't see your wallet? Check\n - ${linuxAppPath.join("\n - ")}\n and move directory that to $preferredPath"); "Not using $preferredPath because $notSoPreferredPath exists, falling back for backwards compatibility");
printV(
"Can't see your wallet? Check\n - ${linuxAppPath.join("\n - ")}\n and move directory that to $preferredPath");
printV("Or use CAKE_WALLET_DIR=/path/to/app/ ${Platform.executable}"); printV("Or use CAKE_WALLET_DIR=/path/to/app/ ${Platform.executable}");
} }
preferredPath = notSoPreferredPath; preferredPath = notSoPreferredPath;
+2 -1
View File
@@ -14,7 +14,8 @@ Future<Uint8List> secRandom(int count) async {
final rng = Random.secure(); final rng = Random.secure();
return Uint8List.fromList(List<int>.generate(count, (_) => rng.nextInt(byteSize))); return Uint8List.fromList(List<int>.generate(count, (_) => rng.nextInt(byteSize)));
} }
return await utils.invokeMethod<Uint8List>('sec_random', {'count': count}) ?? Uint8List.fromList([]); return await utils.invokeMethod<Uint8List>('sec_random', {'count': count}) ??
Uint8List.fromList([]);
} on PlatformException catch (_) { } on PlatformException catch (_) {
return Uint8List.fromList([]); return Uint8List.fromList([]);
} }
+2 -4
View File
@@ -4,14 +4,12 @@ import 'package:on_chain/solana/solana.dart';
class SolanaRPCHTTPService implements SolanaJSONRPCService { class SolanaRPCHTTPService implements SolanaJSONRPCService {
SolanaRPCHTTPService( SolanaRPCHTTPService(
{required this.url, {required this.url, this.defaultRequestTimeout = const Duration(seconds: 30)});
this.defaultRequestTimeout = const Duration(seconds: 30)});
@override @override
final String url; final String url;
final Duration defaultRequestTimeout; final Duration defaultRequestTimeout;
Future<Map<String, dynamic>> call(SolanaRequestDetails params, Future<Map<String, dynamic>> call(SolanaRequestDetails params, [Duration? timeout]) async {
[Duration? timeout]) async {
final response = await ProxyWrapper().post( final response = await ProxyWrapper().post(
clearnetUri: Uri.parse(url), clearnetUri: Uri.parse(url),
body: params.toRequestBody(), body: params.toRequestBody(),
+1 -3
View File
@@ -58,7 +58,5 @@ class SPLTokenAdapter extends TypeAdapter<SPLToken> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is SPLTokenAdapter && other is SPLTokenAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+4 -2
View File
@@ -7,7 +7,8 @@ TransactionDirection parseTransactionDirectionFromInt(int raw) {
case 1: case 1:
return TransactionDirection.outgoing; return TransactionDirection.outgoing;
default: default:
throw Exception('Unexpected token: raw for TransactionDirection parseTransactionDirectionFromInt'); throw Exception(
'Unexpected token: raw for TransactionDirection parseTransactionDirectionFromInt');
} }
} }
@@ -18,6 +19,7 @@ TransactionDirection parseTransactionDirectionFromNumber(String raw) {
case "1": case "1":
return TransactionDirection.outgoing; return TransactionDirection.outgoing;
default: default:
throw Exception('Unexpected token: raw for TransactionDirection parseTransactionDirectionFromNumber'); throw Exception(
'Unexpected token: raw for TransactionDirection parseTransactionDirectionFromNumber');
} }
} }
+1 -2
View File
@@ -2,8 +2,7 @@ import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/transaction_info.dart';
abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> { abstract class TransactionHistoryBase<TransactionType extends TransactionInfo> {
TransactionHistoryBase() TransactionHistoryBase() : transactions = ObservableMap<String, TransactionType>();
: transactions = ObservableMap<String, TransactionType>();
@observable @observable
ObservableMap<String, TransactionType> transactions; ObservableMap<String, TransactionType> transactions;
+3 -3
View File
@@ -1,9 +1,9 @@
import 'package:cw_core/enumerable_item.dart'; import 'package:cw_core/enumerable_item.dart';
abstract class TransactionPriority extends EnumerableItem<int> abstract class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
with Serializable<int> {
final String? description; final String? description;
final String? hint; final String? hint;
const TransactionPriority({required String title, required int raw, this.description, this.hint}) : super(title: title, raw: raw); const TransactionPriority({required String title, required int raw, this.description, this.hint})
: super(title: title, raw: raw);
} }
+1 -3
View File
@@ -55,7 +55,5 @@ class TronTokenAdapter extends TypeAdapter<TronToken> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is TronTokenAdapter && other is TronTokenAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+1 -3
View File
@@ -6,9 +6,7 @@ Future<void> write({required String path, required String password, required Str
writeData(path: path, password: password, data: data); writeData(path: path, password: password, data: data);
Future<void> writeData( Future<void> writeData(
{required String path, {required String path, required String password, required String data}) async {
required String password,
required String data}) async {
final keys = extractKeys(password); final keys = extractKeys(password);
final key = encrypt.Key.fromBase64(keys.first); final key = encrypt.Key.fromBase64(keys.first);
final iv = encrypt.IV.fromBase64(keys.last); final iv = encrypt.IV.fromBase64(keys.last);
@@ -50,14 +50,16 @@ class MemoryProxyLogger implements ProxyLogger {
required String? error, required String? error,
}) { }) {
final trace = StackTrace.current; final trace = StackTrace.current;
logs.add(MemoryProxyLoggerEntry( logs.add(
MemoryProxyLoggerEntry(
method: method, method: method,
trace: trace, trace: trace,
uri: uri, uri: uri,
body: body, body: body,
network: network, network: network,
response: response, response: response,
error: error,), error: error,
),
); );
} }
} }
+6 -3
View File
@@ -16,7 +16,8 @@ class ProxyAddress {
} }
abstract class ProxySocket { abstract class ProxySocket {
static Future<ProxySocket> connect(bool sslEnabled, ProxyAddress address, {Duration? connectionTimeout}) async { static Future<ProxySocket> connect(bool sslEnabled, ProxyAddress address,
{Duration? connectionTimeout}) async {
if (CakeTor.instance!.started) { if (CakeTor.instance!.started) {
var socksSocket = await SOCKSSocket.create( var socksSocket = await SOCKSSocket.create(
proxyHost: InternetAddress.loopbackIPv4.address, proxyHost: InternetAddress.loopbackIPv4.address,
@@ -28,7 +29,8 @@ abstract class ProxySocket {
return ProxySocketSocks(socksSocket); return ProxySocketSocks(socksSocket);
} }
if (sslEnabled == false) { if (sslEnabled == false) {
return ProxySocketInsecure(await Socket.connect(address.host, address.port, timeout: connectionTimeout)); return ProxySocketInsecure(
await Socket.connect(address.host, address.port, timeout: connectionTimeout));
} else { } else {
return ProxySocketSecure(await SecureSocket.connect( return ProxySocketSecure(await SecureSocket.connect(
address.host, address.host,
@@ -43,6 +45,7 @@ abstract class ProxySocket {
void destroy(); void destroy();
void write(String data); void write(String data);
bool get isClosed; bool get isClosed;
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function (Object error)? onError, Function ()? onDone, bool cancelOnError = true}); StreamSubscription<List<int>> listen(Function(Uint8List event) onData,
{Function(Object error)? onError, Function()? onDone, bool cancelOnError = true});
ProxyAddress get address; ProxyAddress get address;
} }
+4 -3
View File
@@ -1,4 +1,3 @@
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_socket/abstract.dart'; import 'package:cw_core/utils/proxy_socket/abstract.dart';
import 'dart:async'; import 'dart:async';
@@ -12,7 +11,8 @@ class ProxySocketInsecure implements ProxySocket {
bool isClosed = false; bool isClosed = false;
ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort); ProxyAddress get address =>
ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort);
@override @override
Future<void> close() async { Future<void> close() async {
@@ -53,7 +53,8 @@ class ProxySocketInsecure implements ProxySocket {
} }
@override @override
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) { StreamSubscription<List<int>> listen(Function(Uint8List event) onData,
{Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
return socket.listen( return socket.listen(
(data) { (data) {
onData(Uint8List.fromList(data)); onData(Uint8List.fromList(data));
+4 -2
View File
@@ -12,7 +12,8 @@ class ProxySocketSecure implements ProxySocket {
ProxySocketSecure(this.socket); ProxySocketSecure(this.socket);
ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort); ProxyAddress get address =>
ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort);
@override @override
Future<void> close() async { Future<void> close() async {
@@ -59,7 +60,8 @@ class ProxySocketSecure implements ProxySocket {
} }
@override @override
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) { StreamSubscription<List<int>> listen(Function(Uint8List event) onData,
{Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
return socket.listen( return socket.listen(
(data) { (data) {
onData(Uint8List.fromList(data)); onData(Uint8List.fromList(data));
+2 -2
View File
@@ -43,7 +43,8 @@ class ProxySocketSocks implements ProxySocket {
} }
@override @override
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) { StreamSubscription<List<int>> listen(Function(Uint8List event) onData,
{Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
return socket.listen( return socket.listen(
(data) { (data) {
onData(Uint8List.fromList(data)); onData(Uint8List.fromList(data));
@@ -54,4 +55,3 @@ class ProxySocketSocks implements ProxySocket {
); );
} }
} }
+8 -12
View File
@@ -18,7 +18,8 @@ class ProxyWrapper {
} }
ProxyWrapper._internal(); ProxyWrapper._internal();
Future<ProxySocket> getSocksSocket(bool sslEnabled, String host, int port, {Duration? connectionTimeout}) async { Future<ProxySocket> getSocksSocket(bool sslEnabled, String host, int port,
{Duration? connectionTimeout}) async {
logger?.log( logger?.log(
uri: Uri( uri: Uri(
scheme: sslEnabled ? "https" : "http", scheme: sslEnabled ? "https" : "http",
@@ -29,9 +30,9 @@ class ProxyWrapper {
body: Uint8List(0), body: Uint8List(0),
response: null, response: null,
network: requestNetwork(), network: requestNetwork(),
error: null error: null);
); return ProxySocket.connect(sslEnabled, ProxyAddress(host: host, port: port),
return ProxySocket.connect(sslEnabled, ProxyAddress(host: host, port: port), connectionTimeout: connectionTimeout); connectionTimeout: connectionTimeout);
} }
RequestNetwork requestNetwork() { RequestNetwork requestNetwork() {
@@ -56,7 +57,8 @@ class ProxyWrapper {
int getPort() => CakeTor.instance!.port; int getPort() => CakeTor.instance!.port;
@Deprecated('Use ProxyWrapper().get/post/put methods instead, and provide proper clearnet and onion uri.') @Deprecated(
'Use ProxyWrapper().get/post/put methods instead, and provide proper clearnet and onion uri.')
HttpClient getHttpClient({int? portOverride, bool internal = false}) { HttpClient getHttpClient({int? portOverride, bool internal = false}) {
if (!internal) { if (!internal) {
logger?.log( logger?.log(
@@ -65,8 +67,7 @@ class ProxyWrapper {
body: Uint8List(0), body: Uint8List(0),
response: null, response: null,
network: requestNetwork(), network: requestNetwork(),
error: null error: null);
);
} }
if (CakeTor.instance!.started) { if (CakeTor.instance!.started) {
// Assign connection factory. // Assign connection factory.
@@ -84,8 +85,6 @@ class ProxyWrapper {
} }
} }
Future<Response> _make({ Future<Response> _make({
required RequestMethod method, required RequestMethod method,
required ioc.IOClient client, required ioc.IOClient client,
@@ -217,7 +216,6 @@ class ProxyWrapper {
throw Exception("Unable to connect to server"); throw Exception("Unable to connect to server");
} }
Future<Response> post({ Future<Response> post({
Map<String, String>? headers, Map<String, String>? headers,
int? portOverride, int? portOverride,
@@ -235,7 +233,6 @@ class ProxyWrapper {
ioc.IOClient clearnetClient = ioc.IOClient(cleatnetHttpClient); ioc.IOClient clearnetClient = ioc.IOClient(cleatnetHttpClient);
bool torEnabled = CakeTor.instance!.started; bool torEnabled = CakeTor.instance!.started;
if (torEnabled) { if (torEnabled) {
@@ -439,7 +436,6 @@ class ProxyWrapper {
} }
} }
class CakeTor { class CakeTor {
static CakeTorInstance? instance; static CakeTorInstance? instance;
} }
+3 -3
View File
@@ -1,4 +1,3 @@
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
@@ -31,8 +30,9 @@ String convertZpubToXpub(String zpub) {
return zpub; return zpub;
} }
final xpubVersionBytes = isZpub ? final xpubVersionBytes = isZpub
[0x04, 0x88, 0xb2, 0x1e] : // xpub mainnet ? [0x04, 0x88, 0xb2, 0x1e]
: // xpub mainnet
[0x04, 0x35, 0x87, 0xcf]; // tpub testnet [0x04, 0x35, 0x87, 0xcf]; // tpub testnet
final newExtendedKey = Uint8List.fromList([ final newExtendedKey = Uint8List.fromList([
+9 -11
View File
@@ -349,11 +349,11 @@ class WalletInfo {
this.addressPageType, this.addressPageType,
this.receiveInfoboxDismissed, this.receiveInfoboxDismissed,
this.showCombinedBalance, this.showCombinedBalance,
this.favoriteTokenAddress this.favoriteTokenAddress)
) : _yatLastUsedAddressController = StreamController<String>.broadcast(); : _yatLastUsedAddressController = StreamController<String>.broadcast();
factory WalletInfo.external({ factory WalletInfo.external(
required String id, {required String id,
required String name, required String name,
required WalletType type, required WalletType type,
required bool isRecovery, required bool isRecovery,
@@ -373,8 +373,7 @@ class WalletInfo {
int? sortOrder, int? sortOrder,
bool? receiveInfoboxDismissed, bool? receiveInfoboxDismissed,
bool? showCombinedBalance, bool? showCombinedBalance,
String? favoriteTokenAddress String? favoriteTokenAddress}) {
}) {
return WalletInfo( return WalletInfo(
0, 0,
id, id,
@@ -398,8 +397,7 @@ class WalletInfo {
null, null,
receiveInfoboxDismissed ?? false, receiveInfoboxDismissed ?? false,
showCombinedBalance ?? true, showCombinedBalance ?? true,
favoriteTokenAddress favoriteTokenAddress);
);
} }
static String get tableName => 'walletInfo'; static String get tableName => 'walletInfo';
@@ -577,7 +575,8 @@ class WalletInfo {
"address": address, "address": address,
"yatEid": yatEid, "yatEid": yatEid,
"yatLastUsedAddressRaw": yatLastUsedAddressRaw, "yatLastUsedAddressRaw": yatLastUsedAddressRaw,
"showIntroCakePayCard": showIntroCakePayCard == true ? 1 : 0, // SQL regression: null -> false "showIntroCakePayCard":
showIntroCakePayCard == true ? 1 : 0, // SQL regression: null -> false
"walletInfoDerivationInfoId": derivationInfoId, "walletInfoDerivationInfoId": derivationInfoId,
"hardwareWalletType": hardwareWalletType?.index, "hardwareWalletType": hardwareWalletType?.index,
"parentAddress": parentAddress, "parentAddress": parentAddress,
@@ -616,8 +615,7 @@ class WalletInfo {
json['addressPageType'] as String? ?? null, json['addressPageType'] as String? ?? null,
json['receiveInfoboxDismissed'] != 0, json['receiveInfoboxDismissed'] != 0,
json["showCombinedBalance"] != 0, json["showCombinedBalance"] != 0,
json["favoriteTokenAddress"] as String? ?? null json["favoriteTokenAddress"] as String? ?? null);
);
} }
Future<int> save() async { Future<int> save() async {
+5 -11
View File
@@ -53,9 +53,7 @@ class DerivationInfoAdapter extends TypeAdapter<DerivationInfo> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is DerivationInfoAdapter && other is DerivationInfoAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
class WalletInfoAdapter extends TypeAdapter<WalletInfo> { class WalletInfoAdapter extends TypeAdapter<WalletInfo> {
@@ -88,8 +86,8 @@ class WalletInfoAdapter extends TypeAdapter<WalletInfo> {
fields[26] == null ? false : fields[26] as bool, fields[26] == null ? false : fields[26] as bool,
) )
..addresses = (fields[10] as Map?)?.cast<String, String>() ..addresses = (fields[10] as Map?)?.cast<String, String>()
..addressInfos = (fields[14] as Map?)?.map((dynamic k, dynamic v) => ..addressInfos = (fields[14] as Map?)
MapEntry(k as int, (v as List).cast<AddressInfo>())) ?.map((dynamic k, dynamic v) => MapEntry(k as int, (v as List).cast<AddressInfo>()))
..usedAddresses = (fields[15] as List?)?.cast<String>() ..usedAddresses = (fields[15] as List?)?.cast<String>()
..derivationType = fields[16] as newWi.DerivationType? ..derivationType = fields[16] as newWi.DerivationType?
..derivationPath = fields[17] as String? ..derivationPath = fields[17] as String?
@@ -163,9 +161,7 @@ class WalletInfoAdapter extends TypeAdapter<WalletInfo> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is WalletInfoAdapter && other is WalletInfoAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
class DerivationTypeAdapter extends TypeAdapter<newWi.DerivationType> { class DerivationTypeAdapter extends TypeAdapter<newWi.DerivationType> {
@@ -217,9 +213,7 @@ class DerivationTypeAdapter extends TypeAdapter<newWi.DerivationType> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is DerivationTypeAdapter && other is DerivationTypeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
class HardwareWalletTypeAdapter extends TypeAdapter<newWi.HardwareWalletType> { class HardwareWalletTypeAdapter extends TypeAdapter<newWi.HardwareWalletType> {
+8 -1
View File
@@ -101,7 +101,14 @@ class WalletKeysData {
final String? scanSecret; final String? scanSecret;
final String? spendPubkey; final String? spendPubkey;
WalletKeysData({this.privateKey, this.mnemonic, this.altMnemonic, this.passphrase, this.xPub, this.scanSecret, this.spendPubkey}); WalletKeysData(
{this.privateKey,
this.mnemonic,
this.altMnemonic,
this.passphrase,
this.xPub,
this.scanSecret,
this.spendPubkey});
String toJSON() => jsonEncode({ String toJSON() => jsonEncode({
"privateKey": privateKey, "privateKey": privateKey,
+5 -4
View File
@@ -334,17 +334,18 @@ WalletType? _cryptoCurrencyToWalletType(CryptoCurrency type) {
WalletType? cryptoCurrencyOrTokenToWalletType(CryptoCurrency type) { WalletType? cryptoCurrencyOrTokenToWalletType(CryptoCurrency type) {
try { try {
if(type.tag == CryptoCurrency.bnb.tag) { if (type.tag == CryptoCurrency.bnb.tag) {
return _cryptoCurrencyToWalletType(CryptoCurrency.bnb); return _cryptoCurrencyToWalletType(CryptoCurrency.bnb);
} }
if(type.tag != null && ![CryptoCurrency.btcln.tag, CryptoCurrency.bnb.tag].contains(type.tag)) { if (type.tag != null &&
![CryptoCurrency.btcln.tag, CryptoCurrency.bnb.tag].contains(type.tag)) {
return _cryptoCurrencyToWalletType(CryptoCurrency.fromString(type.tag!)); return _cryptoCurrencyToWalletType(CryptoCurrency.fromString(type.tag!));
} else { } else {
return _cryptoCurrencyToWalletType(type); return _cryptoCurrencyToWalletType(type);
} }
} catch (e) { } catch (e) {
printV(e); printV(e);
return null; return null;
} }
} }
+1 -3
View File
@@ -130,7 +130,5 @@ class WalletTypeAdapter extends TypeAdapter<WalletType> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is WalletTypeAdapter && other is WalletTypeAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
+1 -3
View File
@@ -70,7 +70,5 @@ class ZanoAssetAdapter extends TypeAdapter<ZanoAsset> {
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is ZanoAssetAdapter && other is ZanoAssetAdapter && runtimeType == other.runtimeType && typeId == other.typeId;
runtimeType == other.runtimeType &&
typeId == other.typeId;
} }
@@ -3,27 +3,27 @@ import 'package:flutter_test/flutter_test.dart';
void main() { void main() {
group('smartAmountSanitizer', () { group('smartAmountSanitizer', () {
test('sanitize decimal dot', (){ test('sanitize decimal dot', () {
final amount = "1,000.00".sanitized(); final amount = "1,000.00".sanitized();
expect(amount, "1000.00"); expect(amount, "1000.00");
}); });
test('sanitize decimal comma', (){ test('sanitize decimal comma', () {
final amount = "1.000,00".sanitized(); final amount = "1.000,00".sanitized();
expect(amount, "1000.00"); expect(amount, "1000.00");
}); });
test('general case', (){ test('general case', () {
final amount = "1000.00".sanitized(); final amount = "1000.00".sanitized();
expect(amount, "1000.00"); expect(amount, "1000.00");
}); });
test('no decimals', (){ test('no decimals', () {
final amount = "1,000".sanitized(); final amount = "1,000".sanitized();
expect(amount, "1.000"); expect(amount, "1.000");
}); });
test('no decimals', (){ test('no decimals', () {
final amount = "1.000".sanitized(); final amount = "1.000".sanitized();
expect(amount, "1.000"); expect(amount, "1.000");
}); });
+2 -2
View File
@@ -316,7 +316,7 @@ void main() {
}); });
}); });
group("toStringWithPrecision", (){ group("toStringWithPrecision", () {
test("with fractionalDigits and padded with zeros", () { test("with fractionalDigits and padded with zeros", () {
final money = Money.parse("1", CryptoCurrency.btc); final money = Money.parse("1", CryptoCurrency.btc);
expect(money.amount, equals(BigInt.parse("100000000"))); expect(money.amount, equals(BigInt.parse("100000000")));
@@ -332,7 +332,7 @@ void main() {
}); });
}); });
group("toStringWithSymbol", (){ group("toStringWithSymbol", () {
test("with fractionalDigits and padded with zeros", () { test("with fractionalDigits and padded with zeros", () {
final money = Money.parse("1", CryptoCurrency.btc); final money = Money.parse("1", CryptoCurrency.btc);
expect(money.amount, equals(BigInt.parse("100000000"))); expect(money.amount, equals(BigInt.parse("100000000")));
+4 -8
View File
@@ -14,14 +14,12 @@ void main() {
group('formatFixed, different fractional digits and trimming zeros', () { group('formatFixed, different fractional digits and trimming zeros', () {
test( test(
'should format 1000001 into 1', 'should format 1000001 into 1',
() => expect( () => expect(formatFixed(BigInt.parse("1000001"), 6, fractionalDigits: 5), '1'),
formatFixed(BigInt.parse("1000001"), 6, fractionalDigits: 5), '1'),
); );
test( test(
'should format 1000000 into 1, fractionalDigits > decimals', 'should format 1000000 into 1, fractionalDigits > decimals',
() => expect( () => expect(formatFixed(BigInt.parse("1000000"), 6, fractionalDigits: 12), '1'),
formatFixed(BigInt.parse("1000000"), 6, fractionalDigits: 12), '1'),
); );
test( test(
@@ -45,8 +43,7 @@ void main() {
test( test(
'should format 1000001 into 1.00000', 'should format 1000001 into 1.00000',
() => expect( () => expect(
formatFixed(BigInt.parse("1000001"), 6, formatFixed(BigInt.parse("1000001"), 6, fractionalDigits: 5, trimZeros: false),
fractionalDigits: 5, trimZeros: false),
'1.00000', '1.00000',
), ),
); );
@@ -54,8 +51,7 @@ void main() {
test( test(
'should format 1000000 into 1.000000', 'should format 1000000 into 1.000000',
() => expect( () => expect(
formatFixed(BigInt.parse("1000000"), 6, formatFixed(BigInt.parse("1000000"), 6, fractionalDigits: 12, trimZeros: false),
fractionalDigits: 12, trimZeros: false),
'1.000000', '1.000000',
), ),
); );
+18 -9
View File
@@ -39,49 +39,58 @@ void main() {
group("isBolt11ZeroInvoice", () { group("isBolt11ZeroInvoice", () {
test("should identify a zero amount invoice", () { test("should identify a zero amount invoice", () {
final invoice = "lnbc1p5564y8pp5vm48jp3w82yjssrtdhvrjacwwzp59hqjm2lq6fud5thfznyuswgqsp54mykkptx9mlqhpe93f9pcgt9p5ml5xhclyn7qsltqy9ldf25j3qqxqyz5vqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjqfvmpdwfesckajzfcf7ff2vqaz9jdgpcsa9xc0fq8ny749dy8y5geapyqr6zgqqqq8hxk2qqae4jsqyugqcqzpgdqq9qyyssqycdyx8r09wgm8vny3n8pf2e0crcdq9mgx3ncxvzsrkljxyrcuwx8zjtje7du40nzdy7x2he67v9asp6ac6ed75r33yyt9pzeepygcmsptc4ve4"; final invoice =
"lnbc1p5564y8pp5vm48jp3w82yjssrtdhvrjacwwzp59hqjm2lq6fud5thfznyuswgqsp54mykkptx9mlqhpe93f9pcgt9p5ml5xhclyn7qsltqy9ldf25j3qqxqyz5vqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjqfvmpdwfesckajzfcf7ff2vqaz9jdgpcsa9xc0fq8ny749dy8y5geapyqr6zgqqqq8hxk2qqae4jsqyugqcqzpgdqq9qyyssqycdyx8r09wgm8vny3n8pf2e0crcdq9mgx3ncxvzsrkljxyrcuwx8zjtje7du40nzdy7x2he67v9asp6ac6ed75r33yyt9pzeepygcmsptc4ve4";
expect(isBolt11ZeroInvoice(invoice), true); expect(isBolt11ZeroInvoice(invoice), true);
}); });
test("should identify a non zero amount invoice", () { test("should identify a non zero amount invoice", () {
final invoice = "lnbc1u1p5564nxpp5mrklx2pjaggkcfs9r5tfk84wszzy9gypcnrt9yjq7n6uf95s70xqsp59fph78twjra598n2mll2arw5enluy7a4uf4y9a94ddd30hm98njsxq9z0rgqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qcqzpgdql2djkuepqw3hjqsmpddjjq4mpd3kx2aq9qyyssq3nf60ey9fgkf0elu2y8j96rx5pm4gx2a976h8yadx83dyg0ltnysrxhep8e2p3yvz4kf597qk3rttgdy72wwqq0mwr8hdht3pqpchyqq0aa9v0"; final invoice =
"lnbc1u1p5564nxpp5mrklx2pjaggkcfs9r5tfk84wszzy9gypcnrt9yjq7n6uf95s70xqsp59fph78twjra598n2mll2arw5enluy7a4uf4y9a94ddd30hm98njsxq9z0rgqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qcqzpgdql2djkuepqw3hjqsmpddjjq4mpd3kx2aq9qyyssq3nf60ey9fgkf0elu2y8j96rx5pm4gx2a976h8yadx83dyg0ltnysrxhep8e2p3yvz4kf597qk3rttgdy72wwqq0mwr8hdht3pqpchyqq0aa9v0";
expect(isBolt11ZeroInvoice(invoice), false); expect(isBolt11ZeroInvoice(invoice), false);
}); });
test("should identify a zero amount prefixed invoice", () { test("should identify a zero amount prefixed invoice", () {
final invoice = "lightning:lnbc1p5564y8pp5vm48jp3w82yjssrtdhvrjacwwzp59hqjm2lq6fud5thfznyuswgqsp54mykkptx9mlqhpe93f9pcgt9p5ml5xhclyn7qsltqy9ldf25j3qqxqyz5vqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjqfvmpdwfesckajzfcf7ff2vqaz9jdgpcsa9xc0fq8ny749dy8y5geapyqr6zgqqqq8hxk2qqae4jsqyugqcqzpgdqq9qyyssqycdyx8r09wgm8vny3n8pf2e0crcdq9mgx3ncxvzsrkljxyrcuwx8zjtje7du40nzdy7x2he67v9asp6ac6ed75r33yyt9pzeepygcmsptc4ve4"; final invoice =
"lightning:lnbc1p5564y8pp5vm48jp3w82yjssrtdhvrjacwwzp59hqjm2lq6fud5thfznyuswgqsp54mykkptx9mlqhpe93f9pcgt9p5ml5xhclyn7qsltqy9ldf25j3qqxqyz5vqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjqfvmpdwfesckajzfcf7ff2vqaz9jdgpcsa9xc0fq8ny749dy8y5geapyqr6zgqqqq8hxk2qqae4jsqyugqcqzpgdqq9qyyssqycdyx8r09wgm8vny3n8pf2e0crcdq9mgx3ncxvzsrkljxyrcuwx8zjtje7du40nzdy7x2he67v9asp6ac6ed75r33yyt9pzeepygcmsptc4ve4";
expect(isBolt11ZeroInvoice(invoice), true); expect(isBolt11ZeroInvoice(invoice), true);
}); });
test("should identify a non zero amount prefixed invoice", () { test("should identify a non zero amount prefixed invoice", () {
final invoice = "lightning:lnbc1u1p5564nxpp5mrklx2pjaggkcfs9r5tfk84wszzy9gypcnrt9yjq7n6uf95s70xqsp59fph78twjra598n2mll2arw5enluy7a4uf4y9a94ddd30hm98njsxq9z0rgqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qcqzpgdql2djkuepqw3hjqsmpddjjq4mpd3kx2aq9qyyssq3nf60ey9fgkf0elu2y8j96rx5pm4gx2a976h8yadx83dyg0ltnysrxhep8e2p3yvz4kf597qk3rttgdy72wwqq0mwr8hdht3pqpchyqq0aa9v0"; final invoice =
"lightning:lnbc1u1p5564nxpp5mrklx2pjaggkcfs9r5tfk84wszzy9gypcnrt9yjq7n6uf95s70xqsp59fph78twjra598n2mll2arw5enluy7a4uf4y9a94ddd30hm98njsxq9z0rgqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qcqzpgdql2djkuepqw3hjqsmpddjjq4mpd3kx2aq9qyyssq3nf60ey9fgkf0elu2y8j96rx5pm4gx2a976h8yadx83dyg0ltnysrxhep8e2p3yvz4kf597qk3rttgdy72wwqq0mwr8hdht3pqpchyqq0aa9v0";
expect(isBolt11ZeroInvoice(invoice), false); expect(isBolt11ZeroInvoice(invoice), false);
}); });
}); });
group("getBolt11Amount", () { group("getBolt11Amount", () {
test("should identify a zero amount invoice", () { test("should identify a zero amount invoice", () {
final invoice = "lnbc1p5564y8pp5vm48jp3w82yjssrtdhvrjacwwzp59hqjm2lq6fud5thfznyuswgqsp54mykkptx9mlqhpe93f9pcgt9p5ml5xhclyn7qsltqy9ldf25j3qqxqyz5vqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjqfvmpdwfesckajzfcf7ff2vqaz9jdgpcsa9xc0fq8ny749dy8y5geapyqr6zgqqqq8hxk2qqae4jsqyugqcqzpgdqq9qyyssqycdyx8r09wgm8vny3n8pf2e0crcdq9mgx3ncxvzsrkljxyrcuwx8zjtje7du40nzdy7x2he67v9asp6ac6ed75r33yyt9pzeepygcmsptc4ve4"; final invoice =
"lnbc1p5564y8pp5vm48jp3w82yjssrtdhvrjacwwzp59hqjm2lq6fud5thfznyuswgqsp54mykkptx9mlqhpe93f9pcgt9p5ml5xhclyn7qsltqy9ldf25j3qqxqyz5vqnp4qvyndeaqzman7h898jxm98dzkm0mlrsx36s93smrur7h0azyyuxc5rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqrt49lmtcqqqqqqqqqqq86qq9qrzjqfvmpdwfesckajzfcf7ff2vqaz9jdgpcsa9xc0fq8ny749dy8y5geapyqr6zgqqqq8hxk2qqae4jsqyugqcqzpgdqq9qyyssqycdyx8r09wgm8vny3n8pf2e0crcdq9mgx3ncxvzsrkljxyrcuwx8zjtje7du40nzdy7x2he67v9asp6ac6ed75r33yyt9pzeepygcmsptc4ve4";
expect(getBolt11Amount(invoice), null); expect(getBolt11Amount(invoice), null);
}); });
test("should get the amount 1 BTC encoded as bitcoin", () { test("should get the amount 1 BTC encoded as bitcoin", () {
final invoice = "lnbc11p5exaxspp5u6e6lx90rw2vqr2e5axt8ur3v98qnmqfsmh8r0l0mcm7ry70vyvsdqqcqzzsxqrrsssp5eqydmrufk39dwhuxzajwx4xyffn0mlcu3qa8vjwry6qev5gsepkq9qxpqysgqt0zldve9uxt3txjt8wp0gev52lquljgugy26nneue85pjwk5yak4hs2d8533tus07pq5ka6zrnd0ruaeepwres8p7ws5mx63xlwff5sqlxcy8a"; final invoice =
"lnbc11p5exaxspp5u6e6lx90rw2vqr2e5axt8ur3v98qnmqfsmh8r0l0mcm7ry70vyvsdqqcqzzsxqrrsssp5eqydmrufk39dwhuxzajwx4xyffn0mlcu3qa8vjwry6qev5gsepkq9qxpqysgqt0zldve9uxt3txjt8wp0gev52lquljgugy26nneue85pjwk5yak4hs2d8533tus07pq5ka6zrnd0ruaeepwres8p7ws5mx63xlwff5sqlxcy8a";
expect(getBolt11Amount(invoice), Money.fromInt(100000000, CryptoCurrency.btcln)); expect(getBolt11Amount(invoice), Money.fromInt(100000000, CryptoCurrency.btcln));
}); });
test("should get the amount 0,1 BTC encoded as millibitcoin", () { test("should get the amount 0,1 BTC encoded as millibitcoin", () {
final invoice = "lnbc100m1p5exagmpp5n4c5tml3h8h7k4gthc9papkyeymceqqvcldkng4nvxwzj7nu9jnsdqqcqzzsxqrrsssp58kgzrh7y3pevantduc4yg33aa6r79ed6xgmhr0dy40zc8pxrz5ms9qxpqysgqcq27km3v3wcz6pntmsfnz259zy6tff0uwjz9kamdrvmxmdv09gp44mh0ygn7gweqf4zdev4x8e67p5kcvahethchdkkjexhtk7emuqcpasz0lp"; final invoice =
"lnbc100m1p5exagmpp5n4c5tml3h8h7k4gthc9papkyeymceqqvcldkng4nvxwzj7nu9jnsdqqcqzzsxqrrsssp58kgzrh7y3pevantduc4yg33aa6r79ed6xgmhr0dy40zc8pxrz5ms9qxpqysgqcq27km3v3wcz6pntmsfnz259zy6tff0uwjz9kamdrvmxmdv09gp44mh0ygn7gweqf4zdev4x8e67p5kcvahethchdkkjexhtk7emuqcpasz0lp";
expect(getBolt11Amount(invoice), Money.fromInt(10000000, CryptoCurrency.btcln)); expect(getBolt11Amount(invoice), Money.fromInt(10000000, CryptoCurrency.btcln));
}); });
test("should get the amount 1000 SATS encoded as microbitcoin", () { test("should get the amount 1000 SATS encoded as microbitcoin", () {
final invoice = "lnbc10u1p5exfgvpp5n3s9dsw9ddax5c3h8437ya7y4g582uyufyna626yr9vqdfjrhwzqdqqcqzzsxqrrsssp5mmkyp5h35fpaxm4063f3kc7d4nmgd4gd8fv8086wxd784m76kmpq9qxpqysgqye9r0vahpjy9l2je6vakxzk3cjnsyx76r29c4amkz4cmapq5tqt5l7rl0emkd003jjvz2d8jqrw6wc4cduvapuyeseh7a855l82wutcpeq30kg"; final invoice =
"lnbc10u1p5exfgvpp5n3s9dsw9ddax5c3h8437ya7y4g582uyufyna626yr9vqdfjrhwzqdqqcqzzsxqrrsssp5mmkyp5h35fpaxm4063f3kc7d4nmgd4gd8fv8086wxd784m76kmpq9qxpqysgqye9r0vahpjy9l2je6vakxzk3cjnsyx76r29c4amkz4cmapq5tqt5l7rl0emkd003jjvz2d8jqrw6wc4cduvapuyeseh7a855l82wutcpeq30kg";
expect(getBolt11Amount(invoice), Money.fromInt(1000, CryptoCurrency.btcln)); expect(getBolt11Amount(invoice), Money.fromInt(1000, CryptoCurrency.btcln));
}); });
test("should get the amount 1 SAT encoded as nanobitcoin", () { test("should get the amount 1 SAT encoded as nanobitcoin", () {
final invoice = "lnbc10n1p5exazppp5szh273r6nzvwydzsdlg0ws0vhxwnc6nqtqt4sjt0vu6x6l8t5csqdqqcqzzsxqrrsssp5nkup6uht7xlfqaj8lxpe5kx0ejum9p4pvv3nlnndr9ykzge3393s9qxpqysgqufh05a7qs0ezeckvmh7tjkr9ngng96nq274twg20z45ysp7afpdrttm2ky73cpjwpjqsmtzzd79w6lyvszgmkanwn8mj0jcfunrwv3qprg3z3j"; final invoice =
"lnbc10n1p5exazppp5szh273r6nzvwydzsdlg0ws0vhxwnc6nqtqt4sjt0vu6x6l8t5csqdqqcqzzsxqrrsssp5nkup6uht7xlfqaj8lxpe5kx0ejum9p4pvv3nlnndr9ykzge3393s9qxpqysgqufh05a7qs0ezeckvmh7tjkr9ngng96nq274twg20z45ysp7afpdrttm2ky73cpjwpjqsmtzzd79w6lyvszgmkanwn8mj0jcfunrwv3qprg3z3j";
expect(getBolt11Amount(invoice), Money.fromInt(1, CryptoCurrency.btcln)); expect(getBolt11Amount(invoice), Money.fromInt(1, CryptoCurrency.btcln));
}); });
}); });
@@ -51,8 +51,7 @@ class _Visitor extends SimpleAstVisitor<void> {
if (uriString.startsWith("package:http")) { if (uriString.startsWith("package:http")) {
final prefixNode = node.prefix; final prefixNode = node.prefix;
if (prefixNode != null && if (prefixNode != null && prefixNode.name == "very_insecure_http_do_not_use") {
prefixNode.name == "very_insecure_http_do_not_use") {
return; return;
} }
@@ -17,8 +17,7 @@ class ReplaceWithPrintV extends ResolvedCorrectionProducer {
); );
@override @override
CorrectionApplicability get applicability => CorrectionApplicability get applicability => CorrectionApplicability.singleLocation;
CorrectionApplicability.singleLocation;
@override @override
FixKind get fixKind => _fixKind; FixKind get fixKind => _fixKind;
-1
View File
@@ -3,4 +3,3 @@ export 'src/dogecoin_wallet_addresses.dart';
export 'src/dogecoin_wallet_creation_credentials.dart'; export 'src/dogecoin_wallet_creation_credentials.dart';
export 'src/dogecoin_wallet_service.dart'; export 'src/dogecoin_wallet_service.dart';
export 'src/dogecoin_transaction_priority.dart'; export 'src/dogecoin_transaction_priority.dart';
@@ -53,4 +53,3 @@ class DogecoinTransactionPriority extends BitcoinTransactionPriority {
return label; return label;
} }
} }
-1
View File
@@ -82,7 +82,6 @@ abstract class DogeCoinWalletBase extends ElectrumWallet with Store {
int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount, {int? size}) => int feeAmountWithFeeRate(int feeRate, int inputsCount, int outputsCount, {int? size}) =>
feeRate * (size ?? estimatedDogeCoinTransactionSize(inputsCount, outputsCount)); feeRate * (size ?? estimatedDogeCoinTransactionSize(inputsCount, outputsCount));
static Future<DogeCoinWallet> create( static Future<DogeCoinWallet> create(
{required String mnemonic, {required String mnemonic,
required String password, required String password,
@@ -8,11 +8,9 @@ import 'package:mobx/mobx.dart';
part 'dogecoin_wallet_addresses.g.dart'; part 'dogecoin_wallet_addresses.g.dart';
class DogeCoinWalletAddresses = DogeCoinWalletAddressesBase class DogeCoinWalletAddresses = DogeCoinWalletAddressesBase with _$DogeCoinWalletAddresses;
with _$DogeCoinWalletAddresses;
abstract class DogeCoinWalletAddressesBase extends ElectrumWalletAddresses abstract class DogeCoinWalletAddressesBase extends ElectrumWalletAddresses with Store {
with Store {
DogeCoinWalletAddressesBase( DogeCoinWalletAddressesBase(
WalletInfo walletInfo, { WalletInfo walletInfo, {
required super.mainHdByType, required super.mainHdByType,
@@ -36,6 +34,5 @@ abstract class DogeCoinWalletAddressesBase extends ElectrumWalletAddresses
generateP2PKHAddress(hd: hd, index: index, network: network); generateP2PKHAddress(hd: hd, index: index, network: network);
@override @override
PaymentURI getPaymentUri(String amount) => PaymentURI getPaymentUri(String amount) => DogeURI(address: address, amount: amount);
DogeURI(address: address, amount: amount);
} }
+1 -2
View File
@@ -3,6 +3,5 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:cw_dogecoin/cw_dogecoin.dart'; import 'package:cw_dogecoin/cw_dogecoin.dart';
void main() { void main() {
test('adds one to input values', () { test('adds one to input values', () {});
});
} }
-1
View File
@@ -43,4 +43,3 @@ class ArbitrumClient extends EVMChainClient {
@override @override
int get chainId => 42161; int get chainId => 42161;
} }
-1
View File
@@ -43,4 +43,3 @@ class BaseClient extends EVMChainClient {
@override @override
int get chainId => 8453; int get chainId => 8453;
} }
-1
View File
@@ -44,4 +44,3 @@ class BSCClient extends EVMChainClient {
@override @override
int get chainId => 56; int get chainId => 56;
} }
-1
View File
@@ -10,4 +10,3 @@ class EthereumClient extends EVMChainClient {
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) => Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) =>
prependTransactionType(0x02, signedTransaction); prependTransactionType(0x02, signedTransaction);
} }
+9 -6
View File
@@ -145,7 +145,9 @@ class EVMChainClient {
final jsonResponse = json.decode(response.body) as Map<String, dynamic>; final jsonResponse = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode >= 200 && response.statusCode < 300 && jsonResponse['status'] != 0 && if (response.statusCode >= 200 &&
response.statusCode < 300 &&
jsonResponse['status'] != 0 &&
jsonResponse['result'] is List) { jsonResponse['result'] is List) {
final symbol = EVMChainUtils.getFeeCurrency(chainId); final symbol = EVMChainUtils.getFeeCurrency(chainId);
@@ -520,9 +522,11 @@ class EVMChainClient {
*/ */
} }
Future<EVMChainERC20Balance> fetchERC20Balances(EthereumAddress userAddress, Erc20Token token) async { Future<EVMChainERC20Balance> fetchERC20Balances(
EthereumAddress userAddress, Erc20Token token) async {
try { try {
final erc20 = ERC20(address: EthereumAddress.fromHex(token.contractAddress), client: _client!); final erc20 =
ERC20(address: EthereumAddress.fromHex(token.contractAddress), client: _client!);
final balance = await erc20.balanceOf(userAddress); final balance = await erc20.balanceOf(userAddress);
return EVMChainERC20Balance(Money(balance, token)); return EVMChainERC20Balance(Money(balance, token));
@@ -659,9 +663,8 @@ class EVMChainClient {
final tokenData = item; final tokenData = item;
final nativeRaw = tokenData['native_token']; final nativeRaw = tokenData['native_token'];
final nativeToken = nativeRaw is bool final nativeToken =
? nativeRaw nativeRaw is bool ? nativeRaw : (nativeRaw?.toString().toLowerCase() == 'true');
: (nativeRaw?.toString().toLowerCase() == 'true');
if (nativeToken) continue; if (nativeToken) continue;
final balanceStr = tokenData['balance'] as String? ?? '0'; final balanceStr = tokenData['balance'] as String? ?? '0';

Some files were not shown because too many files have changed in this diff Show More