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
|
||||
*.pyc
|
||||
*.swp
|
||||
*.zip
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
|
@ -140,6 +141,7 @@ lib/tron/tron.dart
|
|||
lib/wownero/wownero.dart
|
||||
lib/zano/zano.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~ipad.png
|
||||
|
|
|
@ -84,6 +84,12 @@ Cake Wallet includes support for several cryptocurrencies, including:
|
|||
* Automatically generate new addresses
|
||||
* 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
|
||||
|
||||
## Open Source Monero-Only Wallet
|
||||
|
|
|
@ -23,6 +23,7 @@ analyzer:
|
|||
lib/tron/cw_tron.dart,
|
||||
lib/wownero/cw_wownero.dart,
|
||||
lib/zano/cw_zano.dart,
|
||||
lib/xelis/cw_xelis.dart,
|
||||
]
|
||||
language:
|
||||
strict-casts: true
|
||||
|
|
|
@ -14,4 +14,15 @@
|
|||
<natures>
|
||||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||
</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>
|
||||
|
|
|
@ -1,2 +1,13 @@
|
|||
arguments=
|
||||
auto.sync=false
|
||||
build.scans.enabled=false
|
||||
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||
connection.project.dir=
|
||||
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
|
||||
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_archive_name=Cake Wallet.zip
|
||||
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% ===)
|
||||
|
||||
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
|
||||
call flutter pub get > 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.ton,
|
||||
CryptoCurrency.flip,
|
||||
CryptoCurrency.deuro
|
||||
CryptoCurrency.deuro,
|
||||
CryptoCurrency.xel,
|
||||
CryptoCurrency.xet
|
||||
];
|
||||
|
||||
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 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 =
|
||||
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
||||
acc.addAll({item.raw: item});
|
||||
|
|
|
@ -34,6 +34,11 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
|
|||
return CryptoCurrency.zano;
|
||||
case WalletType.decred:
|
||||
return CryptoCurrency.dcr;
|
||||
case WalletType.xelis:
|
||||
if (isTestnet == true) {
|
||||
return CryptoCurrency.xet;
|
||||
}
|
||||
return CryptoCurrency.xel;
|
||||
case WalletType.none:
|
||||
throw Exception(
|
||||
'Unexpected wallet type: ${type.toString()} for CryptoCurrency currencyForWalletType');
|
||||
|
@ -70,6 +75,8 @@ WalletType? walletTypeForCurrency(CryptoCurrency currency) {
|
|||
return WalletType.zano;
|
||||
case CryptoCurrency.dcr:
|
||||
return WalletType.decred;
|
||||
case CryptoCurrency.xel:
|
||||
return WalletType.xelis;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -22,3 +22,4 @@ const MWEB_UTXO_TYPE_ID = 20;
|
|||
const HAVEN_SEED_STORE_TYPE_ID = 21;
|
||||
const ZANO_ASSET_TYPE_ID = 22;
|
||||
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.zano:
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
return Uri.parse(
|
||||
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") || path!.isEmpty ? path : "/$path"}");
|
||||
case WalletType.none:
|
||||
|
@ -165,6 +166,7 @@ class Node extends HiveObject with Keyable {
|
|||
case WalletType.polygon:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
case WalletType.xelis:
|
||||
return requestElectrumServer();
|
||||
case WalletType.zano:
|
||||
return requestZanoNode();
|
||||
|
|
|
@ -18,6 +18,7 @@ const walletTypes = [
|
|||
WalletType.tron,
|
||||
WalletType.zano,
|
||||
WalletType.decred,
|
||||
WalletType.xelis,
|
||||
];
|
||||
|
||||
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
||||
|
@ -65,7 +66,10 @@ enum WalletType {
|
|||
zano,
|
||||
|
||||
@HiveField(14)
|
||||
decred
|
||||
decred,
|
||||
|
||||
@HiveField(15)
|
||||
xelis
|
||||
}
|
||||
|
||||
int serializeToInt(WalletType type) {
|
||||
|
@ -98,6 +102,8 @@ int serializeToInt(WalletType type) {
|
|||
return 12;
|
||||
case WalletType.decred:
|
||||
return 13;
|
||||
case WalletType.xelis:
|
||||
return 14;
|
||||
case WalletType.none:
|
||||
return -1;
|
||||
}
|
||||
|
@ -133,6 +139,8 @@ WalletType deserializeFromInt(int raw) {
|
|||
return WalletType.zano;
|
||||
case 13:
|
||||
return WalletType.decred;
|
||||
case 14:
|
||||
return WalletType.xelis;
|
||||
default:
|
||||
throw Exception(
|
||||
'Unexpected token: $raw for WalletType deserializeFromInt');
|
||||
|
@ -169,6 +177,8 @@ String walletTypeToString(WalletType type) {
|
|||
return 'Zano';
|
||||
case WalletType.decred:
|
||||
return 'Decred';
|
||||
case WalletType.xelis:
|
||||
return 'Xelis';
|
||||
case WalletType.none:
|
||||
return '';
|
||||
}
|
||||
|
@ -204,6 +214,8 @@ String walletTypeToDisplayName(WalletType type) {
|
|||
return 'Zano (ZANO)';
|
||||
case WalletType.decred:
|
||||
return 'Decred (DCR)';
|
||||
case WalletType.xelis:
|
||||
return 'Xelis (XEL)';
|
||||
case WalletType.none:
|
||||
return '';
|
||||
}
|
||||
|
@ -242,6 +254,11 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
|
|||
return CryptoCurrency.zano;
|
||||
case WalletType.decred:
|
||||
return CryptoCurrency.dcr;
|
||||
case WalletType.xelis:
|
||||
if (isTestnet) {
|
||||
return CryptoCurrency.xet;
|
||||
}
|
||||
return CryptoCurrency.xel;
|
||||
case WalletType.none:
|
||||
throw Exception(
|
||||
'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
|
||||
int calculateEstimatedFee(TransactionPriority priority, [int? amount = null]) =>
|
||||
int (TransactionPriority priority, [int? amount = null]) =>
|
||||
getCurrentTxFee(priority);
|
||||
|
||||
@override
|
||||
|
|
|
@ -100,6 +100,15 @@ class WalletKeysAndSeedPageRobot {
|
|||
commonTestCases.hasText(appStore.wallet!.privateKey!);
|
||||
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);
|
||||
|
|
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 IsExecutingState extends ExecutionState {}
|
||||
class IsLoadingState extends ExecutionState {}
|
||||
|
||||
class ExecutedSuccessfullyState extends ExecutionState {
|
||||
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/zano/zano.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:cw_core/wallet_type.dart';
|
||||
|
||||
|
@ -50,6 +51,8 @@ class SeedValidator extends Validator<MnemonicItem> {
|
|||
return zano!.getWordList(language);
|
||||
case WalletType.decred:
|
||||
return decred!.getDecredWordList();
|
||||
case WalletType.xelis:
|
||||
return xelis!.getXelisWordList(language);
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
return [];
|
||||
|
|
|
@ -91,6 +91,7 @@ class WalletCreationService {
|
|||
case WalletType.banano:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ class WalletLoadingService {
|
|||
}
|
||||
final walletService = walletServiceFactory.call(type);
|
||||
final walletPassword = password ?? (await keyService.getWalletPassword(walletName: name));
|
||||
|
||||
final wallet = await walletService.openWallet(name, walletPassword);
|
||||
|
||||
if (type == WalletType.monero) {
|
||||
|
@ -93,6 +94,7 @@ class WalletLoadingService {
|
|||
try {
|
||||
final walletService = walletServiceFactory.call(walletInfo.type);
|
||||
final walletPassword = await keyService.getWalletPassword(walletName: walletInfo.name);
|
||||
|
||||
wallet = await walletService.openWallet(walletInfo.name, walletPassword);
|
||||
|
||||
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/polygon/polygon.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/routes.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
|
@ -1153,6 +1154,8 @@ Future<void> setup({
|
|||
return zano!.createZanoWalletService(_walletInfoSource);
|
||||
case WalletType.decred:
|
||||
return decred!.createDecredWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||
case WalletType.xelis:
|
||||
return xelis!.createXelisWalletService(_walletInfoSource, SettingsStoreBase.walletPasswordDirectInput);
|
||||
case WalletType.haven:
|
||||
return HavenWalletService(_walletInfoSource);
|
||||
case WalletType.none:
|
||||
|
|
|
@ -46,6 +46,8 @@ const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
|||
const zanoDefaultNodeUri = 'zano.cakewallet.com:11211';
|
||||
const moneroWorldNodeUri = '.moneroworld.com';
|
||||
const decredDefaultUri = "default-spv-nodes";
|
||||
const xelisDefaultUri = "us-node.xelis.io";
|
||||
const xelisTestnetUri = "testnet-node.xelis.io";
|
||||
|
||||
Future<void> defaultSettingsMigration(
|
||||
{required int version,
|
||||
|
@ -511,6 +513,17 @@ Future<void> defaultSettingsMigration(
|
|||
enabled: true,
|
||||
);
|
||||
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:
|
||||
break;
|
||||
}
|
||||
|
@ -617,6 +630,8 @@ String _getDefaultNodeUri(WalletType type) {
|
|||
return zanoDefaultNodeUri;
|
||||
case WalletType.decred:
|
||||
return decredDefaultUri;
|
||||
case WalletType.xelis:
|
||||
return xelisDefaultUri;
|
||||
case WalletType.banano:
|
||||
case WalletType.none:
|
||||
return '';
|
||||
|
@ -807,6 +822,12 @@ Node? getBitcoinTestnetDefaultElectrumServer({required Box<Node> nodes}) {
|
|||
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}) {
|
||||
final defaultUri = _getDefaultNodeUri(type);
|
||||
return nodes.values.firstWhereOrNull((Node node) => node.uriRaw == defaultUri) ??
|
||||
|
@ -1045,6 +1066,7 @@ Future<void> checkCurrentNodes(
|
|||
final currentNanoNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoNodeIdKey);
|
||||
final currentNanoPowNodeId = sharedPreferences.getInt(PreferencesKey.currentNanoPowNodeIdKey);
|
||||
final currentDecredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
||||
final currentXelisNodeId = sharedPreferences.getInt(PreferencesKey.currentXelisNodeIdKey);
|
||||
final currentBitcoinCashNodeId =
|
||||
sharedPreferences.getInt(PreferencesKey.currentBitcoinCashNodeIdKey);
|
||||
final currentSolanaNodeId = sharedPreferences.getInt(PreferencesKey.currentSolanaNodeIdKey);
|
||||
|
@ -1079,6 +1101,8 @@ Future<void> checkCurrentNodes(
|
|||
nodeSource.values.firstWhereOrNull((node) => node.key == currentWowneroNodeId);
|
||||
final currentZanoNode =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentZanoNodeId);
|
||||
final currentXelisNodeServer =
|
||||
nodeSource.values.firstWhereOrNull((node) => node.key == currentXelisNodeId);
|
||||
|
||||
if (currentMoneroNode == null) {
|
||||
final newCakeWalletNode = Node(uri: newCakeWalletMoneroUri, type: WalletType.monero);
|
||||
|
@ -1175,6 +1199,15 @@ Future<void> checkCurrentNodes(
|
|||
await nodeSource.add(node);
|
||||
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(
|
||||
|
|
|
@ -46,6 +46,9 @@ Future<List<Node>> loadDefaultNodes(WalletType type) async {
|
|||
case WalletType.decred:
|
||||
path = 'assets/decred_node_list.yml';
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
path = 'assets/xelis_node_list.yml';
|
||||
break;
|
||||
case WalletType.banano:
|
||||
case WalletType.none:
|
||||
path = '';
|
||||
|
@ -96,6 +99,7 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
|||
final tronNodes = await loadDefaultNodes(WalletType.tron);
|
||||
final decredNodes = await loadDefaultNodes(WalletType.decred);
|
||||
final zanoNodes = await loadDefaultNodes(WalletType.zano);
|
||||
final xelisNodes = await loadDefaultNodes(WalletType.xelis);
|
||||
|
||||
final nodes = moneroNodes +
|
||||
bitcoinElectrumServerList +
|
||||
|
@ -108,7 +112,8 @@ Future<void> resetToDefault(Box<Node> nodeSource) async {
|
|||
solanaNodes +
|
||||
tronNodes +
|
||||
zanoNodes +
|
||||
decredNodes;
|
||||
decredNodes +
|
||||
xelisNodes;
|
||||
|
||||
await nodeSource.clear();
|
||||
await nodeSource.addAll(nodes);
|
||||
|
|
|
@ -19,6 +19,7 @@ class PreferencesKey {
|
|||
static const currentSolanaNodeIdKey = 'current_node_id_sol';
|
||||
static const currentTronNodeIdKey = 'current_node_id_trx';
|
||||
static const currentWowneroNodeIdKey = 'current_node_id_wow';
|
||||
static const currentXelisNodeIdKey = 'current_node_id_xelis';
|
||||
static const currentTransactionPriorityKeyLegacy = 'current_fee_priority';
|
||||
static const currentBalanceDisplayModeKey = 'current_balance_display_mode';
|
||||
static const shouldSaveRecipientAddressKey = 'save_recipient_address';
|
||||
|
@ -52,6 +53,7 @@ class PreferencesKey {
|
|||
static const zanoTransactionPriority = 'current_fee_priority_zano';
|
||||
static const wowneroTransactionPriority = 'current_fee_priority_wownero';
|
||||
static const decredTransactionPriority = 'current_fee_priority_decred';
|
||||
static const xelisTransactionPriority = 'current_fee_priority_xelis';
|
||||
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
|
||||
static const silentPaymentsCardDisplay = 'silentPaymentsCardDisplay';
|
||||
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/zano/zano.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/wallet_type.dart';
|
||||
|
||||
|
@ -35,6 +36,8 @@ List<TransactionPriority> priorityForWalletType(WalletType type) {
|
|||
return zano!.getTransactionPriorities();
|
||||
case WalletType.decred:
|
||||
return decred!.getTransactionPriorities();
|
||||
case WalletType.xelis:
|
||||
return xelis!.getTransactionPriorities();
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
return [];
|
||||
|
|
|
@ -52,6 +52,8 @@ import 'package:cw_core/window_size.dart';
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:cake_wallet/core/trade_monitor.dart';
|
||||
|
||||
import 'frb_init.g.dart';
|
||||
|
||||
final navigatorKey = GlobalKey<NavigatorState>();
|
||||
final rootKey = GlobalKey<RootState>();
|
||||
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
||||
|
@ -63,6 +65,7 @@ Future<void> main({Key? topLevelKey}) async {
|
|||
Future<void> runAppWithZone({Key? topLevelKey}) async {
|
||||
bool isAppRunning = false;
|
||||
|
||||
await frb_init();
|
||||
await runZonedGuarded(() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
FlutterError.onError = ExceptionHandler.onError;
|
||||
|
@ -228,7 +231,7 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
|||
payjoinSessionSource: payjoinSessionSource,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
havenSeedStore: havenSeedStore,
|
||||
initialMigrationVersion: 49,
|
||||
initialMigrationVersion: 50,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ bool isBIP39Wallet(WalletType walletType) {
|
|||
case WalletType.haven:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
case WalletType.none:
|
||||
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/settings_store.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/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -54,6 +55,11 @@ Future<void> startFiatRateUpdate(
|
|||
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) {
|
||||
for (final currency in currencies) {
|
||||
// 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/solana/solana.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/transaction_history.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
|
@ -132,6 +133,10 @@ void startCurrentWalletChangeReaction(
|
|||
currencies =
|
||||
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) {
|
||||
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 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 xelisIcon = Image.asset('assets/images/xelis_icon.png', height: 24, width: 24);
|
||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||
|
||||
Image _newWalletImage(BuildContext context) => Image.asset(
|
||||
|
@ -181,6 +182,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
|||
return zanoIcon;
|
||||
case WalletType.decred:
|
||||
return decredIcon;
|
||||
case WalletType.xelis:
|
||||
return xelisIcon;
|
||||
default:
|
||||
return nonWalletTypeIcon;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
this.tronIcon = Image.asset('assets/images/trx_icon.png'),
|
||||
this.wowneroIcon = Image.asset('assets/images/wownero_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;
|
||||
|
||||
|
@ -64,6 +65,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
Image wowneroIcon;
|
||||
Image zanoIcon;
|
||||
Image decredIcon;
|
||||
Image xelisIcon;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -255,6 +257,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
return zanoIcon;
|
||||
case WalletType.decred:
|
||||
return decredIcon;
|
||||
case WalletType.xelis:
|
||||
return xelisIcon;
|
||||
default:
|
||||
throw Exception('No icon for ${type.toString()}');
|
||||
}
|
||||
|
|
|
@ -275,7 +275,8 @@ class _AdvancedPrivacySettingsBodyState extends State<_AdvancedPrivacySettingsBo
|
|||
);
|
||||
}),
|
||||
if (widget.privacySettingsViewModel.type == WalletType.bitcoin ||
|
||||
widget.privacySettingsViewModel.type == WalletType.decred)
|
||||
widget.privacySettingsViewModel.type == WalletType.decred ||
|
||||
widget.privacySettingsViewModel.type == WalletType.xelis)
|
||||
Builder(builder: (_) {
|
||||
final val = testnetValue ?? false;
|
||||
return SettingsSwitcherCell(
|
||||
|
|
|
@ -24,7 +24,7 @@ class RescanPage extends BasePage {
|
|||
@override
|
||||
Widget body(BuildContext context) {
|
||||
Widget child;
|
||||
if (_rescanViewModel.wallet.type != WalletType.decred) {
|
||||
if (_rescanViewModel.wallet.type != WalletType.decred && _rescanViewModel.wallet.type != WalletType.xelis) {
|
||||
child = Padding(
|
||||
padding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
child: Column(
|
||||
|
|
|
@ -584,6 +584,7 @@ class _WalletRestorePageBodyState extends State<_WalletRestorePageBody>
|
|||
|
||||
if (seedWords.length == 14 && walletRestoreViewModel.type == WalletType.wownero) 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) {
|
||||
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 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 xelisIcon = Image.asset('assets/images/xelis_icon.png', height: 24, width: 24);
|
||||
final scrollController = ScrollController();
|
||||
final double tileHeight = 60;
|
||||
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) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
dismissFlushBar(_authBar);
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'dart:io';
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/utilities.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/core/secure_storage.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
|
@ -137,6 +138,7 @@ abstract class SettingsStoreBase with Store {
|
|||
TransactionPriority? initialBitcoinCashTransactionPriority,
|
||||
TransactionPriority? initialZanoTransactionPriority,
|
||||
TransactionPriority? initialDecredTransactionPriority,
|
||||
TransactionPriority? initialXelisTransactionPriority,
|
||||
Country? initialCakePayCountry})
|
||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
|
||||
|
@ -225,6 +227,9 @@ abstract class SettingsStoreBase with Store {
|
|||
if (initialDecredTransactionPriority != null) {
|
||||
priority[WalletType.decred] = initialDecredTransactionPriority;
|
||||
}
|
||||
if (initialXelisTransactionPriority != null) {
|
||||
priority[WalletType.xelis] = initialXelisTransactionPriority;
|
||||
}
|
||||
|
||||
if (initialCakePayCountry != null) {
|
||||
selectedCakePayCountry = initialCakePayCountry;
|
||||
|
@ -283,6 +288,9 @@ abstract class SettingsStoreBase with Store {
|
|||
case WalletType.decred:
|
||||
key = PreferencesKey.decredTransactionPriority;
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
key = PreferencesKey.xelisTransactionPriority;
|
||||
break;
|
||||
default:
|
||||
key = null;
|
||||
}
|
||||
|
@ -912,6 +920,7 @@ abstract class SettingsStoreBase with Store {
|
|||
TransactionPriority? wowneroTransactionPriority;
|
||||
TransactionPriority? zanoTransactionPriority;
|
||||
TransactionPriority? decredTransactionPriority;
|
||||
TransactionPriority? xelisTransactionPriority;
|
||||
|
||||
if (sharedPreferences.getInt(PreferencesKey.havenTransactionPriority) != null) {
|
||||
havenTransactionPriority = monero?.deserializeMoneroTransactionPriority(
|
||||
|
@ -945,6 +954,10 @@ abstract class SettingsStoreBase with Store {
|
|||
decredTransactionPriority = decred?.deserializeDecredTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
|
||||
}
|
||||
if (sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority) != null) {
|
||||
xelisTransactionPriority = xelis?.deserializeXelisTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority)!);
|
||||
}
|
||||
|
||||
moneroTransactionPriority ??= monero?.getDefaultTransactionPriority();
|
||||
bitcoinTransactionPriority ??= bitcoin?.getMediumTransactionPriority();
|
||||
|
@ -954,6 +967,7 @@ abstract class SettingsStoreBase with Store {
|
|||
bitcoinCashTransactionPriority ??= bitcoinCash?.getDefaultTransactionPriority();
|
||||
wowneroTransactionPriority ??= wownero?.getDefaultTransactionPriority();
|
||||
decredTransactionPriority ??= decred?.getDecredTransactionPriorityMedium();
|
||||
xelisTransactionPriority ??= xelis?.getXelisTransactionPriorityMedium();
|
||||
polygonTransactionPriority ??= polygon?.getDefaultTransactionPriority();
|
||||
zanoTransactionPriority ??= zano?.getDefaultTransactionPriority();
|
||||
|
||||
|
@ -1050,6 +1064,7 @@ abstract class SettingsStoreBase with Store {
|
|||
final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
|
||||
final zanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
|
||||
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
||||
final xelisNodeId = sharedPreferences.getInt(PreferencesKey.currentXelisNodeIdKey);
|
||||
|
||||
/// get the selected node, if null, then use the default
|
||||
final moneroNode = nodeSource.get(nodeId) ??
|
||||
|
@ -1068,6 +1083,8 @@ abstract class SettingsStoreBase with Store {
|
|||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultNodeUri);
|
||||
final decredNode = nodeSource.get(decredNodeId) ??
|
||||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == decredDefaultUri);
|
||||
final xelisNode = nodeSource.get(xelisNodeId) ??
|
||||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == xelisDefaultUri);
|
||||
final nanoPowNode = powNodeSource.get(nanoPowNodeId) ??
|
||||
nodeSource.values.firstWhereOrNull((e) => e.uriRaw == nanoDefaultPowNodeUri);
|
||||
final solanaNode = nodeSource.get(solanaNodeId) ??
|
||||
|
@ -1164,6 +1181,10 @@ abstract class SettingsStoreBase with Store {
|
|||
nodes[WalletType.decred] = decredNode;
|
||||
}
|
||||
|
||||
if (xelisNode != null) {
|
||||
nodes[WalletType.xelis] = xelisNode;
|
||||
}
|
||||
|
||||
final savedSyncMode = SyncMode.all.firstWhere((element) {
|
||||
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,
|
||||
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
|
||||
initialDecredTransactionPriority: decredTransactionPriority,
|
||||
initialXelisTransactionPriority: xelisTransactionPriority,
|
||||
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
|
||||
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
|
||||
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
|
||||
|
@ -1412,6 +1434,11 @@ abstract class SettingsStoreBase with Store {
|
|||
priority[WalletType.decred] = decred!.deserializeDecredTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.decredTransactionPriority)!);
|
||||
}
|
||||
if (xelis != null &&
|
||||
sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority) != null) {
|
||||
priority[WalletType.xelis] = xelis!.deserializeXelisTransactionPriority(
|
||||
sharedPreferences.getInt(PreferencesKey.xelisTransactionPriority)!);
|
||||
}
|
||||
|
||||
final generateSubaddresses =
|
||||
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
|
||||
|
@ -1522,6 +1549,7 @@ abstract class SettingsStoreBase with Store {
|
|||
final wowneroNodeId = sharedPreferences.getInt(PreferencesKey.currentWowneroNodeIdKey);
|
||||
final zanoNodeId = sharedPreferences.getInt(PreferencesKey.currentZanoNodeIdKey);
|
||||
final decredNodeId = sharedPreferences.getInt(PreferencesKey.currentDecredNodeIdKey);
|
||||
final xelisNodeId = sharedPreferences.getInt(PreferencesKey.currentXelisNodeIdKey);
|
||||
final moneroNode = nodeSource.get(nodeId);
|
||||
final bitcoinElectrumServer = nodeSource.get(bitcoinElectrumServerId);
|
||||
final litecoinElectrumServer = nodeSource.get(litecoinElectrumServerId);
|
||||
|
@ -1535,6 +1563,7 @@ abstract class SettingsStoreBase with Store {
|
|||
final wowneroNode = nodeSource.get(wowneroNodeId);
|
||||
final zanoNode = nodeSource.get(zanoNodeId);
|
||||
final decredNode = nodeSource.get(decredNodeId);
|
||||
final xelisNode = nodeSource.get(xelisNodeId);
|
||||
|
||||
if (moneroNode != null) {
|
||||
nodes[WalletType.monero] = moneroNode;
|
||||
|
@ -1589,6 +1618,9 @@ abstract class SettingsStoreBase with Store {
|
|||
nodes[WalletType.decred] = decredNode;
|
||||
}
|
||||
|
||||
if (xelisNode != null) {
|
||||
nodes[WalletType.xelis] = xelisNode;
|
||||
}
|
||||
// MIGRATED:
|
||||
|
||||
useTOTP2FA = await SecureKey.getBool(
|
||||
|
@ -1728,6 +1760,9 @@ abstract class SettingsStoreBase with Store {
|
|||
case WalletType.decred:
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentDecredNodeIdKey, node.key as int);
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentXelisNodeIdKey, node.key as int);
|
||||
break;
|
||||
case WalletType.zano:
|
||||
await _sharedPreferences.setInt(PreferencesKey.currentZanoNodeIdKey, node.key as int);
|
||||
default:
|
||||
|
|
|
@ -11,7 +11,103 @@ class AddressFormatter {
|
|||
TextAlign? textAlign,
|
||||
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 isMWEB = address.startsWith('ltcmweb');
|
||||
final chunkSize = walletType != null ? _getChunkSize(walletType) : 4;
|
||||
|
|
|
@ -56,6 +56,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
case WalletType.haven:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,7 +112,8 @@ abstract class BalanceViewModelBase with Store {
|
|||
isEVMCompatibleChain(wallet.type) ||
|
||||
wallet.type == WalletType.solana ||
|
||||
wallet.type == WalletType.tron ||
|
||||
wallet.type == WalletType.zano;
|
||||
wallet.type == WalletType.zano ||
|
||||
wallet.type == WalletType.xelis;
|
||||
|
||||
@computed
|
||||
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/monero/monero.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/app_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;
|
||||
|
||||
@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
|
||||
bool get hasRescan => wallet.hasRescan;
|
||||
|
@ -859,6 +861,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
return true;
|
||||
case WalletType.zano:
|
||||
case WalletType.haven:
|
||||
case WalletType.xelis: // TODO: finalize whether to change this
|
||||
case WalletType.none:
|
||||
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/view_model/dashboard/balance_view_model.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/erc20_token.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) {
|
||||
await tron!.addTronToken(_balanceViewModel.wallet, token, contractAddress);
|
||||
}
|
||||
|
@ -148,6 +157,9 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
if (_balanceViewModel.wallet.type == WalletType.zano) {
|
||||
await zano!.deleteZanoAsset(_balanceViewModel.wallet, token);
|
||||
}
|
||||
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||
await xelis!.deleteAsset(_balanceViewModel.wallet, token);
|
||||
}
|
||||
_updateTokensList();
|
||||
} finally {
|
||||
isDeletingToken = false;
|
||||
|
@ -206,6 +218,11 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
case WalletType.tron:
|
||||
defaultTokenAddresses = tron!.getDefaultTokenContractAddresses();
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
// TODO
|
||||
// defaultTokenAddresses = xelis!.getDefaultAssetIDs();
|
||||
// break;
|
||||
return false;
|
||||
case WalletType.zano:
|
||||
case WalletType.banano:
|
||||
case WalletType.monero:
|
||||
|
@ -388,6 +405,10 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
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) {
|
||||
return await tron!.getTronToken(_balanceViewModel.wallet, contractAddress);
|
||||
}
|
||||
|
@ -430,6 +451,12 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
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) {
|
||||
final address = tron!.getTokenAddress(token);
|
||||
tron!.addTronToken(_balanceViewModel.wallet, token, address);
|
||||
|
@ -501,6 +528,15 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
.toList()
|
||||
..sort(_sortFunc));
|
||||
}
|
||||
|
||||
|
||||
if (_balanceViewModel.wallet.type == WalletType.xelis) {
|
||||
tokens.addAll(xelis!
|
||||
.getXelisAssets(_balanceViewModel.wallet)
|
||||
.where((element) => _matchesSearchText(element))
|
||||
.toList()
|
||||
..sort(_sortFunc));
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
|
@ -549,7 +585,12 @@ abstract class HomeSettingsViewModelBase with Store {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ abstract class ReceiveOptionViewModelBase with Store {
|
|||
_options = [ReceivePageOption.mainnet];
|
||||
break;
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
if (_wallet.isTestnet) {
|
||||
_options = [
|
||||
ReceivePageOption.testnet,
|
||||
|
|
|
@ -10,6 +10,7 @@ import 'package:cake_wallet/solana/solana.dart';
|
|||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.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/transaction_direction.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
|
@ -46,10 +47,17 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
bool get hasTokens =>
|
||||
isEVMCompatibleChain(balanceViewModel.wallet.type) ||
|
||||
balanceViewModel.wallet.type == WalletType.solana ||
|
||||
balanceViewModel.wallet.type == WalletType.tron;
|
||||
balanceViewModel.wallet.type == WalletType.tron ||
|
||||
balanceViewModel.wallet.type == WalletType.xelis;
|
||||
|
||||
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 {
|
||||
|
@ -108,6 +116,7 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
WalletType.wownero,
|
||||
WalletType.litecoin,
|
||||
WalletType.zano,
|
||||
WalletType.xelis
|
||||
].contains(balanceViewModel.wallet.type)) {
|
||||
return formattedPendingStatus;
|
||||
}
|
||||
|
@ -143,6 +152,11 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
final asset = tron!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||
return asset;
|
||||
}
|
||||
|
||||
if (balanceViewModel.wallet.type == WalletType.xelis) {
|
||||
final asset = xelis!.assetOfTransaction(balanceViewModel.wallet, transaction);
|
||||
return asset;
|
||||
}
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
|
@ -224,6 +238,13 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
cryptoAmount: decred!.formatterDecredAmountToDouble(amount: transaction.amount),
|
||||
price: price);
|
||||
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.banano:
|
||||
case WalletType.haven:
|
||||
|
|
|
@ -253,11 +253,16 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
wallet.currency == CryptoCurrency.sol &&
|
||||
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 ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto ||
|
||||
_isEthToken() ||
|
||||
_isPolygonToken() ||
|
||||
_isSplToken() ||
|
||||
_isTronToken();
|
||||
_isTronToken() ||
|
||||
_isXelisAsset();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -779,6 +779,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
depositCurrency = CryptoCurrency.dcr;
|
||||
receiveCurrency = CryptoCurrency.xmr;
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
depositCurrency = CryptoCurrency.xel;
|
||||
receiveCurrency = CryptoCurrency.btc;
|
||||
break;
|
||||
case WalletType.none:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
case WalletType.bitcoin:
|
||||
case WalletType.zano:
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,8 @@ abstract class NodeListViewModelBase with Store {
|
|||
Node node;
|
||||
if (_appStore.wallet!.type == WalletType.bitcoin && _appStore.wallet!.isTestnet) {
|
||||
node = getBitcoinTestnetDefaultElectrumServer(nodes: _nodeSource)!;
|
||||
} else if (_appStore.wallet!.type == WalletType.xelis && _appStore.wallet!.isTestnet) {
|
||||
node = getXelisTestnetDefault(nodes: _nodeSource)!;
|
||||
} else {
|
||||
node = getDefaultNode(nodes: _nodeSource, type: _appStore.wallet!.type)!;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,9 @@ class WalletRestoreFromQRCode {
|
|||
'decred': 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) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.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/core/wallet_change_listener_view_model.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
|
@ -91,6 +92,7 @@ abstract class FeesViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
return transactionPriority == polygon!.getPolygonTransactionPrioritySlow();
|
||||
case WalletType.decred:
|
||||
return transactionPriority == decred!.getDecredTransactionPrioritySlow();
|
||||
case WalletType.xelis:
|
||||
case WalletType.none:
|
||||
case WalletType.nano:
|
||||
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/wownero/wownero.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/utils/print_verbose.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -116,6 +117,9 @@ abstract class OutputBase with Store {
|
|||
case WalletType.zano:
|
||||
_amount = zano!.formatterParseAmount(amount: _cryptoAmount, currency: cryptoCurrencyHandler());
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
_amount = xelis!.formatterStringDoubleToAmount(_cryptoAmount, currency: cryptoCurrencyHandler());
|
||||
break;
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
|
@ -153,6 +157,10 @@ abstract class OutputBase with Store {
|
|||
return solana!.getEstimateFees(_wallet) ?? 0.0;
|
||||
}
|
||||
|
||||
if (_wallet.type == WalletType.xelis) {
|
||||
return xelis!.getEstimateFees(_wallet) ?? 0.0;
|
||||
}
|
||||
|
||||
int? fee = _wallet.calculateEstimatedFee(
|
||||
_settingsStore.priority[_wallet.type]!, formattedCryptoAmount);
|
||||
|
||||
|
@ -193,6 +201,10 @@ abstract class OutputBase with Store {
|
|||
if (_wallet.type == WalletType.decred) {
|
||||
return decred!.formatterDecredAmountToDouble(amount: fee);
|
||||
}
|
||||
|
||||
if (_wallet.type == WalletType.xelis) {
|
||||
return xelis!.formatterXelisAmountToDouble(amount: BigInt.from(fee));
|
||||
}
|
||||
} catch (e) {
|
||||
printV(e.toString());
|
||||
}
|
||||
|
@ -205,7 +217,8 @@ abstract class OutputBase with Store {
|
|||
try {
|
||||
final currency = (isEVMCompatibleChain(_wallet.type) ||
|
||||
_wallet.type == WalletType.solana ||
|
||||
_wallet.type == WalletType.tron)
|
||||
_wallet.type == WalletType.tron ||
|
||||
_wallet.type == WalletType.xelis)
|
||||
? _wallet.currency
|
||||
: cryptoCurrencyHandler();
|
||||
final fiat = calculateFiatAmountRaw(
|
||||
|
@ -302,6 +315,7 @@ abstract class OutputBase with Store {
|
|||
case WalletType.zano:
|
||||
case WalletType.nano:
|
||||
case WalletType.decred:
|
||||
case WalletType.xelis:
|
||||
maximumFractionDigits = 12;
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
|
|
|
@ -101,5 +101,6 @@ abstract class SendTemplateViewModelBase with Store {
|
|||
|
||||
bool get hasMultipleTokens => isEVMCompatibleChain(_wallet.type) ||
|
||||
_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/monero/monero.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/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -69,7 +74,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
hasMultipleTokens = isEVMCompatibleChain(wallet.type) ||
|
||||
wallet.type == WalletType.solana ||
|
||||
wallet.type == WalletType.tron ||
|
||||
wallet.type == WalletType.zano;
|
||||
wallet.type == WalletType.zano ||
|
||||
wallet.type == WalletType.xelis;
|
||||
}
|
||||
|
||||
UnspentCoinsListViewModel unspentCoinsListViewModel;
|
||||
|
@ -91,7 +97,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
hasMultipleTokens = isEVMCompatibleChain(appStore.wallet!.type) ||
|
||||
appStore.wallet!.type == WalletType.solana ||
|
||||
appStore.wallet!.type == WalletType.tron ||
|
||||
appStore.wallet!.type == WalletType.zano,
|
||||
appStore.wallet!.type == WalletType.zano ||
|
||||
appStore.wallet!.type == WalletType.xelis,
|
||||
outputs = ObservableList<Output>(),
|
||||
_settingsStore = appStore.settingsStore,
|
||||
fiatFromSettings = appStore.settingsStore.fiatCurrency,
|
||||
|
@ -199,6 +206,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
case WalletType.polygon:
|
||||
case WalletType.tron:
|
||||
case WalletType.solana:
|
||||
case WalletType.xelis:
|
||||
return wallet.currency;
|
||||
default:
|
||||
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();
|
||||
return pendingTransaction;
|
||||
} 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
|
||||
Future<void> commitTransaction(BuildContext context) async {
|
||||
if (pendingTransaction == null) {
|
||||
|
@ -558,11 +578,25 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
return;
|
||||
}
|
||||
|
||||
String address = outputs.fold('', (acc, value) {
|
||||
late String address;
|
||||
|
||||
if (walletType == WalletType.xelis) {
|
||||
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();
|
||||
|
||||
|
@ -677,6 +711,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
case WalletType.decred:
|
||||
this.coinTypeToSpendFrom = UnspentCoinType.any;
|
||||
return decred!.createDecredTransactionCredentials(outputs, priority!);
|
||||
case WalletType.xelis:
|
||||
return xelis!.createXelisTransactionCredentials(outputs, priority: priority!, currency: selectedCryptoCurrency);
|
||||
default:
|
||||
throw Exception('Unexpected wallet type: ${wallet.type}');
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
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
|
||||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
|
@ -88,16 +93,14 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
case WalletType.decred:
|
||||
_addDecredListItems(tx, dateFormat);
|
||||
break;
|
||||
case WalletType.xelis:
|
||||
_addXelisListItems(tx, dateFormat, description.recipientAddress?.isEmpty ?? true);
|
||||
break;
|
||||
case WalletType.none:
|
||||
case WalletType.banano:
|
||||
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) {
|
||||
final recipientAddress = description.recipientAddress;
|
||||
|
||||
|
@ -193,6 +196,8 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
return 'https://explorer.zano.org/transaction/${txId}';
|
||||
case WalletType.decred:
|
||||
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:
|
||||
return '';
|
||||
}
|
||||
|
@ -227,6 +232,8 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
return S.current.view_transaction_on + 'explorer.zano.org';
|
||||
case WalletType.decred:
|
||||
return S.current.view_transaction_on + 'dcrdata.decred.org';
|
||||
case WalletType.xelis:
|
||||
return S.current.view_transaction_on + 'explorer.xelis.io';
|
||||
case WalletType.none:
|
||||
return '';
|
||||
}
|
||||
|
@ -562,6 +569,58 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
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) {
|
||||
transactionPriority = bitcoin!.getBitcoinTransactionPriorityMedium();
|
||||
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) {
|
||||
if (element.contains('OP_RETURN:') && element.length > 40) {
|
||||
return element.substring(0, 40) + '...';
|
||||
|
@ -670,7 +729,7 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
value: tx.feeFormatted()!,
|
||||
key: ValueKey('standard_list_item_transaction_details_fee_key'),
|
||||
),
|
||||
if (showRecipientAddress && tx.to != null)
|
||||
if (showRecipientAddress && tx.to != null && tx.direction == TransactionDirection.outgoing)
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_recipient_address,
|
||||
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 {
|
||||
WalletAddressListViewModelBase({
|
||||
required AppStore appStore,
|
||||
|
@ -350,6 +366,8 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
|||
return ZanoURI(amount: amount, address: address.address);
|
||||
case WalletType.decred:
|
||||
return DecredURI(amount: amount, address: address.address);
|
||||
case WalletType.xelis:
|
||||
return XelisURI(amount: amount, address: address.address);
|
||||
case WalletType.none:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
case WalletType.bitcoinCash:
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
case WalletType.xelis:
|
||||
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||
//
|
||||
// items.addAll([
|
||||
|
@ -252,6 +253,8 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
return 'zano-wallet';
|
||||
case WalletType.decred:
|
||||
return 'decred-wallet';
|
||||
case WalletType.xelis:
|
||||
return 'xelis-wallet';
|
||||
default:
|
||||
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/wallet_creation_vm.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_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
@ -47,7 +48,7 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
|||
String selectedMnemonicLanguage;
|
||||
|
||||
bool get hasLanguageSelector =>
|
||||
[WalletType.monero, WalletType.haven, WalletType.wownero].contains(type);
|
||||
[WalletType.monero, WalletType.haven, WalletType.wownero, WalletType.xelis].contains(type);
|
||||
|
||||
bool get showLanguageSelector =>
|
||||
newWalletArguments?.mnemonic == null && hasLanguageSelector;
|
||||
|
@ -141,6 +142,11 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
|||
);
|
||||
case WalletType.decred:
|
||||
return decred!.createDecredNewWalletCredentials(name: name);
|
||||
case WalletType.xelis:
|
||||
return xelis!.createXelisNewWalletCredentials(
|
||||
name: name,
|
||||
password: walletPassword,
|
||||
);
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
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