mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-06-28 12:29:51 +00:00
Merge 75e2c67752
into 18c2ba9366
This commit is contained in:
commit
d4efb61d92
139 changed files with 4865 additions and 56 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,6 +3,7 @@
|
||||||
*.log
|
*.log
|
||||||
*.pyc
|
*.pyc
|
||||||
*.swp
|
*.swp
|
||||||
|
*.zip
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.atom/
|
.atom/
|
||||||
.buildlog/
|
.buildlog/
|
||||||
|
@ -140,6 +141,7 @@ lib/tron/tron.dart
|
||||||
lib/wownero/wownero.dart
|
lib/wownero/wownero.dart
|
||||||
lib/zano/zano.dart
|
lib/zano/zano.dart
|
||||||
lib/decred/decred.dart
|
lib/decred/decred.dart
|
||||||
|
lib/xelis/xelis.dart
|
||||||
|
|
||||||
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
|
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
|
||||||
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png
|
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x~ipad.png
|
||||||
|
|
|
@ -84,6 +84,12 @@ Cake Wallet includes support for several cryptocurrencies, including:
|
||||||
* Automatically generate new addresses
|
* Automatically generate new addresses
|
||||||
* Specify multiple recipients for batch sending
|
* Specify multiple recipients for batch sending
|
||||||
|
|
||||||
|
### Xelis Specific Features
|
||||||
|
|
||||||
|
* Store XEL and all native assets/tokens
|
||||||
|
* Add custom tokens by asset ID
|
||||||
|
* Specify multiple recipients for batch sending
|
||||||
|
|
||||||
# Monero.com by Cake Wallet for Android and iOS
|
# Monero.com by Cake Wallet for Android and iOS
|
||||||
|
|
||||||
## Open Source Monero-Only Wallet
|
## Open Source Monero-Only Wallet
|
||||||
|
|
|
@ -23,6 +23,7 @@ analyzer:
|
||||||
lib/tron/cw_tron.dart,
|
lib/tron/cw_tron.dart,
|
||||||
lib/wownero/cw_wownero.dart,
|
lib/wownero/cw_wownero.dart,
|
||||||
lib/zano/cw_zano.dart,
|
lib/zano/cw_zano.dart,
|
||||||
|
lib/xelis/cw_xelis.dart,
|
||||||
]
|
]
|
||||||
language:
|
language:
|
||||||
strict-casts: true
|
strict-casts: true
|
||||||
|
|
|
@ -14,4 +14,15 @@
|
||||||
<natures>
|
<natures>
|
||||||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||||
</natures>
|
</natures>
|
||||||
|
<filteredResources>
|
||||||
|
<filter>
|
||||||
|
<id>1744859372158</id>
|
||||||
|
<name></name>
|
||||||
|
<type>30</type>
|
||||||
|
<matcher>
|
||||||
|
<id>org.eclipse.core.resources.regexFilterMatcher</id>
|
||||||
|
<arguments>node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__</arguments>
|
||||||
|
</matcher>
|
||||||
|
</filter>
|
||||||
|
</filteredResources>
|
||||||
</projectDescription>
|
</projectDescription>
|
||||||
|
|
|
@ -1,2 +1,13 @@
|
||||||
|
arguments=
|
||||||
|
auto.sync=false
|
||||||
|
build.scans.enabled=false
|
||||||
|
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||||
connection.project.dir=
|
connection.project.dir=
|
||||||
eclipse.preferences.version=1
|
eclipse.preferences.version=1
|
||||||
|
gradle.user.home=
|
||||||
|
java.home=
|
||||||
|
jvm.arguments=
|
||||||
|
offline.mode=false
|
||||||
|
override.workspace.settings=false
|
||||||
|
show.console.view=false
|
||||||
|
show.executions.view=false
|
||||||
|
|
BIN
assets/images/xelis_icon.png
Normal file
BIN
assets/images/xelis_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.4 KiB |
BIN
assets/images/xelis_testnet_icon.png
Normal file
BIN
assets/images/xelis_testnet_icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
25
assets/xelis_node_list.yml
Normal file
25
assets/xelis_node_list.yml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
-
|
||||||
|
uri: us-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
is_default: true
|
||||||
|
-
|
||||||
|
uri: pl-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: de-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: fr-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: sg-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: uk-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: ca-node.xelis.io
|
||||||
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: testnet-node.xelis.io
|
||||||
|
useSSL: true
|
|
@ -1,5 +1,5 @@
|
||||||
@echo off
|
@echo off
|
||||||
set cw_win_app_config=--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron
|
set cw_win_app_config=--monero --bitcoin --ethereum --polygon --nano --bitcoinCash --solana --tron --xelis
|
||||||
set cw_root=%cd%
|
set cw_root=%cd%
|
||||||
set cw_archive_name=Cake Wallet.zip
|
set cw_archive_name=Cake Wallet.zip
|
||||||
set cw_archive_path=%cw_root%\%cw_archive_name%
|
set cw_archive_path=%cw_root%\%cw_archive_name%
|
||||||
|
@ -24,7 +24,7 @@ IF NOT EXIST "%secrets_file_path%" (
|
||||||
) ELSE (echo === Using previously/already generated secrets file: %secrets_file_path% ===)
|
) ELSE (echo === Using previously/already generated secrets file: %secrets_file_path% ===)
|
||||||
|
|
||||||
echo === Generating mobx models ===
|
echo === Generating mobx models ===
|
||||||
for /d %%i in (cw_core cw_monero cw_bitcoin cw_ethereum cw_evm cw_polygon cw_nano cw_bitcoin_cash cw_solana cw_tron .) do (
|
for /d %%i in (cw_core cw_monero cw_bitcoin cw_ethereum cw_evm cw_polygon cw_nano cw_bitcoin_cash cw_solana cw_tron cw_xelis.) do (
|
||||||
cd %%i
|
cd %%i
|
||||||
call flutter pub get > nul
|
call flutter pub get > nul
|
||||||
call dart run build_runner build --delete-conflicting-outputs > nul
|
call dart run build_runner build --delete-conflicting-outputs > nul
|
||||||
|
|
|
@ -111,7 +111,9 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
CryptoCurrency.zano,
|
CryptoCurrency.zano,
|
||||||
CryptoCurrency.ton,
|
CryptoCurrency.ton,
|
||||||
CryptoCurrency.flip,
|
CryptoCurrency.flip,
|
||||||
CryptoCurrency.deuro
|
CryptoCurrency.deuro,
|
||||||
|
CryptoCurrency.xel,
|
||||||
|
CryptoCurrency.xet
|
||||||
];
|
];
|
||||||
|
|
||||||
static const havenCurrencies = [
|
static const havenCurrencies = [
|
||||||
|
@ -234,6 +236,9 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
||||||
static const flip = CryptoCurrency(title: 'FLIP', tag: 'ETH', fullName: 'Chainflip', raw: 97, name: 'flip', iconPath: 'assets/images/flip_icon.png', decimals: 18);
|
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);
|
static const deuro = CryptoCurrency(title: 'DEURO', tag: 'ETH', fullName: 'Decentralized Euro', raw: 98, name: 'deuro', iconPath: 'assets/images/deuro_icon.png', decimals: 18);
|
||||||
|
|
||||||
|
static const xel = CryptoCurrency(title: 'XEL', fullName: 'Xelis', raw: 99, name: 'xel', iconPath: 'assets/images/xelis_icon.png', decimals: 8);
|
||||||
|
static const xet = CryptoCurrency(title: 'XET', fullName: 'Testnet Xelis', raw: 100, name: 'xet', iconPath: 'assets/images/xelis_testnet_icon.png', decimals: 8);
|
||||||
|
|
||||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||||
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
||||||
acc.addAll({item.raw: item});
|
acc.addAll({item.raw: item});
|
||||||
|
|
|
@ -34,6 +34,11 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
|
||||||
return CryptoCurrency.zano;
|
return CryptoCurrency.zano;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return CryptoCurrency.dcr;
|
return CryptoCurrency.dcr;
|
||||||
|
case WalletType.xelis:
|
||||||
|
if (isTestnet == true) {
|
||||||
|
return CryptoCurrency.xet;
|
||||||
|
}
|
||||||
|
return CryptoCurrency.xel;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
|
'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
|
||||||
|
@ -70,6 +75,8 @@ WalletType? walletTypeForCurrency(CryptoCurrency currency) {
|
||||||
return WalletType.zano;
|
return WalletType.zano;
|
||||||
case CryptoCurrency.dcr:
|
case CryptoCurrency.dcr:
|
||||||
return WalletType.decred;
|
return WalletType.decred;
|
||||||
|
case CryptoCurrency.xel:
|
||||||
|
return WalletType.xelis;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,3 +22,4 @@ const MWEB_UTXO_TYPE_ID = 20;
|
||||||
const HAVEN_SEED_STORE_TYPE_ID = 21;
|
const HAVEN_SEED_STORE_TYPE_ID = 21;
|
||||||
const ZANO_ASSET_TYPE_ID = 22;
|
const ZANO_ASSET_TYPE_ID = 22;
|
||||||
const PAYJOIN_SESSION_TYPE_ID = 23;
|
const PAYJOIN_SESSION_TYPE_ID = 23;
|
||||||
|
const XELIS_ASSET_TYPE_ID = 24;
|
|
@ -104,6 +104,7 @@ class Node extends HiveObject with Keyable {
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
return Uri.parse(
|
return Uri.parse(
|
||||||
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}");
|
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}");
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
|
@ -165,6 +166,7 @@ class Node extends HiveObject with Keyable {
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
|
case WalletType.xelis:
|
||||||
return requestElectrumServer();
|
return requestElectrumServer();
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
return requestZanoNode();
|
return requestZanoNode();
|
||||||
|
@ -360,13 +362,13 @@ class Node extends HiveObject with Keyable {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> requestDecredNode() async {
|
Future<bool> requestDecredNode() async {
|
||||||
if (uri.host == "default-spv-nodes") {
|
if (uri.host == "default-spv-nodes") {
|
||||||
// Just show default port as ok. The wallet will connect to a list of known
|
// Just show default port as ok. The wallet will connect to a list of known
|
||||||
// nodes automatically.
|
// nodes automatically.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
final socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
|
final socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
return true;
|
return true;
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ const walletTypes = [
|
||||||
WalletType.tron,
|
WalletType.tron,
|
||||||
WalletType.zano,
|
WalletType.zano,
|
||||||
WalletType.decred,
|
WalletType.decred,
|
||||||
|
WalletType.xelis,
|
||||||
];
|
];
|
||||||
|
|
||||||
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
||||||
|
@ -65,7 +66,10 @@ enum WalletType {
|
||||||
zano,
|
zano,
|
||||||
|
|
||||||
@HiveField(14)
|
@HiveField(14)
|
||||||
decred
|
decred,
|
||||||
|
|
||||||
|
@HiveField(15)
|
||||||
|
xelis
|
||||||
}
|
}
|
||||||
|
|
||||||
int serializeToInt(WalletType type) {
|
int serializeToInt(WalletType type) {
|
||||||
|
@ -98,6 +102,8 @@ int serializeToInt(WalletType type) {
|
||||||
return 12;
|
return 12;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return 13;
|
return 13;
|
||||||
|
case WalletType.xelis:
|
||||||
|
return 14;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -133,6 +139,8 @@ WalletType deserializeFromInt(int raw) {
|
||||||
return WalletType.zano;
|
return WalletType.zano;
|
||||||
case 13:
|
case 13:
|
||||||
return WalletType.decred;
|
return WalletType.decred;
|
||||||
|
case 14:
|
||||||
|
return WalletType.xelis;
|
||||||
default:
|
default:
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Unexpected token: $raw for WalletType deserializeFromInt');
|
'Unexpected token: $raw for WalletType deserializeFromInt');
|
||||||
|
@ -169,6 +177,8 @@ String walletTypeToString(WalletType type) {
|
||||||
return 'Zano';
|
return 'Zano';
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return 'Decred';
|
return 'Decred';
|
||||||
|
case WalletType.xelis:
|
||||||
|
return 'Xelis';
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -204,6 +214,8 @@ String walletTypeToDisplayName(WalletType type) {
|
||||||
return 'Zano (ZANO)';
|
return 'Zano (ZANO)';
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return 'Decred (DCR)';
|
return 'Decred (DCR)';
|
||||||
|
case WalletType.xelis:
|
||||||
|
return 'Xelis (XEL)';
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -242,6 +254,11 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
|
||||||
return CryptoCurrency.zano;
|
return CryptoCurrency.zano;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return CryptoCurrency.dcr;
|
return CryptoCurrency.dcr;
|
||||||
|
case WalletType.xelis:
|
||||||
|
if (isTestnet) {
|
||||||
|
return CryptoCurrency.xet;
|
||||||
|
}
|
||||||
|
return CryptoCurrency.xel;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
throw Exception(
|
throw Exception(
|
||||||
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
|
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');
|
||||||
|
|
38
cw_xelis/.gitignore
vendored
Normal file
38
cw_xelis/.gitignore
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.build/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
|
||||||
|
/pubspec.lock
|
||||||
|
**/doc/api/
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
flutter_rust_bridge_local.yaml
|
||||||
|
build/
|
||||||
|
rust_temp/
|
||||||
|
rust_src/
|
||||||
|
lib/src/**
|
||||||
|
xelis-flutter-ffi/
|
27
cw_xelis/.metadata
Normal file
27
cw_xelis/.metadata
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
# This file tracks properties of this Flutter project.
|
||||||
|
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||||
|
#
|
||||||
|
# This file should be version controlled and should not be manually edited.
|
||||||
|
|
||||||
|
version:
|
||||||
|
revision: "c23637390482d4cf9598c3ce3f2be31aa7332daf"
|
||||||
|
channel: "stable"
|
||||||
|
|
||||||
|
project_type: plugin
|
||||||
|
|
||||||
|
# Tracks metadata for the flutter migrate command
|
||||||
|
migration:
|
||||||
|
platforms:
|
||||||
|
- platform: root
|
||||||
|
create_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||||
|
base_revision: c23637390482d4cf9598c3ce3f2be31aa7332daf
|
||||||
|
|
||||||
|
# User provided section
|
||||||
|
|
||||||
|
# List of Local paths (relative to this file) that should be
|
||||||
|
# ignored by the migrate tool.
|
||||||
|
#
|
||||||
|
# Files that are not part of the templates will be ignored by default.
|
||||||
|
unmanaged_files:
|
||||||
|
- 'lib/main.dart'
|
||||||
|
- 'ios/Runner.xcodeproj/project.pbxproj'
|
3
cw_xelis/CHANGELOG.md
Normal file
3
cw_xelis/CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## 0.0.1
|
||||||
|
|
||||||
|
* TODO: Describe initial release.
|
1
cw_xelis/LICENSE
Normal file
1
cw_xelis/LICENSE
Normal file
|
@ -0,0 +1 @@
|
||||||
|
TODO: Add your license here.
|
18
cw_xelis/README.md
Normal file
18
cw_xelis/README.md
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# cw_xelis
|
||||||
|
|
||||||
|
A new Flutter plugin project.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter
|
||||||
|
[plug-in package](https://flutter.dev/to/develop-plugins),
|
||||||
|
a specialized package that includes platform-specific implementation code for
|
||||||
|
Android and/or iOS.
|
||||||
|
|
||||||
|
For help getting started with Flutter development, view the
|
||||||
|
[online documentation](https://docs.flutter.dev), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
||||||
|
|
||||||
|
The plugin project was generated without specifying the `--platforms` flag, no platforms are currently supported.
|
||||||
|
To add platforms, run `flutter create -t plugin --platforms <platforms> .` in this directory.
|
||||||
|
You can also find a detailed instruction on how to add platforms in the `pubspec.yaml` at https://flutter.dev/to/pubspec-plugin-platforms.
|
13
cw_xelis/analysis_options.yaml
Normal file
13
cw_xelis/analysis_options.yaml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
analyzer:
|
||||||
|
exclude:
|
||||||
|
- "lib/src/api/generated/**"
|
||||||
|
- "**/*.g.dart"
|
||||||
|
- "**/*frb_generated*.dart"
|
||||||
|
errors:
|
||||||
|
# Ignore specific errors that might come from generated code
|
||||||
|
invalid_annotation_target: ignore
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
45
cw_xelis/example/.gitignore
vendored
Normal file
45
cw_xelis/example/.gitignore
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# Miscellaneous
|
||||||
|
*.class
|
||||||
|
*.log
|
||||||
|
*.pyc
|
||||||
|
*.swp
|
||||||
|
.DS_Store
|
||||||
|
.atom/
|
||||||
|
.build/
|
||||||
|
.buildlog/
|
||||||
|
.history
|
||||||
|
.svn/
|
||||||
|
.swiftpm/
|
||||||
|
migrate_working_dir/
|
||||||
|
|
||||||
|
# IntelliJ related
|
||||||
|
*.iml
|
||||||
|
*.ipr
|
||||||
|
*.iws
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# The .vscode folder contains launch configuration and tasks you configure in
|
||||||
|
# VS Code which you may wish to be included in version control, so this line
|
||||||
|
# is commented out by default.
|
||||||
|
#.vscode/
|
||||||
|
|
||||||
|
# Flutter/Dart/Pub related
|
||||||
|
**/doc/api/
|
||||||
|
**/ios/Flutter/.last_build_id
|
||||||
|
.dart_tool/
|
||||||
|
.flutter-plugins
|
||||||
|
.flutter-plugins-dependencies
|
||||||
|
.pub-cache/
|
||||||
|
.pub/
|
||||||
|
/build/
|
||||||
|
|
||||||
|
# Symbolication related
|
||||||
|
app.*.symbols
|
||||||
|
|
||||||
|
# Obfuscation related
|
||||||
|
app.*.map.json
|
||||||
|
|
||||||
|
# Android Studio will place build artifacts here
|
||||||
|
/android/app/debug
|
||||||
|
/android/app/profile
|
||||||
|
/android/app/release
|
16
cw_xelis/example/README.md
Normal file
16
cw_xelis/example/README.md
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# cw_xelis_example
|
||||||
|
|
||||||
|
Demonstrates how to use the cw_xelis plugin.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
|
||||||
|
This project is a starting point for a Flutter application.
|
||||||
|
|
||||||
|
A few resources to get you started if this is your first Flutter project:
|
||||||
|
|
||||||
|
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||||
|
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||||
|
|
||||||
|
For help getting started with Flutter development, view the
|
||||||
|
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||||
|
samples, guidance on mobile development, and a full API reference.
|
28
cw_xelis/example/analysis_options.yaml
Normal file
28
cw_xelis/example/analysis_options.yaml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
# This file configures the analyzer, which statically analyzes Dart code to
|
||||||
|
# check for errors, warnings, and lints.
|
||||||
|
#
|
||||||
|
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||||
|
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||||
|
# invoked from the command line by running `flutter analyze`.
|
||||||
|
|
||||||
|
# The following line activates a set of recommended lints for Flutter apps,
|
||||||
|
# packages, and plugins designed to encourage good coding practices.
|
||||||
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
|
linter:
|
||||||
|
# The lint rules applied to this project can be customized in the
|
||||||
|
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||||
|
# included above or to enable additional rules. A list of all available lints
|
||||||
|
# and their documentation is published at https://dart.dev/lints.
|
||||||
|
#
|
||||||
|
# Instead of disabling a lint rule for the entire project in the
|
||||||
|
# section below, it can also be suppressed for a single line of code
|
||||||
|
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||||
|
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||||
|
# producing the lint.
|
||||||
|
rules:
|
||||||
|
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||||
|
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||||
|
|
||||||
|
# Additional information about this file can be found at
|
||||||
|
# https://dart.dev/guides/language/analysis-options
|
|
@ -0,0 +1,25 @@
|
||||||
|
// This is a basic Flutter integration test.
|
||||||
|
//
|
||||||
|
// Since integration tests run in a full Flutter application, they can interact
|
||||||
|
// with the host side of a plugin implementation, unlike Dart unit tests.
|
||||||
|
//
|
||||||
|
// For more information about Flutter integration tests, please see
|
||||||
|
// https://flutter.dev/to/integration-testing
|
||||||
|
|
||||||
|
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:integration_test/integration_test.dart';
|
||||||
|
|
||||||
|
import 'package:cw_xelis/cw_xelis.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
testWidgets('getPlatformVersion test', (WidgetTester tester) async {
|
||||||
|
final CwXelis plugin = CwXelis();
|
||||||
|
final String? version = await plugin.getPlatformVersion();
|
||||||
|
// The version string depends on the host platform running the test, so
|
||||||
|
// just assert that some non-empty string is returned.
|
||||||
|
expect(version?.isNotEmpty, true);
|
||||||
|
});
|
||||||
|
}
|
63
cw_xelis/example/lib/main.dart
Normal file
63
cw_xelis/example/lib/main.dart
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:cw_xelis/cw_xelis.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
runApp(const MyApp());
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyApp extends StatefulWidget {
|
||||||
|
const MyApp({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<MyApp> createState() => _MyAppState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyAppState extends State<MyApp> {
|
||||||
|
String _platformVersion = 'Unknown';
|
||||||
|
final _cwXelisPlugin = CwXelis();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
initPlatformState();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Platform messages are asynchronous, so we initialize in an async method.
|
||||||
|
Future<void> initPlatformState() async {
|
||||||
|
String platformVersion;
|
||||||
|
// Platform messages may fail, so we use a try/catch PlatformException.
|
||||||
|
// We also handle the message potentially returning null.
|
||||||
|
try {
|
||||||
|
platformVersion =
|
||||||
|
await _cwXelisPlugin.getPlatformVersion() ?? 'Unknown platform version';
|
||||||
|
} on PlatformException {
|
||||||
|
platformVersion = 'Failed to get platform version.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the widget was removed from the tree while the asynchronous platform
|
||||||
|
// message was in flight, we want to discard the reply rather than calling
|
||||||
|
// setState to update our non-existent appearance.
|
||||||
|
if (!mounted) return;
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_platformVersion = platformVersion;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return MaterialApp(
|
||||||
|
home: Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('Plugin example app'),
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: Text('Running on: $_platformVersion\n'),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
755
cw_xelis/example/pubspec.lock
Normal file
755
cw_xelis/example/pubspec.lock
Normal file
|
@ -0,0 +1,755 @@
|
||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
|
asn1lib:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: asn1lib
|
||||||
|
sha256: "1c296cd268f486cabcc3930e9b93a8133169305f18d722916e675959a88f6d2c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.9"
|
||||||
|
async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: async
|
||||||
|
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.11.0"
|
||||||
|
blockchain_utils:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: cake-update-v2
|
||||||
|
resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57"
|
||||||
|
url: "https://github.com/cake-tech/blockchain_utils"
|
||||||
|
source: git
|
||||||
|
version: "3.3.0"
|
||||||
|
boolean_selector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: boolean_selector
|
||||||
|
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
build_cli_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_cli_annotations
|
||||||
|
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
cake_backup:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: main
|
||||||
|
resolved-ref: "3aba867dcab6737f6707782f5db15d71f303db38"
|
||||||
|
url: "https://github.com/cake-tech/cake_backup.git"
|
||||||
|
source: git
|
||||||
|
version: "1.0.0+1"
|
||||||
|
characters:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: characters
|
||||||
|
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
clock:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: clock
|
||||||
|
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.19.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
|
cryptography:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cryptography
|
||||||
|
sha256: d146b76d33d94548cf035233fbc2f4338c1242fa119013bead807d033fc4ae05
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
|
cupertino_icons:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: cupertino_icons
|
||||||
|
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.8"
|
||||||
|
cw_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "../../cw_core"
|
||||||
|
relative: true
|
||||||
|
source: path
|
||||||
|
version: "0.0.1"
|
||||||
|
cw_xelis:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
path: ".."
|
||||||
|
relative: true
|
||||||
|
source: path
|
||||||
|
version: "0.0.1"
|
||||||
|
decimal:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: decimal
|
||||||
|
sha256: "24a261d5d5c87e86c7651c417a5dbdf8bcd7080dd592533910e8d0505a279f21"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.3"
|
||||||
|
encrypt:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: encrypt
|
||||||
|
sha256: "62d9aa4670cc2a8798bab89b39fc71b6dfbacf615de6cf5001fb39f7e4a996a2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.3"
|
||||||
|
fake_async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: fake_async
|
||||||
|
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.1"
|
||||||
|
ffi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: ffi
|
||||||
|
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
flutter_driver:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
flutter_lints:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: flutter_lints
|
||||||
|
sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
|
flutter_mobx:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_mobx
|
||||||
|
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
|
flutter_rust_bridge:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_rust_bridge
|
||||||
|
sha256: "5a5c7a5deeef2cc2ffe6076a33b0429f4a20ceac22a397297aed2b1eb067e611"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.9.0"
|
||||||
|
flutter_test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
flutter_web_plugins:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
freezed_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: freezed_annotation
|
||||||
|
sha256: c87ff004c8aa6af2d531668b46a4ea379f7191dc6dfa066acd53d506da6e044b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
fuchsia_remote_debug_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
globbing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: globbing
|
||||||
|
sha256: "4f89cfaf6fa74c9c1740a96259da06bd45411ede56744e28017cc534a12b6e2d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
hive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: hive
|
||||||
|
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.3"
|
||||||
|
http:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http
|
||||||
|
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.2"
|
||||||
|
integration_test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
intl:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.19.0"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.7"
|
||||||
|
json_annotation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_annotation
|
||||||
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.9.0"
|
||||||
|
json_rpc_2:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: json_rpc_2
|
||||||
|
sha256: "3c46c2633aec07810c3d6a2eb08d575b5b4072980db08f1344e66aeb53d6e4a7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
jsontool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: jsontool
|
||||||
|
sha256: e49bf419e82d90f009426cd7fdec8d54ba8382975b3454ed16a3af3ee1d1b697
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
leak_tracker:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker
|
||||||
|
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.0.7"
|
||||||
|
leak_tracker_flutter_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_flutter_testing
|
||||||
|
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.8"
|
||||||
|
leak_tracker_testing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: leak_tracker_testing
|
||||||
|
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
lints:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: lints
|
||||||
|
sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.1.1"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
matcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: matcher
|
||||||
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.16+1"
|
||||||
|
material_color_utilities:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: material_color_utilities
|
||||||
|
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.11.1"
|
||||||
|
meta:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: meta
|
||||||
|
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.15.0"
|
||||||
|
mobx:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mobx
|
||||||
|
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
mutex:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mutex
|
||||||
|
sha256: "8827da25de792088eb33e572115a5eb0d61d61a3c01acbc8bcbe76ed78f1a1f2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
on_chain:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: cake-update-v2
|
||||||
|
resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
|
||||||
|
url: "https://github.com/cake-tech/on_chain.git"
|
||||||
|
source: git
|
||||||
|
version: "3.7.0"
|
||||||
|
path:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.0"
|
||||||
|
path_provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider
|
||||||
|
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.5"
|
||||||
|
path_provider_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_android
|
||||||
|
sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.17"
|
||||||
|
path_provider_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_foundation
|
||||||
|
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
path_provider_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_linux
|
||||||
|
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.1"
|
||||||
|
path_provider_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_platform_interface
|
||||||
|
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
path_provider_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_provider_windows
|
||||||
|
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
|
platform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: platform
|
||||||
|
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.5"
|
||||||
|
plugin_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: plugin_platform_interface
|
||||||
|
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.8"
|
||||||
|
pointycastle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pointycastle
|
||||||
|
sha256: "4be0097fcf3fd3e8449e53730c631200ebc7b88016acecab2b0da2f0149222fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.9.1"
|
||||||
|
process:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: process
|
||||||
|
sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.2"
|
||||||
|
provider:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.5"
|
||||||
|
rational:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: rational
|
||||||
|
sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.3"
|
||||||
|
shared_preferences:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences
|
||||||
|
sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.3"
|
||||||
|
shared_preferences_android:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_android
|
||||||
|
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.10"
|
||||||
|
shared_preferences_foundation:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_foundation
|
||||||
|
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.4"
|
||||||
|
shared_preferences_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_linux
|
||||||
|
sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
shared_preferences_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_platform_interface
|
||||||
|
sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
shared_preferences_web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_web
|
||||||
|
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.3"
|
||||||
|
shared_preferences_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shared_preferences_windows
|
||||||
|
sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.4.1"
|
||||||
|
sky_engine:
|
||||||
|
dependency: transitive
|
||||||
|
description: flutter
|
||||||
|
source: sdk
|
||||||
|
version: "0.0.0"
|
||||||
|
socks5_proxy:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: socks5_proxy
|
||||||
|
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
source_span:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_span
|
||||||
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.0"
|
||||||
|
stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stack_trace
|
||||||
|
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.12.0"
|
||||||
|
stream_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_channel
|
||||||
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
string_scanner:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: string_scanner
|
||||||
|
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
sync_http:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sync_http
|
||||||
|
sha256: "7f0cd72eca000d2e026bcd6f990b81d0ca06022ef4e32fb257b30d3d1014a961"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
|
system_info2:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: system_info2
|
||||||
|
sha256: "65206bbef475217008b5827374767550a5420ce70a04d2d7e94d1d2253f3efc9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
term_glyph:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: term_glyph
|
||||||
|
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
test_api:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_api
|
||||||
|
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.3"
|
||||||
|
tuple:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: tuple
|
||||||
|
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.0"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "8e3870a1caa60bde8352f9597dd3535d8068613269444f8e35ea8925ec84c1f5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1+1"
|
||||||
|
vector_math:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_math
|
||||||
|
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
very_good_analysis:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: very_good_analysis
|
||||||
|
sha256: "62d2b86d183fb81b2edc22913d9f155d26eb5cf3855173adb1f59fac85035c63"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "14.3.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket
|
||||||
|
sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.3"
|
||||||
|
web_socket_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_client
|
||||||
|
sha256: "394789177aa3bc1b7b071622a1dbf52a4631d7ce23c555c39bb2523e92316b07"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.1"
|
||||||
|
webdriver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webdriver
|
||||||
|
sha256: "3d773670966f02a646319410766d3b5e1037efb7f07cc68f844d5e06cd4d61c8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.4"
|
||||||
|
xdg_directories:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xdg_directories
|
||||||
|
sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
xelis_dart_sdk:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xelis_dart_sdk
|
||||||
|
sha256: "990c6be6be5f0410764fd4034f940d2870bc70974feb3ed465123102a3bd9dfd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.28.0"
|
||||||
|
xelis_flutter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
path: "."
|
||||||
|
ref: "83bda92f1b833fe5d8584aa429d5143a3698b33f"
|
||||||
|
resolved-ref: "83bda92f1b833fe5d8584aa429d5143a3698b33f"
|
||||||
|
url: "https://github.com/xelis-project/xelis-flutter-ffi.git"
|
||||||
|
source: git
|
||||||
|
version: "0.2.0"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.6.0 <4.0.0"
|
||||||
|
flutter: ">=3.27.0"
|
85
cw_xelis/example/pubspec.yaml
Normal file
85
cw_xelis/example/pubspec.yaml
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
name: cw_xelis_example
|
||||||
|
description: "Demonstrates how to use the cw_xelis plugin."
|
||||||
|
# The following line prevents the package from being accidentally published to
|
||||||
|
# pub.dev using `flutter pub publish`. This is preferred for private packages.
|
||||||
|
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.0.6 <4.0.0'
|
||||||
|
|
||||||
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
|
# consider running `flutter pub upgrade --major-versions`. Alternatively,
|
||||||
|
# dependencies can be manually updated by changing the version numbers below to
|
||||||
|
# the latest version available on pub.dev. To see which dependencies have newer
|
||||||
|
# versions available, run `flutter pub outdated`.
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
cw_xelis:
|
||||||
|
# When depending on this package from a real application you should use:
|
||||||
|
# cw_xelis: ^x.y.z
|
||||||
|
# See https://dart.dev/tools/pub/dependencies#version-constraints
|
||||||
|
# The example app is bundled with the plugin so we use a path dependency on
|
||||||
|
# the parent directory to use the current plugin's version.
|
||||||
|
path: ../
|
||||||
|
|
||||||
|
# The following adds the Cupertino Icons font to your application.
|
||||||
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
cupertino_icons: ^1.0.8
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
integration_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
|
# The "flutter_lints" package below contains a set of recommended lints to
|
||||||
|
# encourage good coding practices. The lint set provided by the package is
|
||||||
|
# activated in the `analysis_options.yaml` file located at the root of your
|
||||||
|
# package. See that file for information about deactivating specific lint
|
||||||
|
# rules and activating additional ones.
|
||||||
|
flutter_lints: ^5.0.0
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter packages.
|
||||||
|
flutter:
|
||||||
|
|
||||||
|
# The following line ensures that the Material Icons font is
|
||||||
|
# included with your application, so that you can use the icons in
|
||||||
|
# the material Icons class.
|
||||||
|
uses-material-design: true
|
||||||
|
|
||||||
|
# To add assets to your application, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
||||||
|
# For details regarding adding assets from package dependencies, see
|
||||||
|
# https://flutter.dev/to/asset-from-package
|
||||||
|
|
||||||
|
# To add custom fonts to your application, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts from package dependencies,
|
||||||
|
# see https://flutter.dev/to/font-from-package
|
27
cw_xelis/example/test/widget_test.dart
Normal file
27
cw_xelis/example/test/widget_test.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// This is a basic Flutter widget test.
|
||||||
|
//
|
||||||
|
// To perform an interaction with a widget in your test, use the WidgetTester
|
||||||
|
// utility in the flutter_test package. For example, you can send tap and scroll
|
||||||
|
// gestures. You can also use WidgetTester to find child widgets in the widget
|
||||||
|
// tree, read text, and verify that the values of widget properties are correct.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
|
import 'package:cw_xelis_example/main.dart';
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
testWidgets('Verify Platform version', (WidgetTester tester) async {
|
||||||
|
// Build our app and trigger a frame.
|
||||||
|
await tester.pumpWidget(const MyApp());
|
||||||
|
|
||||||
|
// Verify that platform version is retrieved.
|
||||||
|
expect(
|
||||||
|
find.byWidgetPredicate(
|
||||||
|
(Widget widget) => widget is Text &&
|
||||||
|
widget.data!.startsWith('Running on:'),
|
||||||
|
),
|
||||||
|
findsOneWidget,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
14
cw_xelis/lib/cw_xelis.dart
Normal file
14
cw_xelis/lib/cw_xelis.dart
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// You have generated a new plugin project without specifying the `--platforms`
|
||||||
|
// flag. A plugin project with no platform support was generated. To add a
|
||||||
|
// platform, run `flutter create -t plugin --platforms <platforms> .` under the
|
||||||
|
// same directory. You can also find a detailed instruction on how to add
|
||||||
|
// platforms in the `pubspec.yaml` at
|
||||||
|
// https://flutter.dev/to/pubspec-plugin-platforms.
|
||||||
|
|
||||||
|
import 'cw_xelis_platform_interface.dart';
|
||||||
|
|
||||||
|
class CwXelis {
|
||||||
|
Future<String?> getPlatformVersion() {
|
||||||
|
return CwXelisPlatform.instance.getPlatformVersion();
|
||||||
|
}
|
||||||
|
}
|
17
cw_xelis/lib/cw_xelis_method_channel.dart
Normal file
17
cw_xelis/lib/cw_xelis_method_channel.dart
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'cw_xelis_platform_interface.dart';
|
||||||
|
|
||||||
|
/// An implementation of [CwXelisPlatform] that uses method channels.
|
||||||
|
class MethodChannelCwXelis extends CwXelisPlatform {
|
||||||
|
/// The method channel used to interact with the native platform.
|
||||||
|
@visibleForTesting
|
||||||
|
final methodChannel = const MethodChannel('cw_xelis');
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> getPlatformVersion() async {
|
||||||
|
final version = await methodChannel.invokeMethod<String>('getPlatformVersion');
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
}
|
29
cw_xelis/lib/cw_xelis_platform_interface.dart
Normal file
29
cw_xelis/lib/cw_xelis_platform_interface.dart
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||||
|
|
||||||
|
import 'cw_xelis_method_channel.dart';
|
||||||
|
|
||||||
|
abstract class CwXelisPlatform extends PlatformInterface {
|
||||||
|
/// Constructs a CwXelisPlatform.
|
||||||
|
CwXelisPlatform() : super(token: _token);
|
||||||
|
|
||||||
|
static final Object _token = Object();
|
||||||
|
|
||||||
|
static CwXelisPlatform _instance = MethodChannelCwXelis();
|
||||||
|
|
||||||
|
/// The default instance of [CwXelisPlatform] to use.
|
||||||
|
///
|
||||||
|
/// Defaults to [MethodChannelCwXelis].
|
||||||
|
static CwXelisPlatform get instance => _instance;
|
||||||
|
|
||||||
|
/// Platform-specific implementations should set this with their own
|
||||||
|
/// platform-specific class that extends [CwXelisPlatform] when
|
||||||
|
/// they register themselves.
|
||||||
|
static set instance(CwXelisPlatform instance) {
|
||||||
|
PlatformInterface.verifyToken(instance, _token);
|
||||||
|
_instance = instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String?> getPlatformVersion() {
|
||||||
|
throw UnimplementedError('platformVersion() has not been implemented.');
|
||||||
|
}
|
||||||
|
}
|
1
cw_xelis/lib/src/api/api.dart
Normal file
1
cw_xelis/lib/src/api/api.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/api.dart';
|
1
cw_xelis/lib/src/api/logger.dart
Normal file
1
cw_xelis/lib/src/api/logger.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/logger.dart';
|
24
cw_xelis/lib/src/api/network.dart
Normal file
24
cw_xelis/lib/src/api/network.dart
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
export 'package:xelis_flutter/src/api/network.dart';
|
||||||
|
import 'package:xelis_flutter/src/api/network.dart';
|
||||||
|
|
||||||
|
extension NetworkName on Network {
|
||||||
|
String get name {
|
||||||
|
switch (this) {
|
||||||
|
case Network.mainnet:
|
||||||
|
return 'mainnet';
|
||||||
|
case Network.testnet:
|
||||||
|
return 'testnet';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Network fromName(String name) {
|
||||||
|
switch (name) {
|
||||||
|
case 'mainnet':
|
||||||
|
return Network.mainnet;
|
||||||
|
case 'testnet':
|
||||||
|
return Network.testnet;
|
||||||
|
default:
|
||||||
|
throw ArgumentError('Unknown network name: $name');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1
cw_xelis/lib/src/api/progress_report.dart
Normal file
1
cw_xelis/lib/src/api/progress_report.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/progress_report.dart';
|
1
cw_xelis/lib/src/api/seed_search_engine.dart
Normal file
1
cw_xelis/lib/src/api/seed_search_engine.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/seed_search_engine.dart';
|
1
cw_xelis/lib/src/api/table_generation.dart
Normal file
1
cw_xelis/lib/src/api/table_generation.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/table_generation.dart';
|
1
cw_xelis/lib/src/api/utils.dart
Normal file
1
cw_xelis/lib/src/api/utils.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/utils.dart';
|
1
cw_xelis/lib/src/api/wallet.dart
Normal file
1
cw_xelis/lib/src/api/wallet.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/api/wallet.dart';
|
1
cw_xelis/lib/src/frb_generated.dart
Normal file
1
cw_xelis/lib/src/frb_generated.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'package:xelis_flutter/src/frb_generated.dart';
|
115
cw_xelis/lib/xelis_asset.dart
Normal file
115
cw_xelis/lib/xelis_asset.dart
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
import 'package:cw_core/hive_type_ids.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
|
||||||
|
part 'xelis_asset.g.dart';
|
||||||
|
|
||||||
|
@HiveType(typeId: XelisAsset.typeId)
|
||||||
|
class XelisAsset extends CryptoCurrency with HiveObjectMixin {
|
||||||
|
@override
|
||||||
|
@HiveField(0)
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
@HiveField(1)
|
||||||
|
final String symbol;
|
||||||
|
|
||||||
|
@HiveField(2)
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
@HiveField(3)
|
||||||
|
final int decimals;
|
||||||
|
|
||||||
|
@HiveField(4, defaultValue: true)
|
||||||
|
bool _enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@HiveField(5)
|
||||||
|
final String? iconPath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@HiveField(6)
|
||||||
|
final String? tag;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@HiveField(7, defaultValue: false)
|
||||||
|
final bool isPotentialScam;
|
||||||
|
|
||||||
|
XelisAsset({
|
||||||
|
required this.name,
|
||||||
|
required this.symbol,
|
||||||
|
required this.id,
|
||||||
|
required this.decimals,
|
||||||
|
this.iconPath,
|
||||||
|
this.tag = 'XEL',
|
||||||
|
bool enabled = true,
|
||||||
|
this.isPotentialScam = false,
|
||||||
|
}) : _enabled = enabled,
|
||||||
|
super(
|
||||||
|
name: id.toLowerCase(),
|
||||||
|
title: symbol.toUpperCase(),
|
||||||
|
fullName: name,
|
||||||
|
tag: tag,
|
||||||
|
iconPath: iconPath,
|
||||||
|
decimals: decimals,
|
||||||
|
isPotentialScam: isPotentialScam,
|
||||||
|
);
|
||||||
|
|
||||||
|
factory XelisAsset.fromMetadata({
|
||||||
|
required String name,
|
||||||
|
required String id,
|
||||||
|
required String symbol,
|
||||||
|
required int decimals,
|
||||||
|
String? iconPath,
|
||||||
|
bool isPotentialScam = false,
|
||||||
|
}) {
|
||||||
|
return XelisAsset(
|
||||||
|
name: name,
|
||||||
|
symbol: symbol,
|
||||||
|
decimals: decimals,
|
||||||
|
id: id,
|
||||||
|
iconPath: iconPath,
|
||||||
|
isPotentialScam: isPotentialScam,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get enabled => _enabled;
|
||||||
|
|
||||||
|
@override
|
||||||
|
set enabled(bool value) => _enabled = value;
|
||||||
|
|
||||||
|
XelisAsset.copyWith(XelisAsset other, String? icon, String? tag)
|
||||||
|
: name = other.name,
|
||||||
|
symbol = other.symbol,
|
||||||
|
decimals = other.decimals,
|
||||||
|
_enabled = other.enabled,
|
||||||
|
id = other.id,
|
||||||
|
tag = other.tag,
|
||||||
|
iconPath = icon,
|
||||||
|
isPotentialScam = other.isPotentialScam,
|
||||||
|
super(
|
||||||
|
title: other.symbol.toUpperCase(),
|
||||||
|
name: other.symbol.toLowerCase(),
|
||||||
|
decimals: other.decimals,
|
||||||
|
fullName: other.name,
|
||||||
|
tag: other.tag,
|
||||||
|
iconPath: icon,
|
||||||
|
isPotentialScam: other.isPotentialScam,
|
||||||
|
);
|
||||||
|
|
||||||
|
static const typeId = XELIS_ASSET_TYPE_ID;
|
||||||
|
static const boxName = 'XelisAssets';
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
if (identical(this, other)) return true;
|
||||||
|
|
||||||
|
if (other is XelisAsset) {
|
||||||
|
return other.id == id;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => id.hashCode;
|
||||||
|
}
|
56
cw_xelis/lib/xelis_asset_balance.dart
Normal file
56
cw_xelis/lib/xelis_asset_balance.dart
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
import 'package:cw_core/balance.dart';
|
||||||
|
|
||||||
|
import 'package:cw_xelis/xelis_formatting.dart';
|
||||||
|
import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk;
|
||||||
|
|
||||||
|
class XelisAssetBalance extends Balance {
|
||||||
|
XelisAssetBalance({
|
||||||
|
required this.balance,
|
||||||
|
required this.decimals,
|
||||||
|
this.asset = xelis_sdk.xelisAsset,
|
||||||
|
this.symbol = "XEL"
|
||||||
|
}): super(balance, 0);
|
||||||
|
|
||||||
|
final int balance;
|
||||||
|
final int decimals;
|
||||||
|
final String asset;
|
||||||
|
final String symbol;
|
||||||
|
|
||||||
|
String get formatted {
|
||||||
|
final formatter = NumberFormat('0.00##########', 'en_US');
|
||||||
|
final value = (BigInt.from(balance) / BigInt.from(10).pow(decimals)).toDouble();
|
||||||
|
return formatter.format(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
String toJSON() => json.encode({
|
||||||
|
'balance': balance.toString(),
|
||||||
|
'decimals': decimals,
|
||||||
|
'asset': asset,
|
||||||
|
'symbol': symbol
|
||||||
|
});
|
||||||
|
|
||||||
|
static XelisAssetBalance fromJSON(String jsonSource) {
|
||||||
|
final decoded = json.decode(jsonSource) as Map;
|
||||||
|
return XelisAssetBalance(
|
||||||
|
balance: decoded['balance'],
|
||||||
|
decimals: decoded['decimals'],
|
||||||
|
asset: decoded['asset'],
|
||||||
|
symbol: decoded['symbol'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static XelisAssetBalance zero({int? decimals, String? asset, String? symbol}) {
|
||||||
|
return XelisAssetBalance(
|
||||||
|
balance: 0,
|
||||||
|
decimals: decimals ?? 8,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedAvailableBalance => XelisFormatter.formatAmount(balance, decimals: decimals);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get formattedAdditionalBalance => '0';
|
||||||
|
}
|
64
cw_xelis/lib/xelis_events.dart
Normal file
64
cw_xelis/lib/xelis_events.dart
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk;
|
||||||
|
|
||||||
|
abstract class Event {
|
||||||
|
const Event();
|
||||||
|
}
|
||||||
|
|
||||||
|
class NewTopoheight extends Event {
|
||||||
|
final int topoheight;
|
||||||
|
const NewTopoheight(this.topoheight);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NewTransaction extends Event {
|
||||||
|
final xelis_sdk.TransactionEntry tx;
|
||||||
|
const NewTransaction(this.tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
class BalanceChanged extends Event {
|
||||||
|
final String asset;
|
||||||
|
final int balance;
|
||||||
|
const BalanceChanged(this.asset, this.balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Online extends Event {
|
||||||
|
const Online();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Offline extends Event {
|
||||||
|
const Offline();
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rescan extends Event {
|
||||||
|
final int startTopoheight;
|
||||||
|
const Rescan(this.startTopoheight);
|
||||||
|
}
|
||||||
|
|
||||||
|
class HistorySynced extends Event {
|
||||||
|
final int topoheight;
|
||||||
|
const HistorySynced(this.topoheight);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NewAsset extends Event {
|
||||||
|
final String asset;
|
||||||
|
final int decimals;
|
||||||
|
final int? max_supply;
|
||||||
|
final String name;
|
||||||
|
final String? owner;
|
||||||
|
final String ticker;
|
||||||
|
final int topoheight;
|
||||||
|
const NewAsset(
|
||||||
|
this.asset,
|
||||||
|
this.decimals,
|
||||||
|
this.max_supply,
|
||||||
|
this.name,
|
||||||
|
this.owner,
|
||||||
|
this.ticker,
|
||||||
|
this.topoheight
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SyncError extends Event {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
const SyncError(this.message);
|
||||||
|
}
|
25
cw_xelis/lib/xelis_exception.dart
Normal file
25
cw_xelis/lib/xelis_exception.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
|
||||||
|
class XelisMnemonicIsIncorrectException implements Exception {
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'Xelis mnemonic has incorrect format. Mnemonic should contain 25 words separated by space.';
|
||||||
|
}
|
||||||
|
class XelisTransactionCreationException implements Exception {
|
||||||
|
final String exceptionMessage;
|
||||||
|
|
||||||
|
XelisTransactionCreationException(CryptoCurrency currency)
|
||||||
|
: exceptionMessage = 'Wrong balance. Not enough ${currency.title} on your balance.';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => exceptionMessage;
|
||||||
|
}
|
||||||
|
class XelisTooManyOutputsException implements Exception {
|
||||||
|
final int count;
|
||||||
|
|
||||||
|
XelisTooManyOutputsException(this.count);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() =>
|
||||||
|
'Cannot include more than 255 transfers in a single TX. Attempted to use $count.';
|
||||||
|
}
|
54
cw_xelis/lib/xelis_formatting.dart
Normal file
54
cw_xelis/lib/xelis_formatting.dart
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
class XelisFormatter {
|
||||||
|
static int parseXelisAmount(String amount) {
|
||||||
|
try {
|
||||||
|
return (double.parse(amount) * pow(10, 8)).round();
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double parseXelisAmountToDouble(int amount) {
|
||||||
|
try {
|
||||||
|
return amount / pow(10, 8);
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseAmount(String amount, int decimals) {
|
||||||
|
try {
|
||||||
|
return (double.parse(amount) * pow(10, decimals)).round();
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static double parseAmountToDouble(int amount, int decimals) {
|
||||||
|
try {
|
||||||
|
return amount / pow(10, decimals);
|
||||||
|
} catch (_) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatAmountWithSymbol(
|
||||||
|
int rawAmount, {
|
||||||
|
required int decimals,
|
||||||
|
String? symbol,
|
||||||
|
}) {
|
||||||
|
final formatted = rawAmount / pow(10, decimals);
|
||||||
|
// final symbol = assetId == null || assetId == xelisAsset ? 'XEL' : assetId;
|
||||||
|
final sym = symbol ?? 'XEL';
|
||||||
|
return '$formatted $sym';
|
||||||
|
}
|
||||||
|
|
||||||
|
static String formatAmount(
|
||||||
|
int rawAmount, {
|
||||||
|
required int decimals,
|
||||||
|
}) {
|
||||||
|
final formatted = rawAmount / pow(10, decimals);
|
||||||
|
return '$formatted';
|
||||||
|
}
|
||||||
|
}
|
41
cw_xelis/lib/xelis_pending_transaction.dart
Normal file
41
cw_xelis/lib/xelis_pending_transaction.dart
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import 'package:cw_core/pending_transaction.dart';
|
||||||
|
import 'package:cw_xelis/xelis_formatting.dart';
|
||||||
|
|
||||||
|
class XelisPendingTransaction with PendingTransaction {
|
||||||
|
XelisPendingTransaction(
|
||||||
|
{
|
||||||
|
required this.txid,
|
||||||
|
required this.amount,
|
||||||
|
required this.fee,
|
||||||
|
required this.decimals,
|
||||||
|
required this.send,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String amount;
|
||||||
|
final int fee;
|
||||||
|
final String txid;
|
||||||
|
final int decimals;
|
||||||
|
final Future<void> Function() send;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get id => txid;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get amountFormatted => amount.toString();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get feeFormatted => XelisFormatter.formatAmount(fee, decimals: 8);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get hex => "";
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> commit() async {
|
||||||
|
return send();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<String?> commitUR() {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
27
cw_xelis/lib/xelis_store_utils.dart
Normal file
27
cw_xelis/lib/xelis_store_utils.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:cw_xelis/src/api/network.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
Future<String> pathForXelisNetworkFile(String name) async {
|
||||||
|
final walletDir = await pathForWalletDir(name: name, type: WalletType.xelis);
|
||||||
|
return p.join(walletDir, 'network.txt');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> saveXelisNetwork(String name, Network network) async {
|
||||||
|
final path = await pathForXelisNetworkFile(name);
|
||||||
|
await File(path).writeAsString(network.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Network> loadXelisNetwork(String name) async {
|
||||||
|
final path = await pathForXelisNetworkFile(name);
|
||||||
|
final file = File(path);
|
||||||
|
|
||||||
|
if (!await file.exists()) {
|
||||||
|
throw FileSystemException('Missing Xelis network file', path);
|
||||||
|
}
|
||||||
|
|
||||||
|
final contents = await file.readAsString();
|
||||||
|
return NetworkName.fromName(contents.trim());
|
||||||
|
}
|
12
cw_xelis/lib/xelis_transaction_credentials.dart
Normal file
12
cw_xelis/lib/xelis_transaction_credentials.dart
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import 'package:cw_core/output_info.dart';
|
||||||
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
|
|
||||||
|
import 'package:cw_xelis/xelis_transaction_priority.dart';
|
||||||
|
|
||||||
|
class XelisTransactionCredentials {
|
||||||
|
XelisTransactionCredentials(this.outputs, {required this.priority, required this.currency});
|
||||||
|
|
||||||
|
final List<OutputInfo> outputs;
|
||||||
|
final XelisTransactionPriority? priority;
|
||||||
|
final CryptoCurrency currency;
|
||||||
|
}
|
95
cw_xelis/lib/xelis_transaction_history.dart
Normal file
95
cw_xelis/lib/xelis_transaction_history.dart
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:core';
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/transaction_history.dart';
|
||||||
|
import 'package:cw_xelis/xelis_transaction_info.dart';
|
||||||
|
|
||||||
|
part 'xelis_transaction_history.g.dart';
|
||||||
|
|
||||||
|
const transactionsHistoryFileName = 'xelis_transactions.json';
|
||||||
|
|
||||||
|
class XelisTransactionHistory = XelisTransactionHistoryBase with _$XelisTransactionHistory;
|
||||||
|
|
||||||
|
abstract class XelisTransactionHistoryBase
|
||||||
|
extends TransactionHistoryBase<XelisTransactionInfo> with Store {
|
||||||
|
XelisTransactionHistoryBase(
|
||||||
|
{required this.walletInfo, required String password, required this.encryptionFileUtils})
|
||||||
|
: _password = password {
|
||||||
|
transactions = ObservableMap<String, XelisTransactionInfo>();
|
||||||
|
}
|
||||||
|
|
||||||
|
final WalletInfo walletInfo;
|
||||||
|
final EncryptionFileUtils encryptionFileUtils;
|
||||||
|
String _password;
|
||||||
|
|
||||||
|
Future<void> init() async {
|
||||||
|
clear();
|
||||||
|
await _load();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> save() async {
|
||||||
|
try {
|
||||||
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
|
final transactionMaps = transactions.map((key, value) => MapEntry(key, value.toJson()));
|
||||||
|
final data = json.encode({'transactions': transactionMaps});
|
||||||
|
await encryptionFileUtils.write(path: path, password: _password, data: data);
|
||||||
|
} catch (e, s) {
|
||||||
|
printV('Error while saving xelis transaction history: ${e.toString()}');
|
||||||
|
printV(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addOne(XelisTransactionInfo transaction) =>
|
||||||
|
transactions[transaction.id] = transaction;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addMany(Map<String, XelisTransactionInfo> transactions) =>
|
||||||
|
this.transactions.addAll(transactions);
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> _read() async {
|
||||||
|
final dirPath = await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
|
||||||
|
final path = '$dirPath/$transactionsHistoryFileName';
|
||||||
|
final content = await encryptionFileUtils.read(path: path, password: _password);
|
||||||
|
if (content.isEmpty) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return json.decode(content) as Map<String, dynamic>;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _load() async {
|
||||||
|
try {
|
||||||
|
final content = await _read();
|
||||||
|
final txs = content['transactions'] as Map<String, dynamic>? ?? {};
|
||||||
|
|
||||||
|
txs.entries.forEach((entry) {
|
||||||
|
final val = entry.value;
|
||||||
|
|
||||||
|
if (val is Map<String, dynamic>) {
|
||||||
|
final tx = XelisTransactionInfo.fromJson(val, isAssetEnabled: (id) => true); // asset filtering needs to happen elsewhere before serializing
|
||||||
|
addOne(tx);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
printV(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(Map<String, XelisTransactionInfo> txs) {
|
||||||
|
var foundOldTx = false;
|
||||||
|
txs.forEach((_, tx) {
|
||||||
|
if (!transactions.containsKey(tx.id)) {
|
||||||
|
transactions[tx.id] = tx;
|
||||||
|
} else {
|
||||||
|
foundOldTx = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return foundOldTx;
|
||||||
|
}
|
||||||
|
}
|
319
cw_xelis/lib/xelis_transaction_info.dart
Normal file
319
cw_xelis/lib/xelis_transaction_info.dart
Normal file
|
@ -0,0 +1,319 @@
|
||||||
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
|
import 'package:cw_xelis/xelis_formatting.dart';
|
||||||
|
import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk;
|
||||||
|
import 'package:cw_xelis/src/api/wallet.dart' as x_wallet;
|
||||||
|
import 'package:cw_core/format_amount.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
class XelisTxRecipient {
|
||||||
|
final String address;
|
||||||
|
final String amount;
|
||||||
|
final bool isChange;
|
||||||
|
|
||||||
|
const XelisTxRecipient({
|
||||||
|
required this.address,
|
||||||
|
required this.amount,
|
||||||
|
required this.isChange,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class XelisTransfer {
|
||||||
|
final x_wallet.XelisAssetMetadata meta;
|
||||||
|
final int amount;
|
||||||
|
|
||||||
|
XelisTransfer({
|
||||||
|
required this.meta,
|
||||||
|
required this.amount
|
||||||
|
});
|
||||||
|
|
||||||
|
String format() {
|
||||||
|
final amountDouble = (BigInt.from(amount) / BigInt.from(10).pow(meta.decimals)).toString();
|
||||||
|
return '${formatAmount(amountDouble)} ${meta.ticker}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XelisTransactionInfo extends TransactionInfo {
|
||||||
|
XelisTransactionInfo({
|
||||||
|
required this.id,
|
||||||
|
required this.height,
|
||||||
|
required this.direction,
|
||||||
|
required this.date,
|
||||||
|
required this.xelAmount,
|
||||||
|
required this.xelFee,
|
||||||
|
required this.decimals,
|
||||||
|
required this.assetSymbols,
|
||||||
|
required this.assetIds,
|
||||||
|
required this.assetAmounts,
|
||||||
|
required this.to,
|
||||||
|
required this.from,
|
||||||
|
this.isTestnet = false,
|
||||||
|
}) :
|
||||||
|
amount = xelAmount.toInt(),
|
||||||
|
fee = xelFee.toInt()
|
||||||
|
;
|
||||||
|
|
||||||
|
final String id;
|
||||||
|
final int amount;
|
||||||
|
final int fee;
|
||||||
|
final int height;
|
||||||
|
final BigInt xelAmount;
|
||||||
|
final BigInt xelFee;
|
||||||
|
final DateTime date;
|
||||||
|
final TransactionDirection direction;
|
||||||
|
final List<BigInt> assetAmounts;
|
||||||
|
final List<int> decimals;
|
||||||
|
final List<String> assetSymbols;
|
||||||
|
final List<String> assetIds;
|
||||||
|
final String? to;
|
||||||
|
final String? from;
|
||||||
|
final bool isTestnet;
|
||||||
|
final int confirmations = 3; // static/unused atm, purely for compatibility
|
||||||
|
|
||||||
|
String? _fiatAmount;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String amountFormatted() {
|
||||||
|
final List<String> formattedAssets = [];
|
||||||
|
|
||||||
|
if (formattedAssets.length > 1) return ":MULTI:" + multiFormatted();
|
||||||
|
|
||||||
|
final amount = (assetAmounts[0] / BigInt.from(10).pow(decimals[0])).toString();
|
||||||
|
return '$amount ${assetSymbols[0]}';
|
||||||
|
}
|
||||||
|
|
||||||
|
String multiFormatted() {
|
||||||
|
final List<String> formattedAssets = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < assetSymbols.length; i++) {
|
||||||
|
final amount = (assetAmounts[i] / BigInt.from(10).pow(decimals[i])).toString();
|
||||||
|
formattedAssets.add('$amount ${assetSymbols[i]}');
|
||||||
|
}
|
||||||
|
|
||||||
|
return formattedAssets.join('\n\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String feeFormatted() =>
|
||||||
|
XelisFormatter.formatAmountWithSymbol(fee, decimals: 8, symbol: isTestnet ? 'XET' : 'XEL');
|
||||||
|
|
||||||
|
@override
|
||||||
|
String fiatAmount() => _fiatAmount ?? '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
void changeFiatAmount(String amount) {
|
||||||
|
_fiatAmount = formatAmount(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<XelisTransactionInfo> fromTransactionEntry(
|
||||||
|
xelis_sdk.TransactionEntry entry,
|
||||||
|
{required x_wallet.XelisWallet wallet, required bool Function(String assetId) isAssetEnabled, bool isTestnet = false}
|
||||||
|
) async {
|
||||||
|
final txType = entry.txEntryType;
|
||||||
|
|
||||||
|
late TransactionDirection direction;
|
||||||
|
BigInt amount = BigInt.zero;
|
||||||
|
BigInt fee = BigInt.zero;
|
||||||
|
String? to;
|
||||||
|
String? from;
|
||||||
|
|
||||||
|
String asset = xelis_sdk.xelisAsset;
|
||||||
|
|
||||||
|
final Map<String, BigInt> assetAmounts = {};
|
||||||
|
final Map<String, int> assetDecimals = {};
|
||||||
|
final Map<String, String> assetSymbolsMap = {};
|
||||||
|
|
||||||
|
switch (txType) {
|
||||||
|
case xelis_sdk.IncomingEntry():
|
||||||
|
direction = TransactionDirection.incoming;
|
||||||
|
|
||||||
|
for (final transfer in txType.transfers) {
|
||||||
|
final asset = transfer.asset;
|
||||||
|
if (!isAssetEnabled(asset)) continue;
|
||||||
|
|
||||||
|
assetAmounts[asset] = (assetAmounts[asset] ?? BigInt.zero) + BigInt.from(transfer.amount);
|
||||||
|
|
||||||
|
final meta = await wallet.getAssetMetadata(asset: asset);
|
||||||
|
assetDecimals[asset] = meta.decimals;
|
||||||
|
assetSymbolsMap[asset] = meta.ticker;
|
||||||
|
}
|
||||||
|
|
||||||
|
from = txType.from;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xelis_sdk.OutgoingEntry():
|
||||||
|
direction = TransactionDirection.outgoing;
|
||||||
|
|
||||||
|
final formattedTransfers = <String>[];
|
||||||
|
|
||||||
|
for (final transfer in txType.transfers) {
|
||||||
|
final asset = transfer.asset;
|
||||||
|
if (!isAssetEnabled(asset)) continue;
|
||||||
|
|
||||||
|
final meta = await wallet.getAssetMetadata(asset: asset);
|
||||||
|
final formatted = XelisTransfer(meta: meta, amount: transfer.amount).format();
|
||||||
|
|
||||||
|
assetDecimals[asset] = meta.decimals;
|
||||||
|
assetSymbolsMap[asset] = meta.ticker;
|
||||||
|
assetAmounts[asset] = (assetAmounts[asset] ?? BigInt.zero) + BigInt.from(transfer.amount);
|
||||||
|
|
||||||
|
if (txType.transfers.length > 1) {
|
||||||
|
formattedTransfers.add("${transfer.destination} [ $formatted ]");
|
||||||
|
} else {
|
||||||
|
formattedTransfers.add("${transfer.destination}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
to = formattedTransfers.join('\n\n');
|
||||||
|
fee = BigInt.from(txType.fee);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xelis_sdk.BurnEntry():
|
||||||
|
direction = TransactionDirection.outgoing;
|
||||||
|
final asset = txType.asset;
|
||||||
|
final meta = await wallet.getAssetMetadata(asset: asset);
|
||||||
|
|
||||||
|
if (!isAssetEnabled(asset)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
assetAmounts[asset] = BigInt.from(txType.amount);
|
||||||
|
assetDecimals[asset] = meta.decimals;
|
||||||
|
assetSymbolsMap[asset] = meta.ticker;
|
||||||
|
|
||||||
|
to = "Burned";
|
||||||
|
|
||||||
|
fee = BigInt.from(txType.fee);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xelis_sdk.CoinbaseEntry():
|
||||||
|
direction = TransactionDirection.incoming;
|
||||||
|
final meta = await wallet.getAssetMetadata(asset: xelis_sdk.xelisAsset);
|
||||||
|
|
||||||
|
assetAmounts[xelis_sdk.xelisAsset] = BigInt.from(txType.reward);
|
||||||
|
assetDecimals[xelis_sdk.xelisAsset] = meta.decimals;
|
||||||
|
assetSymbolsMap[xelis_sdk.xelisAsset] = meta.ticker;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xelis_sdk.InvokeContractEntry():
|
||||||
|
direction = TransactionDirection.outgoing;
|
||||||
|
|
||||||
|
for (final entry in txType.deposits.entries) {
|
||||||
|
final asset = entry.key;
|
||||||
|
final amount = entry.value;
|
||||||
|
|
||||||
|
if (!isAssetEnabled(asset)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assetAmounts[asset] = (assetAmounts[asset] ?? BigInt.zero) + BigInt.from(amount);
|
||||||
|
|
||||||
|
final meta = await wallet.getAssetMetadata(asset: asset);
|
||||||
|
assetDecimals[asset] = meta.decimals;
|
||||||
|
assetSymbolsMap[asset] = meta.ticker;
|
||||||
|
}
|
||||||
|
|
||||||
|
fee = BigInt.from(txType.fee);
|
||||||
|
to = "SCID:\n${txType.contract}\n\nChunk ID:\n${txType.chunkId}";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case xelis_sdk.DeployContractEntry():
|
||||||
|
direction = TransactionDirection.outgoing;
|
||||||
|
|
||||||
|
final meta = await wallet.getAssetMetadata(asset: xelis_sdk.xelisAsset);
|
||||||
|
|
||||||
|
assetAmounts[xelis_sdk.xelisAsset] = BigInt.zero;
|
||||||
|
assetDecimals[xelis_sdk.xelisAsset] = meta.decimals;
|
||||||
|
assetSymbolsMap[xelis_sdk.xelisAsset] = meta.ticker;
|
||||||
|
fee = BigInt.from(txType.fee);
|
||||||
|
|
||||||
|
default:
|
||||||
|
direction = TransactionDirection.outgoing;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
final filteredAssetIds = assetAmounts.keys.where(isAssetEnabled).toList();
|
||||||
|
final assetIds = filteredAssetIds;
|
||||||
|
final assetSymbols = assetIds.map((id) => assetSymbolsMap[id] ?? '???').toList();
|
||||||
|
final decimals = assetIds.map((id) => assetDecimals[id] ?? 8).toList();
|
||||||
|
final amounts = assetIds.map((id) => assetAmounts[id]!).toList();
|
||||||
|
|
||||||
|
final xelAmount = assetAmounts[xelis_sdk.xelisAsset] ?? BigInt.zero;
|
||||||
|
|
||||||
|
return XelisTransactionInfo(
|
||||||
|
id: entry.hash,
|
||||||
|
height: entry.topoheight,
|
||||||
|
direction: direction,
|
||||||
|
date: entry.timestamp ?? DateTime.now(),
|
||||||
|
xelAmount: xelAmount,
|
||||||
|
xelFee: fee,
|
||||||
|
to: to,
|
||||||
|
from: from,
|
||||||
|
decimals: decimals,
|
||||||
|
assetSymbols: assetSymbols,
|
||||||
|
assetIds: assetIds,
|
||||||
|
assetAmounts: amounts,
|
||||||
|
isTestnet: isTestnet
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory XelisTransactionInfo.fromJson(
|
||||||
|
Map<String, dynamic> data, {
|
||||||
|
required bool Function(String assetId) isAssetEnabled,
|
||||||
|
}) {
|
||||||
|
final allAssetIds = List<String>.from(data['assetIds']);
|
||||||
|
final allAssetSymbols = List<String>.from(data['assetSymbols']);
|
||||||
|
final allAssetAmounts = (data['assetAmounts'] as List)
|
||||||
|
.map<BigInt>((val) => BigInt.parse(val.toString()))
|
||||||
|
.toList();
|
||||||
|
final allDecimals = List<int>.from(data['decimals']);
|
||||||
|
|
||||||
|
final filteredIndices = <int>[];
|
||||||
|
for (int i = 0; i < allAssetIds.length; i++) {
|
||||||
|
if (isAssetEnabled(allAssetIds[i])) {
|
||||||
|
filteredIndices.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final assetIds = filteredIndices.map((i) => allAssetIds[i]).toList();
|
||||||
|
final assetSymbols = filteredIndices.map((i) => allAssetSymbols[i]).toList();
|
||||||
|
final assetAmounts = filteredIndices.map((i) => allAssetAmounts[i]).toList();
|
||||||
|
final decimals = filteredIndices.map((i) => allDecimals[i]).toList();
|
||||||
|
|
||||||
|
final xelAmount = assetAmounts.isNotEmpty ? assetAmounts[0] : BigInt.zero;
|
||||||
|
|
||||||
|
return XelisTransactionInfo(
|
||||||
|
id: data['id'] as String,
|
||||||
|
height: data['height'] as int,
|
||||||
|
decimals: decimals,
|
||||||
|
assetAmounts: assetAmounts,
|
||||||
|
xelAmount: xelAmount,
|
||||||
|
xelFee: BigInt.parse(data['xelFee']),
|
||||||
|
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
||||||
|
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
||||||
|
assetSymbols: assetSymbols,
|
||||||
|
assetIds: assetIds,
|
||||||
|
to: data['to'],
|
||||||
|
from: data['from'],
|
||||||
|
isTestnet: data['isTestnet'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'id': id,
|
||||||
|
'height': height,
|
||||||
|
'decimals': decimals,
|
||||||
|
'assetSymbols': assetSymbols,
|
||||||
|
'assetIds': assetIds,
|
||||||
|
'assetAmounts': assetAmounts.map((e) => e.toString()).toList(),
|
||||||
|
'xelAmount': xelAmount.toString(),
|
||||||
|
'xelFee': xelFee.toString(),
|
||||||
|
'direction': direction.index,
|
||||||
|
'date': date.millisecondsSinceEpoch,
|
||||||
|
'to': to,
|
||||||
|
'from': from,
|
||||||
|
'isTestnet': isTestnet,
|
||||||
|
};
|
||||||
|
}
|
48
cw_xelis/lib/xelis_transaction_priority.dart
Normal file
48
cw_xelis/lib/xelis_transaction_priority.dart
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
|
|
||||||
|
class XelisTransactionPriority extends TransactionPriority {
|
||||||
|
const XelisTransactionPriority({required String title, required int raw})
|
||||||
|
: super(title: title, raw: raw);
|
||||||
|
|
||||||
|
static const List<XelisTransactionPriority> all = [medium];
|
||||||
|
static const XelisTransactionPriority slow = XelisTransactionPriority(title: 'Slow', raw: 1);
|
||||||
|
static const XelisTransactionPriority medium =
|
||||||
|
XelisTransactionPriority(title: 'Medium', raw: 2);
|
||||||
|
static const XelisTransactionPriority fast = XelisTransactionPriority(title: 'Fast', raw: 4);
|
||||||
|
|
||||||
|
static XelisTransactionPriority deserialize({required int raw}) {
|
||||||
|
switch (raw) {
|
||||||
|
case 1:
|
||||||
|
return slow;
|
||||||
|
case 2:
|
||||||
|
return medium;
|
||||||
|
case 4:
|
||||||
|
return fast;
|
||||||
|
default:
|
||||||
|
throw Exception('Unexpected token: $raw for XelisTransactionPriority deserialize');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String get units => 'atom';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var label = '';
|
||||||
|
|
||||||
|
switch (this) {
|
||||||
|
case XelisTransactionPriority.slow:
|
||||||
|
label = 'Slow';
|
||||||
|
break;
|
||||||
|
case XelisTransactionPriority.medium:
|
||||||
|
label = 'Standard';
|
||||||
|
break;
|
||||||
|
case XelisTransactionPriority.fast:
|
||||||
|
label = 'Fast';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
}
|
1051
cw_xelis/lib/xelis_wallet.dart
Normal file
1051
cw_xelis/lib/xelis_wallet.dart
Normal file
File diff suppressed because it is too large
Load diff
61
cw_xelis/lib/xelis_wallet_addresses.dart
Normal file
61
cw_xelis/lib/xelis_wallet_addresses.dart
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cw_core/wallet_addresses.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/address_info.dart';
|
||||||
|
import 'package:cw_xelis/src/api/wallet.dart' as x_wallet;
|
||||||
|
|
||||||
|
part 'xelis_wallet_addresses.g.dart';
|
||||||
|
|
||||||
|
class XelisWalletAddresses = XelisWalletAddressesBase with _$XelisWalletAddresses;
|
||||||
|
|
||||||
|
abstract class XelisWalletAddressesBase extends WalletAddresses with Store {
|
||||||
|
XelisWalletAddressesBase(this.walletInfo, this.wallet)
|
||||||
|
: super(walletInfo);
|
||||||
|
|
||||||
|
final WalletInfo walletInfo;
|
||||||
|
final x_wallet.XelisWallet wallet;
|
||||||
|
@observable
|
||||||
|
String selectedAddr = '';
|
||||||
|
|
||||||
|
@override
|
||||||
|
@computed
|
||||||
|
String get address {
|
||||||
|
return selectedAddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
set address(String addr) {
|
||||||
|
selectedAddr = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> init() async {
|
||||||
|
address = wallet.getAddressStr();
|
||||||
|
addressesMap[address] = '';
|
||||||
|
addressInfos[0] = [
|
||||||
|
AddressInfo(
|
||||||
|
address: address,
|
||||||
|
label: '',
|
||||||
|
accountIndex: 0,
|
||||||
|
)
|
||||||
|
];
|
||||||
|
usedAddresses.add(address);
|
||||||
|
await saveAddressesInBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> updateAddressesInBox() async {}
|
||||||
|
|
||||||
|
List<AddressInfo> getAddressInfos() => addressInfos[0] ?? [];
|
||||||
|
|
||||||
|
Future<void> updateAddress(String addr, String label) async {
|
||||||
|
final infos = addressInfos[0];
|
||||||
|
if (infos == null) return;
|
||||||
|
for (var info in infos) {
|
||||||
|
if (info.address == addr) {
|
||||||
|
info.label = label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await saveAddressesInBox();
|
||||||
|
}
|
||||||
|
}
|
15
cw_xelis/lib/xelis_wallet_creation_credentials.dart
Normal file
15
cw_xelis/lib/xelis_wallet_creation_credentials.dart
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
|
|
||||||
|
class XelisNewWalletCredentials extends WalletCredentials {
|
||||||
|
XelisNewWalletCredentials(
|
||||||
|
{required String name, String? password})
|
||||||
|
: super(name: name, password: password);
|
||||||
|
}
|
||||||
|
|
||||||
|
class XelisRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||||
|
XelisRestoreWalletFromSeedCredentials(
|
||||||
|
{required String name, required this.mnemonic, int height = 0, String? password})
|
||||||
|
: super(name: name, password: password, height: height);
|
||||||
|
|
||||||
|
final String mnemonic;
|
||||||
|
}
|
497
cw_xelis/lib/xelis_wallet_service.dart
Normal file
497
cw_xelis/lib/xelis_wallet_service.dart
Normal file
|
@ -0,0 +1,497 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:system_info2/system_info2.dart';
|
||||||
|
|
||||||
|
import 'package:cw_core/wallet_base.dart';
|
||||||
|
import 'package:cw_core/wallet_service.dart';
|
||||||
|
import 'package:cw_core/pathForWallet.dart';
|
||||||
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
import 'package:cw_core/root_dir.dart';
|
||||||
|
import 'package:cw_core/encryption_file_utils.dart';
|
||||||
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
|
||||||
|
import 'package:cw_xelis/xelis_wallet.dart';
|
||||||
|
import 'package:cw_xelis/src/api/network.dart';
|
||||||
|
import 'package:cw_xelis/src/api/wallet.dart' as x_wallet;
|
||||||
|
import 'package:cw_xelis/xelis_wallet_creation_credentials.dart';
|
||||||
|
import 'package:cw_xelis/xelis_store_utils.dart';
|
||||||
|
import 'package:cw_xelis/src/api/logger.dart' as x_logger;
|
||||||
|
import 'package:cw_xelis/src/api/api.dart' as x_api;
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
|
|
||||||
|
class MemoryTierCalculator {
|
||||||
|
Future<int> getDeviceRAMInGB() async {
|
||||||
|
if (kIsWeb) return 2; // Default for web
|
||||||
|
|
||||||
|
try {
|
||||||
|
final totalRAM = SysInfo.getTotalPhysicalMemory();
|
||||||
|
// Convert bytes to GB (1 GB = 1024³ bytes)
|
||||||
|
final ramGB = totalRAM / (1024 * 1024 * 1024);
|
||||||
|
return ramGB.round();
|
||||||
|
} catch (e) {
|
||||||
|
print('Error getting RAM info: $e');
|
||||||
|
return 4; // Default fallback
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class XelisLoggerFactory {
|
||||||
|
static bool _isSetup = false;
|
||||||
|
static const LOG_LEVEL = 3;
|
||||||
|
/*
|
||||||
|
Log level for FFI Rust outputs in xelis_flutter
|
||||||
|
|
||||||
|
0: None
|
||||||
|
1: Error
|
||||||
|
2: Warn
|
||||||
|
3: Info
|
||||||
|
4: Debug
|
||||||
|
5: Trace
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
static Future<void> setupIfNeeded() async {
|
||||||
|
if (_isSetup) return;
|
||||||
|
await x_api.setUpRustLogger();
|
||||||
|
_setupLogStream();
|
||||||
|
_isSetup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _setupLogStream() {
|
||||||
|
x_api.createLogStream().listen((entry) {
|
||||||
|
final logLine = 'XELIS LOG | [${entry.level.name}] ${entry.tag}: ${entry.msg}';
|
||||||
|
|
||||||
|
switch (entry.level) {
|
||||||
|
case x_logger.Level.error:
|
||||||
|
if (LOG_LEVEL > 0) {
|
||||||
|
printV('❌ $logLine');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case x_logger.Level.warn:
|
||||||
|
if (LOG_LEVEL > 1) {
|
||||||
|
printV('⚠️ $logLine');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case x_logger.Level.info:
|
||||||
|
if (LOG_LEVEL > 2) {
|
||||||
|
printV('ℹ️ $logLine');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case x_logger.Level.debug:
|
||||||
|
if (LOG_LEVEL > 3) {
|
||||||
|
printV('🐛 $logLine');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case x_logger.Level.trace:
|
||||||
|
if (LOG_LEVEL > 4) {
|
||||||
|
printV('🔍 $logLine');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onError: (dynamic e) {
|
||||||
|
printV("Error receiving Xelis Rust logs: $e");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum XelisTableSize {
|
||||||
|
initial,
|
||||||
|
web,
|
||||||
|
low,
|
||||||
|
medium,
|
||||||
|
high;
|
||||||
|
|
||||||
|
BigInt get l1Size {
|
||||||
|
switch (this) {
|
||||||
|
case XelisTableSize.initial:
|
||||||
|
case XelisTableSize.web:
|
||||||
|
return BigInt.from(23);
|
||||||
|
case XelisTableSize.low:
|
||||||
|
return BigInt.from(24);
|
||||||
|
case XelisTableSize.medium:
|
||||||
|
return BigInt.from(25);
|
||||||
|
case XelisTableSize.high:
|
||||||
|
return BigInt.from(26);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<XelisTableSize> getPlatformDefault() async {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return XelisTableSize.web;
|
||||||
|
}
|
||||||
|
|
||||||
|
final calculator = MemoryTierCalculator();
|
||||||
|
final ramInGB = await calculator.getDeviceRAMInGB();
|
||||||
|
|
||||||
|
if (ramInGB <= 2) {
|
||||||
|
return XelisTableSize.web;
|
||||||
|
} else if (ramInGB <= 4) {
|
||||||
|
return XelisTableSize.low;
|
||||||
|
} else if (ramInGB <= 8) {
|
||||||
|
return XelisTableSize.medium;
|
||||||
|
} else {
|
||||||
|
return XelisTableSize.high;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool get kIsMobile {
|
||||||
|
if (kIsWeb) return false;
|
||||||
|
return Platform.isAndroid || Platform.isIOS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Future<BigInt> getTableSize() async {
|
||||||
|
final tableSize = await XelisTableSize.getPlatformDefault();
|
||||||
|
return tableSize.l1Size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class XelisTableState {
|
||||||
|
final XelisTableSize currentSize;
|
||||||
|
final XelisTableSize _desiredSize;
|
||||||
|
|
||||||
|
XelisTableSize get desiredSize {
|
||||||
|
if (kIsWeb) {
|
||||||
|
return XelisTableSize.low;
|
||||||
|
}
|
||||||
|
return _desiredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const XelisTableState({
|
||||||
|
this.currentSize = XelisTableSize.low,
|
||||||
|
XelisTableSize desiredSize = XelisTableSize.high,
|
||||||
|
}) : _desiredSize = desiredSize;
|
||||||
|
|
||||||
|
XelisTableState copyWith({
|
||||||
|
XelisTableSize? currentSize,
|
||||||
|
XelisTableSize? desiredSize,
|
||||||
|
}) {
|
||||||
|
return XelisTableState(
|
||||||
|
currentSize: currentSize ?? this.currentSize,
|
||||||
|
desiredSize: kIsWeb ? XelisTableSize.low : (desiredSize ?? this._desiredSize),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
factory XelisTableState.fromJson(Map<String, dynamic> json) {
|
||||||
|
return XelisTableState(
|
||||||
|
currentSize: XelisTableSize.values[json['currentSize'] as int],
|
||||||
|
desiredSize: XelisTableSize.values[json['desiredSize'] as int],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'currentSize': currentSize.index,
|
||||||
|
'desiredSize': _desiredSize.index,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
class XelisWalletService extends WalletService<
|
||||||
|
XelisNewWalletCredentials,
|
||||||
|
XelisRestoreWalletFromSeedCredentials, // TODO: add view key credentials when supported by Xelis
|
||||||
|
XelisNewWalletCredentials,
|
||||||
|
XelisNewWalletCredentials
|
||||||
|
> {
|
||||||
|
XelisWalletService(this.walletInfoSource, {required this.isDirect}) {
|
||||||
|
XelisLoggerFactory.setupIfNeeded();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final bool isDirect;
|
||||||
|
|
||||||
|
static bool isGenerating = false;
|
||||||
|
static final _tableUpgradeMutex = Mutex();
|
||||||
|
static Completer<void>? _tableUpgradeCompleter;
|
||||||
|
static XelisWallet? _activeWallet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
WalletType getType() => WalletType.xelis;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isWalletExit(String name) async =>
|
||||||
|
await File(await pathForWalletDir(name: name, type: getType())).exists();
|
||||||
|
|
||||||
|
Future<void> _closeActiveWalletIfNeeded() async {
|
||||||
|
if (_activeWallet != null) {
|
||||||
|
try {
|
||||||
|
await _activeWallet!.close();
|
||||||
|
} catch (e) {
|
||||||
|
printV("Error closing active Xelis wallet: $e");
|
||||||
|
}
|
||||||
|
_activeWallet = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<XelisTableState> _getTableState() async {
|
||||||
|
final tablesPath = await _getTablePath();
|
||||||
|
final tablesDir = Directory(tablesPath);
|
||||||
|
final desiredSize = await XelisTableSize.getPlatformDefault();
|
||||||
|
|
||||||
|
final files = await tablesDir.list().toList();
|
||||||
|
|
||||||
|
// Check for the device-appropriate full table
|
||||||
|
final expectedFullTableName = 'tables_${desiredSize.l1Size}.bin';
|
||||||
|
|
||||||
|
final hasFullTables = files.any((file) =>
|
||||||
|
file is File && file.path.contains(expectedFullTableName)
|
||||||
|
);
|
||||||
|
|
||||||
|
final hasLowTables = files.isNotEmpty;
|
||||||
|
|
||||||
|
final currentSize = hasFullTables
|
||||||
|
? desiredSize
|
||||||
|
: hasLowTables
|
||||||
|
? XelisTableSize.initial
|
||||||
|
: XelisTableSize.initial;
|
||||||
|
|
||||||
|
return XelisTableState(
|
||||||
|
currentSize: currentSize,
|
||||||
|
desiredSize: desiredSize,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> _getTablePath() async {
|
||||||
|
final root = await getAppDir();
|
||||||
|
final prefix = walletTypeToString(getType()).toLowerCase();
|
||||||
|
final tablesDir = Directory('${root.path}/wallets/$prefix/tables/');
|
||||||
|
|
||||||
|
if (!await tablesDir.exists()) {
|
||||||
|
await tablesDir.create(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tablesDir.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<XelisWallet> create(XelisNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||||
|
final fullPath = await pathForWalletDir(name: credentials.name, type: getType());
|
||||||
|
final tableState = await _getTableState();
|
||||||
|
final tablesRoot = await _getTablePath();
|
||||||
|
|
||||||
|
final network = isTestnet == true ? Network.testnet : Network.mainnet;
|
||||||
|
|
||||||
|
await _closeActiveWalletIfNeeded();
|
||||||
|
final frbWallet = await x_wallet.createXelisWallet(
|
||||||
|
name: fullPath,
|
||||||
|
directory: "",
|
||||||
|
password: credentials.password ?? "x",
|
||||||
|
network: network,
|
||||||
|
precomputedTablesPath: tablesRoot,
|
||||||
|
l1Size: (await _getTableState()).currentSize.l1Size,
|
||||||
|
);
|
||||||
|
|
||||||
|
credentials.walletInfo!.address = frbWallet.getAddressStr();
|
||||||
|
credentials.walletInfo!.network = network.name;
|
||||||
|
|
||||||
|
final wallet = XelisWallet(
|
||||||
|
walletInfo:credentials.walletInfo!,
|
||||||
|
libWallet: frbWallet,
|
||||||
|
password: credentials.password ?? "x",
|
||||||
|
network: network,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
unawaited(_upgradeTablesIfNeeded());
|
||||||
|
_activeWallet = wallet;
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<XelisWallet> openWallet(String name, String password) async {
|
||||||
|
final walletInfo = walletInfoSource.values
|
||||||
|
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
||||||
|
|
||||||
|
final fullPath = await pathForWalletDir(name: name, type: getType());
|
||||||
|
final tableState = await _getTableState();
|
||||||
|
final tablesRoot = await _getTablePath();
|
||||||
|
|
||||||
|
late final Network network;
|
||||||
|
|
||||||
|
if (walletInfo?.network != null) {
|
||||||
|
network = NetworkName.fromName(walletInfo!.network!);
|
||||||
|
} else {
|
||||||
|
network = await loadXelisNetwork(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
await _closeActiveWalletIfNeeded();
|
||||||
|
|
||||||
|
late final x_wallet.XelisWallet frbWallet;
|
||||||
|
try {
|
||||||
|
frbWallet = await x_wallet.openXelisWallet(
|
||||||
|
name: fullPath,
|
||||||
|
directory: "",
|
||||||
|
password: password,
|
||||||
|
network: network,
|
||||||
|
precomputedTablesPath: tablesRoot,
|
||||||
|
l1Size: (await _getTableState()).currentSize.l1Size,
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
try {
|
||||||
|
await restoreWalletFilesFromBackup(name);
|
||||||
|
frbWallet = await x_wallet.openXelisWallet(
|
||||||
|
name: fullPath,
|
||||||
|
directory: "",
|
||||||
|
password: password,
|
||||||
|
network: network,
|
||||||
|
precomputedTablesPath: tablesRoot,
|
||||||
|
l1Size: (await _getTableState()).currentSize.l1Size,
|
||||||
|
);
|
||||||
|
} catch(_) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final wallet = XelisWallet(
|
||||||
|
walletInfo: walletInfo,
|
||||||
|
libWallet: frbWallet,
|
||||||
|
password: password,
|
||||||
|
network: network,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
saveBackup(name);
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
unawaited(_upgradeTablesIfNeeded());
|
||||||
|
_activeWallet = wallet;
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> rename(String currentName, String password, String newName) async {
|
||||||
|
final currentWalletInfo = walletInfoSource.values
|
||||||
|
.firstWhere((info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||||
|
|
||||||
|
final fullPath = await pathForWalletDir(name: currentName, type: getType());
|
||||||
|
|
||||||
|
final newPath = await pathForWalletDir(name: newName, type: getType());
|
||||||
|
final newDir = Directory(newPath);
|
||||||
|
final exists = await newDir.exists();
|
||||||
|
if (exists) {
|
||||||
|
throw 'A wallet with this name already exists.';
|
||||||
|
}
|
||||||
|
|
||||||
|
await Directory(fullPath).rename(newPath);
|
||||||
|
await saveBackup(newName);
|
||||||
|
|
||||||
|
final newWalletInfo = currentWalletInfo;
|
||||||
|
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||||
|
newWalletInfo.name = newName;
|
||||||
|
newWalletInfo.dirPath = await pathForWalletDir(name: newName, type: getType());
|
||||||
|
|
||||||
|
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> remove(String wallet) async {
|
||||||
|
File(await pathForWalletDir(name: wallet, type: getType())).deleteSync(recursive: true);
|
||||||
|
|
||||||
|
final walletInfo = walletInfoSource.values
|
||||||
|
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
|
||||||
|
|
||||||
|
await walletInfoSource.delete(walletInfo.key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<XelisWallet> restoreFromSeed(XelisRestoreWalletFromSeedCredentials credentials, {bool? isTestnet}) async {
|
||||||
|
final fullPath = await pathForWalletDir(name: credentials.walletInfo!.name, type: getType());
|
||||||
|
final tableState = await _getTableState();
|
||||||
|
final tablesRoot = await _getTablePath();
|
||||||
|
|
||||||
|
final network = isTestnet == true ? Network.testnet : Network.mainnet;
|
||||||
|
|
||||||
|
await _closeActiveWalletIfNeeded();
|
||||||
|
final frbWallet = await x_wallet.createXelisWallet(
|
||||||
|
name: fullPath,
|
||||||
|
directory: "",
|
||||||
|
password: credentials.password ?? "x",
|
||||||
|
seed: credentials.mnemonic,
|
||||||
|
network: network,
|
||||||
|
precomputedTablesPath: tablesRoot,
|
||||||
|
l1Size: (await _getTableState()).currentSize.l1Size,
|
||||||
|
);
|
||||||
|
|
||||||
|
credentials.walletInfo!.address = frbWallet.getAddressStr();
|
||||||
|
credentials.walletInfo!.network = network.name;
|
||||||
|
|
||||||
|
final wallet = XelisWallet(
|
||||||
|
walletInfo: credentials.walletInfo!,
|
||||||
|
libWallet: frbWallet,
|
||||||
|
password: credentials.password ?? "x",
|
||||||
|
network: network,
|
||||||
|
encryptionFileUtils: encryptionFileUtilsFor(isDirect),
|
||||||
|
);
|
||||||
|
await wallet.init();
|
||||||
|
await wallet.save();
|
||||||
|
unawaited(_upgradeTablesIfNeeded());
|
||||||
|
_activeWallet = wallet;
|
||||||
|
return wallet;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _upgradeTablesIfNeeded() async {
|
||||||
|
if (isGenerating || kIsWeb) return;
|
||||||
|
|
||||||
|
if (_tableUpgradeCompleter != null) {
|
||||||
|
try {
|
||||||
|
await _tableUpgradeCompleter!.future;
|
||||||
|
return;
|
||||||
|
} catch (_) {
|
||||||
|
// Previous upgrade failed, try again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await _tableUpgradeMutex.protect(() async {
|
||||||
|
if (_tableUpgradeCompleter != null) {
|
||||||
|
try {
|
||||||
|
await _tableUpgradeCompleter!.future;
|
||||||
|
return;
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
final state = await _getTableState();
|
||||||
|
if (state.currentSize == state.desiredSize) return;
|
||||||
|
|
||||||
|
_tableUpgradeCompleter = Completer<void>();
|
||||||
|
isGenerating = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
printV("Xelis: Starting background table generation...");
|
||||||
|
|
||||||
|
final tablesPath = await _getTablePath();
|
||||||
|
|
||||||
|
await x_wallet.updateTables(
|
||||||
|
precomputedTablesPath: tablesPath,
|
||||||
|
l1Size: await getTableSize(),
|
||||||
|
);
|
||||||
|
|
||||||
|
printV("Xelis: Table upgrade to ${state.desiredSize.name} complete");
|
||||||
|
_tableUpgradeCompleter?.complete();
|
||||||
|
} catch (e, s) {
|
||||||
|
printV("Xelis: Failed to generate tables, $e, $s");
|
||||||
|
_tableUpgradeCompleter?.completeError(e);
|
||||||
|
} finally {
|
||||||
|
isGenerating = false;
|
||||||
|
_tableUpgradeCompleter = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<XelisWallet> restoreFromHardwareWallet(
|
||||||
|
XelisNewWalletCredentials credentials) async =>
|
||||||
|
throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<XelisWallet> restoreFromKeys(
|
||||||
|
XelisNewWalletCredentials credentials, {bool? isTestnet}) async =>
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
91
cw_xelis/pubspec.yaml
Normal file
91
cw_xelis/pubspec.yaml
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
name: cw_xelis
|
||||||
|
description: "A new Flutter plugin project."
|
||||||
|
version: 0.0.1
|
||||||
|
homepage:
|
||||||
|
publish_to: none
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.6.0 <4.0.0'
|
||||||
|
flutter: ">=1.17.0"
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
flutter:
|
||||||
|
sdk: flutter
|
||||||
|
http: ^1.1.0
|
||||||
|
path_provider: ^2.0.11
|
||||||
|
mobx: ^2.0.7+4
|
||||||
|
shared_preferences: ^2.0.15
|
||||||
|
flutter_mobx: ^2.0.6+1
|
||||||
|
intl: ^0.19.0
|
||||||
|
cw_core:
|
||||||
|
path: ../cw_core
|
||||||
|
xelis_flutter:
|
||||||
|
git:
|
||||||
|
url: https://github.com/xelis-project/xelis-flutter-ffi.git
|
||||||
|
ref: 83bda92f1b833fe5d8584aa429d5143a3698b33f
|
||||||
|
# path: ./xelis-flutter-ffi
|
||||||
|
xelis_dart_sdk: ^0.28.0
|
||||||
|
mutex: ^3.1.0
|
||||||
|
hive: ^2.2.3
|
||||||
|
system_info2: ^4.0.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
flutter_test:
|
||||||
|
sdk: flutter
|
||||||
|
flutter_lints: ^5.0.0
|
||||||
|
build_runner: ^2.4.7
|
||||||
|
mobx_codegen: ^2.3.0
|
||||||
|
hive_generator: ^2.0.1
|
||||||
|
build: ^2.4.0
|
||||||
|
path: ^1.8.3
|
||||||
|
analyzer: ^6.2.0
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
watcher: ^1.1.0
|
||||||
|
|
||||||
|
# For information on the generic Dart part of this file, see the
|
||||||
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
# The following section is specific to Flutter packages.
|
||||||
|
flutter:
|
||||||
|
# This section identifies this Flutter project as a plugin project.
|
||||||
|
# The 'pluginClass' specifies the class (in Java, Kotlin, Swift, Objective-C, etc.)
|
||||||
|
# which should be registered in the plugin registry. This is required for
|
||||||
|
# using method channels.
|
||||||
|
# The Android 'package' specifies package in which the registered class is.
|
||||||
|
# This is required for using method channels on Android.
|
||||||
|
# The 'ffiPlugin' specifies that native code should be built and bundled.
|
||||||
|
# This is required for using `dart:ffi`.
|
||||||
|
# All these are used by the tooling to maintain consistency when
|
||||||
|
# adding or updating assets for this project.
|
||||||
|
|
||||||
|
# To add assets to your plugin package, add an assets section, like this:
|
||||||
|
# assets:
|
||||||
|
# - images/a_dot_burr.jpeg
|
||||||
|
# - images/a_dot_ham.jpeg
|
||||||
|
#
|
||||||
|
# For details regarding assets in packages, see
|
||||||
|
# https://flutter.dev/to/asset-from-package
|
||||||
|
#
|
||||||
|
# An image asset can refer to one or more resolution-specific "variants", see
|
||||||
|
# https://flutter.dev/to/resolution-aware-images
|
||||||
|
|
||||||
|
# To add custom fonts to your plugin package, add a fonts section here,
|
||||||
|
# in this "flutter" section. Each entry in this list should have a
|
||||||
|
# "family" key with the font family name, and a "fonts" key with a
|
||||||
|
# list giving the asset and other descriptors for the font. For
|
||||||
|
# example:
|
||||||
|
# fonts:
|
||||||
|
# - family: Schyler
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/Schyler-Regular.ttf
|
||||||
|
# - asset: fonts/Schyler-Italic.ttf
|
||||||
|
# style: italic
|
||||||
|
# - family: Trajan Pro
|
||||||
|
# fonts:
|
||||||
|
# - asset: fonts/TrajanPro.ttf
|
||||||
|
# - asset: fonts/TrajanPro_Bold.ttf
|
||||||
|
# weight: 700
|
||||||
|
#
|
||||||
|
# For details regarding fonts in packages, see
|
||||||
|
# https://flutter.dev/to/font-from-package
|
|
@ -121,7 +121,7 @@ abstract class ZanoWalletBase
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int calculateEstimatedFee(TransactionPriority priority, [int? amount = null]) =>
|
int (TransactionPriority priority, [int? amount = null]) =>
|
||||||
getCurrentTxFee(priority);
|
getCurrentTxFee(priority);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -100,6 +100,15 @@ class WalletKeysAndSeedPageRobot {
|
||||||
commonTestCases.hasText(appStore.wallet!.privateKey!);
|
commonTestCases.hasText(appStore.wallet!.privateKey!);
|
||||||
tester.printToConsole('$walletName wallet has private key properly displayed');
|
tester.printToConsole('$walletName wallet has private key properly displayed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (walletType == WalletType.xelis) {
|
||||||
|
if (hasSeed) {
|
||||||
|
commonTestCases.hasText(appStore.wallet!.seed);
|
||||||
|
tester.printToConsole('$walletName wallet has seeds properly displayed');
|
||||||
|
commonTestCases.hasText(appStore.wallet!.langSeed(lang.nameEnglish));
|
||||||
|
tester.printToConsole('$walletName wallet has language seed variant properly displayed');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await commonTestCases.defaultSleepTime(seconds: 5);
|
await commonTestCases.defaultSleepTime(seconds: 5);
|
||||||
|
|
BIN
key.jks
Normal file
BIN
key.jks
Normal file
Binary file not shown.
|
@ -5,6 +5,7 @@ class InitialExecutionState extends ExecutionState {}
|
||||||
class LoadingTemplateExecutingState extends ExecutionState {}
|
class LoadingTemplateExecutingState extends ExecutionState {}
|
||||||
|
|
||||||
class IsExecutingState extends ExecutionState {}
|
class IsExecutingState extends ExecutionState {}
|
||||||
|
class IsLoadingState extends ExecutionState {}
|
||||||
|
|
||||||
class ExecutedSuccessfullyState extends ExecutionState {
|
class ExecutedSuccessfullyState extends ExecutionState {
|
||||||
ExecutedSuccessfullyState({this.payload});
|
ExecutedSuccessfullyState({this.payload});
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/tron/tron.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
import 'package:cake_wallet/zano/zano.dart';
|
import 'package:cake_wallet/zano/zano.dart';
|
||||||
import 'package:cake_wallet/decred/decred.dart';
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cake_wallet/utils/language_list.dart';
|
import 'package:cake_wallet/utils/language_list.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
@ -50,6 +51,8 @@ class SeedValidator extends Validator<MnemonicItem> {
|
||||||
return zano!.getWordList(language);
|
return zano!.getWordList(language);
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decred!.getDecredWordList();
|
return decred!.getDecredWordList();
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelis!.getXelisWordList(language);
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return [];
|
return [];
|
||||||
|
|
|
@ -91,6 +91,7 @@ class WalletCreationService {
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ class WalletLoadingService {
|
||||||
}
|
}
|
||||||
final walletService = walletServiceFactory.call(type);
|
final walletService = walletServiceFactory.call(type);
|
||||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||||
|
|
||||||
final wallet = await walletService.openWallet(name, walletPassword);
|
final wallet = await walletService.openWallet(name, walletPassword);
|
||||||
|
|
||||||
if (type == WalletType.monero) {
|
if (type == WalletType.monero) {
|
||||||
|
@ -93,6 +94,7 @@ class WalletLoadingService {
|
||||||
try {
|
try {
|
||||||
final walletService = walletServiceFactory.call(walletInfo.type);
|
final walletService = walletServiceFactory.call(walletInfo.type);
|
||||||
final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name);
|
final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name);
|
||||||
|
|
||||||
wallet = await walletService.openWallet(walletInfo.name, walletPassword);
|
wallet = await walletService.openWallet(walletInfo.name, walletPassword);
|
||||||
|
|
||||||
if (walletInfo.type == WalletType.monero) {
|
if (walletInfo.type == WalletType.monero) {
|
||||||
|
|
|
@ -80,6 +80,7 @@ import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/decred/decred.dart';
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/solana/solana.dart';
|
import 'package:cake_wallet/solana/solana.dart';
|
||||||
|
@ -1153,6 +1154,8 @@ Future<void> setup({
|
||||||
return zano!.createZanoWalletService(_walletInfoSource);
|
return zano!.createZanoWalletService(_walletInfoSource);
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decred!.createDecredWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
return decred!.createDecredWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelis!.createXelisWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return HavenWalletService(_walletInfoSource);
|
return HavenWalletService(_walletInfoSource);
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
|
|
|
@ -46,6 +46,8 @@ const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
||||||
const zanoDefaultNodeUri = 'zano.cakewallet.com:11211';
|
const zanoDefaultNodeUri = 'zano.cakewallet.com:11211';
|
||||||
const moneroWorldNodeUri = '.moneroworld.com';
|
const moneroWorldNodeUri = '.moneroworld.com';
|
||||||
const decredDefaultUri = "default-spv-nodes";
|
const decredDefaultUri = "default-spv-nodes";
|
||||||
|
const xelisDefaultUri = "us-node.xelis.io";
|
||||||
|
const xelisTestnetUri = "testnet-node.xelis.io";
|
||||||
|
|
||||||
Future<void> defaultSettingsMigration(
|
Future<void> defaultSettingsMigration(
|
||||||
{required int version,
|
{required int version,
|
||||||
|
@ -511,6 +513,17 @@ Future<void> defaultSettingsMigration(
|
||||||
enabled: true,
|
enabled: true,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 50:
|
||||||
|
await _fixNodesUseSSLFlag(nodes);
|
||||||
|
await addWalletNodeList(nodes: nodes, type: WalletType.xelis);
|
||||||
|
await _changeDefaultNode(
|
||||||
|
nodes: nodes,
|
||||||
|
sharedPreferences: sharedPreferences,
|
||||||
|
type: WalletType.xelis,
|
||||||
|
currentNodePreferenceKey: PreferencesKey.currentXelisNodeIdKey,
|
||||||
|
useSSL: true,
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -617,6 +630,8 @@ String _getDefaultNodeUri(WalletType type) {
|
||||||
return zanoDefaultNodeUri;
|
return zanoDefaultNodeUri;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decredDefaultUri;
|
return decredDefaultUri;
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelisDefaultUri;
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return '';
|
return '';
|
||||||
|
@ -807,6 +822,12 @@ Node? getBitcoinTestnetDefaultElectrumServer({required Box<Node> nodes}) {
|
||||||
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
|
nodes.values.firstWhereOrNull((node) => node.type == WalletType.bitcoin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Node? getXelisTestnetDefault({required Box<Node> nodes}) {
|
||||||
|
return nodes.values
|
||||||
|
.firstWhereOrNull((Node node) => node.uriRaw == xelisTestnetUri) ??
|
||||||
|
nodes.values.firstWhereOrNull((node) => node.type == WalletType.xelis);
|
||||||
|
}
|
||||||
|
|
||||||
Node? getDefaultNode({required Box<Node> nodes, required WalletType type}) {
|
Node? getDefaultNode({required Box<Node> nodes, required WalletType type}) {
|
||||||
final defaultUri = _getDefaultNodeUri(type);
|
final defaultUri = _getDefaultNodeUri(type);
|
||||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == defaultUri) ??
|
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == defaultUri) ??
|
||||||
|
@ -1045,6 +1066,7 @@ Future<void> checkCurrentNodes(
|
||||||
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||||
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
||||||
final currentDecredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
final currentDecredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
||||||
|
final currentXelisNodeId = sharedPreferences.getInt(PreferencesKey.currentXelisNodeIdKey);
|
||||||
final currentBitcoinCashNodeId =
|
final currentBitcoinCashNodeId =
|
||||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
||||||
final currentSolanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
|
final currentSolanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
|
||||||
|
@ -1079,6 +1101,8 @@ Future<void> checkCurrentNodes(
|
||||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentWowneroNodeId);
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentWowneroNodeId);
|
||||||
final currentZanoNode =
|
final currentZanoNode =
|
||||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentZanoNodeId);
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentZanoNodeId);
|
||||||
|
final currentXelisNodeServer =
|
||||||
|
nodeSource.values.firstWhereOrNull((node) => node.key == currentXelisNodeId);
|
||||||
|
|
||||||
if (currentMoneroNode == null) {
|
if (currentMoneroNode == null) {
|
||||||
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
||||||
|
@ -1175,6 +1199,15 @@ Future<void> checkCurrentNodes(
|
||||||
await nodeSource.add(node);
|
await nodeSource.add(node);
|
||||||
await sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
|
await sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentXelisNodeServer == null) {
|
||||||
|
final node = Node(uri: xelisDefaultUri, type: WalletType.xelis);
|
||||||
|
await nodeSource.add(node);
|
||||||
|
final xelisTestnet =
|
||||||
|
Node(uri: xelisTestnetUri, type: WalletType.xelis, useSSL: true);
|
||||||
|
await nodeSource.add(xelisTestnet);
|
||||||
|
await sharedPreferences.setInt(PreferencesKey.currentXelisNodeIdKey, node.key as int);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> resetBitcoinElectrumServer(
|
Future<void> resetBitcoinElectrumServer(
|
||||||
|
|
|
@ -46,6 +46,9 @@ Future<List<Node>> loadDefaultNodes(WalletType type) async {
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
path = 'assets/decred_node_list.yml';
|
path = 'assets/decred_node_list.yml';
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
path = 'assets/xelis_node_list.yml';
|
||||||
|
break;
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
path = '';
|
path = '';
|
||||||
|
@ -96,6 +99,7 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||||
final tronNodes = await loadDefaultNodes(WalletType.tron);
|
final tronNodes = await loadDefaultNodes(WalletType.tron);
|
||||||
final decredNodes = await loadDefaultNodes(WalletType.decred);
|
final decredNodes = await loadDefaultNodes(WalletType.decred);
|
||||||
final zanoNodes = await loadDefaultNodes(WalletType.zano);
|
final zanoNodes = await loadDefaultNodes(WalletType.zano);
|
||||||
|
final xelisNodes = await loadDefaultNodes(WalletType.xelis);
|
||||||
|
|
||||||
final nodes = moneroNodes +
|
final nodes = moneroNodes +
|
||||||
bitcoinElectrumServerList +
|
bitcoinElectrumServerList +
|
||||||
|
@ -108,7 +112,8 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
||||||
solanaNodes +
|
solanaNodes +
|
||||||
tronNodes +
|
tronNodes +
|
||||||
zanoNodes +
|
zanoNodes +
|
||||||
decredNodes;
|
decredNodes +
|
||||||
|
xelisNodes;
|
||||||
|
|
||||||
await nodeSource.clear();
|
await nodeSource.clear();
|
||||||
await nodeSource.addAll(nodes);
|
await nodeSource.addAll(nodes);
|
||||||
|
|
|
@ -19,6 +19,7 @@ class PreferencesKey {
|
||||||
static const currentSolanaNodeIdKey = 'current_node_id_sol';
|
static const currentSolanaNodeIdKey = 'current_node_id_sol';
|
||||||
static const currentTronNodeIdKey = 'current_node_id_trx';
|
static const currentTronNodeIdKey = 'current_node_id_trx';
|
||||||
static const currentWowneroNodeIdKey = 'current_node_id_wow';
|
static const currentWowneroNodeIdKey = 'current_node_id_wow';
|
||||||
|
static const currentXelisNodeIdKey = 'current_node_id_xelis';
|
||||||
static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
|
static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
|
||||||
static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
|
static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
|
||||||
static const shouldSaveRecipientAddressKey = 'save_recipient_address';
|
static const shouldSaveRecipientAddressKey = 'save_recipient_address';
|
||||||
|
@ -52,6 +53,7 @@ class PreferencesKey {
|
||||||
static const zanoTransactionPriority = 'current_fee_priority_zano';
|
static const zanoTransactionPriority = 'current_fee_priority_zano';
|
||||||
static const wowneroTransactionPriority = 'current_fee_priority_wownero';
|
static const wowneroTransactionPriority = 'current_fee_priority_wownero';
|
||||||
static const decredTransactionPriority = 'current_fee_priority_decred';
|
static const decredTransactionPriority = 'current_fee_priority_decred';
|
||||||
|
static const xelisTransactionPriority = 'current_fee_priority_xelis';
|
||||||
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
||||||
static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
|
static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
|
||||||
static const silentPaymentsAlwaysScan = 'silentPaymentsAlwaysScan';
|
static const silentPaymentsAlwaysScan = 'silentPaymentsAlwaysScan';
|
||||||
|
|
|
@ -6,6 +6,7 @@ import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
import 'package:cake_wallet/zano/zano.dart';
|
import 'package:cake_wallet/zano/zano.dart';
|
||||||
import 'package:cake_wallet/decred/decred.dart';
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/transaction_priority.dart';
|
import 'package:cw_core/transaction_priority.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
|
||||||
|
@ -35,6 +36,8 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
|
||||||
return zano!.getTransactionPriorities();
|
return zano!.getTransactionPriorities();
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decred!.getTransactionPriorities();
|
return decred!.getTransactionPriorities();
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelis!.getTransactionPriorities();
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
return [];
|
return [];
|
||||||
|
|
|
@ -52,6 +52,8 @@ import 'package:cw_core/window_size.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:cake_wallet/core/trade_monitor.dart';
|
import 'package:cake_wallet/core/trade_monitor.dart';
|
||||||
|
|
||||||
|
import 'frb_init.g.dart';
|
||||||
|
|
||||||
final navigatorKey = GlobalKey<NavigatorState>();
|
final navigatorKey = GlobalKey<NavigatorState>();
|
||||||
final rootKey = GlobalKey<RootState>();
|
final rootKey = GlobalKey<RootState>();
|
||||||
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
||||||
|
@ -63,6 +65,7 @@ Future<void> main({Key? topLevelKey}) async {
|
||||||
Future<void> runAppWithZone({Key? topLevelKey}) async {
|
Future<void> runAppWithZone({Key? topLevelKey}) async {
|
||||||
bool isAppRunning = false;
|
bool isAppRunning = false;
|
||||||
|
|
||||||
|
await frb_init();
|
||||||
await runZonedGuarded(() async {
|
await runZonedGuarded(() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
FlutterError.onError = ExceptionHandler.onError;
|
FlutterError.onError = ExceptionHandler.onError;
|
||||||
|
@ -228,7 +231,7 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||||
payjoinSessionSource: payjoinSessionSource,
|
payjoinSessionSource: payjoinSessionSource,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
havenSeedStore: havenSeedStore,
|
havenSeedStore: havenSeedStore,
|
||||||
initialMigrationVersion: 49,
|
initialMigrationVersion: 50,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ bool isBIP39Wallet(WalletType walletType) {
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||||
import 'package:cake_wallet/store/settings_store.dart';
|
import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'package:cw_core/wallet_type.dart';
|
import 'package:cw_core/wallet_type.dart';
|
||||||
|
@ -54,6 +55,11 @@ Future<void> startFiatRateUpdate(
|
||||||
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (appStore.wallet!.type == WalletType.xelis) {
|
||||||
|
currencies =
|
||||||
|
xelis!.getXelisAssets(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
if (currencies != null) {
|
if (currencies != null) {
|
||||||
for (final currency in currencies) {
|
for (final currency in currencies) {
|
||||||
// skip potential scams:
|
// skip potential scams:
|
||||||
|
|
|
@ -7,6 +7,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/solana/solana.dart';
|
import 'package:cake_wallet/solana/solana.dart';
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/transaction_history.dart';
|
import 'package:cw_core/transaction_history.dart';
|
||||||
import 'package:cw_core/balance.dart';
|
import 'package:cw_core/balance.dart';
|
||||||
|
@ -132,6 +133,10 @@ void startCurrentWalletChangeReaction(
|
||||||
currencies =
|
currencies =
|
||||||
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||||
}
|
}
|
||||||
|
if (wallet.type == WalletType.xelis) {
|
||||||
|
currencies =
|
||||||
|
xelis!.getXelisAssets(appStore.wallet!).where((element) => element.enabled);
|
||||||
|
}
|
||||||
|
|
||||||
if (currencies != null) {
|
if (currencies != null) {
|
||||||
for (final currency in currencies) {
|
for (final currency in currencies) {
|
||||||
|
|
|
@ -45,6 +45,7 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
|
final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
|
||||||
final zanoIcon = Image.asset('assets/images/zano_icon.png', height: 24, width: 24);
|
final zanoIcon = Image.asset('assets/images/zano_icon.png', height: 24, width: 24);
|
||||||
final decredIcon = Image.asset('assets/images/decred_icon.png', height: 24, width: 24);
|
final decredIcon = Image.asset('assets/images/decred_icon.png', height: 24, width: 24);
|
||||||
|
final xelisIcon = Image.asset('assets/images/xelis_icon.png', height: 24, width: 24);
|
||||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||||
|
|
||||||
Image _newWalletImage(BuildContext context) => Image.asset(
|
Image _newWalletImage(BuildContext context) => Image.asset(
|
||||||
|
@ -181,6 +182,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
||||||
return zanoIcon;
|
return zanoIcon;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decredIcon;
|
return decredIcon;
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelisIcon;
|
||||||
default:
|
default:
|
||||||
return nonWalletTypeIcon;
|
return nonWalletTypeIcon;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
this.tronIcon = Image.asset('assets/images/trx_icon.png'),
|
this.tronIcon = Image.asset('assets/images/trx_icon.png'),
|
||||||
this.wowneroIcon = Image.asset('assets/images/wownero_icon.png'),
|
this.wowneroIcon = Image.asset('assets/images/wownero_icon.png'),
|
||||||
this.zanoIcon = Image.asset('assets/images/zano_icon.png'),
|
this.zanoIcon = Image.asset('assets/images/zano_icon.png'),
|
||||||
this.decredIcon = Image.asset('assets/images/decred_menu.png');
|
this.decredIcon = Image.asset('assets/images/decred_menu.png'),
|
||||||
|
this.xelisIcon = Image.asset('assets/images/xelis_icon.png');
|
||||||
|
|
||||||
final largeScreen = 731;
|
final largeScreen = 731;
|
||||||
|
|
||||||
|
@ -64,6 +65,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
Image wowneroIcon;
|
Image wowneroIcon;
|
||||||
Image zanoIcon;
|
Image zanoIcon;
|
||||||
Image decredIcon;
|
Image decredIcon;
|
||||||
|
Image xelisIcon;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -255,6 +257,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
||||||
return zanoIcon;
|
return zanoIcon;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decredIcon;
|
return decredIcon;
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelisIcon;
|
||||||
default:
|
default:
|
||||||
throw Exception('No icon for ${type.toString()}');
|
throw Exception('No icon for ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,7 +275,8 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
if (widget.privacySettingsViewModel.type == WalletType.bitcoin ||
|
if (widget.privacySettingsViewModel.type == WalletType.bitcoin ||
|
||||||
widget.privacySettingsViewModel.type == WalletType.decred)
|
widget.privacySettingsViewModel.type == WalletType.decred ||
|
||||||
|
widget.privacySettingsViewModel.type == WalletType.xelis)
|
||||||
Builder(builder: (_) {
|
Builder(builder: (_) {
|
||||||
final val = testnetValue ?? false;
|
final val = testnetValue ?? false;
|
||||||
return SettingsSwitcherCell(
|
return SettingsSwitcherCell(
|
||||||
|
|
|
@ -24,7 +24,7 @@ class RescanPage extends BasePage {
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
Widget child;
|
Widget child;
|
||||||
if (_rescanViewModel.wallet.type != WalletType.decred) {
|
if (_rescanViewModel.wallet.type != WalletType.decred && _rescanViewModel.wallet.type != WalletType.xelis) {
|
||||||
child = Padding(
|
child = Padding(
|
||||||
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|
|
@ -584,6 +584,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
||||||
|
|
||||||
if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true;
|
if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) return true;
|
||||||
if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true;
|
if (seedWords.length == 26 && walletRestoreViewModel.type == WalletType.zano) return true;
|
||||||
|
if (seedWords.length == 25 && walletRestoreViewModel.type == WalletType.xelis) return true;
|
||||||
|
|
||||||
if (seedWords.length == 12 && walletRestoreViewModel.type == WalletType.monero) {
|
if (seedWords.length == 12 && walletRestoreViewModel.type == WalletType.monero) {
|
||||||
return walletRestoreFromSeedFormKey.currentState?.blockchainHeightKey.currentState
|
return walletRestoreFromSeedFormKey.currentState?.blockchainHeightKey.currentState
|
||||||
|
|
|
@ -129,6 +129,7 @@ class WalletListBodyState extends State<WalletListBody> {
|
||||||
final tronIcon = Image.asset('assets/images/trx_icon.png', height: 24, width: 24);
|
final tronIcon = Image.asset('assets/images/trx_icon.png', height: 24, width: 24);
|
||||||
final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
|
final wowneroIcon = Image.asset('assets/images/wownero_icon.png', height: 24, width: 24);
|
||||||
final zanoIcon = Image.asset('assets/images/zano_icon.png', height: 24, width: 24);
|
final zanoIcon = Image.asset('assets/images/zano_icon.png', height: 24, width: 24);
|
||||||
|
final xelisIcon = Image.asset('assets/images/xelis_icon.png', height: 24, width: 24);
|
||||||
final scrollController = ScrollController();
|
final scrollController = ScrollController();
|
||||||
final double tileHeight = 60;
|
final double tileHeight = 60;
|
||||||
Flushbar<void>? _progressBar;
|
Flushbar<void>? _progressBar;
|
||||||
|
|
|
@ -56,6 +56,13 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state is IsLoadingState) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
// null duration to make it indefinite until its disposed
|
||||||
|
_authBar = createBar<void>(S.of(context).loading_wallet, context, duration: null)..show(context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (state is FailureState) {
|
if (state is FailureState) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
dismissFlushBar(_authBar);
|
dismissFlushBar(_authBar);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:io';
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/core/utilities.dart';
|
import 'package:cake_wallet/core/utilities.dart';
|
||||||
import 'package:cake_wallet/decred/decred.dart';
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
import 'package:cake_wallet/core/secure_storage.dart';
|
import 'package:cake_wallet/core/secure_storage.dart';
|
||||||
import 'package:cake_wallet/di.dart';
|
import 'package:cake_wallet/di.dart';
|
||||||
|
@ -137,6 +138,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
TransactionPriority? initialBitcoinCashTransactionPriority,
|
TransactionPriority? initialBitcoinCashTransactionPriority,
|
||||||
TransactionPriority? initialZanoTransactionPriority,
|
TransactionPriority? initialZanoTransactionPriority,
|
||||||
TransactionPriority? initialDecredTransactionPriority,
|
TransactionPriority? initialDecredTransactionPriority,
|
||||||
|
TransactionPriority? initialXelisTransactionPriority,
|
||||||
Country? initialCakePayCountry})
|
Country? initialCakePayCountry})
|
||||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||||
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
|
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
|
||||||
|
@ -225,6 +227,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
if (initialDecredTransactionPriority != null) {
|
if (initialDecredTransactionPriority != null) {
|
||||||
priority[WalletType.decred] = initialDecredTransactionPriority;
|
priority[WalletType.decred] = initialDecredTransactionPriority;
|
||||||
}
|
}
|
||||||
|
if (initialXelisTransactionPriority != null) {
|
||||||
|
priority[WalletType.xelis] = initialXelisTransactionPriority;
|
||||||
|
}
|
||||||
|
|
||||||
if (initialCakePayCountry != null) {
|
if (initialCakePayCountry != null) {
|
||||||
selectedCakePayCountry = initialCakePayCountry;
|
selectedCakePayCountry = initialCakePayCountry;
|
||||||
|
@ -283,6 +288,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
key = PreferencesKey.decredTransactionPriority;
|
key = PreferencesKey.decredTransactionPriority;
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
key = PreferencesKey.xelisTransactionPriority;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
key = null;
|
key = null;
|
||||||
}
|
}
|
||||||
|
@ -912,6 +920,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
TransactionPriority? wowneroTransactionPriority;
|
TransactionPriority? wowneroTransactionPriority;
|
||||||
TransactionPriority? zanoTransactionPriority;
|
TransactionPriority? zanoTransactionPriority;
|
||||||
TransactionPriority? decredTransactionPriority;
|
TransactionPriority? decredTransactionPriority;
|
||||||
|
TransactionPriority? xelisTransactionPriority;
|
||||||
|
|
||||||
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
||||||
havenTransactionPriority = monero?.deserializeMoneroTransactionPriority(
|
havenTransactionPriority = monero?.deserializeMoneroTransactionPriority(
|
||||||
|
@ -945,6 +954,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
decredTransactionPriority = decred?.deserializeDecredTransactionPriority(
|
decredTransactionPriority = decred?.deserializeDecredTransactionPriority(
|
||||||
sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
|
sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
|
||||||
}
|
}
|
||||||
|
if (sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority) != null) {
|
||||||
|
xelisTransactionPriority = xelis?.deserializeXelisTransactionPriority(
|
||||||
|
sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority)!);
|
||||||
|
}
|
||||||
|
|
||||||
moneroTransactionPriority ??= monero?.getDefaultTransactionPriority();
|
moneroTransactionPriority ??= monero?.getDefaultTransactionPriority();
|
||||||
bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority();
|
bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority();
|
||||||
|
@ -954,6 +967,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
|
bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
|
||||||
wowneroTransactionPriority ??= wownero?.getDefaultTransactionPriority();
|
wowneroTransactionPriority ??= wownero?.getDefaultTransactionPriority();
|
||||||
decredTransactionPriority ??= decred?.getDecredTransactionPriorityMedium();
|
decredTransactionPriority ??= decred?.getDecredTransactionPriorityMedium();
|
||||||
|
xelisTransactionPriority ??= xelis?.getXelisTransactionPriorityMedium();
|
||||||
polygonTransactionPriority ??= polygon?.getDefaultTransactionPriority();
|
polygonTransactionPriority ??= polygon?.getDefaultTransactionPriority();
|
||||||
zanoTransactionPriority ??= zano?.getDefaultTransactionPriority();
|
zanoTransactionPriority ??= zano?.getDefaultTransactionPriority();
|
||||||
|
|
||||||
|
@ -1050,6 +1064,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
|
final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
|
||||||
final zanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
|
final zanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
|
||||||
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
||||||
|
final xelisNodeId = sharedPreferences.getInt(PreferencesKey.currentXelisNodeIdKey);
|
||||||
|
|
||||||
/// get the selected node, if null, then use the default
|
/// get the selected node, if null, then use the default
|
||||||
final moneroNode = nodeSource.get(nodeId) ??
|
final moneroNode = nodeSource.get(nodeId) ??
|
||||||
|
@ -1068,6 +1083,8 @@ abstract class SettingsStoreBase with Store {
|
||||||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultNodeUri);
|
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultNodeUri);
|
||||||
final decredNode = nodeSource.get(decredNodeId) ??
|
final decredNode = nodeSource.get(decredNodeId) ??
|
||||||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == decredDefaultUri);
|
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == decredDefaultUri);
|
||||||
|
final xelisNode = nodeSource.get(xelisNodeId) ??
|
||||||
|
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == xelisDefaultUri);
|
||||||
final nanoPowNode = powNodeSource.get(nanoPowNodeId) ??
|
final nanoPowNode = powNodeSource.get(nanoPowNodeId) ??
|
||||||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultPowNodeUri);
|
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultPowNodeUri);
|
||||||
final solanaNode = nodeSource.get(solanaNodeId) ??
|
final solanaNode = nodeSource.get(solanaNodeId) ??
|
||||||
|
@ -1164,6 +1181,10 @@ abstract class SettingsStoreBase with Store {
|
||||||
nodes[WalletType.decred] = decredNode;
|
nodes[WalletType.decred] = decredNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xelisNode != null) {
|
||||||
|
nodes[WalletType.xelis] = xelisNode;
|
||||||
|
}
|
||||||
|
|
||||||
final savedSyncMode = SyncMode.all.firstWhere((element) {
|
final savedSyncMode = SyncMode.all.firstWhere((element) {
|
||||||
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 2); // default to 2 - daily sync
|
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 2); // default to 2 - daily sync
|
||||||
});
|
});
|
||||||
|
@ -1334,6 +1355,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
initialLitecoinTransactionPriority: litecoinTransactionPriority,
|
initialLitecoinTransactionPriority: litecoinTransactionPriority,
|
||||||
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
|
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
|
||||||
initialDecredTransactionPriority: decredTransactionPriority,
|
initialDecredTransactionPriority: decredTransactionPriority,
|
||||||
|
initialXelisTransactionPriority: xelisTransactionPriority,
|
||||||
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
|
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
|
||||||
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
|
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
|
||||||
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
|
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
|
||||||
|
@ -1412,6 +1434,11 @@ abstract class SettingsStoreBase with Store {
|
||||||
priority[WalletType.decred] = decred!.deserializeDecredTransactionPriority(
|
priority[WalletType.decred] = decred!.deserializeDecredTransactionPriority(
|
||||||
sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
|
sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
|
||||||
}
|
}
|
||||||
|
if (xelis != null &&
|
||||||
|
sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority) != null) {
|
||||||
|
priority[WalletType.xelis] = xelis!.deserializeXelisTransactionPriority(
|
||||||
|
sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority)!);
|
||||||
|
}
|
||||||
|
|
||||||
final generateSubaddresses =
|
final generateSubaddresses =
|
||||||
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
|
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
|
||||||
|
@ -1522,6 +1549,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
|
final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
|
||||||
final zanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
|
final zanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
|
||||||
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
||||||
|
final xelisNodeId = sharedPreferences.getInt(PreferencesKey.currentXelisNodeIdKey);
|
||||||
final moneroNode = nodeSource.get(nodeId);
|
final moneroNode = nodeSource.get(nodeId);
|
||||||
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
||||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||||
|
@ -1535,6 +1563,7 @@ abstract class SettingsStoreBase with Store {
|
||||||
final wowneroNode = nodeSource.get(wowneroNodeId);
|
final wowneroNode = nodeSource.get(wowneroNodeId);
|
||||||
final zanoNode = nodeSource.get(zanoNodeId);
|
final zanoNode = nodeSource.get(zanoNodeId);
|
||||||
final decredNode = nodeSource.get(decredNodeId);
|
final decredNode = nodeSource.get(decredNodeId);
|
||||||
|
final xelisNode = nodeSource.get(xelisNodeId);
|
||||||
|
|
||||||
if (moneroNode != null) {
|
if (moneroNode != null) {
|
||||||
nodes[WalletType.monero] = moneroNode;
|
nodes[WalletType.monero] = moneroNode;
|
||||||
|
@ -1589,6 +1618,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
nodes[WalletType.decred] = decredNode;
|
nodes[WalletType.decred] = decredNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (xelisNode != null) {
|
||||||
|
nodes[WalletType.xelis] = xelisNode;
|
||||||
|
}
|
||||||
// MIGRATED:
|
// MIGRATED:
|
||||||
|
|
||||||
useTOTP2FA = await SecureKey.getBool(
|
useTOTP2FA = await SecureKey.getBool(
|
||||||
|
@ -1728,6 +1760,9 @@ abstract class SettingsStoreBase with Store {
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
await _sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
|
await _sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
await _sharedPreferences.setInt(PreferencesKey.currentXelisNodeIdKey, node.key as int);
|
||||||
|
break;
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
await _sharedPreferences.setInt(PreferencesKey.currentZanoNodeIdKey, node.key as int);
|
await _sharedPreferences.setInt(PreferencesKey.currentZanoNodeIdKey, node.key as int);
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -11,7 +11,103 @@ class AddressFormatter {
|
||||||
TextAlign? textAlign,
|
TextAlign? textAlign,
|
||||||
bool shouldTruncate = false,
|
bool shouldTruncate = false,
|
||||||
}) {
|
}) {
|
||||||
|
// Check for parentheses in the address
|
||||||
|
final bracketIndex = address.indexOf('[');
|
||||||
|
|
||||||
|
if (bracketIndex != -1) {
|
||||||
|
// Split address and amount parts
|
||||||
|
final addressPart = address.substring(0, bracketIndex).trim();
|
||||||
|
final amountPart = address.substring(bracketIndex);
|
||||||
|
|
||||||
|
// For truncated addresses, handle differently
|
||||||
|
if (shouldTruncate) {
|
||||||
|
final addressWidget = _buildAddressWidget(
|
||||||
|
address: addressPart,
|
||||||
|
walletType: walletType,
|
||||||
|
evenTextStyle: evenTextStyle,
|
||||||
|
oddTextStyle: oddTextStyle,
|
||||||
|
textAlign: textAlign,
|
||||||
|
shouldTruncate: shouldTruncate,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
addressWidget,
|
||||||
|
Text(amountPart, style: evenTextStyle),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For full addresses, integrate amount with last line
|
||||||
|
final cleanAddress = addressPart.replaceAll('bitcoincash:', '');
|
||||||
|
final isMWEB = addressPart.startsWith('ltcmweb');
|
||||||
|
final chunkSize = walletType != null ? _getChunkSize(walletType) : 4;
|
||||||
|
|
||||||
|
// Build chunks
|
||||||
|
final chunks = <String>[];
|
||||||
|
if (isMWEB) {
|
||||||
|
const mwebDisplayPrefix = 'ltcmweb';
|
||||||
|
chunks.add(mwebDisplayPrefix);
|
||||||
|
final startIndex = mwebDisplayPrefix.length;
|
||||||
|
for (int i = startIndex; i < cleanAddress.length; i += chunkSize) {
|
||||||
|
final chunk = cleanAddress.substring(
|
||||||
|
i,
|
||||||
|
math.min(i + chunkSize, cleanAddress.length),
|
||||||
|
);
|
||||||
|
chunks.add(chunk);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < cleanAddress.length; i += chunkSize) {
|
||||||
|
final chunk = cleanAddress.substring(
|
||||||
|
i,
|
||||||
|
math.min(i + chunkSize, cleanAddress.length),
|
||||||
|
);
|
||||||
|
chunks.add(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build text spans with amount appended to last chunk
|
||||||
|
final spans = <TextSpan>[];
|
||||||
|
for (int i = 0; i < chunks.length; i++) {
|
||||||
|
final style = (i % 2 == 0) ? evenTextStyle : oddTextStyle ?? evenTextStyle.copyWith(color: evenTextStyle.color!.withAlpha(128));
|
||||||
|
|
||||||
|
if (i == chunks.length - 1) {
|
||||||
|
// Last chunk - append amount
|
||||||
|
spans.add(TextSpan(text: '${chunks[i]} ', style: style));
|
||||||
|
spans.add(TextSpan(text: amountPart, style: evenTextStyle));
|
||||||
|
} else {
|
||||||
|
spans.add(TextSpan(text: '${chunks[i]} ', style: style));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RichText(
|
||||||
|
text: TextSpan(children: spans),
|
||||||
|
textAlign: textAlign ?? TextAlign.start,
|
||||||
|
overflow: TextOverflow.visible,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No parentheses - use original logic
|
||||||
|
return _buildAddressWidget(
|
||||||
|
address: address,
|
||||||
|
walletType: walletType,
|
||||||
|
evenTextStyle: evenTextStyle,
|
||||||
|
oddTextStyle: oddTextStyle,
|
||||||
|
textAlign: textAlign,
|
||||||
|
shouldTruncate: shouldTruncate,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Widget _buildAddressWidget({
|
||||||
|
required String address,
|
||||||
|
WalletType? walletType,
|
||||||
|
required TextStyle evenTextStyle,
|
||||||
|
TextStyle? oddTextStyle,
|
||||||
|
TextAlign? textAlign,
|
||||||
|
bool shouldTruncate = false,
|
||||||
|
}) {
|
||||||
final cleanAddress = address.replaceAll('bitcoincash:', '');
|
final cleanAddress = address.replaceAll('bitcoincash:', '');
|
||||||
final isMWEB = address.startsWith('ltcmweb');
|
final isMWEB = address.startsWith('ltcmweb');
|
||||||
final chunkSize = walletType != null ? _getChunkSize(walletType) : 4;
|
final chunkSize = walletType != null ? _getChunkSize(walletType) : 4;
|
||||||
|
|
|
@ -56,6 +56,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,8 @@ abstract class BalanceViewModelBase with Store {
|
||||||
isEVMCompatibleChain(wallet.type) ||
|
isEVMCompatibleChain(wallet.type) ||
|
||||||
wallet.type == WalletType.solana ||
|
wallet.type == WalletType.solana ||
|
||||||
wallet.type == WalletType.tron ||
|
wallet.type == WalletType.tron ||
|
||||||
wallet.type == WalletType.zano;
|
wallet.type == WalletType.zano ||
|
||||||
|
wallet.type == WalletType.xelis;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get hasAccounts => wallet.type == WalletType.monero || wallet.type == WalletType.wownero;
|
bool get hasAccounts => wallet.type == WalletType.monero || wallet.type == WalletType.wownero;
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||||
import 'package:cake_wallet/store/app_store.dart';
|
import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
import 'package:cake_wallet/store/dashboard/orders_store.dart';
|
||||||
|
@ -468,7 +469,8 @@ abstract class DashboardViewModelBase with Store {
|
||||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet;
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get isTestnet => wallet.type == WalletType.bitcoin && bitcoin!.isTestnet(wallet);
|
bool get isTestnet => (wallet.type == WalletType.bitcoin && bitcoin!.isTestnet(wallet)) ||
|
||||||
|
(wallet.type == WalletType.xelis && xelis!.isTestnet(wallet));
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
bool get hasRescan => wallet.hasRescan;
|
bool get hasRescan => wallet.hasRescan;
|
||||||
|
@ -859,6 +861,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
return true;
|
return true;
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
|
case WalletType.xelis: // TODO: finalize whether to change this
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import 'package:cake_wallet/store/settings_store.dart';
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
|
||||||
import 'package:cake_wallet/zano/zano.dart';
|
import 'package:cake_wallet/zano/zano.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/erc20_token.dart';
|
import 'package:cw_core/erc20_token.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
|
@ -109,6 +110,14 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
await xelis!.updateAssetState(
|
||||||
|
_balanceViewModel.wallet,
|
||||||
|
token,
|
||||||
|
contractAddress,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
||||||
await tron!.addTronToken(_balanceViewModel.wallet, token, contractAddress);
|
await tron!.addTronToken(_balanceViewModel.wallet, token, contractAddress);
|
||||||
}
|
}
|
||||||
|
@ -148,6 +157,9 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||||
await zano!.deleteZanoAsset(_balanceViewModel.wallet, token);
|
await zano!.deleteZanoAsset(_balanceViewModel.wallet, token);
|
||||||
}
|
}
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
await xelis!.deleteAsset(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
_updateTokensList();
|
_updateTokensList();
|
||||||
} finally {
|
} finally {
|
||||||
isDeletingToken = false;
|
isDeletingToken = false;
|
||||||
|
@ -206,6 +218,11 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
defaultTokenAddresses = tron!.getDefaultTokenContractAddresses();
|
defaultTokenAddresses = tron!.getDefaultTokenContractAddresses();
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
// TODO
|
||||||
|
// defaultTokenAddresses = xelis!.getDefaultAssetIDs();
|
||||||
|
// break;
|
||||||
|
return false;
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
|
@ -388,6 +405,10 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
return await solana!.getSPLToken(_balanceViewModel.wallet, contractAddress);
|
return await solana!.getSPLToken(_balanceViewModel.wallet, contractAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
return await xelis!.getAsset(_balanceViewModel.wallet, contractAddress);
|
||||||
|
}
|
||||||
|
|
||||||
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
||||||
return await tron!.getTronToken(_balanceViewModel.wallet, contractAddress);
|
return await tron!.getTronToken(_balanceViewModel.wallet, contractAddress);
|
||||||
}
|
}
|
||||||
|
@ -430,6 +451,12 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
solana!.addSPLToken(_balanceViewModel.wallet, token, address);
|
solana!.addSPLToken(_balanceViewModel.wallet, token, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
final id = xelis!.getAssetId(token);
|
||||||
|
xelis!.updateAssetState(_balanceViewModel.wallet, token, id);
|
||||||
|
if (!value) await xelis!.removeAssetTransactionsInHistory(_balanceViewModel.wallet, token);
|
||||||
|
}
|
||||||
|
|
||||||
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
if (_balanceViewModel.wallet.type == WalletType.tron) {
|
||||||
final address = tron!.getTokenAddress(token);
|
final address = tron!.getTokenAddress(token);
|
||||||
tron!.addTronToken(_balanceViewModel.wallet, token, address);
|
tron!.addTronToken(_balanceViewModel.wallet, token, address);
|
||||||
|
@ -501,6 +528,15 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
.toList()
|
.toList()
|
||||||
..sort(_sortFunc));
|
..sort(_sortFunc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
tokens.addAll(xelis!
|
||||||
|
.getXelisAssets(_balanceViewModel.wallet)
|
||||||
|
.where((element) => _matchesSearchText(element))
|
||||||
|
.toList()
|
||||||
|
..sort(_sortFunc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -549,7 +585,12 @@ abstract class HomeSettingsViewModelBase with Store {
|
||||||
return zano!.getZanoAssetAddress(asset);
|
return zano!.getZanoAssetAddress(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We return null if it's neither Tron, Polygon, Ethereum or Solana wallet (which is actually impossible because we only display home settings for either of these three wallets).
|
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
return xelis!.getAssetId(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// We return null if it's neither Tron, Polygon, Ethereum, Xelis or Solana wallet (which is actually impossible because we only display home settings for either of these five wallets).
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ abstract class ReceiveOptionViewModelBase with Store {
|
||||||
_options = [ReceivePageOption.mainnet];
|
_options = [ReceivePageOption.mainnet];
|
||||||
break;
|
break;
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
if (_wallet.isTestnet) {
|
if (_wallet.isTestnet) {
|
||||||
_options = [
|
_options = [
|
||||||
ReceivePageOption.testnet,
|
ReceivePageOption.testnet,
|
||||||
|
|
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/solana/solana.dart';
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
import 'package:cake_wallet/zano/zano.dart';
|
import 'package:cake_wallet/zano/zano.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/transaction_direction.dart';
|
import 'package:cw_core/transaction_direction.dart';
|
||||||
import 'package:cw_core/transaction_info.dart';
|
import 'package:cw_core/transaction_info.dart';
|
||||||
|
@ -46,10 +47,17 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
bool get hasTokens =>
|
bool get hasTokens =>
|
||||||
isEVMCompatibleChain(balanceViewModel.wallet.type) ||
|
isEVMCompatibleChain(balanceViewModel.wallet.type) ||
|
||||||
balanceViewModel.wallet.type == WalletType.solana ||
|
balanceViewModel.wallet.type == WalletType.solana ||
|
||||||
balanceViewModel.wallet.type == WalletType.tron;
|
balanceViewModel.wallet.type == WalletType.tron ||
|
||||||
|
balanceViewModel.wallet.type == WalletType.xelis;
|
||||||
|
|
||||||
String get formattedCryptoAmount {
|
String get formattedCryptoAmount {
|
||||||
return displayMode == BalanceDisplayMode.hiddenBalance ? '---' : transaction.amountFormatted();
|
late final String amtText;
|
||||||
|
if (transaction.amountFormatted() == "MULTI") {
|
||||||
|
amtText = S.current.multi_transfer;
|
||||||
|
} else {
|
||||||
|
amtText = transaction.amountFormatted();
|
||||||
|
}
|
||||||
|
return displayMode == BalanceDisplayMode.hiddenBalance ? '---' : amtText;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get formattedTitle {
|
String get formattedTitle {
|
||||||
|
@ -108,6 +116,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
WalletType.wownero,
|
WalletType.wownero,
|
||||||
WalletType.litecoin,
|
WalletType.litecoin,
|
||||||
WalletType.zano,
|
WalletType.zano,
|
||||||
|
WalletType.xelis
|
||||||
].contains(balanceViewModel.wallet.type)) {
|
].contains(balanceViewModel.wallet.type)) {
|
||||||
return formattedPendingStatus;
|
return formattedPendingStatus;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +152,11 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
final asset = tron!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
final asset = tron!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (balanceViewModel.wallet.type == WalletType.xelis) {
|
||||||
|
final asset = xelis!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -224,6 +238,13 @@ class TransactionListItem extends ActionListItem with Keyable {
|
||||||
cryptoAmount: decred!.formatterDecredAmountToDouble(amount: transaction.amount),
|
cryptoAmount: decred!.formatterDecredAmountToDouble(amount: transaction.amount),
|
||||||
price: price);
|
price: price);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
final asset = xelis!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||||
|
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
||||||
|
amount = calculateFiatAmountRaw(
|
||||||
|
cryptoAmount: xelis!.formatterXelisAmountToDouble(amount: xelis!.getTransactionAmountRaw(transaction)),
|
||||||
|
price: price);
|
||||||
|
break;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
|
|
|
@ -253,11 +253,16 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||||
wallet.currency == CryptoCurrency.sol &&
|
wallet.currency == CryptoCurrency.sol &&
|
||||||
tradesStore.trade!.from.tag == CryptoCurrency.sol.title;
|
tradesStore.trade!.from.tag == CryptoCurrency.sol.title;
|
||||||
|
|
||||||
|
bool _isXelisAsset() =>
|
||||||
|
wallet.currency == CryptoCurrency.xel &&
|
||||||
|
tradesStore.trade!.from.tag == CryptoCurrency.xel.title;
|
||||||
|
|
||||||
return tradesStore.trade!.from == wallet.currency ||
|
return tradesStore.trade!.from == wallet.currency ||
|
||||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
||||||
_isEthToken() ||
|
_isEthToken() ||
|
||||||
_isPolygonToken() ||
|
_isPolygonToken() ||
|
||||||
_isSplToken() ||
|
_isSplToken() ||
|
||||||
_isTronToken();
|
_isTronToken() ||
|
||||||
|
_isXelisAsset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -779,6 +779,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
||||||
depositCurrency = CryptoCurrency.dcr;
|
depositCurrency = CryptoCurrency.dcr;
|
||||||
receiveCurrency = CryptoCurrency.xmr;
|
receiveCurrency = CryptoCurrency.xmr;
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
depositCurrency = CryptoCurrency.xel;
|
||||||
|
receiveCurrency = CryptoCurrency.btc;
|
||||||
|
break;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,6 +87,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ abstract class NodeListViewModelBase with Store {
|
||||||
Node node;
|
Node node;
|
||||||
if (_appStore.wallet!.type == WalletType.bitcoin && _appStore.wallet!.isTestnet) {
|
if (_appStore.wallet!.type == WalletType.bitcoin && _appStore.wallet!.isTestnet) {
|
||||||
node = getBitcoinTestnetDefaultElectrumServer(nodes: _nodeSource)!;
|
node = getBitcoinTestnetDefaultElectrumServer(nodes: _nodeSource)!;
|
||||||
|
} else if (_appStore.wallet!.type == WalletType.xelis && _appStore.wallet!.isTestnet) {
|
||||||
|
node = getXelisTestnetDefault(nodes: _nodeSource)!;
|
||||||
} else {
|
} else {
|
||||||
node = getDefaultNode(nodes: _nodeSource, type: _appStore.wallet!.type)!;
|
node = getDefaultNode(nodes: _nodeSource, type: _appStore.wallet!.type)!;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,6 +47,9 @@ class WalletRestoreFromQRCode {
|
||||||
'decred': WalletType.decred,
|
'decred': WalletType.decred,
|
||||||
'decred-wallet': WalletType.decred,
|
'decred-wallet': WalletType.decred,
|
||||||
'decred_wallet': WalletType.decred,
|
'decred_wallet': WalletType.decred,
|
||||||
|
'xelis': WalletType.xelis,
|
||||||
|
'xelis-wallet': WalletType.xelis,
|
||||||
|
'xelis_wallet': WalletType.xelis,
|
||||||
};
|
};
|
||||||
|
|
||||||
static WalletType? _extractWalletType(String code) {
|
static WalletType? _extractWalletType(String code) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||||
import 'package:cake_wallet/decred/decred.dart';
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
|
||||||
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
||||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||||
|
@ -91,6 +92,7 @@ abstract class FeesViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
return transactionPriority == polygon!.getPolygonTransactionPrioritySlow();
|
return transactionPriority == polygon!.getPolygonTransactionPrioritySlow();
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return transactionPriority == decred!.getDecredTransactionPrioritySlow();
|
return transactionPriority == decred!.getDecredTransactionPrioritySlow();
|
||||||
|
case WalletType.xelis:
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/send/widgets/extract_address_from_parsed
|
||||||
import 'package:cake_wallet/tron/tron.dart';
|
import 'package:cake_wallet/tron/tron.dart';
|
||||||
import 'package:cake_wallet/wownero/wownero.dart';
|
import 'package:cake_wallet/wownero/wownero.dart';
|
||||||
import 'package:cake_wallet/zano/zano.dart';
|
import 'package:cake_wallet/zano/zano.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/crypto_currency.dart';
|
import 'package:cw_core/crypto_currency.dart';
|
||||||
import 'package:cw_core/utils/print_verbose.dart';
|
import 'package:cw_core/utils/print_verbose.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -116,6 +117,9 @@ abstract class OutputBase with Store {
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
_amount = zano!.formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
|
_amount = zano!.formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
_amount = xelis!.formatterStringDoubleToAmount(_cryptoAmount, currency: cryptoCurrencyHandler());
|
||||||
|
break;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
|
@ -153,6 +157,10 @@ abstract class OutputBase with Store {
|
||||||
return solana!.getEstimateFees(_wallet) ?? 0.0;
|
return solana!.getEstimateFees(_wallet) ?? 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_wallet.type == WalletType.xelis) {
|
||||||
|
return xelis!.getEstimateFees(_wallet) ?? 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
int? fee = _wallet.calculateEstimatedFee(
|
int? fee = _wallet.calculateEstimatedFee(
|
||||||
_settingsStore.priority[_wallet.type]!, formattedCryptoAmount);
|
_settingsStore.priority[_wallet.type]!, formattedCryptoAmount);
|
||||||
|
|
||||||
|
@ -193,6 +201,10 @@ abstract class OutputBase with Store {
|
||||||
if (_wallet.type == WalletType.decred) {
|
if (_wallet.type == WalletType.decred) {
|
||||||
return decred!.formatterDecredAmountToDouble(amount: fee);
|
return decred!.formatterDecredAmountToDouble(amount: fee);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_wallet.type == WalletType.xelis) {
|
||||||
|
return xelis!.formatterXelisAmountToDouble(amount: BigInt.from(fee));
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
printV(e.toString());
|
printV(e.toString());
|
||||||
}
|
}
|
||||||
|
@ -205,7 +217,8 @@ abstract class OutputBase with Store {
|
||||||
try {
|
try {
|
||||||
final currency = (isEVMCompatibleChain(_wallet.type) ||
|
final currency = (isEVMCompatibleChain(_wallet.type) ||
|
||||||
_wallet.type == WalletType.solana ||
|
_wallet.type == WalletType.solana ||
|
||||||
_wallet.type == WalletType.tron)
|
_wallet.type == WalletType.tron ||
|
||||||
|
_wallet.type == WalletType.xelis)
|
||||||
? _wallet.currency
|
? _wallet.currency
|
||||||
: cryptoCurrencyHandler();
|
: cryptoCurrencyHandler();
|
||||||
final fiat = calculateFiatAmountRaw(
|
final fiat = calculateFiatAmountRaw(
|
||||||
|
@ -302,6 +315,7 @@ abstract class OutputBase with Store {
|
||||||
case WalletType.zano:
|
case WalletType.zano:
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
|
case WalletType.xelis:
|
||||||
maximumFractionDigits = 12;
|
maximumFractionDigits = 12;
|
||||||
break;
|
break;
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
|
|
|
@ -101,5 +101,6 @@ abstract class SendTemplateViewModelBase with Store {
|
||||||
|
|
||||||
bool get hasMultipleTokens => isEVMCompatibleChain(_wallet.type) ||
|
bool get hasMultipleTokens => isEVMCompatibleChain(_wallet.type) ||
|
||||||
_wallet.type == WalletType.solana ||
|
_wallet.type == WalletType.solana ||
|
||||||
_wallet.type == WalletType.tron;
|
_wallet.type == WalletType.tron ||
|
||||||
|
_wallet.type == WalletType.xelis;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,11 @@ import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/monero/monero.dart';
|
import 'package:cake_wallet/monero/monero.dart';
|
||||||
import 'package:cake_wallet/nano/nano.dart';
|
import 'package:cake_wallet/nano/nano.dart';
|
||||||
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
|
import 'package:cake_wallet/core/wallet_change_listener_view_model.dart';
|
||||||
|
import 'package:cake_wallet/entities/contact_record.dart';
|
||||||
|
import 'package:cake_wallet/entities/wallet_contact.dart';
|
||||||
import 'package:cake_wallet/polygon/polygon.dart';
|
import 'package:cake_wallet/polygon/polygon.dart';
|
||||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
|
@ -69,7 +74,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
hasMultipleTokens = isEVMCompatibleChain(wallet.type) ||
|
hasMultipleTokens = isEVMCompatibleChain(wallet.type) ||
|
||||||
wallet.type == WalletType.solana ||
|
wallet.type == WalletType.solana ||
|
||||||
wallet.type == WalletType.tron ||
|
wallet.type == WalletType.tron ||
|
||||||
wallet.type == WalletType.zano;
|
wallet.type == WalletType.zano ||
|
||||||
|
wallet.type == WalletType.xelis;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnspentCoinsListViewModel unspentCoinsListViewModel;
|
UnspentCoinsListViewModel unspentCoinsListViewModel;
|
||||||
|
@ -91,7 +97,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type) ||
|
hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type) ||
|
||||||
appStore.wallet!.type == WalletType.solana ||
|
appStore.wallet!.type == WalletType.solana ||
|
||||||
appStore.wallet!.type == WalletType.tron ||
|
appStore.wallet!.type == WalletType.tron ||
|
||||||
appStore.wallet!.type == WalletType.zano,
|
appStore.wallet!.type == WalletType.zano ||
|
||||||
|
appStore.wallet!.type == WalletType.xelis,
|
||||||
outputs = ObservableList<Output>(),
|
outputs = ObservableList<Output>(),
|
||||||
_settingsStore = appStore.settingsStore,
|
_settingsStore = appStore.settingsStore,
|
||||||
fiatFromSettings = appStore.settingsStore.fiatCurrency,
|
fiatFromSettings = appStore.settingsStore.fiatCurrency,
|
||||||
|
@ -199,6 +206,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
|
case WalletType.xelis:
|
||||||
return wallet.currency;
|
return wallet.currency;
|
||||||
default:
|
default:
|
||||||
return selectedCryptoCurrency;
|
return selectedCryptoCurrency;
|
||||||
|
@ -482,6 +490,13 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (wallet.type == WalletType.xelis) {
|
||||||
|
final outputCount = pendingTransaction?.outputCount ?? 0;
|
||||||
|
if (outputCount > 255) {
|
||||||
|
throw Exception("Xelis does not support more than 255 outputs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
state = ExecutedSuccessfullyState();
|
state = ExecutedSuccessfullyState();
|
||||||
return pendingTransaction;
|
return pendingTransaction;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -534,6 +549,11 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String normalizeAmount(String amount) {
|
||||||
|
if (amount.contains('.')) return amount;
|
||||||
|
return '$amount.0';
|
||||||
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<void> commitTransaction(BuildContext context) async {
|
Future<void> commitTransaction(BuildContext context) async {
|
||||||
if (pendingTransaction == null) {
|
if (pendingTransaction == null) {
|
||||||
|
@ -558,11 +578,25 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String address = outputs.fold('', (acc, value) {
|
late String address;
|
||||||
return value.isParsedAddress
|
|
||||||
? '$acc${value.address}\n${value.extractedAddress}\n\n'
|
if (walletType == WalletType.xelis) {
|
||||||
: '$acc${value.address}\n\n';
|
address = outputs.fold('', (acc, value) {
|
||||||
});
|
final nameLine = value.isParsedAddress ? '${value.address}\n' : '';
|
||||||
|
final realAddress = value.isParsedAddress ? value.extractedAddress : value.address;
|
||||||
|
final amount = normalizeAmount(value.cryptoAmount ?? '0.0');
|
||||||
|
final symbol = value.cryptoCurrencyHandler().title ?? '';
|
||||||
|
final amountPart = outputs.length > 1 ? ' ($amount $symbol)' : '';
|
||||||
|
|
||||||
|
return '$acc$nameLine$realAddress$amountPart\n\n';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
address = outputs.fold('', (acc, value) {
|
||||||
|
return value.isParsedAddress
|
||||||
|
? '$acc${value.address}\n${value.extractedAddress}\n\n'
|
||||||
|
: '$acc${value.address}\n\n';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
address = address.trim();
|
address = address.trim();
|
||||||
|
|
||||||
|
@ -677,6 +711,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
this.coinTypeToSpendFrom = UnspentCoinType.any;
|
this.coinTypeToSpendFrom = UnspentCoinType.any;
|
||||||
return decred!.createDecredTransactionCredentials(outputs, priority!);
|
return decred!.createDecredTransactionCredentials(outputs, priority!);
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelis!.createXelisTransactionCredentials(outputs, priority: priority!, currency: selectedCryptoCurrency);
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${wallet.type}');
|
throw Exception('Unexpected wallet type: ${wallet.type}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,11 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
final dateFormat = DateFormatter.withCurrentLocal();
|
final dateFormat = DateFormatter.withCurrentLocal();
|
||||||
final tx = transactionInfo;
|
final tx = transactionInfo;
|
||||||
|
|
||||||
|
final descriptionKey = '${transactionInfo.txHash}_${wallet.walletAddresses.primaryAddress}';
|
||||||
|
final description = transactionDescriptionBox.values.firstWhere(
|
||||||
|
(val) => val.id == descriptionKey || val.id == transactionInfo.txHash,
|
||||||
|
orElse: () => TransactionDescription(id: descriptionKey));
|
||||||
|
|
||||||
// TODO: can be cleaned further
|
// TODO: can be cleaned further
|
||||||
switch (wallet.type) {
|
switch (wallet.type) {
|
||||||
case WalletType.monero:
|
case WalletType.monero:
|
||||||
|
@ -88,16 +93,14 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
_addDecredListItems(tx, dateFormat);
|
_addDecredListItems(tx, dateFormat);
|
||||||
break;
|
break;
|
||||||
|
case WalletType.xelis:
|
||||||
|
_addXelisListItems(tx, dateFormat, description.recipientAddress?.isEmpty ?? true);
|
||||||
|
break;
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
final descriptionKey = '${transactionInfo.txHash}_${wallet.walletAddresses.primaryAddress}';
|
|
||||||
final description = transactionDescriptionBox.values.firstWhere(
|
|
||||||
(val) => val.id == descriptionKey || val.id == transactionInfo.txHash,
|
|
||||||
orElse: () => TransactionDescription(id: descriptionKey));
|
|
||||||
|
|
||||||
if (showRecipientAddress && !isRecipientAddressShown) {
|
if (showRecipientAddress && !isRecipientAddressShown) {
|
||||||
final recipientAddress = description.recipientAddress;
|
final recipientAddress = description.recipientAddress;
|
||||||
|
|
||||||
|
@ -193,6 +196,8 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
return 'https://explorer.zano.org/transaction/${txId}';
|
return 'https://explorer.zano.org/transaction/${txId}';
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return 'https://${wallet.isTestnet ? "testnet" : "dcrdata"}.decred.org/tx/${txId.split(':')[0]}';
|
return 'https://${wallet.isTestnet ? "testnet" : "dcrdata"}.decred.org/tx/${txId.split(':')[0]}';
|
||||||
|
case WalletType.xelis:
|
||||||
|
return 'https://${wallet.isTestnet ? "testnet-" : ""}explorer.xelis.io/txs/${txId}';
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -227,6 +232,8 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
return S.current.view_transaction_on + 'explorer.zano.org';
|
return S.current.view_transaction_on + 'explorer.zano.org';
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return S.current.view_transaction_on + 'dcrdata.decred.org';
|
return S.current.view_transaction_on + 'dcrdata.decred.org';
|
||||||
|
case WalletType.xelis:
|
||||||
|
return S.current.view_transaction_on + 'explorer.xelis.io';
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@ -562,6 +569,58 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
items.addAll(_items);
|
items.addAll(_items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _addXelisListItems(TransactionInfo tx, DateFormat dateFormat, bool showTo) {
|
||||||
|
final _items = [
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_transaction_id,
|
||||||
|
value: tx.id,
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_id_key'),
|
||||||
|
),
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_date,
|
||||||
|
value: dateFormat.format(tx.date),
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_date_key'),
|
||||||
|
),
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_height,
|
||||||
|
value: '${tx.height}',
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_height_key'),
|
||||||
|
),
|
||||||
|
if (!tx.amountFormatted().startsWith(":MULTI:"))
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_amount,
|
||||||
|
value: tx.amountFormatted(),
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_amount_key'),
|
||||||
|
),
|
||||||
|
if (tx.amountFormatted().startsWith(":MULTI:"))
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_multi_breakdown,
|
||||||
|
value: tx.amountFormatted().split(":MULTI:")[1]!,
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_multi_breakdown_key'),
|
||||||
|
),
|
||||||
|
if (tx.feeFormatted()?.isNotEmpty ?? false && tx.direction == TransactionDirection.outgoing)
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_fee,
|
||||||
|
value: tx.feeFormatted()!,
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_fee_key'),
|
||||||
|
),
|
||||||
|
if (showRecipientAddress && tx.to != null && showTo)
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_recipient_address,
|
||||||
|
value: tx.to!,
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_recipient_address_key'),
|
||||||
|
),
|
||||||
|
if (tx.from != null)
|
||||||
|
StandartListItem(
|
||||||
|
title: S.current.transaction_details_source_address,
|
||||||
|
value: tx.from!,
|
||||||
|
key: ValueKey('standard_list_item_transaction_details_source_address_key'),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
items.addAll(_items);
|
||||||
|
}
|
||||||
|
|
||||||
void addBumpFeesListItems(TransactionInfo tx, String rawTransaction) {
|
void addBumpFeesListItems(TransactionInfo tx, String rawTransaction) {
|
||||||
transactionPriority = bitcoin!.getBitcoinTransactionPriorityMedium();
|
transactionPriority = bitcoin!.getBitcoinTransactionPriorityMedium();
|
||||||
final inputsCount = (transactionInfo.inputAddresses?.isEmpty ?? true)
|
final inputsCount = (transactionInfo.inputAddresses?.isEmpty ?? true)
|
||||||
|
@ -629,7 +688,7 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transactionInfo.outputAddresses != null && transactionInfo.outputAddresses!.isNotEmpty) {
|
if (transactionInfo.outputAddresses != null && transactionInfo.outputAddresses!.isNotEmpty && wallet.type != WalletType.xelis) {
|
||||||
final outputAddresses = transactionInfo.outputAddresses!.map((element) {
|
final outputAddresses = transactionInfo.outputAddresses!.map((element) {
|
||||||
if (element.contains('OP_RETURN:') && element.length > 40) {
|
if (element.contains('OP_RETURN:') && element.length > 40) {
|
||||||
return element.substring(0, 40) + '...';
|
return element.substring(0, 40) + '...';
|
||||||
|
@ -670,7 +729,7 @@ abstract class TransactionDetailsViewModelBase with Store {
|
||||||
value: tx.feeFormatted()!,
|
value: tx.feeFormatted()!,
|
||||||
key: ValueKey('standard_list_item_transaction_details_fee_key'),
|
key: ValueKey('standard_list_item_transaction_details_fee_key'),
|
||||||
),
|
),
|
||||||
if (showRecipientAddress && tx.to != null)
|
if (showRecipientAddress && tx.to != null && tx.direction == TransactionDirection.outgoing)
|
||||||
StandartListItem(
|
StandartListItem(
|
||||||
title: S.current.transaction_details_recipient_address,
|
title: S.current.transaction_details_recipient_address,
|
||||||
value: tron!.getTronBase58Address(tx.to!, wallet),
|
value: tron!.getTronBase58Address(tx.to!, wallet),
|
||||||
|
|
|
@ -242,6 +242,22 @@ class DecredURI extends PaymentURI {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class XelisURI extends PaymentURI {
|
||||||
|
XelisURI({required String amount, required String address})
|
||||||
|
: super(amount: amount, address: address);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
var base = 'xelis:' + address;
|
||||||
|
|
||||||
|
if (amount.isNotEmpty) {
|
||||||
|
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||||
|
}
|
||||||
|
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
|
abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewModel with Store {
|
||||||
WalletAddressListViewModelBase({
|
WalletAddressListViewModelBase({
|
||||||
required AppStore appStore,
|
required AppStore appStore,
|
||||||
|
@ -350,6 +366,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
||||||
return ZanoURI(amount: amount, address: address.address);
|
return ZanoURI(amount: amount, address: address.address);
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return DecredURI(amount: amount, address: address.address);
|
return DecredURI(amount: amount, address: address.address);
|
||||||
|
case WalletType.xelis:
|
||||||
|
return XelisURI(amount: amount, address: address.address);
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,7 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
|
case WalletType.xelis:
|
||||||
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||||
//
|
//
|
||||||
// items.addAll([
|
// items.addAll([
|
||||||
|
@ -252,6 +253,8 @@ abstract class WalletKeysViewModelBase with Store {
|
||||||
return 'zano-wallet';
|
return 'zano-wallet';
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return 'decred-wallet';
|
return 'decred-wallet';
|
||||||
|
case WalletType.xelis:
|
||||||
|
return 'xelis-wallet';
|
||||||
default:
|
default:
|
||||||
throw Exception('Unexpected wallet type: ${_wallet.type.toString()}');
|
throw Exception('Unexpected wallet type: ${_wallet.type.toString()}');
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ import 'package:cake_wallet/store/app_store.dart';
|
||||||
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
import 'package:cake_wallet/view_model/seed_settings_view_model.dart';
|
||||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||||
import 'package:cake_wallet/decred/decred.dart';
|
import 'package:cake_wallet/decred/decred.dart';
|
||||||
|
import 'package:cake_wallet/xelis/xelis.dart';
|
||||||
import 'package:cw_core/wallet_base.dart';
|
import 'package:cw_core/wallet_base.dart';
|
||||||
import 'package:cw_core/wallet_credentials.dart';
|
import 'package:cw_core/wallet_credentials.dart';
|
||||||
import 'package:cw_core/wallet_info.dart';
|
import 'package:cw_core/wallet_info.dart';
|
||||||
|
@ -47,7 +48,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||||
String selectedMnemonicLanguage;
|
String selectedMnemonicLanguage;
|
||||||
|
|
||||||
bool get hasLanguageSelector =>
|
bool get hasLanguageSelector =>
|
||||||
[WalletType.monero, WalletType.haven, WalletType.wownero].contains(type);
|
[WalletType.monero, WalletType.haven, WalletType.wownero, WalletType.xelis].contains(type);
|
||||||
|
|
||||||
bool get showLanguageSelector =>
|
bool get showLanguageSelector =>
|
||||||
newWalletArguments?.mnemonic == null && hasLanguageSelector;
|
newWalletArguments?.mnemonic == null && hasLanguageSelector;
|
||||||
|
@ -141,6 +142,11 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
||||||
);
|
);
|
||||||
case WalletType.decred:
|
case WalletType.decred:
|
||||||
return decred!.createDecredNewWalletCredentials(name: name);
|
return decred!.createDecredNewWalletCredentials(name: name);
|
||||||
|
case WalletType.xelis:
|
||||||
|
return xelis!.createXelisNewWalletCredentials(
|
||||||
|
name: name,
|
||||||
|
password: walletPassword,
|
||||||
|
);
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
case WalletType.haven:
|
case WalletType.haven:
|
||||||
throw Exception('Unexpected type: ${type.toString()}');
|
throw Exception('Unexpected type: ${type.toString()}');
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue