Merge remote-tracking branch 'origin/main' into electrum-sp-refactors

This commit is contained in:
Rafael Saes 2025-03-24 12:31:21 -03:00
commit 917d62e12f
98 changed files with 1991 additions and 1041 deletions

View file

@ -55,7 +55,7 @@ jobs:
- name: Flutter action
uses: subosito/flutter-action@v1
with:
flutter-version: "3.24.0"
flutter-version: "3.27.4"
channel: stable
- name: Install package dependencies

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
container:
image: ghcr.io/cake-tech/cake_wallet:3.24.4-linux
image: ghcr.io/cake-tech/cake_wallet:3.27.4-linux
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet

View file

@ -9,7 +9,7 @@ jobs:
PR_test_build:
runs-on: linux-amd64
container:
image: ghcr.io/cake-tech/cake_wallet:3.24.4-linux
image: ghcr.io/cake-tech/cake_wallet:3.27.4-linux
env:
STORE_PASS: test@cake_wallet
KEY_PASS: test@cake_wallet

View file

@ -1,6 +1,5 @@
# Usage:
# docker build . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:3.24.4-linux
# docker push ghcr.io/cake-tech/cake_wallet:3.24.4-linux
# docker build . -f Dockerfile -t ghcr.io/cake-tech/cake_wallet:3.27.4-linux
# docker push ghcr.io/cake-tech/cake_wallet:3.27.4-linux
# Heavily inspired by cirrusci images
# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile
@ -17,7 +16,7 @@ LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet
ENV GOLANG_VERSION=1.23.4
# Pin Flutter version to latest known-working version
ENV FLUTTER_VERSION=3.24.4
ENV FLUTTER_VERSION=3.27.4
# Pin Android Studio, platform, and build tools versions to latest known-working version
# Comes from https://developer.android.com/studio/#command-tools

View file

@ -1,3 +1,9 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@ -6,11 +12,6 @@ if (localPropertiesFile.exists()) {
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
@ -21,9 +22,6 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
def keystoreProperties = new Properties()
def keystorePropertiesFile = rootProject.file('key.properties')
if (keystorePropertiesFile.exists()) {
@ -37,8 +35,8 @@ if (appPropertiesFile.exists()) {
}
android {
compileSdkVersion 34
buildToolsVersion "34.0.0"
compileSdkVersion 35
buildToolsVersion "35.0.0"
lintOptions {
disable 'InvalidPackage'
@ -81,6 +79,9 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.release
}
}
ndkVersion "27.0.12077973"

View file

@ -1,17 +1,3 @@
buildscript {
ext.kotlin_version = '2.0.21'
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.7.1'
classpath 'com.google.gms:google-services:4.3.8'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
allprojects {
repositories {
google()

View file

@ -1,15 +1,26 @@
include ':app'
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "8.7.1" apply false
id "org.jetbrains.kotlin.android" version "2.0.21" apply false
id "com.google.gms.google-services" version "4.3.8" apply false
}
include ":app"

View file

@ -17,14 +17,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.7.0"
archive:
dependency: transitive
description:
name: archive
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
url: "https://pub.dev"
source: hosted
version: "3.6.1"
args:
dependency: transitive
description:
@ -93,7 +85,7 @@ packages:
source: git
version: "5.0.0"
blockchain_utils:
dependency: "direct overridden"
dependency: "direct main"
description:
path: "."
ref: cake-update-v4
@ -105,10 +97,10 @@ packages:
dependency: transitive
description:
name: bluez
sha256: "203a1924e818a9dd74af2b2c7a8f375ab8e5edf0e486bba8f90a0d8a17ed9fce"
sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545"
url: "https://pub.dev"
source: hosted
version: "0.8.2"
version: "0.8.3"
boolean_selector:
dependency: transitive
description:
@ -242,10 +234,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -447,10 +439,10 @@ packages:
dependency: "direct main"
description:
name: grpc
sha256: e93ee3bce45c134bf44e9728119102358c7cd69de7832d9a874e2e74eb8cab40
sha256: "5b99b7a420937d4361ece68b798c9af8e04b5bc128a7859f2a4be87427694813"
url: "https://pub.dev"
source: hosted
version: "3.2.4"
version: "4.0.1"
hex:
dependency: transitive
description:
@ -543,18 +535,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -874,10 +866,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
@ -906,7 +898,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -945,17 +937,17 @@ packages:
path: "."
ref: cake-update-v4
resolved-ref: "888bd27c3c4495c890580ebaaba6771b4f40eff6"
url: "https://github.com/cake-tech/sp_scanner.git"
url: "https://github.com/cake-tech/sp_scanner"
source: git
version: "0.0.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -976,10 +968,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -992,10 +984,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
@ -1056,10 +1048,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
@ -1072,10 +1064,10 @@ packages:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:

View file

@ -24,6 +24,10 @@ dependencies:
git:
url: https://github.com/cake-tech/bitcoin_base
ref: cake-update-v15
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v4
bitbox:
git:
url: https://github.com/cake-tech/bitbox-flutter.git
@ -32,10 +36,10 @@ dependencies:
cryptography: ^2.0.5
cw_mweb:
path: ../cw_mweb
grpc: ^3.2.4
grpc: ^4.0.1
sp_scanner:
git:
url: https://github.com/cake-tech/sp_scanner.git
url: https://github.com/cake-tech/sp_scanner
ref: cake-update-v4
bech32:
git:
@ -61,10 +65,6 @@ dev_dependencies:
dependency_overrides:
watcher: ^1.1.0
protobuf: ^3.1.0
blockchain_utils:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v4
pointycastle: 3.7.4
ffi: 2.1.0

View file

@ -1,9 +1,9 @@
import 'package:flutter/services.dart';
void setIsAppSecureNative(bool isAppSecure) {
Future<void> setIsAppSecureNative(bool isAppSecure) async {
try {
final utils = const MethodChannel('com.cake_wallet/native_utils');
utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
await utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
} catch (_) {}
}

View file

@ -1,3 +1,5 @@
import 'dart:math';
void printV(dynamic content) {
CustomTrace programInfo = CustomTrace(StackTrace.current);
print("${programInfo.fileName}#${programInfo.lineNumber}:${programInfo.columnNumber} ${programInfo.callerFunctionName}: $content");
@ -29,7 +31,7 @@ class CustomTrace {
var indexOfWhiteSpace = currentTrace.indexOf(' ');
/* Create a substring from the first whitespace index till the end of the string */
var subStr = currentTrace.substring(indexOfWhiteSpace);
var subStr = currentTrace.substring(max(0, indexOfWhiteSpace));
/* Grab the function name using reg expr */
var indexOfFunction = subStr.indexOf(RegExp(r'[A-Za-z0-9_]'));
@ -40,7 +42,7 @@ class CustomTrace {
indexOfWhiteSpace = subStr.indexOf(RegExp(r'[ .]'));
/* Create a new substring from start to the first index of a whitespace. This substring gives us the function name */
subStr = subStr.substring(0, indexOfWhiteSpace);
subStr = subStr.substring(0, max(0, indexOfWhiteSpace));
return subStr;
}
@ -61,7 +63,7 @@ class CustomTrace {
/* Search through the string and find the index of the file name by looking for the '.dart' regex */
var indexOfFileName = traceString.indexOf(RegExp(r'[/A-Za-z_]+.dart'), 1); // 1 to offest and not print the printV function name
var fileInfo = traceString.substring(indexOfFileName);
var fileInfo = traceString.substring(max(0, indexOfFileName));
var listOfInfos = fileInfo.split(":");
@ -78,7 +80,7 @@ class CustomTrace {
columnStr = columnStr.replaceFirst(")", "");
this.columnNumber = int.tryParse(columnStr);
} catch (e) {
print("Unable to parse trace (printV): $e");
}
}
}

View file

@ -70,6 +70,12 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
// there is a default definition here because only coins with a pow node (nano based) need to override this
Future<void> connectToPowNode({required Node node}) async {}
// startBackgroundSync is used to start sync in the background, without doing any
// extra things in the background.
// startSync is used as a fallback.
Future<void> startBackgroundSync() => startSync();
Future<void> stopBackgroundSync(String password) => stopSync();
Future<void> startSync();
Future<void> stopSync() async {}

View file

@ -5,23 +5,23 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
url: "https://pub.dev"
source: hosted
version: "72.0.0"
version: "76.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
version: "0.3.3"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
url: "https://pub.dev"
source: hosted
version: "6.7.0"
version: "6.11.0"
args:
dependency: transitive
description:
@ -34,10 +34,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.8"
async:
dependency: transitive
description:
@ -123,10 +123,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: "direct main"
description:
@ -164,18 +164,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -273,10 +273,10 @@ packages:
dependency: "direct main"
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -294,10 +294,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -326,18 +326,18 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
@ -358,10 +358,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -382,18 +382,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -414,10 +414,10 @@ packages:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
version: "0.1.3-main.0"
matcher:
dependency: transitive
description:
@ -454,18 +454,18 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
name: mobx_codegen
sha256: "8e0d8653a0c720ad933cd8358f6f89f740ce89203657c13f25bea772ef1fff7c"
sha256: "990da80722f7d7c0017dec92040b31545d625b15d40204c36a1e63d167c73cdc"
url: "https://pub.dev"
source: hosted
version: "2.6.1"
version: "2.7.0"
nested:
dependency: transitive
description:
@ -487,10 +487,10 @@ packages:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -503,26 +503,26 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -591,18 +591,18 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
rational:
dependency: transitive
description:
@ -623,15 +623,15 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: "direct main"
description:
@ -652,10 +652,10 @@ packages:
dependency: transitive
description:
name: source_helper
sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd"
sha256: "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c"
url: "https://pub.dev"
source: hosted
version: "1.3.4"
version: "1.3.5"
source_span:
dependency: transitive
description:
@ -668,10 +668,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -684,18 +684,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -708,18 +708,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -756,26 +756,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -788,10 +788,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -804,10 +804,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -5,23 +5,23 @@ packages:
dependency: transitive
description:
name: _fe_analyzer_shared
sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834
sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab"
url: "https://pub.dev"
source: hosted
version: "72.0.0"
version: "76.0.0"
_macros:
dependency: transitive
description: dart
source: sdk
version: "0.3.2"
version: "0.3.3"
analyzer:
dependency: transitive
description:
name: analyzer
sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139
sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e"
url: "https://pub.dev"
source: hosted
version: "6.7.0"
version: "6.11.0"
args:
dependency: transitive
description:
@ -180,10 +180,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -405,18 +405,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -437,10 +437,10 @@ packages:
dependency: transitive
description:
name: macros
sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536"
sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656"
url: "https://pub.dev"
source: hosted
version: "0.1.2-main.4"
version: "0.1.3-main.0"
matcher:
dependency: transitive
description:
@ -662,7 +662,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -699,10 +699,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -723,10 +723,10 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -739,10 +739,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
@ -787,10 +787,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: transitive
description:

View file

@ -37,7 +37,8 @@ List<monero.SubaddressAccountRow> getAllAccount() {
int size = monero.SubaddressAccount_getAll_size(subaddressAccount!);
if (size == 0) {
monero.Wallet_addSubaddressAccount(wptr!);
return getAllAccount();
monero.Wallet_status(wptr!);
return [];
}
return List.generate(size, (index) {
return monero.SubaddressAccount_getAll_byIndex(subaddressAccount!, index: index);

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:ffi';
import 'dart:isolate';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_monero/api/account_list.dart';
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
@ -108,9 +109,13 @@ Map<int, Map<int, Map<int, String>>> addressCache = {};
String getAddress({int accountIndex = 0, int addressIndex = 0}) {
// printV("getaddress: ${accountIndex}/${addressIndex}: ${monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)}: ${monero.Wallet_address(wptr!, accountIndex: accountIndex, addressIndex: addressIndex)}");
while (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
printV("adding subaddress");
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
// this could be a while loop, but I'm in favor of making it if to not cause freezes
if (monero.Wallet_numSubaddresses(wptr!, accountIndex: accountIndex)-1 < addressIndex) {
if (monero.Wallet_numSubaddressAccounts(wptr!) < accountIndex) {
monero.Wallet_addSubaddressAccount(wptr!);
} else {
monero.Wallet_addSubaddress(wptr!, accountIndex: accountIndex);
}
}
addressCache[wptr!.address] ??= {};
addressCache[wptr!.address]![accountIndex] ??= {};
@ -149,6 +154,7 @@ Future<bool> setupNodeSync(
}
''');
final addr = wptr!.address;
printV("init: start");
await Isolate.run(() {
monero.Wallet_init(Pointer.fromAddress(addr),
daemonAddress: address,
@ -157,6 +163,7 @@ Future<bool> setupNodeSync(
daemonUsername: login ?? '',
daemonPassword: password ?? '');
});
printV("init: end");
final status = monero.Wallet_status(wptr!);
@ -168,7 +175,7 @@ Future<bool> setupNodeSync(
}
}
if (kDebugMode && debugMonero) {
if (true) {
monero.Wallet_init3(
wptr!, argv0: '',
defaultLogBaseName: 'moneroc',
@ -243,7 +250,9 @@ class SyncListener {
SyncListener(this.onNewBlock, this.onNewTransaction)
: _cachedBlockchainHeight = 0,
_lastKnownBlockHeight = 0,
_initialSyncHeight = 0;
_initialSyncHeight = 0 {
_start();
}
void Function(int, int, double) onNewBlock;
void Function() onNewTransaction;
@ -261,7 +270,7 @@ class SyncListener {
return _cachedBlockchainHeight;
}
void start() {
void _start() {
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
@ -282,7 +291,7 @@ class SyncListener {
}
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
// printV("syncHeight: $syncHeight, _lastKnownBlockHeight: $_lastKnownBlockHeight, bchHeight: $bchHeight");
if (_lastKnownBlockHeight == syncHeight) {
return;
}
@ -379,4 +388,4 @@ String signMessage(String message, {String address = ""}) {
bool verifyMessage(String message, String address, String signature) {
return monero.Wallet_verifySignedMessage(wptr!, message: message, address: address, signature: signature);
}
}

View file

@ -11,6 +11,7 @@ import 'package:cw_monero/api/exceptions/wallet_restore_from_seed_exception.dart
import 'package:cw_monero/api/transaction_history.dart';
import 'package:cw_monero/api/wallet.dart';
import 'package:cw_monero/ledger.dart';
import 'package:flutter/foundation.dart';
import 'package:monero/monero.dart' as monero;
class MoneroCException implements Exception {
@ -50,7 +51,13 @@ final monero.WalletManager wmPtr = Pointer.fromAddress((() {
// codebase, so it will be easier to debug what happens. At least easier
// than plugging gdb in. Especially on windows/android.
monero.printStarts = false;
if (kDebugMode && debugMonero) {
monero.WalletManagerFactory_setLogLevel(4);
}
_wmPtr ??= monero.WalletManagerFactory_getWalletManager();
if (kDebugMode && debugMonero) {
monero.WalletManagerFactory_setLogLevel(4);
}
printV("ptr: $_wmPtr");
} catch (e) {
printV(e);
@ -77,10 +84,17 @@ void createWalletSync(
final newWptr = monero.WalletManager_createWallet(wmPtr,
path: path, password: password, language: language, networkType: 0);
final status = monero.Wallet_status(newWptr);
int status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
wptr = newWptr;
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: passphrase);
monero.Wallet_store(wptr!, path: path);
@ -166,12 +180,19 @@ void restoreWalletFromKeysSync(
nettype: 0,
);
final status = monero.Wallet_status(newWptr);
int status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletRestoreFromKeysException(
message: monero.Wallet_errorString(newWptr));
}
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
// CW-712 - Try to restore deterministic wallet first, if the view key doesn't
// match the view key provided
if (spendKey != "") {
@ -190,11 +211,17 @@ void restoreWalletFromKeysSync(
spendKeyString: spendKey,
nettype: 0,
);
final status = monero.Wallet_status(newWptr);
int status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletRestoreFromKeysException(
message: monero.Wallet_errorString(newWptr));
}
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
}
}
@ -227,7 +254,7 @@ void restoreWalletFromPolyseedWithOffset(
kdfRounds: 1,
);
final status = monero.Wallet_status(newWptr);
int status = monero.Wallet_status(newWptr);
if (status != 0) {
final err = monero.Wallet_errorString(newWptr);
@ -240,6 +267,12 @@ void restoreWalletFromPolyseedWithOffset(
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.passphrase", value: seedOffset);
monero.Wallet_store(wptr!);
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
storeSync();
openedWalletsByPath[path] = wptr!;
@ -277,7 +310,7 @@ void restoreWalletFromSpendKeySync(
restoreHeight: restoreHeight,
);
final status = monero.Wallet_status(newWptr);
int status = monero.Wallet_status(newWptr);
if (status != 0) {
final err = monero.Wallet_errorString(newWptr);
@ -290,6 +323,12 @@ void restoreWalletFromSpendKeySync(
monero.Wallet_setCacheAttribute(wptr!, key: "cakewallet.seed", value: seed);
storeSync();
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
}
openedWalletsByPath[path] = wptr!;
_lastOpenedWallet = path;
@ -321,6 +360,14 @@ Future<void> restoreWalletFromHardwareWallet(
final error = monero.Wallet_errorString(newWptr);
throw WalletRestoreFromSeedException(message: error);
}
// TODO: Check with upstream if we can use background sync here
// monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
// status = monero.Wallet_status(newWptr);
// if (status != 0) {
// throw WalletCreationException(message: monero.Wallet_errorString(newWptr));
// }
wptr = newWptr;
_lastOpenedWallet = path;
openedWalletsByPath[path] = wptr!;
@ -384,7 +431,14 @@ Future<void> loadWallet(
final newWptr = Pointer<Void>.fromAddress(newWptrAddr);
final status = monero.Wallet_status(newWptr);
int status = monero.Wallet_status(newWptr);
if (status != 0) {
final err = monero.Wallet_errorString(newWptr);
printV("loadWallet:"+err);
throw WalletOpeningException(message: err);
}
monero.Wallet_setupBackgroundSync(newWptr, backgroundSyncType: 2, walletPassword: password, backgroundCachePassword: '');
status = monero.Wallet_status(newWptr);
if (status != 0) {
final err = monero.Wallet_errorString(newWptr);
printV("loadWallet:"+err);

View file

@ -218,7 +218,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
// FIXME: hardcoded value
socksProxyAddress: node.socksProxyAddress);
monero_wallet.setTrustedDaemon(node.trusted);
await monero_wallet.setTrustedDaemon(node.trusted);
syncStatus = ConnectedSyncStatus();
} catch (e) {
syncStatus = FailedSyncStatus();
@ -226,6 +226,57 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
}
}
@override
Future<void> startBackgroundSync() async {
if (isBackgroundSyncRunning) {
printV("Background sync already running");
return;
}
isBackgroundSyncRunning = true;
int status = monero.Wallet_status(wptr!);
if (status != 0) {
final err = monero.Wallet_errorString(wptr!);
throw Exception("unable to setup background sync: $err");
}
await save();
monero.Wallet_startBackgroundSync(wptr!);
status = monero.Wallet_status(wptr!);
if (status != 0) {
final err = monero.Wallet_errorString(wptr!);
throw Exception("unable to start background sync: $err");
}
await save();
await init();
await startSync();
}
bool isBackgroundSyncRunning = false;
@action
@override
Future<void> stopSync() async {
if (isBackgroundSyncRunning) {
printV("Stopping background sync");
await save();
monero.Wallet_stopBackgroundSync(wptr!, '');
await save();
isBackgroundSyncRunning = false;
}
}
@action
@override
Future<void> stopBackgroundSync(String password) async {
if (isBackgroundSyncRunning) {
printV("Stopping background sync");
await save();
monero.Wallet_stopBackgroundSync(wptr!, password);
await save();
isBackgroundSyncRunning = false;
}
}
@override
Future<void> startSync() async {
try {
@ -250,7 +301,6 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
syncStatus = AttemptingSyncStatus();
monero_wallet.startRefresh();
_setListeners();
_listener?.start();
} catch (e) {
syncStatus = FailedSyncStatus();
printV(e);
@ -782,6 +832,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, MoneroTransact
}
void _onNewBlock(int height, int blocksLeft, double ptc) async {
printV("onNewBlock: $height, $blocksLeft, $ptc");
try {
if (walletInfo.isRecovery) {
await _askForUpdateTransactionHistory();

View file

@ -1 +1 @@
/home/parallels/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/
/home/rafael/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/

View file

@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.8"
async:
dependency: transitive
description:
@ -54,10 +54,10 @@ packages:
dependency: transitive
description:
name: bluez
sha256: "203a1924e818a9dd74af2b2c7a8f375ab8e5edf0e486bba8f90a0d8a17ed9fce"
sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545"
url: "https://pub.dev"
source: hosted
version: "0.8.2"
version: "0.8.3"
boolean_selector:
dependency: transitive
description:
@ -126,10 +126,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: transitive
description:
@ -167,18 +167,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -230,10 +230,10 @@ packages:
dependency: transitive
description:
name: dbus
sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac"
sha256: "79e0c23480ff85dc68de79e2cd6334add97e48f7f4865d17686dd6ea81a47e8c"
url: "https://pub.dev"
source: hosted
version: "0.7.10"
version: "0.7.11"
decimal:
dependency: transitive
description:
@ -291,10 +291,10 @@ packages:
dependency: "direct main"
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -304,10 +304,10 @@ packages:
dependency: transitive
description:
name: flutter_web_bluetooth
sha256: "52ce64f65d7321c4bf6abfe9dac02fb888731339a5e0ad6de59fb916c20c9f02"
sha256: "1363831def5eed1e1064d1eca04e8ccb35446e8f758579c3c519e156b77926da"
url: "https://pub.dev"
source: hosted
version: "0.2.3"
version: "1.0.0"
frontend_server_client:
dependency: transitive
description:
@ -320,10 +320,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -336,10 +336,10 @@ packages:
dependency: transitive
description:
name: hashlib
sha256: f572f2abce09fc7aee53f15927052b9732ea1053e540af8cae211111ee0b99b1
sha256: e13e8237d93fb275cd1c55fc339bb90638994d1a4f140c7ee270173b51f3d169
url: "https://pub.dev"
source: hosted
version: "1.21.0"
version: "1.21.1"
hashlib_codecs:
dependency: transitive
description:
@ -368,18 +368,18 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
@ -400,10 +400,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -424,18 +424,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -448,10 +448,10 @@ packages:
dependency: "direct main"
description:
name: ledger_flutter_plus
sha256: c7b04008553193dbca7e17b430768eecc372a72b0ff3625b5e7fc5e5c8d3231b
sha256: "1c03f3c4a9754b5f0170a9eb9552ec54fa86e985f8ee71a255ee2c5629b53d31"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
version: "1.5.1"
ledger_usb_plus:
dependency: transitive
description:
@ -504,10 +504,10 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
@ -554,10 +554,10 @@ packages:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -570,26 +570,26 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -674,18 +674,18 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
rational:
dependency: transitive
description:
@ -714,15 +714,15 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -759,10 +759,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -775,18 +775,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -799,18 +799,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -831,10 +831,10 @@ packages:
dependency: transitive
description:
name: universal_ble
sha256: "0dfbd6b64bff3ad61ed7a895c232530d9614e9b01ab261a74433a43267edb7f3"
sha256: "1fad089150a29db82b3b7d60327e18c5ad6b3a5bb509defc1c690b0a76b9c098"
url: "https://pub.dev"
source: hosted
version: "0.12.0"
version: "0.15.0"
universal_platform:
dependency: transitive
description:
@ -863,26 +863,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -895,10 +895,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -919,10 +919,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -10,7 +10,7 @@ environment:
dependencies:
flutter:
sdk: flutter
grpc: ^3.2.4
grpc: ^4.0.1
path_provider: ^2.1.2
plugin_platform_interface: ^2.0.2
cw_core:

View file

@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.8"
async:
dependency: transitive
description:
@ -142,10 +142,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: transitive
description:
@ -183,18 +183,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -315,10 +315,10 @@ packages:
dependency: transitive
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -341,10 +341,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -381,18 +381,18 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
@ -413,10 +413,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -437,18 +437,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -509,10 +509,10 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
@ -559,10 +559,10 @@ packages:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -575,26 +575,26 @@ packages:
dependency: transitive
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -671,18 +671,18 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
rational:
dependency: transitive
description:
@ -695,26 +695,26 @@ packages:
dependency: "direct main"
description:
name: shared_preferences
sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051"
sha256: "846849e3e9b68f3ef4b60c60cf4b3e02e9321bc7f4d8c4692cf87ffa82fc8a3a"
url: "https://pub.dev"
source: hosted
version: "2.3.2"
version: "2.5.2"
shared_preferences_android:
dependency: transitive
description:
name: shared_preferences_android
sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab"
sha256: a768fc8ede5f0c8e6150476e14f38e2417c0864ca36bb4582be8e21925a03c22
url: "https://pub.dev"
source: hosted
version: "2.3.3"
version: "2.4.6"
shared_preferences_foundation:
dependency: transitive
description:
name: shared_preferences_foundation
sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d"
sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03"
url: "https://pub.dev"
source: hosted
version: "2.5.3"
version: "2.5.4"
shared_preferences_linux:
dependency: transitive
description:
@ -735,10 +735,10 @@ packages:
dependency: transitive
description:
name: shared_preferences_web
sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e
sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019
url: "https://pub.dev"
source: hosted
version: "2.4.2"
version: "2.4.3"
shared_preferences_windows:
dependency: transitive
description:
@ -759,15 +759,15 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -804,10 +804,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -820,18 +820,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -844,18 +844,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -892,26 +892,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -924,10 +924,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -940,10 +940,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -349,6 +349,7 @@ void loadWallet(
txhistory = null;
final newWptr = wownero.WalletManager_openWallet(wmPtr,
path: path, password: password);
_lastOpenedWallet = path;
final status = wownero.Wallet_status(newWptr);
if (status != 0) {

View file

@ -29,10 +29,10 @@ packages:
dependency: transitive
description:
name: asn1lib
sha256: "6b151826fcc95ff246cd219a0bf4c753ea14f4081ad71c61939becf3aba27f70"
sha256: "4bae5ae63e6d6dd17c4aac8086f3dec26c0236f6a0f03416c6c19d830c367cf5"
url: "https://pub.dev"
source: hosted
version: "1.5.5"
version: "1.5.8"
async:
dependency: transitive
description:
@ -118,10 +118,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: transitive
description:
@ -159,18 +159,18 @@ packages:
dependency: transitive
description:
name: code_builder
sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37
sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e"
url: "https://pub.dev"
source: hosted
version: "4.10.0"
version: "4.10.1"
collection:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -275,10 +275,10 @@ packages:
dependency: "direct main"
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -296,10 +296,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -312,10 +312,10 @@ packages:
dependency: transitive
description:
name: hashlib
sha256: f572f2abce09fc7aee53f15927052b9732ea1053e540af8cae211111ee0b99b1
sha256: e13e8237d93fb275cd1c55fc339bb90638994d1a4f140c7ee270173b51f3d169
url: "https://pub.dev"
source: hosted
version: "1.21.0"
version: "1.21.1"
hashlib_codecs:
dependency: transitive
description:
@ -344,18 +344,18 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
@ -376,10 +376,10 @@ packages:
dependency: transitive
description:
name: io
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b
url: "https://pub.dev"
source: hosted
version: "1.0.4"
version: "1.0.5"
js:
dependency: transitive
description:
@ -400,18 +400,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -464,10 +464,10 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "63920b27b32ad1910adfe767ab1750e4c212e8923232a1f891597b362074ea5e"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.3.3+2"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
@ -514,10 +514,10 @@ packages:
dependency: transitive
description:
name: package_config
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
sha256: "92d4488434b520a62570293fbd33bb556c7d49230791c1b4bbd973baf6d2dc67"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
path:
dependency: transitive
description:
@ -530,26 +530,26 @@ packages:
dependency: "direct main"
description:
name: path_provider
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a
sha256: "4adf4fd5423ec60a29506c76581bc05854c55e3a0b72d35bb28d661c9686edf2"
url: "https://pub.dev"
source: hosted
version: "2.2.12"
version: "2.2.15"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942"
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.4.1"
path_provider_linux:
dependency: transitive
description:
@ -626,18 +626,18 @@ packages:
dependency: transitive
description:
name: pub_semver
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
sha256: "7b3cfbf654f3edd0c6298ecd5be782ce997ddf0e00531b9464b55245185bbbbd"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.1.5"
pubspec_parse:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
rational:
dependency: transitive
description:
@ -658,15 +658,15 @@ packages:
dependency: transitive
description:
name: shelf_web_socket
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67
url: "https://pub.dev"
source: hosted
version: "2.0.0"
version: "2.0.1"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -703,10 +703,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -719,18 +719,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -743,18 +743,18 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
name: timing
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe"
url: "https://pub.dev"
source: hosted
version: "1.0.1"
version: "1.0.2"
tuple:
dependency: transitive
description:
@ -791,26 +791,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -823,10 +823,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -839,10 +839,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -118,10 +118,10 @@ packages:
dependency: transitive
description:
name: built_value
sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb
sha256: "8b158ab94ec6913e480dc3f752418348b5ae099eb75868b5f4775f0572999c61"
url: "https://pub.dev"
source: hosted
version: "8.9.2"
version: "8.9.4"
cake_backup:
dependency: transitive
description:
@ -167,10 +167,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
url: "https://pub.dev"
source: hosted
version: "1.18.0"
version: "1.19.0"
convert:
dependency: transitive
description:
@ -275,10 +275,10 @@ packages:
dependency: "direct main"
description:
name: flutter_mobx
sha256: "859fbf452fa9c2519d2700b125dd7fb14c508bbdd7fb65e26ca8ff6c92280e2e"
sha256: ba5e93467866a2991259dc51cffd41ef45f695c667c2b8e7b087bf24118b50fe
url: "https://pub.dev"
source: hosted
version: "2.2.1+1"
version: "2.3.0"
flutter_test:
dependency: "direct dev"
description: flutter
@ -293,10 +293,10 @@ packages:
dependency: "direct main"
description:
name: fluttertoast
sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc"
sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1"
url: "https://pub.dev"
source: hosted
version: "8.2.8"
version: "8.2.12"
frontend_server_client:
dependency: transitive
description:
@ -309,10 +309,10 @@ packages:
dependency: transitive
description:
name: glob
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.3"
graphs:
dependency: transitive
description:
@ -341,18 +341,18 @@ packages:
dependency: "direct main"
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.2.2"
version: "1.3.0"
http_multi_server:
dependency: transitive
description:
name: http_multi_server
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8
url: "https://pub.dev"
source: hosted
version: "3.2.1"
version: "3.2.2"
http_parser:
dependency: transitive
description:
@ -405,18 +405,18 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
url: "https://pub.dev"
source: hosted
version: "10.0.5"
version: "10.0.7"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.0.8"
leak_tracker_testing:
dependency: transitive
description:
@ -469,10 +469,10 @@ packages:
dependency: "direct main"
description:
name: mobx
sha256: "1f01a429529ac55e5e80c0fcad62c60112fb91df3dec11a9113d71cf0c2e2c4c"
sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0
url: "https://pub.dev"
source: hosted
version: "2.4.0"
version: "2.5.0"
mobx_codegen:
dependency: "direct dev"
description:
@ -631,10 +631,10 @@ packages:
dependency: transitive
description:
name: pubspec_parse
sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8
sha256: "81876843eb50dc2e1e5b151792c9a985c5ed2536914115ed04e9c8528f6647b0"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
rational:
dependency: transitive
description:
@ -663,7 +663,7 @@ packages:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
version: "0.0.0"
socks5_proxy:
dependency: transitive
description:
@ -700,10 +700,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
version: "1.12.0"
stream_channel:
dependency: transitive
description:
@ -716,18 +716,18 @@ packages:
dependency: transitive
description:
name: stream_transform
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
version: "1.3.0"
term_glyph:
dependency: transitive
description:
@ -740,10 +740,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
url: "https://pub.dev"
source: hosted
version: "0.7.2"
version: "0.7.3"
timing:
dependency: transitive
description:
@ -788,26 +788,26 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
url: "https://pub.dev"
source: hosted
version: "14.2.5"
version: "14.3.0"
watcher:
dependency: "direct overridden"
description:
name: watcher
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
sha256: "69da27e49efa56a15f8afe8f4438c4ec02eff0a117df1b22ea4aad194fe1c104"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web:
dependency: transitive
description:
name: web
sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
version: "1.1.1"
web_socket:
dependency: transitive
description:
@ -820,10 +820,10 @@ packages:
dependency: transitive
description:
name: web_socket_channel
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
sha256: "0b8e2457400d8a859b7b2030786835a28a8e80836ef64402abef392ff4f1d0e5"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
xdg_directories:
dependency: transitive
description:
@ -836,10 +836,10 @@ packages:
dependency: transitive
description:
name: yaml
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce
url: "https://pub.dev"
source: hosted
version: "3.1.2"
version: "3.1.3"
sdks:
dart: ">=3.5.0 <4.0.0"
flutter: ">=3.24.0"

View file

@ -22,7 +22,7 @@ dependencies:
cw_core:
path: ../cw_core
json_bigint: ^3.0.0
fluttertoast: ^8.2.8
fluttertoast: ^8.2.12
monero:
git:
url: https://github.com/mrcyjanek/monero_c

View file

@ -28,6 +28,7 @@ pushd scripts/android
# source ./app_env.sh monero.com # Uncomment this line to build monero.com
./app_config.sh
./build_monero_all.sh
./build_decred.sh
./build_mwebd.sh --dont-install
popd
pushd android/app

View file

@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your iOS devi
```txt
macOS 15.3.1
Xcode 16.2
Flutter 3.24.4
Flutter 3.27.4
```
NOTE: Newer versions of macOS and Xcode may also work, but have not been confirmed to work by the Cake team.
@ -43,9 +43,9 @@ To enable iOS build support for Xcode, perform the following:
### 3. Installing Flutter
Install Flutter, specifically version `3.24.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
NOTE: as `3.24.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
### 4. Installing Rust
@ -65,7 +65,7 @@ The output of this command should appear like this, indicating successful instal
```zsh
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.4, on macOS 15.x.x)
[✓] Flutter (Channel stable, 3.27.4, on macOS 15.x.x)
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
```
@ -101,6 +101,7 @@ Build the necessary libraries and their dependencies:
```zsh
./build_monero_all.sh
./build_mwebd.sh
./build_decred.sh
```
NOTE: This step will take quite a while, so be sure you grab a cup of coffee or a good book!

View file

@ -7,7 +7,7 @@ The following are the system requirements to build Cake Wallet for your macOS de
```txt
macOS 15.3.1
Xcode 16.2
Flutter 3.24.4
Flutter 3.27.4
```
### 1. Installing dependencies
@ -34,9 +34,9 @@ sudo xcodebuild -runFirstLaunch
### 3. Installing Flutter
Install Flutter, specifically version `3.24.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/macos/desktop?tab=download).
NOTE: as `3.24.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
### 4. Installing Rust
@ -56,7 +56,7 @@ The output of this command should appear like this, indicating successful instal
```zsh
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.4, on macOS 15.x.x)
[✓] Flutter (Channel stable, 3.27.4, on macOS 15.x.x)
...
[✓] Xcode - develop for iOS and macOS (Xcode 16.2)
...
@ -93,6 +93,7 @@ Build the necessary libraries and their dependencies:
```zsh
./build_monero_all.sh
./build_decred.sh
```
NOTE: This step will take quite a while, so be sure you grab a cup of coffee or a good book!

View file

@ -6,18 +6,18 @@ The following are the system requirements to build Cake Wallet for your Windows
```txt
Windows 10 or later (64-bit), x86-64 based
Flutter 3.24.4
Flutter 3.27.4
```
### 1. Installing Flutter
Install Flutter, specifically version `3.24.4` by following the [official docs](https://docs.flutter.dev/get-started/install/windows).
Install Flutter, specifically version `3.27.4` by following the [official docs](https://docs.flutter.dev/get-started/install/windows).
In order for Flutter to function, you'll also need to enable Developer Mode:
Start Menu > search for "Run" > type `ms-settings:developers`, and turn on Developer Mode.
NOTE: as `3.24.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
NOTE: as `3.27.4` is not the latest version, you'll need to download it from <https://docs.flutter.dev/release/archive> instead of the link in the docs above.
### 2. Install Development Tools

View file

@ -3,38 +3,11 @@ PODS:
- Flutter
- ReachabilitySwift
- CryptoSwift (1.8.3)
- cw_haven (0.0.1):
- cw_haven/Boost (= 0.0.1)
- cw_haven/Haven (= 0.0.1)
- cw_haven/OpenSSL (= 0.0.1)
- cw_haven/Sodium (= 0.0.1)
- cw_shared_external
- Flutter
- cw_haven/Boost (0.0.1):
- cw_shared_external
- Flutter
- cw_haven/Haven (0.0.1):
- cw_shared_external
- Flutter
- cw_haven/OpenSSL (0.0.1):
- cw_shared_external
- Flutter
- cw_haven/Sodium (0.0.1):
- cw_shared_external
- Flutter
- cw_mweb (0.0.1):
- Flutter
- cw_decred (0.0.1):
- cw_shared_external (0.0.1):
- cw_shared_external/Boost (= 0.0.1)
- cw_shared_external/OpenSSL (= 0.0.1)
- cw_shared_external/Sodium (= 0.0.1)
- Flutter
- cw_shared_external/Boost (0.0.1):
- Flutter
- cw_shared_external/OpenSSL (0.0.1):
- Flutter
- cw_shared_external/Sodium (0.0.1):
- cw_mweb (0.0.1):
- Flutter
- device_display_brightness (0.0.1):
- Flutter
@ -94,7 +67,6 @@ PODS:
- Flutter
- fluttertoast (0.0.2):
- Flutter
- Toast
- in_app_review (2.0.0):
- Flutter
- integration_test (0.0.1):
@ -105,7 +77,7 @@ PODS:
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.1.1):
- permission_handler_apple (9.3.0):
- Flutter
- ReachabilitySwift (5.2.4)
- SDWebImage (5.19.7):
@ -121,7 +93,6 @@ PODS:
- sp_scanner (0.0.1):
- Flutter
- SwiftyGif (5.4.5)
- Toast (4.1.1)
- uni_links (0.0.1):
- Flutter
- universal_ble (0.0.1):
@ -131,16 +102,13 @@ PODS:
- Flutter
- wakelock_plus (0.0.1):
- Flutter
- workmanager (0.0.1):
- Flutter
DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- CryptoSwift
- cw_haven (from `.symlinks/plugins/cw_haven/ios`)
- cw_mweb (from `.symlinks/plugins/cw_mweb/ios`)
- cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
- cw_decred (from `.symlinks/plugins/cw_decred/ios`)
- cw_mweb (from `.symlinks/plugins/cw_mweb/ios`)
- device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
@ -165,7 +133,6 @@ DEPENDENCIES:
- universal_ble (from `.symlinks/plugins/universal_ble/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
- workmanager (from `.symlinks/plugins/workmanager/ios`)
SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
@ -176,19 +143,16 @@ SPEC REPOS:
- ReachabilitySwift
- SDWebImage
- SwiftyGif
- Toast
EXTERNAL SOURCES:
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
cw_haven:
:path: ".symlinks/plugins/cw_haven/ios"
cw_mweb:
:path: ".symlinks/plugins/cw_mweb/ios"
cw_shared_external:
:path: ".symlinks/plugins/cw_shared_external/ios"
cw_decred:
:path: ".symlinks/plugins/cw_decred/ios"
cw_mweb:
:path: ".symlinks/plugins/cw_mweb/ios"
device_display_brightness:
:path: ".symlinks/plugins/device_display_brightness/ios"
device_info_plus:
@ -237,48 +201,43 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
workmanager:
:path: ".symlinks/plugins/workmanager/ios"
SPEC CHECKSUMS:
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483
cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a
cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc
file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4
flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
in_app_review: a31b5257259646ea78e0e35fc914979b0031d011
integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4
flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418
fluttertoast: 2c67e14dce98bbdb200df9e1acf610d7a6264ea1
in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
universal_ble: ff19787898040d721109c6324472e5dd4bc86adc
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49
PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597

View file

@ -48,6 +48,7 @@
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
enableGPUValidationMode = "1"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">

View file

@ -1,6 +1,5 @@
import UIKit
import Flutter
import workmanager
@main
@objc class AppDelegate: FlutterAppDelegate {
@ -12,15 +11,6 @@ import workmanager
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
WorkmanagerPlugin.setPluginRegistrantCallback { registry in
// Registry in this case is the FlutterEngine that is created in Workmanager's
// performFetchWithCompletionHandler or BGAppRefreshTask.
// This will make other plugins available during a background operation.
GeneratedPluginRegistrant.register(with: registry)
}
WorkmanagerPlugin.registerTask(withIdentifier: "com.fotolockr.cakewallet.monero_sync_task")
makeSecure()
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController

View file

@ -0,0 +1,110 @@
import 'dart:async';
import 'dart:math';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cw_core/sync_status.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
class BackgroundSync {
Future<void> sync() async {
printV("Background sync started");
await _syncMonero();
printV("Background sync completed");
}
Future<void> _syncMonero() async {
final walletLoadingService = getIt.get<WalletLoadingService>();
final walletListViewModel = getIt.get<WalletListViewModel>();
final settingsStore = getIt.get<SettingsStore>();
final List<WalletListItem> moneroWallets = walletListViewModel.wallets
.where((element) => !element.isHardware)
.where((element) => [WalletType.monero].contains(element.type))
.toList();
for (int i = 0; i < moneroWallets.length; i++) {
final wallet = await walletLoadingService.load(moneroWallets[i].type, moneroWallets[i].name);
int syncedTicks = 0;
final keyService = getIt.get<KeyService>();
int stuckTicks = 0;
inner:
while (true) {
await Future.delayed(const Duration(seconds: 1));
final syncStatus = wallet.syncStatus;
final progress = syncStatus.progress();
if (syncStatus is ConnectedSyncStatus ||
syncStatus is AttemptingSyncStatus ||
syncStatus is NotConnectedSyncStatus) {
stuckTicks++;
if (stuckTicks > 30) {
printV("${wallet.name} STUCK SYNCING");
break inner;
}
} else {
stuckTicks = 0;
}
if (syncStatus is NotConnectedSyncStatus) {
printV("${wallet.name} NOT CONNECTED");
final node = settingsStore.getCurrentNode(wallet.type);
await wallet.connectToNode(node: node);
await wallet.startBackgroundSync();
printV("STARTED SYNC");
continue inner;
}
if (progress > 0.999 || syncStatus is SyncedSyncStatus) {
syncedTicks++;
if (syncedTicks > 5) {
syncedTicks = 0;
printV("WALLET $i SYNCED");
try {
await wallet.stopBackgroundSync(
(await keyService.getWalletPassword(walletName: wallet.name)));
} catch (e) {
printV("error stopping sync: $e");
}
break inner;
}
} else {
syncedTicks = 0;
}
if (kDebugMode) {
if (syncStatus is SyncingSyncStatus) {
final blocksLeft = syncStatus.blocksLeft;
printV("$blocksLeft Blocks Left");
} else if (syncStatus is SyncedSyncStatus) {
printV("Synced");
} else if (syncStatus is SyncedTipSyncStatus) {
printV("Scanned Tip: ${syncStatus.tip}");
} else if (syncStatus is NotConnectedSyncStatus) {
printV("Still Not Connected");
} else if (syncStatus is AttemptingSyncStatus) {
printV("Attempting Sync");
} else if (syncStatus is StartingScanSyncStatus) {
printV("Starting Scan");
} else if (syncStatus is SynchronizingSyncStatus) {
printV("Syncronizing");
} else if (syncStatus is FailedSyncStatus) {
printV("Failed Sync");
} else if (syncStatus is ConnectingSyncStatus) {
printV("Connecting");
} else {
printV("Unknown Sync Status ${syncStatus.runtimeType}");
}
}
}
await wallet.stopBackgroundSync(await keyService.getWalletPassword(walletName: wallet.name));
await wallet.close(shouldCleanup: true);
}
}
}

View file

@ -24,118 +24,26 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cake_backup/backup.dart' as cake_backup;
class BackupService {
BackupService(this._secureStorage, this._walletInfoSource, this._transactionDescriptionBox,
this._keyService, this._sharedPreferences)
: _cipher = Cryptography.instance.chacha20Poly1305Aead(),
_correctWallets = <WalletInfo>[];
class $BackupService {
$BackupService(this._secureStorage, this.walletInfoSource, this.transactionDescriptionBox,
this.keyService, this.sharedPreferences)
: cipher = Cryptography.instance.chacha20Poly1305Aead(),
correctWallets = <WalletInfo>[];
static const currentVersion = _v2;
static const currentVersion = _v3;
static const _v1 = 1;
static const _v2 = 2;
static const _v3 = 3;
final Cipher _cipher;
final Cipher cipher;
final SecureStorage _secureStorage;
final SharedPreferences _sharedPreferences;
final Box<WalletInfo> _walletInfoSource;
final Box<TransactionDescription> _transactionDescriptionBox;
final KeyService _keyService;
List<WalletInfo> _correctWallets;
final SharedPreferences sharedPreferences;
final Box<WalletInfo> walletInfoSource;
final Box<TransactionDescription> transactionDescriptionBox;
final KeyService keyService;
List<WalletInfo> correctWallets;
Future<void> importBackup(Uint8List data, String password,
{String nonce = secrets.backupSalt}) async {
final version = getVersion(data);
switch (version) {
case _v1:
final backupBytes = data.toList()..removeAt(0);
final backupData = Uint8List.fromList(backupBytes);
await _importBackupV1(backupData, password, nonce: nonce);
break;
case _v2:
await _importBackupV2(data, password);
break;
default:
break;
}
}
Future<Uint8List> exportBackup(String password,
{String nonce = secrets.backupSalt, int version = currentVersion}) async {
switch (version) {
case _v1:
return await _exportBackupV1(password, nonce: nonce);
case _v2:
return await _exportBackupV2(password);
default:
throw Exception('Incorrect version: $version for exportBackup');
}
}
@Deprecated('Use v2 instead')
Future<Uint8List> _exportBackupV1(String password, {String nonce = secrets.backupSalt}) async =>
throw Exception('Deprecated. Export for backups v1 is deprecated. Please use export v2.');
Future<Uint8List> _exportBackupV2(String password) async {
final zipEncoder = ZipFileEncoder();
final appDir = await getAppDir();
final now = DateTime.now();
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
final archivePath = '${tmpDir.path}/backup_${now.toString()}.zip';
final fileEntities = appDir.listSync(recursive: false);
final keychainDump = await _exportKeychainDumpV2(password);
final preferencesDump = await _exportPreferencesJSON();
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
final transactionDescriptionDumpFile =
File('${tmpDir.path}/~_transaction_descriptions_dump_TMP');
final transactionDescriptionData = _transactionDescriptionBox
.toMap()
.map((key, value) => MapEntry(key.toString(), value.toJson()));
final transactionDescriptionDump = jsonEncode(transactionDescriptionData);
if (tmpDir.existsSync()) {
tmpDir.deleteSync(recursive: true);
}
tmpDir.createSync();
zipEncoder.create(archivePath);
fileEntities.forEach((entity) {
if (entity.path == archivePath || entity.path == tmpDir.path) {
return;
}
final filename = entity.absolute;
for (var ignore in ignoreFiles) {
final filename = entity.absolute.path;
if (filename.endsWith(ignore) && !filename.contains("wallets/")) {
printV("ignoring backup file: $filename");
return;
}
}
printV("restoring: $filename");
if (entity.statSync().type == FileSystemEntityType.directory) {
zipEncoder.addDirectory(Directory(entity.path));
} else {
zipEncoder.addFile(File(entity.path));
}
});
await keychainDumpFile.writeAsBytes(keychainDump.toList());
await preferencesDumpFile.writeAsString(preferencesDump);
await transactionDescriptionDumpFile.writeAsString(transactionDescriptionDump);
await zipEncoder.addFile(preferencesDumpFile, '~_preferences_dump');
await zipEncoder.addFile(keychainDumpFile, '~_keychain_dump');
await zipEncoder.addFile(transactionDescriptionDumpFile, '~_transaction_descriptions_dump');
zipEncoder.close();
final content = File(archivePath).readAsBytesSync();
tmpDir.deleteSync(recursive: true);
return await _encryptV2(content, password);
}
Future<void> _importBackupV1(Uint8List data, String password, {required String nonce}) async {
Future<void> importBackupV1(Uint8List data, String password, {required String nonce}) async {
final appDir = await getAppDir();
final decryptedData = await _decryptV1(data, password, nonce);
final zip = ZipDecoder().decodeBytes(decryptedData);
@ -153,9 +61,9 @@ class BackupService {
}
}
await _verifyWallets();
await verifyWallets();
await _importKeychainDumpV1(password, nonce: nonce);
await _importPreferencesDump();
await importPreferencesDump();
}
// checked with .endsWith - so this should be the last part of the filename
@ -163,12 +71,13 @@ class BackupService {
"flutter_assets/kernel_blob.bin",
"flutter_assets/vm_snapshot_data",
"flutter_assets/isolate_snapshot_data",
"README.txt",
".lock",
];
Future<void> _importBackupV2(Uint8List data, String password) async {
Future<void> importBackupV2(Uint8List data, String password) async {
final appDir = await getAppDir();
final decryptedData = await _decryptV2(data, password);
final decryptedData = await decryptV2(data, password);
final zip = ZipDecoder().decodeBytes(decryptedData);
outer:
@ -187,22 +96,25 @@ class BackupService {
..createSync(recursive: true)
..writeAsBytesSync(content, flush: true);
} else {
Directory('${appDir.path}/' + filename)..create(recursive: true);
final dir = Directory('${appDir.path}/' + filename);
if (!dir.existsSync()) {
dir.createSync(recursive: true);
}
}
}
await _verifyWallets();
await _importKeychainDumpV2(password);
await _importPreferencesDump();
await _importTransactionDescriptionDump(); // HiveError: Box has already been closed
await verifyWallets();
await importKeychainDumpV2(password);
await importPreferencesDump();
await importTransactionDescriptionDump(); // HiveError: Box has already been closed
}
Future<void> _verifyWallets() async {
Future<void> verifyWallets() async {
final walletInfoSource = await _reloadHiveWalletInfoBox();
_correctWallets =
correctWallets =
walletInfoSource.values.where((info) => availableWalletTypes.contains(info.type)).toList();
if (_correctWallets.isEmpty) {
if (correctWallets.isEmpty) {
throw Exception('Correct wallets not detected');
}
}
@ -219,7 +131,7 @@ class BackupService {
return await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
}
Future<void> _importTransactionDescriptionDump() async {
Future<void> importTransactionDescriptionDump() async {
final appDir = await getAppDir();
final transactionDescriptionFile = File('${appDir.path}/~_transaction_descriptions_dump');
@ -231,7 +143,7 @@ class BackupService {
json.decode(transactionDescriptionFile.readAsStringSync()) as Map<String, dynamic>;
final descriptionsMap = jsonData.map((key, value) =>
MapEntry(key, TransactionDescription.fromJson(value as Map<String, dynamic>)));
var box = _transactionDescriptionBox;
var box = transactionDescriptionBox;
if (!box.isOpen) {
final transactionDescriptionsBoxKey = await getEncryptionKey(
secureStorage: _secureStorage, forKey: TransactionDescription.boxKey);
@ -241,7 +153,7 @@ class BackupService {
await box.putAll(descriptionsMap);
}
Future<void> _importPreferencesDump() async {
Future<void> importPreferencesDump() async {
final appDir = await getAppDir();
final preferencesFile = File('${appDir.path}/~_preferences_dump');
@ -253,12 +165,12 @@ class BackupService {
String currentWalletName = data[PreferencesKey.currentWalletName] as String;
int currentWalletType = data[PreferencesKey.currentWalletType] as int;
final isCorrentCurrentWallet = _correctWallets
final isCorrentCurrentWallet = correctWallets
.any((info) => info.name == currentWalletName && info.type.index == currentWalletType);
if (!isCorrentCurrentWallet) {
currentWalletName = _correctWallets.first.name;
currentWalletType = serializeToInt(_correctWallets.first.type);
currentWalletName = correctWallets.first.name;
currentWalletType = serializeToInt(correctWallets.first.type);
}
final currentNodeId = data[PreferencesKey.currentNodeIdKey] as int?;
@ -297,114 +209,113 @@ class BackupService {
final autoGenerateSubaddressStatus =
data[PreferencesKey.autoGenerateSubaddressStatusKey] as int?;
await _sharedPreferences.setString(PreferencesKey.currentWalletName, currentWalletName);
await sharedPreferences.setString(PreferencesKey.currentWalletName, currentWalletName);
if (currentNodeId != null)
await _sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, currentNodeId);
await sharedPreferences.setInt(PreferencesKey.currentNodeIdKey, currentNodeId);
if (currentBalanceDisplayMode != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.currentBalanceDisplayModeKey, currentBalanceDisplayMode);
await _sharedPreferences.setInt(PreferencesKey.currentWalletType, currentWalletType);
await sharedPreferences.setInt(PreferencesKey.currentWalletType, currentWalletType);
if (currentFiatCurrency != null)
await _sharedPreferences.setString(
PreferencesKey.currentFiatCurrencyKey, currentFiatCurrency);
await sharedPreferences.setString(PreferencesKey.currentFiatCurrencyKey, currentFiatCurrency);
if (shouldSaveRecipientAddress != null)
await _sharedPreferences.setBool(
await sharedPreferences.setBool(
PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress);
if (isAppSecure != null)
await _sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure);
await sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure);
if (disableTradeOption != null)
await _sharedPreferences.setBool(PreferencesKey.disableTradeOption, disableTradeOption);
await sharedPreferences.setBool(PreferencesKey.disableTradeOption, disableTradeOption);
if (currentTransactionPriorityKeyLegacy != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.currentTransactionPriorityKeyLegacy, currentTransactionPriorityKeyLegacy);
if (currentBitcoinElectrumSererId != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.currentBitcoinElectrumSererIdKey, currentBitcoinElectrumSererId);
if (currentLanguageCode != null)
await _sharedPreferences.setString(PreferencesKey.currentLanguageCode, currentLanguageCode);
await sharedPreferences.setString(PreferencesKey.currentLanguageCode, currentLanguageCode);
if (displayActionListMode != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.displayActionListModeKey, displayActionListMode);
if (fiatApiMode != null)
await _sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, fiatApiMode);
await sharedPreferences.setInt(PreferencesKey.currentFiatApiModeKey, fiatApiMode);
if (autoGenerateSubaddressStatus != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.autoGenerateSubaddressStatusKey, autoGenerateSubaddressStatus);
if (currentTheme != null && DeviceInfo.instance.isMobile) {
await _sharedPreferences.setInt(PreferencesKey.currentTheme, currentTheme);
await sharedPreferences.setInt(PreferencesKey.currentTheme, currentTheme);
// enforce dark theme on desktop platforms until the design is ready:
} else if (DeviceInfo.instance.isDesktop) {
await _sharedPreferences.setInt(PreferencesKey.currentTheme, ThemeList.darkTheme.raw);
await sharedPreferences.setInt(PreferencesKey.currentTheme, ThemeList.darkTheme.raw);
}
if (exchangeStatus != null)
await _sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, exchangeStatus);
await sharedPreferences.setInt(PreferencesKey.exchangeStatusKey, exchangeStatus);
if (currentDefaultSettingsMigrationVersion != null)
await _sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion,
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion,
currentDefaultSettingsMigrationVersion);
if (moneroTransactionPriority != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.moneroTransactionPriority, moneroTransactionPriority);
if (bitcoinTransactionPriority != null)
await _sharedPreferences.setInt(
await sharedPreferences.setInt(
PreferencesKey.bitcoinTransactionPriority, bitcoinTransactionPriority);
if (sortBalanceTokensBy != null)
await _sharedPreferences.setInt(PreferencesKey.sortBalanceBy, sortBalanceTokensBy);
await sharedPreferences.setInt(PreferencesKey.sortBalanceBy, sortBalanceTokensBy);
if (pinNativeTokenAtTop != null)
await _sharedPreferences.setBool(PreferencesKey.pinNativeTokenAtTop, pinNativeTokenAtTop);
await sharedPreferences.setBool(PreferencesKey.pinNativeTokenAtTop, pinNativeTokenAtTop);
if (useEtherscan != null)
await _sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan);
await sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan);
if (defaultNanoRep != null)
await _sharedPreferences.setString(PreferencesKey.defaultNanoRep, defaultNanoRep);
await sharedPreferences.setString(PreferencesKey.defaultNanoRep, defaultNanoRep);
if (defaultBananoRep != null)
await _sharedPreferences.setString(PreferencesKey.defaultBananoRep, defaultBananoRep);
await sharedPreferences.setString(PreferencesKey.defaultBananoRep, defaultBananoRep);
if (syncAll != null) await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
if (syncAll != null) await sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
if (lookupsTwitter != null)
await _sharedPreferences.setBool(PreferencesKey.lookupsTwitter, lookupsTwitter);
await sharedPreferences.setBool(PreferencesKey.lookupsTwitter, lookupsTwitter);
if (lookupsMastodon != null)
await _sharedPreferences.setBool(PreferencesKey.lookupsMastodon, lookupsMastodon);
await sharedPreferences.setBool(PreferencesKey.lookupsMastodon, lookupsMastodon);
if (lookupsYatService != null)
await _sharedPreferences.setBool(PreferencesKey.lookupsYatService, lookupsYatService);
await sharedPreferences.setBool(PreferencesKey.lookupsYatService, lookupsYatService);
if (lookupsUnstoppableDomains != null)
await _sharedPreferences.setBool(
await sharedPreferences.setBool(
PreferencesKey.lookupsUnstoppableDomains, lookupsUnstoppableDomains);
if (lookupsOpenAlias != null)
await _sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, lookupsOpenAlias);
await sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, lookupsOpenAlias);
if (lookupsENS != null) await _sharedPreferences.setBool(PreferencesKey.lookupsENS, lookupsENS);
if (lookupsENS != null) await sharedPreferences.setBool(PreferencesKey.lookupsENS, lookupsENS);
if (lookupsWellKnown != null)
await _sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, lookupsWellKnown);
await sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, lookupsWellKnown);
if (syncAll != null) await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
if (syncAll != null) await sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
if (syncMode != null) await _sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode);
if (syncMode != null) await sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode);
await preferencesFile.delete();
}
@ -435,12 +346,12 @@ class BackupService {
keychainDumpFile.deleteSync();
}
Future<void> _importKeychainDumpV2(String password,
Future<void> importKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final appDir = await getAppDir();
final keychainDumpFile = File('${appDir.path}/~_keychain_dump');
final decryptedKeychainDumpFileData =
await _decryptV2(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
await decryptV2(keychainDumpFile.readAsBytesSync(), '$keychainSalt$password');
final keychainJSON =
json.decode(utf8.decode(decryptedKeychainDumpFileData)) as Map<String, dynamic>;
final keychainWalletsInfo = keychainJSON['wallets'] as List;
@ -461,7 +372,7 @@ class BackupService {
final name = info['name'] as String;
final password = info['password'] as String;
await _keyService.saveWalletPassword(walletName: name, password: password);
await keyService.saveWalletPassword(walletName: name, password: password);
}
@Deprecated('Use v2 instead')
@ -469,14 +380,14 @@ class BackupService {
{required String nonce, String keychainSalt = secrets.backupKeychainSalt}) async =>
throw Exception('Deprecated');
Future<Uint8List> _exportKeychainDumpV2(String password,
Future<Uint8List> exportKeychainDumpV2(String password,
{String keychainSalt = secrets.backupKeychainSalt}) async {
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
final wallets = await Future.wait(_walletInfoSource.values.map((walletInfo) async {
final wallets = await Future.wait(walletInfoSource.values.map((walletInfo) async {
return {
'name': walletInfo.name,
'type': walletInfo.type.toString(),
'password': await _keyService.getWalletPassword(walletName: walletInfo.name)
'password': await keyService.getWalletPassword(walletName: walletInfo.name)
};
}));
final backupPasswordKey = generateStoreKeyFor(key: SecretStoreKey.backupPassword);
@ -487,58 +398,56 @@ class BackupService {
return encrypted;
}
Future<String> _exportPreferencesJSON() async {
Future<String> exportPreferencesJSON() async {
final preferences = <String, dynamic>{
PreferencesKey.currentWalletName:
_sharedPreferences.getString(PreferencesKey.currentWalletName),
PreferencesKey.currentNodeIdKey: _sharedPreferences.getInt(PreferencesKey.currentNodeIdKey),
sharedPreferences.getString(PreferencesKey.currentWalletName),
PreferencesKey.currentNodeIdKey: sharedPreferences.getInt(PreferencesKey.currentNodeIdKey),
PreferencesKey.currentBalanceDisplayModeKey:
_sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey),
PreferencesKey.currentWalletType: _sharedPreferences.getInt(PreferencesKey.currentWalletType),
sharedPreferences.getInt(PreferencesKey.currentBalanceDisplayModeKey),
PreferencesKey.currentWalletType: sharedPreferences.getInt(PreferencesKey.currentWalletType),
PreferencesKey.currentFiatCurrencyKey:
_sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey),
sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey),
PreferencesKey.shouldSaveRecipientAddressKey:
_sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey),
sharedPreferences.getBool(PreferencesKey.shouldSaveRecipientAddressKey),
PreferencesKey.disableTradeOption:
_sharedPreferences.getBool(PreferencesKey.disableTradeOption),
sharedPreferences.getBool(PreferencesKey.disableTradeOption),
PreferencesKey.currentTransactionPriorityKeyLegacy:
_sharedPreferences.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy),
sharedPreferences.getInt(PreferencesKey.currentTransactionPriorityKeyLegacy),
PreferencesKey.currentBitcoinElectrumSererIdKey:
_sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey),
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey),
PreferencesKey.currentLanguageCode:
_sharedPreferences.getString(PreferencesKey.currentLanguageCode),
sharedPreferences.getString(PreferencesKey.currentLanguageCode),
PreferencesKey.displayActionListModeKey:
_sharedPreferences.getInt(PreferencesKey.displayActionListModeKey),
PreferencesKey.currentTheme: _sharedPreferences.getInt(PreferencesKey.currentTheme),
PreferencesKey.exchangeStatusKey: _sharedPreferences.getInt(PreferencesKey.exchangeStatusKey),
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey),
PreferencesKey.currentTheme: sharedPreferences.getInt(PreferencesKey.currentTheme),
PreferencesKey.exchangeStatusKey: sharedPreferences.getInt(PreferencesKey.exchangeStatusKey),
PreferencesKey.currentDefaultSettingsMigrationVersion:
_sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion),
sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion),
PreferencesKey.bitcoinTransactionPriority:
_sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority),
sharedPreferences.getInt(PreferencesKey.bitcoinTransactionPriority),
PreferencesKey.moneroTransactionPriority:
_sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority),
sharedPreferences.getInt(PreferencesKey.moneroTransactionPriority),
PreferencesKey.currentFiatApiModeKey:
_sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey),
PreferencesKey.sortBalanceBy: _sharedPreferences.getInt(PreferencesKey.sortBalanceBy),
sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey),
PreferencesKey.sortBalanceBy: sharedPreferences.getInt(PreferencesKey.sortBalanceBy),
PreferencesKey.pinNativeTokenAtTop:
_sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop),
PreferencesKey.useEtherscan: _sharedPreferences.getBool(PreferencesKey.useEtherscan),
PreferencesKey.defaultNanoRep: _sharedPreferences.getString(PreferencesKey.defaultNanoRep),
PreferencesKey.defaultBananoRep:
_sharedPreferences.getString(PreferencesKey.defaultBananoRep),
PreferencesKey.lookupsTwitter: _sharedPreferences.getBool(PreferencesKey.lookupsTwitter),
PreferencesKey.lookupsMastodon: _sharedPreferences.getBool(PreferencesKey.lookupsMastodon),
PreferencesKey.lookupsYatService:
_sharedPreferences.getBool(PreferencesKey.lookupsYatService),
sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop),
PreferencesKey.useEtherscan: sharedPreferences.getBool(PreferencesKey.useEtherscan),
PreferencesKey.defaultNanoRep: sharedPreferences.getString(PreferencesKey.defaultNanoRep),
PreferencesKey.defaultBananoRep: sharedPreferences.getString(PreferencesKey.defaultBananoRep),
PreferencesKey.lookupsTwitter: sharedPreferences.getBool(PreferencesKey.lookupsTwitter),
PreferencesKey.lookupsMastodon: sharedPreferences.getBool(PreferencesKey.lookupsMastodon),
PreferencesKey.lookupsYatService: sharedPreferences.getBool(PreferencesKey.lookupsYatService),
PreferencesKey.lookupsUnstoppableDomains:
_sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains),
PreferencesKey.lookupsOpenAlias: _sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias),
PreferencesKey.lookupsENS: _sharedPreferences.getBool(PreferencesKey.lookupsENS),
PreferencesKey.lookupsWellKnown: _sharedPreferences.getBool(PreferencesKey.lookupsWellKnown),
PreferencesKey.syncModeKey: _sharedPreferences.getInt(PreferencesKey.syncModeKey),
PreferencesKey.syncAllKey: _sharedPreferences.getBool(PreferencesKey.syncAllKey),
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains),
PreferencesKey.lookupsOpenAlias: sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias),
PreferencesKey.lookupsENS: sharedPreferences.getBool(PreferencesKey.lookupsENS),
PreferencesKey.lookupsWellKnown: sharedPreferences.getBool(PreferencesKey.lookupsWellKnown),
PreferencesKey.syncModeKey: sharedPreferences.getInt(PreferencesKey.syncModeKey),
PreferencesKey.syncAllKey: sharedPreferences.getBool(PreferencesKey.syncAllKey),
PreferencesKey.autoGenerateSubaddressStatusKey:
_sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey),
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey),
};
return json.encode(preferences);
@ -562,13 +471,13 @@ class BackupService {
final nonce = base64.decode(nonceBase64).toList();
final box = SecretBox(Uint8List.sublistView(data, 0, data.lengthInBytes - macLength).toList(),
nonce: nonce, mac: Mac(Uint8List.sublistView(data, data.lengthInBytes - macLength)));
final plainData = await _cipher.decrypt(box, secretKey: secretKey);
final plainData = await cipher.decrypt(box, secretKey: secretKey);
return Uint8List.fromList(plainData);
}
Future<Uint8List> _encryptV2(Uint8List data, String passphrase) async =>
cake_backup.encrypt(passphrase, data, version: _v2);
Future<Uint8List> _decryptV2(Uint8List data, String passphrase) async =>
Future<Uint8List> decryptV2(Uint8List data, String passphrase) async =>
cake_backup.decrypt(passphrase, data);
}

View file

@ -0,0 +1,470 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:archive/archive_io.dart';
import 'package:cake_wallet/core/backup_service.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_backup/backup.dart' as cake_backup;
import 'package:cake_wallet/utils/package_info.dart';
import 'package:crypto/crypto.dart';
import 'package:cw_core/root_dir.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/foundation.dart';
enum BackupVersion {
unknown, // index 0
v1,
v2,
v3,
}
class ChunkChecksum {
ChunkChecksum({
required this.encrypted,
required this.plain,
});
final String encrypted;
final String plain;
factory ChunkChecksum.fromJson(Map<String, dynamic> json) {
return ChunkChecksum(
encrypted: json['encrypted'] as String,
plain: json['plain'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'encrypted': encrypted,
'plain': plain,
};
}
@override
String toString() {
return 'ChunkChecksum(encrypted: $encrypted, plain: $plain)';
}
}
class ChunkLength {
ChunkLength({
required this.encrypted,
required this.plain,
});
final int encrypted;
final int plain;
factory ChunkLength.fromJson(Map<String, dynamic> json) {
return ChunkLength(
encrypted: json['encrypted'] as int,
plain: json['plain'] as int,
);
}
Map<String, dynamic> toJson() {
return {
'encrypted': encrypted,
'plain': plain,
};
}
@override
String toString() {
return 'ChunkLength(encrypted: $encrypted, plain: $plain)';
}
}
class ChunkDetails {
ChunkDetails({
required this.sha512sum,
required this.length,
});
final ChunkChecksum sha512sum;
final ChunkLength length;
factory ChunkDetails.fromJson(Map<String, dynamic> json) {
return ChunkDetails(
sha512sum: ChunkChecksum.fromJson(json['sha512sum'] as Map<String, dynamic>),
length: ChunkLength.fromJson(json['length'] as Map<String, dynamic>),
);
}
Map<String, dynamic> toJson() {
return {
'sha512sum': sha512sum,
'length': length,
};
}
@override
String toString() {
return 'ChunkDetails(sha512sum: $sha512sum, length: $length)';
}
}
class BackupMetadata {
BackupMetadata({
required this.version,
required this.sha512sum,
required this.chunks,
required this.cakeVersion,
});
final BackupVersion version;
String sha512sum;
final List<ChunkDetails> chunks;
String cakeVersion;
factory BackupMetadata.fromJson(Map<String, dynamic> json) {
return BackupMetadata(
version: BackupVersion.values[json['version'] as int],
sha512sum: json['sha512sum'] as String,
chunks: (json['chunks'] as List<dynamic>).map((chunk) => ChunkDetails.fromJson(chunk as Map<String, dynamic>)).toList(),
cakeVersion: json['cakeVersion'] as String,
);
}
Map<String, dynamic> toJson() {
return {
'version': version.index,
'sha512sum': sha512sum,
'chunks': chunks.map((chunk) => chunk.toJson()).toList(),
'cakeVersion': cakeVersion,
};
}
@override
String toString() {
return 'BackupMetadata(version: $version, sha512sum: $sha512sum, chunks: $chunks)';
}
}
class BackupServiceV3 extends $BackupService {
BackupServiceV3(super.secureStorage, super.walletInfoSource, super.transactionDescriptionBox, super.keyService, super.sharedPreferences);
static BackupVersion get currentVersion => BackupVersion.v3;
Future<File> exportBackupFile(String password, {String nonce = secrets.backupSalt}) {
return exportBackupFileV3(password, nonce: nonce);
}
BackupVersion getVersionFile(File data) {
final raf = data.openSync(mode: FileMode.read);
try {
// Read first 4 bytes to check both version and zip signature
final buffer = Uint8List(1);
final bytesRead = raf.readIntoSync(buffer);
if (bytesRead == 0) {
throw Exception('Invalid backup file: empty file');
}
// Check if first byte is version 1 or 2
if (buffer[0] == 1) {
return BackupVersion.v1;
} else if (buffer[0] == 2) {
return BackupVersion.v2;
} else if (buffer[0] == 0x50) {
// $ head -c 64 test-archive.zip | hexdump -C
// 00000000 50 4b 03 04 ....
// Here we just check if the first byte is the zip signature
// Inside of v3 backup we have multiple files.
// Check metadata.json for version in v3 backup
final inputStream = InputFileStream(data.path);
final archive = ZipDecoder().decodeStream(inputStream);
final metadataFile = archive.findFile('metadata.json');
if (metadataFile == null) {
throw Exception('Invalid v3 backup: missing metadata.json');
}
final metadataBytes = metadataFile.rawContent!.readBytes();
final metadataString = utf8.decode(metadataBytes);
final metadataJsonRaw = json.decode(metadataString) as Map<String, dynamic>;
final metadata = BackupMetadata.fromJson(metadataJsonRaw);
if (metadata.version == BackupVersion.v3) {
return BackupVersion.v3;
}
}
throw Exception('Invalid backup file: unknown version');
} finally {
raf.closeSync();
}
}
Future<void> importBackupFile(File file, String password, {String nonce = secrets.backupSalt}) {
final version = getVersionFile(file);
switch (version) {
case BackupVersion.unknown:
throw Exception('Invalid backup file: unknown version');
case BackupVersion.v1:
final data = file.readAsBytesSync();
final backupBytes = data.toList()..removeAt(0);
final backupData = Uint8List.fromList(backupBytes);
return super.importBackupV1(backupData, password, nonce: nonce);
case BackupVersion.v2:
return super.importBackupV2(file.readAsBytesSync(), password);
case BackupVersion.v3:
return importBackupFileV3(file, password, nonce: nonce);
}
}
Future<void> importBackupFileV3(File file, String password, {String nonce = secrets.backupSalt}) async{
// Overall design of v3 backup is the following:
// 1. backup.zip - plaintext zip file that user can open with any archive manager
// 2. backup.zip/README.txt - text file to let user know what is inside of this file
// 3. backup.zip/metadata.json - json file with metadata about backup.
// 4. backup.zip/data.bin - v2 backup file
final inputStream = InputFileStream(file.path);
final archive = ZipDecoder().decodeStream(inputStream);
final metadataFile = archive.findFile('metadata.json');
if (metadataFile == null) {
throw Exception('Invalid v3 backup: missing metadata.json');
}
final metadataBytes = metadataFile.rawContent!.readBytes();
final metadataString = utf8.decode(metadataBytes);
final metadataJsonRaw = json.decode(metadataString) as Map<String, dynamic>;
final metadata = BackupMetadata.fromJson(metadataJsonRaw);
final dataFile = archive.findFile('data.bin');
if (dataFile == null) {
throw Exception('Invalid v3 backup: missing data.bin');
}
final dataStream = dataFile.rawContent!.getStream();
final decryptedData = File('${file.path}_decrypted'); // decrypted zip file
if (decryptedData.existsSync()) {
decryptedData.deleteSync();
}
decryptedData.createSync(recursive: true);
decryptedData.writeAsBytesSync(Uint8List(0), mode: FileMode.write, flush: true);
int chunkIndex = 0;
for (var chunk in metadata.chunks) {
chunkIndex++;
final chunkBytes = dataStream.readBytes(chunk.length.encrypted).toUint8List();
final chunkChecksum = (await sha512.bind(Stream.fromIterable([chunkBytes])).first).toString();
// readBytes stores position internally, so we don't need to think about it.
if (chunk.sha512sum.encrypted != chunkChecksum) {
throw Exception('Invalid v3 backup: chunk (${chunk.length.encrypted} bytes) checksum mismatch at index $chunkIndex\n'
'expected: ${chunk.sha512sum.encrypted}\n'
'got: $chunkChecksum');
}
final decryptedChunk = await cake_backup.decrypt(password, chunkBytes);
decryptedData.writeAsBytesSync(decryptedChunk, mode: FileMode.append, flush: true);
}
final sha512sum = (await sha512.bind(decryptedData.openRead()).first).toString();
if (sha512sum.toString() != metadata.sha512sum) {
throw Exception('Invalid v3 backup: SHA512 checksum mismatch\n'
'expected: ${metadata.sha512sum}\n'
'got: $sha512sum');
}
// Decryption done, now we can import the backup (that is, unzip app data)
// archive is **NOT** backup, it is just a zip file that contains data.bin inside.
// We need to unzip it to get the backup.
// data.bin after decryption is available in decryptedData.
final zip = ZipDecoder();
final decryptedDataStream = InputFileStream(decryptedData.path);
final backupArchive = zip.decodeStream(decryptedDataStream);
final appDir = await getAppDir();
outer:
for (var file in backupArchive.files) {
final filename = file.name;
for (var ignore in $BackupService.ignoreFiles) {
if (filename.endsWith(ignore) && !filename.contains("wallets/")) {
printV("ignoring backup file: $filename");
continue outer;
}
}
printV("restoring: $filename");
if (file.isFile) {
final output = File('${appDir.path}/' + filename)
..createSync(recursive: true);
final outputStream = OutputFileStream(output.path);
file.writeContent(outputStream);
outputStream.flush();
} else {
final dir = Directory('${appDir.path}/' + filename);
if (!dir.existsSync()) {
dir.createSync(recursive: true);
}
}
};
// Continue importing the backup the old way
await super.verifyWallets();
await super.importKeychainDumpV2(password);
await super.importPreferencesDump();
await super.importTransactionDescriptionDump();
// Delete decrypted data file
decryptedData.deleteSync();
}
Future<File> exportBackupFileV3(String password, {String nonce = secrets.backupSalt}) async {
final metadata = BackupMetadata(
version: BackupVersion.v3,
sha512sum: 'tbd',
chunks: [],
cakeVersion: 'tbd',
);
final zipEncoder = ZipFileEncoder();
final appDir = await getAppDir();
final now = DateTime.now().toIso8601String().replaceAll(':', '-');
final tmpDir = Directory('${appDir.path}/~_BACKUP_TMP');
final archivePath = '${tmpDir.path}/backup_${now}.tmp.zip';
final archivePathExport = '${tmpDir.path}/backup_${now}.zip';
final fileEntities = appDir.listSync(recursive: false);
final keychainDump = await super.exportKeychainDumpV2(password);
final preferencesDump = await super.exportPreferencesJSON();
final preferencesDumpFile = File('${tmpDir.path}/~_preferences_dump_TMP');
final keychainDumpFile = File('${tmpDir.path}/~_keychain_dump_TMP');
final transactionDescriptionDumpFile =
File('${tmpDir.path}/~_transaction_descriptions_dump_TMP');
final transactionDescriptionData = super.transactionDescriptionBox
.toMap()
.map((key, value) => MapEntry(key.toString(), value.toJson()));
final transactionDescriptionDump = jsonEncode(transactionDescriptionData);
if (tmpDir.existsSync()) {
tmpDir.deleteSync(recursive: true);
}
tmpDir.createSync();
zipEncoder.create(archivePath);
outer:
for (var entity in fileEntities) {
if (entity.path == archivePath || entity.path == tmpDir.path) {
continue;
}
for (var ignore in $BackupService.ignoreFiles) {
final filename = entity.absolute.path;
if (filename.endsWith(ignore) && !filename.contains("wallets/")) {
printV("ignoring backup file: $filename");
continue outer;
}
}
if (entity.statSync().type == FileSystemEntityType.directory) {
await zipEncoder.addDirectory(Directory(entity.path));
} else {
await zipEncoder.addFile(File(entity.path));
}
}
await keychainDumpFile.writeAsBytes(keychainDump.toList());
await preferencesDumpFile.writeAsString(preferencesDump);
await transactionDescriptionDumpFile.writeAsString(transactionDescriptionDump);
await zipEncoder.addFile(preferencesDumpFile, '~_preferences_dump');
await zipEncoder.addFile(keychainDumpFile, '~_keychain_dump');
await zipEncoder.addFile(transactionDescriptionDumpFile, '~_transaction_descriptions_dump');
await zipEncoder.close();
final dataBinUnencrypted = File(archivePath);
final dataBin = File('${tmpDir.path}/data.bin');
dataBin.writeAsBytesSync(Uint8List(0), mode: FileMode.write, flush: true);
final dataBinWriter = dataBin.openWrite();
printV("------ Backup stats ------");
printV("Backup version: ${metadata.version}");
printV("Backup size: ${await dataBinUnencrypted.length()}");
printV("Backup chunks: ${(await dataBinUnencrypted.length()) / chunkSize}");
printV("------ Backup stats ------");
int chunkIndex = 0;
final stopwatch = Stopwatch()..start();
printV("Starting backup encryption...");
metadata.sha512sum = (await sha512.bind(dataBinUnencrypted.openRead()).first).toString();
final raf = await dataBinUnencrypted.open();
while (true) {
printV("Reading chunk ${chunkIndex++}");
stopwatch.reset();
final chunk = await raf.read(chunkSize);
printV("Chunk read completed in ${stopwatch.elapsed}");
printV("Chunk length: ${chunk.length} expected: $chunkSize");
if (chunk.length == 0) {
break;
}
stopwatch.reset();
final encryptedChunk = await cake_backup.encrypt(password, chunk);
printV("Encryption completed in ${stopwatch.elapsed}");
stopwatch.reset();
final sha512sumEncryptedChunk = await sha512.bind(Stream.fromIterable([encryptedChunk])).first;
final sha512sumUnencryptedChunk = await sha512.bind(Stream.fromIterable([chunk])).first;
printV("Hashing completed in ${stopwatch.elapsed}");
stopwatch.reset();
dataBinWriter.add(encryptedChunk);
metadata.chunks.add(ChunkDetails(
sha512sum: ChunkChecksum(
encrypted: sha512sumEncryptedChunk.toString(),
plain: sha512sumUnencryptedChunk.toString(),
),
length: ChunkLength(
encrypted: encryptedChunk.length,
plain: chunk.length,
),
));
await dataBinWriter.flush();
printV("Writing completed in ${stopwatch.elapsed}");
}
await raf.close();
// Give the file to the user
final metadataFile = File('${tmpDir.path}/metadata.json');
final packageInfo = await PackageInfo.fromPlatform();
metadata.cakeVersion = packageInfo.version;
metadataFile.writeAsStringSync(JsonEncoder.withIndent(' ').convert(metadata.toJson()));
final readmeFile = File('${tmpDir.path}/README.txt');
readmeFile.writeAsStringSync('''This is a ${packageInfo.appName} backup. Do not modify this archive.
App version: ${packageInfo.version}
If you have any issues with this backup, please contact our in-app support.
This backup was created on ${DateTime.now().toIso8601String()}
''');
final zip = ZipFileEncoder();
zip.create(archivePathExport, level: 9);
await zip.addFile(dataBin, 'data.bin');
await zip.addFile(metadataFile, 'metadata.json');
await zip.addFile(readmeFile, 'README.txt');
await zip.close();
// tmpDir.deleteSync(recursive: true);
final file = File(archivePathExport);
return file;
}
static const chunkSize = 24 * 1024 * 1024; // 24MiB
File setVersionFile(File file, BackupVersion version) {
if (version == BackupVersion.v3) return file; // v3 uses
// helper function to call super.setVersion();
final data = file.readAsBytesSync();
super.setVersion(data, version.index);
file.writeAsBytesSync(data);
return file;
}
}

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/core/backup_service_v3.dart';
import 'package:cake_wallet/core/new_wallet_arguments.dart';
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/core/auth_service.dart';
@ -26,7 +27,6 @@ import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/core/yat_service.dart';
import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/biometric_auth.dart';
import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/entities/contact_record.dart';
@ -34,6 +34,9 @@ import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/hardware_wallet/require_hardware_wallet_connection.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
import 'package:cake_wallet/src/screens/settings/background_sync_page.dart';
import 'package:cake_wallet/view_model/dev/monero_background_sync.dart';
import 'package:cake_wallet/view_model/link_view_model.dart';
import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
@ -310,9 +313,6 @@ Future<void> setup({
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
getIt.registerSingleton<SecureStorage>(secureStorage);
}
if (!_isSetupFinished) {
getIt.registerFactory(() => BackgroundTasks());
}
final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty) &&
(secrets.wyreApiKey.isNotEmpty) &&
@ -935,6 +935,8 @@ Future<void> setup({
getIt.registerFactory<SeedSettingsViewModel>(
() => SeedSettingsViewModel(getIt.get<AppStore>(), getIt.get<SeedSettingsStore>()));
getIt.registerFactory(() => DevMoneroBackgroundSync(getIt.get<AppStore>().wallet!));
getIt.registerFactoryParam<WalletSeedPage, bool, void>((bool isWalletCreated, _) =>
WalletSeedPage(getIt.get<WalletSeedViewModel>(), isNewWalletCreated: isWalletCreated));
@ -1094,6 +1096,8 @@ Future<void> setup({
getIt.registerFactory(() =>
ExchangeTradeExternalSendPage(exchangeTradeViewModel: getIt.get<ExchangeTradeViewModel>()));
getIt.registerFactory(() => BackgroundSyncPage(getIt.get<DashboardViewModel>()));
getIt.registerFactory(() => ExchangeTemplatePage(getIt.get<ExchangeViewModel>()));
getIt.registerFactoryParam<WalletService, WalletType, void>((WalletType param1, __) {
@ -1247,11 +1251,11 @@ Future<void> setup({
getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<CakePayService>()));
getIt.registerFactory(() => BackupService(getIt.get<SecureStorage>(), _walletInfoSource,
getIt.registerFactory(() => BackupServiceV3(getIt.get<SecureStorage>(), _walletInfoSource,
_transactionDescriptionBox, getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
getIt.registerFactory(() => BackupViewModel(
getIt.get<SecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupService>()));
getIt.get<SecureStorage>(), getIt.get<SecretStore>(), getIt.get<BackupServiceV3>()));
getIt.registerFactory(() => BackupPage(getIt.get<BackupViewModel>()));
@ -1263,7 +1267,7 @@ Future<void> setup({
getIt.registerFactoryParam<RestoreOptionsPage, bool, void>(
(bool isNewInstall, _) => RestoreOptionsPage(isNewInstall: isNewInstall));
getIt.registerFactory(() => RestoreFromBackupViewModel(getIt.get<BackupService>()));
getIt.registerFactory(() => RestoreFromBackupViewModel(getIt.get<BackupServiceV3>()));
getIt.registerFactory(() => RestoreFromBackupPage(getIt.get<RestoreFromBackupViewModel>()));
@ -1476,5 +1480,6 @@ Future<void> setup({
getIt.registerFactory(() => SeedVerificationPage(getIt.get<WalletSeedViewModel>()));
getIt.registerFactory(() => DevMoneroBackgroundSyncPage(getIt.get<DevMoneroBackgroundSync>()));
_isSetupFinished = true;
}

View file

@ -1,166 +0,0 @@
import 'dart:io';
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:workmanager/workmanager.dart';
import 'package:cake_wallet/main.dart';
import 'package:cake_wallet/di.dart';
const moneroSyncTaskKey = "com.fotolockr.cakewallet.monero_sync_task";
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
try {
switch (task) {
case moneroSyncTaskKey:
/// The work manager runs on a separate isolate from the main flutter isolate.
/// thus we initialize app configs first; hive, getIt, etc...
await initializeAppConfigs();
final walletLoadingService = getIt.get<WalletLoadingService>();
final typeRaw = getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType);
WalletBase? wallet;
if (inputData!['sync_all'] as bool) {
/// get all Monero wallets of the user and sync them
final List<WalletListItem> moneroWallets = getIt
.get<WalletListViewModel>()
.wallets
.where((element) => [WalletType.monero, WalletType.wownero].contains(element.type))
.toList();
for (int i = 0; i < moneroWallets.length; i++) {
wallet =
await walletLoadingService.load(moneroWallets[i].type, moneroWallets[i].name);
final node = getIt.get<SettingsStore>().getCurrentNode(moneroWallets[i].type);
await wallet.connectToNode(node: node);
await wallet.startSync();
}
} else {
/// if the user chose to sync only active wallet
/// if the current wallet is monero; sync it only
if (typeRaw == WalletType.monero.index || typeRaw == WalletType.wownero.index) {
final name =
getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName);
wallet = await walletLoadingService.load(WalletType.values[typeRaw!], name!);
final node = getIt.get<SettingsStore>().getCurrentNode(WalletType.values[typeRaw]);
await wallet.connectToNode(node: node);
await wallet.startSync();
}
}
if (wallet?.syncStatus.progress() == null) {
return Future.error("No Monero/Wownero wallet found");
}
for (int i = 0;; i++) {
await Future<void>.delayed(const Duration(seconds: 1));
if (wallet?.syncStatus.progress() == 1.0) {
break;
}
if (i > 600) {
return Future.error("Synchronization Timed out");
}
}
break;
}
return Future.value(true);
} catch (error, stackTrace) {
printV(error);
printV(stackTrace);
return Future.error(error);
}
});
}
class BackgroundTasks {
void registerSyncTask({bool changeExisting = false}) async {
try {
bool hasMonero = getIt
.get<WalletListViewModel>()
.wallets
.any((element) => element.type == WalletType.monero);
/// if its not android nor ios, or the user has no monero wallets; exit
if (!DeviceInfo.instance.isMobile || !hasMonero) {
return;
}
final settingsStore = getIt.get<SettingsStore>();
final SyncMode syncMode = settingsStore.currentSyncMode;
final bool syncAll = settingsStore.currentSyncAll;
if (syncMode.type == SyncType.disabled || !FeatureFlag.isBackgroundSyncEnabled) {
cancelSyncTask();
return;
}
await Workmanager().initialize(
callbackDispatcher,
isInDebugMode: kDebugMode,
);
final inputData = <String, dynamic>{"sync_all": syncAll};
final constraints = Constraints(
networkType:
syncMode.type == SyncType.unobtrusive ? NetworkType.unmetered : NetworkType.connected,
requiresBatteryNotLow: syncMode.type == SyncType.unobtrusive,
requiresCharging: syncMode.type == SyncType.unobtrusive,
requiresDeviceIdle: syncMode.type == SyncType.unobtrusive,
);
if (Platform.isIOS) {
await Workmanager().registerOneOffTask(
moneroSyncTaskKey,
moneroSyncTaskKey,
initialDelay: syncMode.frequency,
existingWorkPolicy: ExistingWorkPolicy.replace,
inputData: inputData,
constraints: constraints,
);
return;
}
await Workmanager().registerPeriodicTask(
moneroSyncTaskKey,
moneroSyncTaskKey,
initialDelay: syncMode.frequency,
frequency: syncMode.frequency,
existingWorkPolicy: changeExisting ? ExistingWorkPolicy.replace : ExistingWorkPolicy.keep,
inputData: inputData,
constraints: constraints,
);
} catch (error, stackTrace) {
printV(error);
printV(stackTrace);
}
}
void cancelSyncTask() {
try {
Workmanager().cancelByUniqueName(moneroSyncTaskKey);
} catch (error, stackTrace) {
printV(error);
printV(stackTrace);
}
}
}

View file

@ -1,7 +1,6 @@
import 'package:cake_wallet/di.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart';
@ -26,6 +25,4 @@ Future<void> loadCurrentWallet({String? password}) async {
name,
password: password);
await appStore.changeCurrentWallet(wallet);
getIt.get<BackgroundTasks>().registerSyncTask();
}

View file

@ -825,7 +825,6 @@ class _HaCupertinoLocalizationsDelegate extends LocalizationsDelegate<CupertinoL
patterns: haLocaleDatePatterns,
symbols: intl.DateSymbols.deserializeFromMap(haDateSymbols),
);
return SynchronousFuture<CupertinoLocalizations>(
HaCupertinoLocalizations(
localeName: localeName,
@ -847,6 +846,7 @@ class _HaCupertinoLocalizationsDelegate extends LocalizationsDelegate<CupertinoL
singleDigitHourFormat: intl.DateFormat('j', localeName),
singleDigitMinuteFormat: intl.DateFormat.m(localeName),
singleDigitSecondFormat: intl.DateFormat.s(localeName),
weekdayFormat: intl.DateFormat.E(localeName),
),
);
}
@ -871,6 +871,7 @@ class HaCupertinoLocalizations extends GlobalCupertinoLocalizations {
required super.singleDigitMinuteFormat,
required super.doubleDigitMinuteFormat,
required super.singleDigitSecondFormat,
required super.weekdayFormat,
});
@override

View file

@ -846,6 +846,7 @@ class _YoCupertinoLocalizationsDelegate extends LocalizationsDelegate<CupertinoL
singleDigitHourFormat: intl.DateFormat('j', localeName),
singleDigitMinuteFormat: intl.DateFormat.m(localeName),
singleDigitSecondFormat: intl.DateFormat.s(localeName),
weekdayFormat: intl.DateFormat.E(localeName),
),
);
}
@ -870,6 +871,7 @@ class YoCupertinoLocalizations extends GlobalCupertinoLocalizations {
required super.singleDigitMinuteFormat,
required super.doubleDigitMinuteFormat,
required super.singleDigitSecondFormat,
required super.weekdayFormat,
});
@override

View file

@ -1,9 +1,11 @@
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/app_scroll_behavior.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/background_sync.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/contact.dart';
import 'package:cake_wallet/entities/default_settings_migration.dart';
@ -34,11 +36,13 @@ import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/mweb_utxo.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_daemon/flutter_daemon.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:hive/hive.dart';
import 'package:cw_core/root_dir.dart';
@ -68,6 +72,7 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
return true;
};
await FlutterDaemon().unmarkBackgroundSync();
await initializeAppAtRoot();
if (kDebugMode) {
@ -100,7 +105,7 @@ Future<void> initializeAppAtRoot({bool reInitializing = false}) async {
await initializeAppConfigs();
}
Future<void> initializeAppConfigs() async {
Future<void> initializeAppConfigs({bool loadWallet = true}) async {
setRootDirFromEnv();
final appDir = await getAppDir();
CakeHive.init(appDir.path);
@ -200,6 +205,7 @@ Future<void> initializeAppConfigs() async {
encryptionKey: havenSeedStoreBoxKey);
await initialSetup(
loadWallet: loadWallet,
sharedPreferences: await SharedPreferences.getInstance(),
nodes: nodes,
powNodes: powNodes,
@ -220,7 +226,8 @@ Future<void> initializeAppConfigs() async {
}
Future<void> initialSetup(
{required SharedPreferences sharedPreferences,
{required bool loadWallet,
required SharedPreferences sharedPreferences,
required Box<Node> nodes,
required Box<Node> powNodes,
required Box<WalletInfo> walletInfoSource,
@ -262,7 +269,7 @@ Future<void> initialSetup(
navigatorKey: navigatorKey,
secureStorage: secureStorage,
);
await bootstrap(navigatorKey);
await bootstrap(navigatorKey, loadWallet: loadWallet);
}
class App extends StatefulWidget {
@ -390,3 +397,34 @@ class TopLevelErrorWidget extends StatelessWidget {
);
}
}
@pragma('vm:entry-point')
Future<void> backgroundSync() async {
bool shouldUnmark = false;
try {
printV("Background sync triggered");
printV("- WidgetsFlutterBinding.ensureInitialized()");
WidgetsFlutterBinding.ensureInitialized();
printV("- DartPluginRegistrant.ensureInitialized()");
DartPluginRegistrant.ensureInitialized();
printV("- FlutterDaemon.markBackgroundSync()");
final val = await FlutterDaemon().markBackgroundSync();
if (val) {
printV("Background sync already in progress");
return;
}
shouldUnmark = true;
printV("Starting background sync");
final backgroundSync = BackgroundSync();
await initializeAppConfigs(loadWallet: false);
await backgroundSync.sync();
printV("Background sync completed");
} finally {
if (shouldUnmark) {
printV("Unmarking background sync");
await FlutterDaemon().unmarkBackgroundSync();
} else {
printV("Not unmarking background sync");
}
}
}

View file

@ -15,7 +15,7 @@ import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey, {required bool loadWallet}) async {
final appStore = getIt.get<AppStore>();
final authenticationStore = getIt.get<AuthenticationStore>();
final settingsStore = getIt.get<SettingsStore>();
@ -27,7 +27,9 @@ Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey) async {
authenticationStore.installed();
}
startAuthenticationStateChange(authenticationStore, navigatorKey);
if (loadWallet) {
startAuthenticationStateChange(authenticationStore, navigatorKey);
}
startCurrentWalletChangeReaction(appStore, settingsStore, fiatConversionStore);
startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore);
startCurrentFiatApiModeChangeReaction(appStore, settingsStore, fiatConversionStore);

View file

@ -36,6 +36,7 @@ import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/nft_details_page.dart';
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
import 'package:cake_wallet/src/screens/dashboard/sign_page.dart';
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
import 'package:cake_wallet/src/screens/disclaimer/disclaimer_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
@ -73,6 +74,7 @@ import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
import 'package:cake_wallet/src/screens/send/send_page.dart';
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
import 'package:cake_wallet/src/screens/send/transaction_success_info_page.dart';
import 'package:cake_wallet/src/screens/settings/background_sync_page.dart';
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
@ -848,6 +850,14 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => getIt.get<ExchangeTradeExternalSendPage>(),
);
case Routes.backgroundSync:
return CupertinoPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<BackgroundSyncPage>());
case Routes.devMoneroBackgroundSync:
return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevMoneroBackgroundSyncPage>(),
);
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(

View file

@ -110,6 +110,8 @@ class Routes {
static const nftDetailsPage = '/nft_details_page';
static const importNFTPage = '/import_nft_page';
static const torPage = '/tor_page';
static const backgroundSync = '/background_sync';
static const devMoneroBackgroundSync = '/dev/monero_background_sync';
static const signPage = '/sign_page';
static const connectDevices = '/device/connect';

View file

@ -137,7 +137,7 @@ class BackupPage extends BasePage {
leftButtonText: S.of(context).share,
actionRightButton: () async {
await backupViewModelBase.saveToDownload(
backup.name, backup.content);
backup.name, backup.file);
Navigator.of(dialogContext).pop();
},
actionLeftButton: () async {
@ -160,8 +160,7 @@ class BackupPage extends BasePage {
fileName: backup.name);
try {
File returnedFile = File(outputFile!);
await returnedFile.writeAsBytes(backup.content);
await backup.file.copy(outputFile!);
} catch (exception, stackTrace) {
await ExceptionHandler.onError(FlutterErrorDetails(
exception: exception,

View file

@ -384,7 +384,7 @@ class CakePayBuyCardDetailPage extends BasePage {
paymentId: S.of(popupContext).payment_id,
paymentIdValue: order?.orderId,
expirationTime: cakePayPurchaseViewModel.formattedRemainingTime,
titleText: 'Confirm Transaction',
titleText: S.of(popupContext).confirm_transaction,
titleIconPath: cakePayPurchaseViewModel.sendViewModel.selectedCryptoCurrency.iconPath,
currency: cakePayPurchaseViewModel.sendViewModel.selectedCryptoCurrency,
amount: S.of(popupContext).send_amount,
@ -432,7 +432,7 @@ class CakePayBuyCardDetailPage extends BasePage {
builder: (BuildContext context) {
loadingBottomSheetContext = context;
return LoadingBottomSheet(
titleText: 'Generating transaction',
titleText: S.of(context).generating_transaction,
);
},
);

View file

@ -0,0 +1,112 @@
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/view_model/dev/monero_background_sync.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class DevMoneroBackgroundSyncPage extends BasePage {
final DevMoneroBackgroundSync viewModel;
DevMoneroBackgroundSyncPage(this.viewModel);
@override
String? get title => "[dev] xmr background sync";
Widget _buildSingleCell(String title, String value) {
return Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.all(8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
Text(value, maxLines: 1, overflow: TextOverflow.ellipsis),
],
),
);
}
@override
Widget body(BuildContext context) {
return Observer(
builder: (_) {
return GridView.count(
padding: const EdgeInsets.all(16),
crossAxisCount: 2,
childAspectRatio: 25/9,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: [
_buildSingleCell('Height (local)', viewModel.localBlockHeight ?? ''),
_buildSingleCell('Height (node)', viewModel.nodeBlockHeight ?? ''),
_buildSingleCell('Time', viewModel.tick.toString()),
_buildSingleCell('Background Sync', viewModel.isBackgroundSyncing ? 'Enabled' : 'Disabled'),
_buildSingleCell('Public View Key', viewModel.publicViewKey ?? ''),
_buildSingleCell('Private View Key', viewModel.privateViewKey ?? ''),
_buildSingleCell('Public Spend Key', viewModel.publicSpendKey ?? ''),
_buildSingleCell('Private Spend Key', viewModel.privateSpendKey ?? ''),
_buildSingleCell('Primary Address', viewModel.primaryAddress ?? ''),
_buildSingleCell('Passphrase', viewModel.passphrase ?? ''),
_buildSingleCell('Seed', viewModel.seed ?? ''),
_buildSingleCell('Seed Legacy', viewModel.seedLegacy ?? ''),
_enableBackgroundSyncButton(),
_disableBackgroundSyncButton(),
_refreshButton(),
_manualRescanButton(),
],
);
},
);
}
PrimaryButton _enableBackgroundSyncButton() {
return PrimaryButton(
text: "Enable background sync",
color: Colors.purple,
textColor: Colors.white,
onPressed: () {
viewModel.startBackgroundSync();
},
);
}
PrimaryButton _disableBackgroundSyncButton() {
return PrimaryButton(
text: "Disable background sync",
color: Colors.purple,
textColor: Colors.white,
onPressed: () {
viewModel.stopBackgroundSync();
},
);
}
PrimaryButton _refreshButton() {
return PrimaryButton(
text: viewModel.refreshTimer == null ? "Enable refresh" : "Disable refresh",
color: Colors.purple,
textColor: Colors.white,
onPressed: () {
if (viewModel.refreshTimer == null) {
viewModel.startRefreshTimer();
} else {
viewModel.stopRefreshTimer();
}
},
);
}
PrimaryButton _manualRescanButton() {
return PrimaryButton(
text: "Manual rescan",
color: Colors.purple,
textColor: Colors.white,
onPressed: () {
viewModel.manualRescan();
},
);
}
}

View file

@ -252,7 +252,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
builder: (BuildContext context) {
loadingBottomSheetContext = context;
return LoadingBottomSheet(
titleText: 'Generating transaction',
titleText: S.of(context).generating_transaction,
);
},
);
@ -271,7 +271,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
return ConfirmSendingBottomSheet(
key: ValueKey('exchange_trade_page_confirm_sending_bottom_sheet_key'),
currentTheme: widget.currentTheme,
titleText: 'Confirm Transaction',
titleText: S.of(bottomSheetContext).confirm_transaction,
titleIconPath: widget.exchangeTradeViewModel.sendViewModel.selectedCryptoCurrency.iconPath,
currency: widget.exchangeTradeViewModel.sendViewModel.selectedCryptoCurrency,
amount: S.of(bottomSheetContext).send_amount,
@ -307,7 +307,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
builder: (BuildContext bottomSheetContext) {
return InfoBottomSheet(
currentTheme: widget.currentTheme,
titleText: 'Transaction Sent',
titleText: S.of(bottomSheetContext).transaction_sent,
contentImage: 'assets/images/birthday_cake.svg',
actionButtonText: S.of(bottomSheetContext).close,
actionButtonKey: ValueKey('send_page_sent_dialog_ok_button_key'),

View file

@ -532,7 +532,7 @@ class SendPage extends BasePage {
builder: (BuildContext context) {
loadingBottomSheetContext = context;
return LoadingBottomSheet(
titleText: 'Generating transaction',
titleText: S.of(context).generating_transaction,
);
},
);
@ -550,7 +550,7 @@ class SendPage extends BasePage {
builder: (BuildContext bottomSheetContext) {
return ConfirmSendingBottomSheet(
key: ValueKey('send_page_confirm_sending_dialog_key'),
titleText: 'Confirm Transaction',
titleText: S.of(bottomSheetContext).confirm_transaction,
currentTheme: currentTheme,
titleIconPath: sendViewModel.selectedCryptoCurrency.iconPath,
currency: sendViewModel.selectedCryptoCurrency,
@ -598,7 +598,7 @@ class SendPage extends BasePage {
currentTheme: currentTheme,
showDontAskMeCheckbox: true,
onCheckboxChanged: (value) => sendViewModel.setShowAddressBookPopup(!value),
titleText: 'Transaction Sent',
titleText: S.of(bottomSheetContext).transaction_sent,
contentImage: 'assets/images/contact_icon.svg',
contentImageColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
content: S.of(bottomSheetContext).add_contact_to_address_book,
@ -607,6 +607,8 @@ class SendPage extends BasePage {
rightButtonText: 'Yes',
actionLeftButton: () {
Navigator.of(bottomSheetContext).pop();
Navigator.of(context)
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
RequestReviewHandler.requestReview();
newContactAddress = null;
},
@ -620,11 +622,17 @@ class SendPage extends BasePage {
)
: InfoBottomSheet(
currentTheme: currentTheme,
titleText: 'Transaction Sent',
titleText: S.of(bottomSheetContext).transaction_sent,
contentImage: 'assets/images/birthday_cake.svg',
actionButtonText: S.of(bottomSheetContext).close,
actionButtonKey: ValueKey('send_page_sent_dialog_ok_button_key'),
actionButton: () => Navigator.of(bottomSheetContext).pop());
actionButton: () {
Navigator.of(bottomSheetContext).pop();
Navigator.of(context)
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);
RequestReviewHandler.requestReview();
newContactAddress = null;
});
},
);

View file

@ -0,0 +1,91 @@
import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
import 'package:cake_wallet/src/widgets/alert_with_no_action.dart.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class BackgroundSyncPage extends BasePage {
BackgroundSyncPage(this.dashboardViewModel);
@override
String get title => S.current.background_sync;
final DashboardViewModel dashboardViewModel;
@override
Widget body(BuildContext context) {
return Container(
padding: EdgeInsets.only(top: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (dashboardViewModel.hasBatteryOptimization)
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.unrestricted_background_service,
value: !dashboardViewModel.batteryOptimizationEnabled,
onValueChange: (_, bool value) {
dashboardViewModel.disableBatteryOptimization();
},
);
}),
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.background_sync,
value: dashboardViewModel.backgroundSyncEnabled,
onValueChange: (dashboardViewModel.batteryOptimizationEnabled && dashboardViewModel.hasBatteryOptimization) ? (_, bool value) {
unawaited(showPopUp(context: context, builder: (context) => AlertWithOneAction(
alertTitle: S.current.background_sync,
alertContent: S.current.unrestricted_background_service_notice,
buttonText: S.current.ok,
buttonAction: () => Navigator.of(context).pop(),
)));
} : (_, bool value) {
if (value) {
dashboardViewModel.enableBackgroundSync();
} else {
dashboardViewModel.disableBackgroundSync();
}
},
);
}),
Observer(builder: (context) {
return SettingsPickerCell<SyncMode>(
title: S.current.background_sync_mode,
items: SyncMode.all,
displayItem: (SyncMode syncMode) => syncMode.name,
selectedItem: dashboardViewModel.settingsStore.currentSyncMode,
onItemSelected: (dashboardViewModel.batteryOptimizationEnabled && dashboardViewModel.hasBatteryOptimization) ? null : (syncMode) async {
dashboardViewModel.setSyncMode(syncMode);
});
}),
// Observer(builder: (context) {
// return SettingsSwitcherCell(
// title: S.current.background_sync_on_battery,
// value: dashboardViewModel.backgroundSyncOnBattery,
// onValueChange: (_, bool value) =>
// dashboardViewModel.setBackgroundSyncOnBattery(value),
// );
// }),
// Observer(builder: (context) {
// return SettingsSwitcherCell(
// title: S.current.background_sync_on_data,
// value: dashboardViewModel.backgroundSyncOnData,
// onValueChange: (_, bool value) => dashboardViewModel.setBackgroundSyncOnData(value),
// );
// }),
],
),
);
}
}

View file

@ -44,56 +44,17 @@ class ConnectionSyncPage extends BasePage {
: S.current.rescan,
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
),
if (DeviceInfo.instance.isMobile && FeatureFlag.isBackgroundSyncEnabled) ...[
Observer(builder: (context) {
return SettingsPickerCell<SyncMode>(
title: S.current.background_sync_mode,
items: SyncMode.all,
displayItem: (SyncMode syncMode) => syncMode.name,
selectedItem: dashboardViewModel.syncMode,
onItemSelected: (syncMode) async {
dashboardViewModel.setSyncMode(syncMode);
if (Platform.isIOS) return;
if (syncMode.type != SyncType.disabled) {
final isDisabled = await isBatteryOptimizationDisabled();
if (isDisabled) return;
await showPopUp<void>(
context: context,
builder: (BuildContext dialogContext) {
return AlertWithTwoActions(
alertTitle: S.current.disableBatteryOptimization,
alertContent: S.current.disableBatteryOptimizationDescription,
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).ok,
actionLeftButton: () => Navigator.of(dialogContext).pop(),
actionRightButton: () async {
await requestDisableBatteryOptimization();
Navigator.of(dialogContext).pop();
},
);
},
);
}
});
}),
Observer(builder: (context) {
return SettingsSwitcherCell(
title: S.current.sync_all_wallets,
value: dashboardViewModel.syncAll,
onValueChange: (_, bool value) => dashboardViewModel.setSyncAll(value),
);
}),
],
],
SettingsCellWithArrow(
title: S.current.manage_nodes,
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
),
if (dashboardViewModel.hasBackgroundSync && Platform.isAndroid && FeatureFlag.isBackgroundSyncEnabled) ...[
SettingsCellWithArrow(
title: S.current.background_sync,
handler: (context) => Navigator.of(context).pushNamed(Routes.backgroundSync),
),
],
Observer(
builder: (context) {
if (!dashboardViewModel.hasPowNodes) return const SizedBox();

View file

@ -10,6 +10,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@ -63,6 +64,12 @@ class OtherSettingsPage extends BasePage {
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.readDisclaimer),
),
if (kDebugMode && _otherSettingsViewModel.walletType == WalletType.monero)
SettingsCellWithArrow(
title: '[dev] monero background sync',
handler: (BuildContext context) =>
Navigator.of(context).pushNamed(Routes.devMoneroBackgroundSync),
),
Spacer(),
SettingsVersionCell(
title: S.of(context).version(_otherSettingsViewModel.currentVersion)),

View file

@ -170,7 +170,7 @@ class RBFDetailsPage extends BasePage {
builder: (BuildContext context) {
loadingBottomSheetContext = context;
return LoadingBottomSheet(
titleText: 'Generating transaction',
titleText: S.of(context).generating_transaction,
);
},
);
@ -188,7 +188,7 @@ class RBFDetailsPage extends BasePage {
builder: (BuildContext bottomSheetContext) {
return ConfirmSendingBottomSheet(
key: ValueKey('rbf_confirm_sending_bottom_sheet'),
titleText: 'Confirm Transaction',
titleText: S.of(bottomSheetContext).confirm_transaction,
currentTheme: currentTheme,
titleIconPath: transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency.iconPath,
currency: transactionDetailsViewModel.sendViewModel.selectedCryptoCurrency,

View file

@ -276,7 +276,7 @@ class AddressTile extends StatelessWidget {
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: currentTheme.type == ThemeType.bright
? Theme.of(context).extension<BalancePageTheme>()!.labelTextColor
? Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.5)
: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
decoration: TextDecoration.none,
);
@ -298,8 +298,7 @@ class AddressTile extends StatelessWidget {
),
buildSegmentedAddress(
address: address,
evenTextStyle:
currentTheme.type == ThemeType.bright ? itemSubTitleTextStyle : addressTextStyle,
evenTextStyle: addressTextStyle,
oddTextStyle: itemSubTitleTextStyle,
),
],
@ -365,7 +364,7 @@ class AddressExpansionTile extends StatelessWidget {
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: currentTheme.type == ThemeType.bright
? Theme.of(context).extension<BalancePageTheme>()!.labelTextColor
? Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.5)
: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
decoration: TextDecoration.none,
);
@ -380,14 +379,16 @@ class AddressExpansionTile extends StatelessWidget {
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 14, vertical: isBatchSending ? 0 : 8),
child: ExpansionTile(
childrenPadding: EdgeInsets.zero,
childrenPadding: isBatchSending ? const EdgeInsets.only(bottom: 8) : EdgeInsets.zero,
tilePadding: EdgeInsets.zero,
dense: true,
visualDensity: VisualDensity.compact,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(isBatchSending ? name : contactType, style: itemTitleTextStyle),
Expanded(
child: Text(isBatchSending ? name : contactType,
style: itemTitleTextStyle, softWrap: true)),
Text(isBatchSending ? amount : name,
style: TextStyle(
fontSize: 14,
@ -407,9 +408,7 @@ class AddressExpansionTile extends StatelessWidget {
children: [
buildSegmentedAddress(
address: address,
evenTextStyle: currentTheme.type == ThemeType.bright
? itemSubTitleTextStyle
: addressTextStyle,
evenTextStyle: addressTextStyle,
oddTextStyle: itemSubTitleTextStyle,
),
if (stealthAddressText(stealthAddress) != null)
@ -417,9 +416,7 @@ class AddressExpansionTile extends StatelessWidget {
padding: const EdgeInsets.only(top: 8.0),
child: buildSegmentedAddress(
address: stealthAddressText(stealthAddress)!,
evenTextStyle: currentTheme.type == ThemeType.bright
? itemSubTitleTextStyle
: addressTextStyle,
evenTextStyle: addressTextStyle,
oddTextStyle: itemSubTitleTextStyle,
),
),

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
@ -8,7 +9,6 @@ import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/action_list_display_mode.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
import 'package:cake_wallet/entities/country.dart';
@ -42,6 +42,7 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_daemon/flutter_daemon.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -53,7 +54,6 @@ class SettingsStore = SettingsStoreBase with _$SettingsStore;
abstract class SettingsStoreBase with Store {
SettingsStoreBase(
{required SecureStorage secureStorage,
required BackgroundTasks backgroundTasks,
required SharedPreferences sharedPreferences,
required bool initialShouldShowMarketPlaceInDashboard,
required bool initialShowAddressBookPopupEnabled,
@ -141,7 +141,6 @@ abstract class SettingsStoreBase with Store {
powNodes = ObservableMap<WalletType, Node>.of(powNodes),
_secureStorage = secureStorage,
_sharedPreferences = sharedPreferences,
_backgroundTasks = backgroundTasks,
fiatCurrency = initialFiatCurrency,
balanceDisplayMode = initialBalanceDisplayMode,
shouldSaveRecipientAddress = initialSaveRecipientAddress,
@ -295,11 +294,11 @@ abstract class SettingsStoreBase with Store {
PreferencesKey.shouldSaveRecipientAddressKey, shouldSaveRecipientAddress));
if (DeviceInfo.instance.isMobile) {
setIsAppSecureNative(isAppSecure);
unawaited(setIsAppSecureNative(isAppSecure));
reaction((_) => isAppSecure, (bool isAppSecure) {
sharedPreferences.setBool(PreferencesKey.isAppSecureKey, isAppSecure);
setIsAppSecureNative(isAppSecure);
unawaited(setIsAppSecureNative(isAppSecure));
});
}
@ -396,14 +395,11 @@ abstract class SettingsStoreBase with Store {
reaction((_) => currentSyncMode, (SyncMode syncMode) {
sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode.type.index);
_backgroundTasks.registerSyncTask(changeExisting: true);
FlutterDaemon().startBackgroundSync(syncMode.frequency.inMinutes);
});
reaction((_) => currentSyncAll, (bool syncAll) {
sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
_backgroundTasks.registerSyncTask(changeExisting: true);
});
reaction(
@ -796,6 +792,7 @@ abstract class SettingsStoreBase with Store {
@observable
bool lookupsWellKnown;
@observable
SyncMode currentSyncMode;
@ -829,7 +826,6 @@ abstract class SettingsStoreBase with Store {
final SecureStorage _secureStorage;
final SharedPreferences _sharedPreferences;
final BackgroundTasks _backgroundTasks;
ObservableMap<WalletType, Node> nodes;
ObservableMap<WalletType, Node> powNodes;
@ -871,7 +867,6 @@ abstract class SettingsStoreBase with Store {
ThemeBase? initialTheme}) async {
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
final secureStorage = await getIt.get<SecureStorage>();
final backgroundTasks = getIt.get<BackgroundTasks>();
final currentFiatCurrency = FiatCurrency.deserialize(
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
final savedCakePayCountryRaw =
@ -1142,7 +1137,7 @@ abstract class SettingsStoreBase with Store {
}
final savedSyncMode = SyncMode.all.firstWhere((element) {
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 0);
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 2); // default to 2 - daily sync
});
final savedSyncAll = sharedPreferences.getBool(PreferencesKey.syncAllKey) ?? true;
@ -1323,7 +1318,6 @@ abstract class SettingsStoreBase with Store {
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
initialEthereumTransactionPriority: ethereumTransactionPriority,
initialPolygonTransactionPriority: polygonTransactionPriority,
backgroundTasks: backgroundTasks,
initialSyncMode: savedSyncMode,
initialSyncAll: savedSyncAll,
shouldShowYatPopup: shouldShowYatPopup,

View file

@ -4,6 +4,6 @@ class FeatureFlag {
static const bool isCakePayEnabled = false;
static const bool isExolixEnabled = true;
static const bool isInAppTorEnabled = false;
static const bool isBackgroundSyncEnabled = false;
static const bool isBackgroundSyncEnabled = true;
static const int verificationWordsCount = kDebugMode ? 0 : 2;
}

View file

@ -1,5 +1,6 @@
import 'dart:io';
import 'package:cake_wallet/core/backup_service.dart';
import 'package:cake_wallet/core/backup_service_v3.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/core/secure_storage.dart';
import 'package:cake_wallet/entities/secret_store_key.dart';
@ -15,10 +16,10 @@ import 'package:path_provider/path_provider.dart';
part 'backup_view_model.g.dart';
class BackupExportFile {
BackupExportFile(this.content, {required this.name});
BackupExportFile(this.file, {required this.name});
final String name;
final List<int> content;
final File file;
}
class BackupViewModel = BackupViewModelBase with _$BackupViewModel;
@ -38,7 +39,7 @@ abstract class BackupViewModelBase with Store {
final SecureStorage secureStorage;
final SecretStore secretStore;
final BackupService backupService;
final BackupServiceV3 backupService;
@observable
ExecutionState state;
@ -59,14 +60,14 @@ abstract class BackupViewModelBase with Store {
Future<BackupExportFile?> exportBackup() async {
try {
state = IsExecutingState();
final backupContent = await backupService.exportBackup(backupPassword);
final backupFile = await backupService.exportBackupFile(backupPassword);
state = ExecutedSuccessfullyState();
final now = DateTime.now();
final formatter = DateFormat('yyyy-MM-dd_Hm');
final snakeAppName = approximatedAppName.replaceAll(' ', '_').toLowerCase();
final fileName = '${snakeAppName}_backup_${formatter.format(now)}';
final fileName = '${snakeAppName}_backup_${formatter.format(now)}.zip';
return BackupExportFile(backupContent.toList(), name: fileName);
return BackupExportFile(backupFile, name: fileName);
} catch (e) {
printV(e.toString());
state = FailureState(e.toString());
@ -77,26 +78,35 @@ abstract class BackupViewModelBase with Store {
Future<String> saveBackupFileLocally(BackupExportFile backup) async {
final appDir = await getAppDir();
final path = '${appDir.path}/${backup.name}';
final backupFile = File(path);
await backupFile.writeAsBytes(backup.content);
if (File(path).existsSync()) {
File(path).deleteSync();
}
await backup.file.copy(path);
return path;
}
Future<void> removeBackupFileLocally(BackupExportFile backup) async {
final appDir = await getAppDir();
final path = '${appDir.path}/${backup.name}';
final backupFile = File(path);
await backupFile.delete();
if (File(path).existsSync()) {
File(path).deleteSync();
}
}
@action
void showMasterPassword() => isBackupPasswordVisible = true;
@action
Future<void> saveToDownload(String name, List<int> content) async {
Future<void> saveToDownload(String name, File file) async {
if (!Platform.isAndroid) {
return;
}
const downloadDirPath = '/storage/emulated/0/Download'; // For Android
final filePath = '$downloadDirPath/${name}';
final file = File(filePath);
await file.writeAsBytes(content);
final downloadFile = File(filePath);
if (downloadFile.existsSync()) {
downloadFile.deleteSync();
}
await file.copy(filePath);
}
}

View file

@ -4,6 +4,7 @@ import 'dart:io' show Platform;
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/background_sync.dart';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
@ -41,12 +42,14 @@ import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/utils/file.dart';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_daemon/flutter_daemon.dart';
import 'package:http/http.dart' as http;
import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
@ -179,6 +182,8 @@ abstract class DashboardViewModelBase with Store {
isShowFirstYatIntroduction = false;
isShowSecondYatIntroduction = false;
isShowThirdYatIntroduction = false;
unawaited(isBackgroundSyncEnabled());
unawaited(isBatteryOptimizationEnabled());
final _wallet = wallet;
@ -404,6 +409,11 @@ abstract class DashboardViewModelBase with Store {
@computed
bool get hasRescan => wallet.hasRescan;
@computed
bool get hasBackgroundSync => [
WalletType.monero,
].contains(wallet.type);
@computed
bool get isMoneroViewOnly {
if (wallet.type != WalletType.monero) return false;
@ -496,6 +506,69 @@ abstract class DashboardViewModelBase with Store {
@observable
late bool showDecredInfoCard;
@observable
bool backgroundSyncEnabled = false;
@action
Future<bool> isBackgroundSyncEnabled() async {
if (!Platform.isAndroid) {
return false;
}
final resp = await FlutterDaemon().getBackgroundSyncStatus();
backgroundSyncEnabled = resp;
return resp;
}
bool get hasBatteryOptimization => Platform.isAndroid;
@observable
bool batteryOptimizationEnabled = false;
@action
Future<bool> isBatteryOptimizationEnabled() async {
if (!hasBatteryOptimization) {
return false;
}
final resp = await FlutterDaemon().isBatteryOptimizationDisabled();
batteryOptimizationEnabled = !resp;
if (batteryOptimizationEnabled && await isBackgroundSyncEnabled()) {
// If the battery optimization is enabled, we need to disable the background sync
await disableBackgroundSync();
}
return resp;
}
@action
Future<void> disableBatteryOptimization() async {
final resp = await FlutterDaemon().requestDisableBatteryOptimization();
unawaited((() async {
// android doesn't return if the permission was granted, so we need to poll it,
// minute should be enough for the fallback method (opening settings and changing the permission)
for (var i = 0; i < 4 * 60; i++) {
await Future.delayed(Duration(milliseconds: 250));
await isBatteryOptimizationEnabled();
}
})());
}
@action
Future<void> enableBackgroundSync() async {
if (hasBatteryOptimization && batteryOptimizationEnabled) {
disableBackgroundSync();
return;
}
final resp = await FlutterDaemon().startBackgroundSync(settingsStore.currentSyncMode.frequency.inMinutes);
printV("Background sync enabled: $resp");
backgroundSyncEnabled = true;
}
@action
Future<void> disableBackgroundSync() async {
final resp = await FlutterDaemon().stopBackgroundSync();
printV("Background sync disabled: $resp");
backgroundSyncEnabled = false;
}
@computed
bool get hasEnabledMwebBefore => settingsStore.hasEnabledMwebBefore;
@ -800,11 +873,11 @@ abstract class DashboardViewModelBase with Store {
}
}
@computed
SyncMode get syncMode => settingsStore.currentSyncMode;
@action
void setSyncMode(SyncMode syncMode) => settingsStore.currentSyncMode = syncMode;
Future<void> setSyncMode(SyncMode syncMode) async {
settingsStore.currentSyncMode = syncMode;
await enableBackgroundSync();
}
@computed
bool get syncAll => settingsStore.currentSyncAll;

View file

@ -0,0 +1,106 @@
import 'dart:async';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cw_monero/monero_wallet.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/wallet_base.dart';
part 'monero_background_sync.g.dart';
class DevMoneroBackgroundSync = DevMoneroBackgroundSyncBase with _$DevMoneroBackgroundSync;
abstract class DevMoneroBackgroundSyncBase with Store {
DevMoneroBackgroundSyncBase(WalletBase wallet) : wallet = wallet;
final WalletBase wallet;
@observable
Timer? refreshTimer;
@observable
String? localBlockHeight;
@observable
String? nodeBlockHeight;
@observable
String? primaryAddress;
@observable
String? publicViewKey;
@observable
String? privateViewKey;
@observable
String? publicSpendKey;
@observable
String? privateSpendKey;
@observable
String? passphrase;
@observable
String? seed;
@observable
String? seedLegacy;
@observable
int tick = -1;
@observable
bool isBackgroundSyncing = false;
Future<void> _setValues() async {
final w = (wallet as MoneroWallet);
localBlockHeight = (await monero!.getCurrentHeight()).toString();
nodeBlockHeight = (await w.getNodeHeight()).toString();
final keys = w.keys;
primaryAddress = keys.primaryAddress;
publicViewKey = keys.publicViewKey;
privateViewKey = keys.privateViewKey;
publicSpendKey = keys.publicSpendKey;
privateSpendKey = keys.privateSpendKey;
passphrase = keys.passphrase;
seed = w.seed;
seedLegacy = w.seedLegacy("English");
tick = refreshTimer?.tick ?? -1;
isBackgroundSyncing = w.isBackgroundSyncRunning;
}
@action
Future<void> manualRescan() async {
final w = (wallet as MoneroWallet);
await wallet.rescan(height: await w.getNodeHeight() - 10000);
}
@action
void startRefreshTimer() {
refreshTimer = Timer.periodic(Duration(seconds: 1), (timer) async {
await _setValues();
});
}
@action
void stopRefreshTimer() {
refreshTimer?.cancel();
refreshTimer = null;
}
@action
void startBackgroundSync() {
final w = (wallet as MoneroWallet);
w.startBackgroundSync();
}
@action
Future<void> stopBackgroundSync() async {
final w = (wallet as MoneroWallet);
final keyService = getIt.get<KeyService>();
await w.stopBackgroundSync(await keyService.getWalletPassword(walletName: wallet.name));
}
}

View file

@ -1,4 +1,5 @@
import 'dart:io';
import 'package:cake_wallet/core/backup_service_v3.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:flutter/material.dart';
@ -20,7 +21,7 @@ abstract class RestoreFromBackupViewModelBase with Store {
: state = InitialExecutionState(),
filePath = '';
final BackupService backupService;
final BackupServiceV3 backupService;
@observable
String filePath;
@ -42,10 +43,9 @@ abstract class RestoreFromBackupViewModelBase with Store {
}
final file = File(filePath);
final data = await file.readAsBytes();
await backupService.importBackup(data, password);
await backupService.importBackupFile(file, password);
try {
await initializeAppAtRoot(reInitializing: true);

View file

@ -1,4 +1,4 @@
enum SyncType { disabled, unobtrusive, aggressive }
enum SyncType { aggresive, hourly, daily }
class SyncMode {
SyncMode(this.name, this.type, this.frequency);
@ -8,8 +8,10 @@ class SyncMode {
final Duration frequency;
static final all = [
SyncMode("Disabled", SyncType.disabled, Duration.zero),
SyncMode("Unobtrusive", SyncType.unobtrusive, Duration(hours: 12)),
SyncMode("Aggressive", SyncType.aggressive, Duration(hours: 3)),
// **Technically** we could call aggressive option "15 minutes" but OS may "not feel like it",
// so instead we will call it aggressive so user knows that it will be as frequent as possible.
SyncMode("Aggressive", SyncType.aggresive, Duration(minutes: 15)),
SyncMode("Hourly", SyncType.hourly, Duration(hours: 1)),
SyncMode("Daily", SyncType.daily, Duration(hours: 18)), // yes this is straight up lie.
];
}

View file

@ -2,7 +2,6 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/core/wallet_creation_service.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/generate_name.dart';
import 'package:cake_wallet/entities/hash_wallet_identifier.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -113,7 +112,6 @@ abstract class WalletCreationVMBase with Store {
walletInfo.address = wallet.walletAddresses.address;
await _walletInfoSource.add(walletInfo);
await _appStore.changeCurrentWallet(wallet);
getIt.get<BackgroundTasks>().registerSyncTask();
_appStore.authenticationStore.allowedCreate();
state = ExecutedSuccessfullyState();
} catch (e, s) {

View file

@ -158,6 +158,7 @@ abstract class WalletGroupsDisplayViewModelBase with Store {
isCurrent: info.name == _appStore.wallet?.name && info.type == _appStore.wallet?.type,
isEnabled: availableWalletTypes.contains(info.type),
isTestnet: info.network?.toLowerCase().contains('testnet') ?? false,
isHardware: info.isHardwareWallet,
);
}
}

View file

@ -5,6 +5,7 @@ class WalletListItem {
required this.name,
required this.type,
required this.key,
required this.isHardware,
this.isCurrent = false,
this.isEnabled = true,
this.isTestnet = false,
@ -16,4 +17,5 @@ class WalletListItem {
final dynamic key;
final bool isEnabled;
final bool isTestnet;
final bool isHardware;
}

View file

@ -265,6 +265,7 @@ abstract class WalletListViewModelBase with Store {
info.type == _appStore.wallet?.type,
isEnabled: availableWalletTypes.contains(info.type),
isTestnet: info.network?.toLowerCase().contains('testnet') ?? false,
isHardware: info.isHardwareWallet,
);
}
}

View file

@ -45,7 +45,7 @@ dependencies:
url: https://github.com/MrCyjaneK/uni_links
ref: 8e9efa4d9beb19e4ac44009576337f1ce51c22e2
path: uni_links
lottie: ^1.3.0
lottie: ^3.3.1
animate_do: ^2.1.0
cupertino_icons: ^1.0.5
encrypt: 5.0.2
@ -57,23 +57,22 @@ dependencies:
connectivity_plus: ^5.0.2
keyboard_actions: ^4.0.1
another_flushbar: ^1.12.29
archive: ^3.3.0
archive: ^4.0.3
cryptography: ^2.0.5
file_picker:
git:
url: https://github.com/cake-tech/flutter_file_picker.git
ref: master
permission_handler: ^10.0.0
ref: c414574bc5ac349450f601e7f72c7b9f31b4d087
permission_handler: 11.4.0
device_display_brightness:
git:
url: https://github.com/MrCyjaneK/device_display_brightness.git
ref: 4cac18c446ce686f3d75b1565badbd7da439bbd9
workmanager: ^0.5.2
wakelock_plus: ^1.2.5
flutter_mailer:
git:
url: https://github.com/taljacobson/flutter_mailer
ref: 2a7d04d61f56e1ca166ab42e91e0daf1bfddfaf2
ref: 9c4ed111a9151a2bbfb9afe2c18a37599c6f84f3
device_info_plus: ^9.1.0
base32: 2.1.3
in_app_review: ^2.0.6
@ -97,7 +96,7 @@ dependencies:
git:
url: https://github.com/cake-tech/ens_dart.git
ref: main
fluttertoast: 8.2.8
fluttertoast: 8.2.12
# tor:
# git:
# url: https://github.com/cake-tech/tor.git
@ -119,6 +118,10 @@ dependencies:
git:
url: https://github.com/cake-tech/blockchain_utils
ref: cake-update-v4
flutter_daemon:
git:
url: https://github.com/MrCyjaneK/flutter_daemon
ref: 5c369e0e69e6f459357b9802bc694a221397298a
dev_dependencies:
flutter_test:
@ -139,7 +142,6 @@ dev_dependencies:
git:
url: https://github.com/cake-tech/google-translator.git
version: 1.0.0
archive: ^3.6.1
dependency_overrides:
bech32:

View file

@ -69,6 +69,7 @@
"avg_savings": "متوسط مدخرات",
"awaitDAppProcessing": ".ﺔﺠﻟﺎﻌﻤﻟﺍ ﻦﻣ dApp ﻲﻬﺘﻨﻳ ﻰﺘﺣ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ",
"awaiting_payment_confirmation": "في انتظار تأكيد الدفع",
"background_sync": "مزامنة الخلفية",
"background_sync_mode": "وضع مزامنة الخلفية",
"backup": "نسخ الاحتياطي",
"backup_file": "ملف النسخ الاحتياطي",
@ -161,6 +162,7 @@
"confirm_passphrase": "تأكيد عبارة المرور",
"confirm_sending": "تأكيد الإرسال",
"confirm_silent_payments_switch_node": "العقدة الحالية لا تدعم المدفوعات الصامتة \\ ncake wallet سوف تتحول إلى عقدة متوافقة ، فقط للمسح الضوئي",
"confirm_transaction": "تأكيد المعاملة",
"confirmations": "التأكيدات",
"confirmed": "رصيد مؤكد",
"confirmed_tx": "مؤكد",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
"generate_name": "توليد الاسم",
"generating_gift_card": "يتم توليد بطاقة هدية",
"generating_transaction": "توليد معاملة",
"get_a": "احصل على",
"get_card_note": " يمكنك إعادة تحميلها بالعملات الرقمية. لا توجد معلومات إضافية مطلوبة!",
"get_your_yat": "احصل على Yat",
@ -928,6 +931,8 @@
"understand": "لقد فهمت",
"unlock": "الغاء القفل",
"unmatched_currencies": "عملة محفظتك الحالية لا تتطابق مع عملة QR الممسوحة ضوئيًا",
"unrestricted_background_service": "خدمة خلفية غير مقيدة",
"unrestricted_background_service_notice": "من أجل تمكين مزامنة الخلفية ، تحتاج إلى تمكين خدمة الخلفية غير المقيدة",
"unspent_change": "يتغير",
"unspent_coins_details_title": "تفاصيل العملات الغير المنفقة",
"unspent_coins_title": "العملات الغير المنفقة",

View file

@ -69,6 +69,7 @@
"avg_savings": "Средни спестявания",
"awaitDAppProcessing": "Моля, изчакайте dApp да завърши обработката.",
"awaiting_payment_confirmation": "Чака се потвърждение на плащането",
"background_sync": "Фон Синхх",
"background_sync_mode": "Режим на синхронизиране на фона",
"backup": "Резервно копие",
"backup_file": "Резервно копие",
@ -161,6 +162,7 @@
"confirm_passphrase": "Потвърдете парола",
"confirm_sending": "Потвърждаване на изпращането",
"confirm_silent_payments_switch_node": "Текущият ви възел не поддържа Silent Payments \\ Ncake Wallet ще премине към съвместим възел, само за сканиране",
"confirm_transaction": "Потвърдете транзакцията",
"confirmations": "потвърждения",
"confirmed": "Потвърден баланс",
"confirmed_tx": "Потвърдено",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
"generate_name": "Генериране на име",
"generating_gift_card": "Създаване на Gift Card",
"generating_transaction": "Генериране на транзакция",
"get_a": "Вземете ",
"get_card_note": ", която можете да заредите с дигитална валута. Без нужда от допълнителна информация!",
"get_your_yat": "Получете своя Yat",
@ -928,6 +931,8 @@
"understand": "Разбирам",
"unlock": "Отключване",
"unmatched_currencies": "Валутата на този портфейл не съвпада с тази от сканирания QR код",
"unrestricted_background_service": "Неограничена фонова услуга",
"unrestricted_background_service_notice": "За да активирате синхронизирането на фона, трябва да активирате неограничена фонова услуга",
"unspent_change": "Промяна",
"unspent_coins_details_title": "Подробности за неизползваните монети",
"unspent_coins_title": "Неизползвани монети",

View file

@ -69,6 +69,7 @@
"avg_savings": "Prům. ušetřeno",
"awaitDAppProcessing": "Počkejte, až dApp dokončí zpracování.",
"awaiting_payment_confirmation": "Čeká se na potvrzení platby",
"background_sync": "Synchronizace pozadí",
"background_sync_mode": "Režim synchronizace pozadí",
"backup": "Záloha",
"backup_file": "Soubor se zálohou",
@ -161,6 +162,7 @@
"confirm_passphrase": "Potvrďte přístupovou frázi",
"confirm_sending": "Potvrdit odeslání",
"confirm_silent_payments_switch_node": "Váš aktuální uzel nepodporuje tiché platby \\ Ncake peněženka se přepne na kompatibilní uzel, pouze pro skenování",
"confirm_transaction": "Potvrďte transakci",
"confirmations": "Potvrzení",
"confirmed": "Potvrzený zůstatek",
"confirmed_tx": "Potvrzeno",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
"generate_name": "Generovat jméno",
"generating_gift_card": "Generuji dárkovou kartu",
"generating_transaction": "Generování transakce",
"get_a": "Získejte ",
"get_card_note": " které můžete nabít digitální měnou. Žádné další informace nejsou vyžadovány!",
"get_your_yat": "Získat Yat",
@ -928,6 +931,8 @@
"understand": "Rozumím",
"unlock": "Odemknout",
"unmatched_currencies": "Měna vaší současné peněženky neodpovídá té v naskenovaném QR kódu",
"unrestricted_background_service": "Neomezená služba na pozadí",
"unrestricted_background_service_notice": "Chcete -li povolit synchronizaci pozadí, musíte povolit neomezenou službu na pozadí",
"unspent_change": "Změna",
"unspent_coins_details_title": "Podrobnosti o neutracených mincích",
"unspent_coins_title": "Neutracené mince",

View file

@ -69,6 +69,7 @@
"avg_savings": "Durchschn. Einsparungen",
"awaitDAppProcessing": "Bitte warten Sie, bis die dApp die Verarbeitung abgeschlossen hat.",
"awaiting_payment_confirmation": "Warten auf Zahlungsbestätigung",
"background_sync": "Hintergrundsynchronisation",
"background_sync_mode": "Hintergrundsynchronisierungsmodus",
"backup": "Sicherung",
"backup_file": "Sicherungsdatei",
@ -161,6 +162,7 @@
"confirm_passphrase": "Passphrase bestätigen",
"confirm_sending": "Senden bestätigen",
"confirm_silent_payments_switch_node": "Ihr aktueller Knoten unterstützt keine Silent Payments.\\n\\nCake Wallet wechselt zu einem kompatiblen Knoten, nur zum Scannen",
"confirm_transaction": "Transaktion bestätigen",
"confirmations": "Bestätigungen",
"confirmed": "Bestätigter Saldo",
"confirmed_tx": "Bestätigt",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
"generate_name": "Namen generieren",
"generating_gift_card": "Geschenkkarte wird erstellt",
"generating_transaction": "Transaktion erzeugen",
"get_a": "Hole ein",
"get_card_note": " die Sie mit digitaler Währung aufladen können. Keine zusätzlichen Informationen erforderlich!",
"get_your_yat": "Holen Sie sich Ihre Yat",
@ -528,8 +531,8 @@
"please_choose_one": "Bitte wählen Sie einen",
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
"Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.",
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
"please_select": "Bitte auswählen:",
"please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.",
"please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
@ -930,6 +933,8 @@
"understand": "Ich verstehe",
"unlock": "Freischalten",
"unmatched_currencies": "Die Währung Ihres aktuellen Wallets stimmt nicht mit der des gescannten QR überein",
"unrestricted_background_service": "Uneingeschränkter Hintergrunddienst",
"unrestricted_background_service_notice": "Um die Hintergrundsynchronisierung zu ermöglichen, müssen Sie einen uneingeschränkten Hintergrundservice aktivieren",
"unspent_change": "Wechselgeld",
"unspent_coins_details_title": "Details zu nicht ausgegebenen Coins",
"unspent_coins_title": "Nicht ausgegebene Coins",

View file

@ -69,6 +69,7 @@
"avg_savings": "Avg. Savings",
"awaitDAppProcessing": "Kindly wait for the dApp to finish processing.",
"awaiting_payment_confirmation": "Awaiting Payment Confirmation",
"background_sync": "Background sync",
"background_sync_mode": "Background sync mode",
"backup": "Backup",
"backup_file": "Backup file",
@ -161,6 +162,7 @@
"confirm_passphrase": "Confirm passphrase",
"confirm_sending": "Confirm sending",
"confirm_silent_payments_switch_node": "Your current node does not support Silent Payments.\\n\\nCake Wallet will switch to a compatible node while scanning.",
"confirm_transaction": "Confirm transaction",
"confirmations": "Confirmations",
"confirmed": "Confirmed Balance",
"confirmed_tx": "Confirmed",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
"generate_name": "Generate Name",
"generating_gift_card": "Generating Gift Card",
"generating_transaction": "Generating transaction",
"get_a": "Get a ",
"get_card_note": " that you can reload with digital currencies. No additional information needed!",
"get_your_yat": "Get your Yat",
@ -929,6 +932,8 @@
"understand": "I understand",
"unlock": "Unlock",
"unmatched_currencies": "Your current wallet's currency does not match that of the scanned QR",
"unrestricted_background_service": "Unrestricted background service",
"unrestricted_background_service_notice": "In order to enable background sync you need to enable unrestricted background service",
"unspent_change": "Change",
"unspent_coins_details_title": "Unspent coins details",
"unspent_coins_title": "Unspent coins",

View file

@ -69,6 +69,7 @@
"avg_savings": "Ahorro promedio",
"awaitDAppProcessing": "Espere a que la dApp termine de procesarse.",
"awaiting_payment_confirmation": "Esperando confirmación de pago",
"background_sync": "Sincronización de fondo",
"background_sync_mode": "Modo de sincronización en segundo plano",
"backup": "Apoyo",
"backup_file": "Archivo de respaldo",
@ -161,6 +162,7 @@
"confirm_passphrase": "Confirmar la contraseña",
"confirm_sending": "Confirmar envío",
"confirm_silent_payments_switch_node": "Tu nodo actual no admite pagos silenciosos \\ nCake cambiará a un nodo compatible, solo para escanear",
"confirm_transaction": "Confirmar transacción",
"confirmations": "Confirmaciones",
"confirmed": "Saldo confirmado",
"confirmed_tx": "Confirmado",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
"generate_name": "Generar nombre",
"generating_gift_card": "Generando tarjeta de regalo",
"generating_transaction": "Generación de transacciones",
"get_a": "Obtener un",
"get_card_note": " que puedes recargar con monedas digitales. ¡No se necesita información adicional!",
"get_your_yat": "Obtén tu Yat",
@ -929,6 +932,8 @@
"understand": "Entiendo",
"unlock": "desbloquear",
"unmatched_currencies": "La moneda de tu billetera actual no coincide con la del QR escaneado",
"unrestricted_background_service": "Servicio de antecedentes sin restricciones",
"unrestricted_background_service_notice": "Para habilitar la sincronización de antecedentes, debe habilitar el servicio de fondo sin restricciones",
"unspent_change": "Cambiar",
"unspent_coins_details_title": "Detalles de monedas no gastadas",
"unspent_coins_title": "Monedas no gastadas",

View file

@ -69,6 +69,7 @@
"avg_savings": "Économies moy.",
"awaitDAppProcessing": "Veuillez attendre que l'application décentralisée (dApp) termine le traitement.",
"awaiting_payment_confirmation": "En attente de confirmation de paiement",
"background_sync": "Synchronisation de fond",
"background_sync_mode": "Mode de synchronisation en arrière-plan",
"backup": "Sauvegarde",
"backup_file": "Fichier de sauvegarde",
@ -161,6 +162,7 @@
"confirm_passphrase": "Confirmer la phrase passante",
"confirm_sending": "Confirmer l'envoi",
"confirm_silent_payments_switch_node": "Votre nœud actuel ne prend pas en charge les paiements silencieux.\n\nCake Wallet passera à un nœud compatible pendant l'analyse.",
"confirm_transaction": "Confirmer la transaction",
"confirmations": "Confirmations",
"confirmed": "Solde confirmé",
"confirmed_tx": "Confirmé",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
"generate_name": "Générer un nom",
"generating_gift_card": "Génération d'une carte-cadeau",
"generating_transaction": "Transaction de génération",
"get_a": "Obtenir un ",
"get_card_note": " que vous pouvez recharger avec des devises numériques. Aucune information supplémentaire n'est nécessaire !",
"get_your_yat": "Obtenir votre Yat",
@ -928,6 +931,8 @@
"understand": "J'ai compris",
"unlock": "Ouvrir",
"unmatched_currencies": "La devise de votre portefeuille (wallet) actuel ne correspond pas à celle du QR code scanné",
"unrestricted_background_service": "Service de fond sans restriction",
"unrestricted_background_service_notice": "Afin d'activer la synchronisation des antécédents, vous devez activer le service de fond sans restriction",
"unspent_change": "Monnaie",
"unspent_coins_details_title": "Détails des pièces (coins) non dépensées",
"unspent_coins_title": "Pièces (coins) non dépensées",

View file

@ -69,6 +69,7 @@
"avg_savings": "Matsakaici Adana",
"awaitDAppProcessing": "Da fatan za a jira dApp ya gama aiki.",
"awaiting_payment_confirmation": "Ana jiran Tabbacin Biyan Kuɗi",
"background_sync": "Tunawa da Setc",
"background_sync_mode": "Yanayin Sync",
"backup": "Ajiyayyen",
"backup_file": "Ajiyayyen fayil",
@ -161,6 +162,7 @@
"confirm_passphrase": "Tabbatar da kalmar wucewa",
"confirm_sending": "Tabbatar da aikawa",
"confirm_silent_payments_switch_node": "Kumburinku na yanzu ba ya goyan bayan biyan shiru da shiru \\ NCADA Wallet zai canza zuwa kumburi mai dacewa, don bincika",
"confirm_transaction": "Tabbatar da ma'amala",
"confirmations": "Tabbatar",
"confirmed": "An tabbatar",
"confirmed_tx": "Tabbatar",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
"generate_name": "Ƙirƙirar Suna",
"generating_gift_card": "Samar da Katin Kyauta",
"generating_transaction": "Ma'amala samar da ma'amala",
"get_a": "Samu a",
"get_card_note": "cewa zaku iya sake lodawa tare da kudaden dijital. Babu ƙarin bayani da ake buƙata!",
"get_your_yat": "Samun Yat ka",
@ -930,6 +933,8 @@
"understand": "na gane",
"unlock": "Buɗe",
"unmatched_currencies": "Nau'in walat ɗin ku na yanzu bai dace da na lambar QR da aka bincika ba",
"unrestricted_background_service": "Sabis na baya",
"unrestricted_background_service_notice": "Don ba da damar Sync na asali kuna buƙatar kunna sabis na baya da ba a santa ba",
"unspent_change": "Canza",
"unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba",
"unspent_coins_title": "Tsabar da ba a kashe ba",

View file

@ -69,6 +69,7 @@
"avg_savings": "औसत बचत",
"awaitDAppProcessing": "कृपया डीएपी की प्रोसेसिंग पूरी होने तक प्रतीक्षा करें।",
"awaiting_payment_confirmation": "भुगतान की पुष्टि की प्रतीक्षा में",
"background_sync": "पृष्ठभूमि सिंक",
"background_sync_mode": "बैकग्राउंड सिंक मोड",
"backup": "बैकअप",
"backup_file": "बैकअपफ़ाइल",
@ -161,6 +162,7 @@
"confirm_passphrase": "पासफ़्रेज़ की पुष्टि करें",
"confirm_sending": "भेजने की पुष्टि करें",
"confirm_silent_payments_switch_node": "आपका वर्तमान नोड मूक भुगतान का समर्थन नहीं करता है \\ ncake वॉलेट एक संगत नोड पर स्विच करेगा, बस स्कैनिंग के लिए",
"confirm_transaction": "लेनदेन की पुष्टि करें",
"confirmations": "पुष्टिकरण",
"confirmed": "पुष्टि की गई शेष राशिी",
"confirmed_tx": "की पुष्टि",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
"generate_name": "नाम जनरेट करें",
"generating_gift_card": "गिफ्ट कार्ड जनरेट कर रहा है",
"generating_transaction": "सृजन लेन -देन",
"get_a": "एक प्राप्त करें",
"get_card_note": " कि आप डिजिटल मुद्राओं के साथ पुनः लोड कर सकते हैं। कोई अतिरिक्त जानकारी की आवश्यकता नहीं है!",
"get_your_yat": "अपना प्राप्त करें Yat",
@ -517,8 +520,8 @@
"paste": "पेस्ट करें",
"pause_wallet_creation": "हेवन वॉलेट बनाने की क्षमता फिलहाल रुकी हुई है।",
"payment_id": "भुगतान ID: ",
"Payment_was_received": "आपका भुगतान प्राप्त हो गया था।",
"payment_was_received": "आपका भुगतान प्राप्त हुआ था।",
"Payment_was_received": "आपका भुगतान प्राप्त हो गया था।",
"pending": " (अपूर्ण)",
"percentageOf": "${amount} का",
"pin_at_top": "शीर्ष पर ${token} पिन करें",
@ -930,6 +933,8 @@
"understand": "मुझे समझ",
"unlock": "अनलॉक",
"unmatched_currencies": "आपके वर्तमान वॉलेट की मुद्रा स्कैन किए गए क्यूआर से मेल नहीं खाती",
"unrestricted_background_service": "अप्रतिबंधित पृष्ठभूमि सेवा",
"unrestricted_background_service_notice": "पृष्ठभूमि सिंक को सक्षम करने के लिए आपको अप्रतिबंधित पृष्ठभूमि सेवा को सक्षम करने की आवश्यकता है",
"unspent_change": "परिवर्तन",
"unspent_coins_details_title": "अव्ययित सिक्कों का विवरण",
"unspent_coins_title": "खर्च न किए गए सिक्के",

View file

@ -69,6 +69,7 @@
"avg_savings": "Prosj. ušteda",
"awaitDAppProcessing": "Molimo pričekajte da dApp završi obradu.",
"awaiting_payment_confirmation": "Čeka se potvrda plaćanja",
"background_sync": "Sinkronizacija pozadine",
"background_sync_mode": "Sinkronizacija u pozadini",
"backup": "Sigurnosna kopija",
"backup_file": "Sigurnosna kopija datoteke",
@ -161,6 +162,7 @@
"confirm_passphrase": "Potvrdite prolaznu frazu",
"confirm_sending": "Potvrdi slanje",
"confirm_silent_payments_switch_node": "Vaš trenutni čvor ne podržava tiha plaćanja \\ ncake novčanik prebacit će se na kompatibilni čvor, samo za skeniranje",
"confirm_transaction": "Potvrdite transakciju",
"confirmations": "Potvrde",
"confirmed": "Potvrđeno stanje",
"confirmed_tx": "Potvrđen",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
"generate_name": "Generiraj ime",
"generating_gift_card": "Generiranje darovne kartice",
"generating_transaction": "Generiranje transakcije",
"get_a": "Nabavite ",
"get_card_note": " koju možete ponovno napuniti digitalnim valutama. Nisu potrebne dodatne informacije!",
"get_your_yat": "Uzmi svoj Yat",
@ -928,6 +931,8 @@
"understand": "Razumijem",
"unlock": "Otključati",
"unmatched_currencies": "Valuta vašeg trenutnog novčanika ne odgovara onoj na skeniranom QR-u",
"unrestricted_background_service": "Neograničena pozadinska usluga",
"unrestricted_background_service_notice": "Da biste omogućili sinkronizaciju pozadine, morate omogućiti neograničenu pozadinsku uslugu",
"unspent_change": "Promijeniti",
"unspent_coins_details_title": "Nepotrošeni detalji o novčićima",
"unspent_coins_title": "Nepotrošeni novčići",

View file

@ -69,6 +69,7 @@
"avg_savings": "Միջին խնայողություն",
"awaitDAppProcessing": "Խնդրեմ սպասեք, մինչև դիմումը կավարտի մշակումը։",
"awaiting_payment_confirmation": "Վճարման հաստատման սպասում",
"background_sync": "Ֆոնային համաժամեցում",
"background_sync_mode": "Հետին պլանի համաժամացման ռեժիմ",
"backup": "Կրկնօրինակ",
"backup_file": "Կրկնօրինակի ֆայլ",
@ -161,6 +162,7 @@
"confirm_passphrase": "Հաստատեք գաղտնաբառը",
"confirm_sending": "Հաստատեք ուղարկումը",
"confirm_silent_payments_switch_node": "Ձեր ընթացիկ հանգույցը չի աջակցում Լուռ վճարումներին\nCake Wallet-ը կանցնի համատեղելի հանգույց, միայն սկանավորման համար",
"confirm_transaction": "Հաստատեք գործարքը",
"confirmations": "Հաստատումներ",
"confirmed": "Հաստատված մնացորդ",
"confirmed_tx": "Հաստատված",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
"generate_name": "Գեներացնել անուն",
"generating_gift_card": "Գեներացնում է նվեր քարտ",
"generating_transaction": "Ստեղծող գործարք",
"get_a": "Ստանալ ",
"get_card_note": " որը կարող եք լրացնել թվային արժույթներով: Հավելյալ տեղեկատվություն պետք չէ!",
"get_your_yat": "Ստանալ ձեր Yat",
@ -926,6 +929,8 @@
"understand": "Ես հասկանում եմ",
"unlock": "Բացել",
"unmatched_currencies": "Ձեր ընթացիկ դրամապանակի արժույթը չի համապատասխանում սկանավորված QR կոդի արժույթին",
"unrestricted_background_service": "Անսահմանափակ ֆոնային ծառայություն",
"unrestricted_background_service_notice": "Ֆոնային համաժամացման համար անհրաժեշտ է միացնել անսահմանափակ ֆոնային ծառայություն",
"unspent_change": "Մնացորդ",
"unspent_coins_details_title": "Չծախսված արժույթների մանրամասները",
"unspent_coins_title": "Չծախսված արժույթներ",

View file

@ -69,6 +69,7 @@
"avg_savings": "Rata-rata Pembayaran",
"awaitDAppProcessing": "Mohon tunggu hingga dApp menyelesaikan pemrosesan.",
"awaiting_payment_confirmation": "Menunggu Konfirmasi Pembayaran",
"background_sync": "Sinkronisasi Latar Belakang",
"background_sync_mode": "Mode Sinkronisasi Latar Belakang",
"backup": "Cadangan",
"backup_file": "File cadangan",
@ -161,6 +162,7 @@
"confirm_passphrase": "Konfirmasi frasa sandi",
"confirm_sending": "Konfirmasi pengiriman",
"confirm_silent_payments_switch_node": "Node Anda saat ini tidak mendukung pembayaran diam \\ ncake Wallet akan beralih ke simpul yang kompatibel, hanya untuk pemindaian",
"confirm_transaction": "Konfirmasi transaksi",
"confirmations": "Konfirmasi",
"confirmed": "Saldo Terkonfirmasi",
"confirmed_tx": "Dikonfirmasi",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
"generate_name": "Hasilkan Nama",
"generating_gift_card": "Membuat Kartu Hadiah",
"generating_transaction": "Menghasilkan transaksi",
"get_a": "Dapatkan ",
"get_card_note": " yang dapat Anda muat ulang dengan mata uang digital. Tidak perlu informasi tambahan!",
"get_your_yat": "Dapatkan Yat Anda",
@ -931,6 +934,8 @@
"understand": "Saya mengerti",
"unlock": "Membuka kunci",
"unmatched_currencies": "Mata uang dompet Anda saat ini tidak cocok dengan yang ditandai QR",
"unrestricted_background_service": "Layanan latar belakang tidak terbatas",
"unrestricted_background_service_notice": "Untuk mengaktifkan sinkronisasi latar belakang, Anda perlu mengaktifkan layanan latar belakang yang tidak dibatasi",
"unspent_change": "Mengubah",
"unspent_coins_details_title": "Rincian koin yang tidak terpakai",
"unspent_coins_title": "Koin yang tidak terpakai",

View file

@ -69,6 +69,7 @@
"avg_savings": "Risparmio medio",
"awaitDAppProcessing": "Attendi gentilmente che la dApp termini l'elaborazione.",
"awaiting_payment_confirmation": "In attesa di conferma del pagamento",
"background_sync": "Sincronizzazione in background",
"background_sync_mode": "Modalità di sincronizzazione in background",
"backup": "Backup",
"backup_file": "Backup file",
@ -161,6 +162,7 @@
"confirm_passphrase": "Conferma passphrase",
"confirm_sending": "Conferma l'invio",
"confirm_silent_payments_switch_node": "Il tuo nodo corrente non supporta Silent Payments\\n\\nCake Wallet passerà a un nodo compatibile durante la scansione.",
"confirm_transaction": "Conferma la transazione",
"confirmations": "Conferme",
"confirmed": "Saldo Confermato",
"confirmed_tx": "Confermato",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Il Gas richiesto dalla transazione supera il limite consentito.",
"generate_name": "Genera nome",
"generating_gift_card": "Generazione carta regalo",
"generating_transaction": "Generazione di transazione",
"get_a": "Prendi un ",
"get_card_note": "che puoi ricaricare con le valute digitali. Non sono necessarie informazioni aggiuntive!",
"get_your_yat": "Ottieni il tuo Yat",
@ -928,6 +931,8 @@
"understand": "Capisco",
"unlock": "Sblocca",
"unmatched_currencies": "La valuta del tuo portafoglio attuale non corrisponde a quella del QR scansionato",
"unrestricted_background_service": "Servizio di background senza restrizioni",
"unrestricted_background_service_notice": "Per abilitare la sincronizzazione in background è necessario abilitare il servizio di background senza restrizioni",
"unspent_change": "Resto",
"unspent_coins_details_title": "Dettagli sulle monete non spese",
"unspent_coins_title": "Monete non spese",

View file

@ -69,6 +69,7 @@
"avg_savings": "平均節約額",
"awaitDAppProcessing": "dAppの処理が完了するまでお待ちください。",
"awaiting_payment_confirmation": "支払い確認を待っています",
"background_sync": "背景同期",
"background_sync_mode": "バックグラウンド同期モード",
"backup": "バックアップ",
"backup_file": "バックアップファイル",
@ -161,6 +162,7 @@
"confirm_passphrase": "パスフレーズを確認します",
"confirm_sending": "送信を確認",
"confirm_silent_payments_switch_node": "現在のノードはサイレントペイメントをサポートしていません\\ ncakeウォレットは、スキャン用に互換性のあるードに切り替えます",
"confirm_transaction": "トランザクションを確認します",
"confirmations": "確認",
"confirmed": "確認済み残高",
"confirmed_tx": "確認済み",
@ -345,6 +347,7 @@
"generate_name": "名前の生成",
"generated_gift_card": "ギフトカードの生成",
"generating_gift_card": "ギフトカードの生成",
"generating_transaction": "トランザクションの生成",
"get_a": "Get a",
"get_card_note": "デジタル通貨でリロードできます。追加情報は必要ありません!",
"get_your_yat": "あなたのYatを入手してください",
@ -929,6 +932,8 @@
"understand": "わかります",
"unlock": "ロックを解除します",
"unmatched_currencies": "現在のウォレットの通貨がスキャンされたQRの通貨と一致しません",
"unrestricted_background_service": "無制限のバックグラウンドサービス",
"unrestricted_background_service_notice": "バックグラウンドの同期を有​​効にするには、無制限のバックグラウンドサービスを有効にする必要があります",
"unspent_change": "変化",
"unspent_coins_details_title": "未使用のコインの詳細",
"unspent_coins_title": "未使用のコイン",

View file

@ -69,6 +69,7 @@
"avg_savings": "평균 절감액",
"awaitDAppProcessing": "dApp이 처리를 마칠 때까지 기다려주세요.",
"awaiting_payment_confirmation": "결제 확인 대기 중",
"background_sync": "배경 동기화",
"background_sync_mode": "백그라운드 동기화 모드",
"backup": "지원",
"backup_file": "백업 파일",
@ -161,6 +162,7 @@
"confirm_passphrase": "암호를 확인하십시오",
"confirm_sending": "전송 확인",
"confirm_silent_payments_switch_node": "현재 노드는 무음 지불을 지원하지 않습니다 \\ ncake 지갑은 스캔을 위해 호환 가능한 노드로 전환됩니다.",
"confirm_transaction": "거래 확인",
"confirmations": "확인",
"confirmed": "확인된 잔액",
"confirmed_tx": "확인",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
"generate_name": "이름 생성",
"generating_gift_card": "기프트 카드 생성 중",
"generating_transaction": "거래 생성",
"get_a": "가져오기",
"get_card_note": " 디지털 통화로 충전할 수 있습니다. 추가 정보가 필요하지 않습니다!",
"get_your_yat": "당신의 Yat를 얻으십시오",
@ -928,6 +931,8 @@
"understand": "이해 했어요",
"unlock": "터놓다",
"unmatched_currencies": "현재 지갑의 통화가 스캔한 QR의 통화와 일치하지 않습니다.",
"unrestricted_background_service": "무제한 배경 서비스",
"unrestricted_background_service_notice": "배경 동기화를 활성화하려면 무제한 배경 서비스를 활성화해야합니다.",
"unspent_change": "변화",
"unspent_coins_details_title": "사용하지 않은 동전 세부 정보",
"unspent_coins_title": "사용하지 않은 동전",

View file

@ -69,6 +69,7 @@
"avg_savings": "ပျမ်းမျှ စုဆောင်းငွေ",
"awaitDAppProcessing": "ကျေးဇူးပြု၍ dApp ကို စီမံလုပ်ဆောင်ခြင်း အပြီးသတ်ရန် စောင့်ပါ။",
"awaiting_payment_confirmation": "ငွေပေးချေမှု အတည်ပြုချက်ကို စောင့်မျှော်နေပါသည်။",
"background_sync": "နောက်ခံထပ်တူပြုခြင်း",
"background_sync_mode": "နောက်ခံထပ်တူပြုခြင်း mode ကို",
"backup": "မိတ္တူ",
"backup_file": "အရန်ဖိုင်",
@ -161,6 +162,7 @@
"confirm_passphrase": "passphrase အတည်ပြုပါ",
"confirm_sending": "ပေးပို့အတည်ပြုပါ။",
"confirm_silent_payments_switch_node": "သင်၏လက်ရှိ node သည်အသံတိတ်ငွေပေးချေမှုကိုမပံ့ပိုးပါဟု \\ t",
"confirm_transaction": "ငွေပေးငွေယူအတည်ပြုပါ",
"confirmations": "အတည်ပြုချက်များ",
"confirmed": "အတည်ပြုထားသော လက်ကျန်ငွေ",
"confirmed_tx": "အတည်ပြုသည်",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
"generate_name": "အမည်ဖန်တီးပါ။",
"generating_gift_card": "လက်ဆောင်ကတ်ထုတ်ပေးခြင်း။",
"generating_transaction": "ငွေပေးငွေယူကိုထုတ်လုပ်",
"get_a": "တစ်ခုရယူပါ။",
"get_card_note": " ဒစ်ဂျစ်တယ်ငွေကြေးများဖြင့် ပြန်လည်စတင်နိုင်သည်။ နောက်ထပ် အချက်အလက် မလိုအပ်ပါ။",
"get_your_yat": "မင်းရဲ့ Yat ကိုယူလိုက်ပါ။",
@ -928,6 +931,8 @@
"understand": "ကျွန်တော်နားလည်ပါတယ်",
"unlock": "သော့ဖွင့်",
"unmatched_currencies": "သင့်လက်ရှိပိုက်ဆံအိတ်၏ငွေကြေးသည် စကင်ဖတ်ထားသော QR နှင့် မကိုက်ညီပါ။",
"unrestricted_background_service": "အကန့်အသတ်မရှိနောက်ခံဝန်ဆောင်မှု",
"unrestricted_background_service_notice": "နောက်ခံထပ်တူပြုခြင်းကို Enable လုပ်ရန်သင်ကန့်သတ်ထားသောနောက်ခံဝန်ဆောင်မှုကိုဖွင့်ရန်လိုအပ်သည်",
"unspent_change": "ပေြာင်းလဲခြင်း",
"unspent_coins_details_title": "အသုံးမဝင်သော အကြွေစေ့အသေးစိတ်များ",
"unspent_coins_title": "အသုံးမဝင်သော အကြွေစေ့များ",

View file

@ -69,6 +69,7 @@
"avg_savings": "Gem. besparingen",
"awaitDAppProcessing": "Wacht tot de dApp klaar is met verwerken.",
"awaiting_payment_confirmation": "In afwachting van betalingsbevestiging",
"background_sync": "Achtergrondsynchronisatie",
"background_sync_mode": "Achtergrondsynchronisatiemodus",
"backup": "Back-up",
"backup_file": "Backup bestand",
@ -161,6 +162,7 @@
"confirm_passphrase": "Bevestig Passaspherase",
"confirm_sending": "Bevestig verzending",
"confirm_silent_payments_switch_node": "Uw huidige knooppunt ondersteunt geen stille betalingen \\ ncake -portemonnee schakelt over naar een compatibele knoop",
"confirm_transaction": "Bevestig transactie",
"confirmations": "Bevestigingen",
"confirmed": "Bevestigd saldo",
"confirmed_tx": "Bevestigd",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
"generate_name": "Naam genereren",
"generating_gift_card": "Cadeaubon genereren",
"generating_transaction": "Transactie genereren",
"get_a": "Krijg een ",
"get_card_note": " die u kunt herladen met digitale valuta. Geen aanvullende informatie nodig!",
"get_your_yat": "Haal je Yato",
@ -928,6 +931,8 @@
"understand": "Ik begrijp het",
"unlock": "Ontgrendelen",
"unmatched_currencies": "De valuta van uw huidige portemonnee komt niet overeen met die van de gescande QR",
"unrestricted_background_service": "Onbeperkte achtergrondservice",
"unrestricted_background_service_notice": "Om achtergrondsynchronisatie in te schakelen, moet u onbeperkte achtergrondservice inschakelen",
"unspent_change": "Wijziging",
"unspent_coins_details_title": "Details van niet-uitgegeven munten",
"unspent_coins_title": "Ongebruikte munten",

View file

@ -69,6 +69,7 @@
"avg_savings": "Śr. oszczędności",
"awaitDAppProcessing": "Poczekaj, aż dApp zakończy przetwarzanie.",
"awaiting_payment_confirmation": "Oczekiwanie na potwierdzenie płatności",
"background_sync": "Synchronizacja tła",
"background_sync_mode": "Tryb synchronizacji w tle",
"backup": "Kopia zapasowa",
"backup_file": "Plik kopii zapasowej",
@ -161,6 +162,7 @@
"confirm_passphrase": "Potwierdź hasło",
"confirm_sending": "Potwierdź wysłanie",
"confirm_silent_payments_switch_node": "Twój obecny węzeł nie obsługuje cichych płatności \\ NCAKE Portfel przełączy się na kompatybilny węzeł, tylko do skanowania",
"confirm_transaction": "Potwierdź transakcję",
"confirmations": "Potwierdzenia",
"confirmed": "Potwierdzone saldo",
"confirmed_tx": "Potwierdzony",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
"generate_name": "Wygeneruj nazwę",
"generating_gift_card": "Generowanie karty podarunkowej",
"generating_transaction": "Generowanie transakcji",
"get_a": "Zdobądź ",
"get_card_note": " które możesz doładować walutami cyfrowymi. Nie są potrzebne żadne dodatkowe informacje!",
"get_your_yat": "Zdobądź swój Yat",
@ -928,6 +931,8 @@
"understand": "Rozumiem",
"unlock": "Odblokować",
"unmatched_currencies": "Waluta Twojego obecnego portfela nie zgadza się z waluctą zeskanowanego kodu QR",
"unrestricted_background_service": "Nieograniczona usługa w tle",
"unrestricted_background_service_notice": "Aby włączyć synchronizację tła, musisz włączyć nieograniczoną usługę w tle",
"unspent_change": "Zmiana",
"unspent_coins_details_title": "Szczegóły niewydanych monet",
"unspent_coins_title": "Niewydane monety",

View file

@ -69,6 +69,7 @@
"avg_savings": "Poupança média",
"awaitDAppProcessing": "Aguarde até que o dApp termine o processamento.",
"awaiting_payment_confirmation": "Aguardando confirmação de pagamento",
"background_sync": "Sincronização de fundo",
"background_sync_mode": "Modo de sincronização em segundo plano",
"backup": "Cópia de segurança",
"backup_file": "Arquivo de backup",
@ -161,6 +162,7 @@
"confirm_passphrase": "Confirme a senha",
"confirm_sending": "Confirmar o envio",
"confirm_silent_payments_switch_node": "Seu nó atual não suporta pagamentos silenciosos \n A Cake Wallet mudará para um nó compatível, apenas para escanear",
"confirm_transaction": "Confirme a transação",
"confirmations": "Confirmações",
"confirmed": "Saldo Confirmado",
"confirmed_tx": "Confirmado",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
"generate_name": "Gerar nome",
"generating_gift_card": "Gerando Cartão Presente",
"generating_transaction": "Gerando transação",
"get_a": "Obter um ",
"get_card_note": " que você pode recarregar com moedas digitais. Nenhuma informação adicional é necessária!",
"get_your_yat": "Pegue seu Yat",
@ -930,6 +933,8 @@
"understand": "Entendo",
"unlock": "Desbloquear",
"unmatched_currencies": "A moeda da sua carteira atual não corresponde à do QR digitalizado",
"unrestricted_background_service": "Serviço de fundo irrestrito",
"unrestricted_background_service_notice": "Para ativar a sincronização de fundo, você precisa ativar o serviço de fundo irrestrito",
"unspent_change": "Troco",
"unspent_coins_details_title": "Detalhes de moedas não gastas",
"unspent_coins_title": "Moedas não gastas",

View file

@ -69,6 +69,7 @@
"avg_savings": "Средняя экономия",
"awaitDAppProcessing": "Пожалуйста, подождите, пока dApp завершит обработку.",
"awaiting_payment_confirmation": "Ожидается подтверждения платежа",
"background_sync": "Фоновая синхронизация",
"background_sync_mode": "Режим фоновой синхронизации",
"backup": "Резервная копия",
"backup_file": "Файл резервной копии",
@ -161,6 +162,7 @@
"confirm_passphrase": "Подтвердите Passfrase",
"confirm_sending": "Подтвердить отправку",
"confirm_silent_payments_switch_node": "Ваш текущий узел не поддерживает Silent Payments \\ ncake Wallet переключится на совместимый узел, только для сканирования",
"confirm_transaction": "Подтвердите транзакцию",
"confirmations": "Подтверждения",
"confirmed": "Подтвержденный баланс",
"confirmed_tx": "Подтвержденный",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
"generate_name": "Создать имя",
"generating_gift_card": "Создание подарочной карты",
"generating_transaction": "Генерирующая транзакция",
"get_a": "Получить ",
"get_card_note": " которую вы можете пополнить цифровой валютой. Дополнительная информация не требуется!",
"get_your_yat": "Получить свой Yat",
@ -929,6 +932,8 @@
"understand": "Понятно",
"unlock": "Разблокировать",
"unmatched_currencies": "Валюта вашего текущего кошелька не соответствует валюте отсканированного QR-кода.",
"unrestricted_background_service": "Неограниченная фоновая служба",
"unrestricted_background_service_notice": "Чтобы включить фона синхронизации, необходимо включить неограниченную фоновую службу",
"unspent_change": "Изменять",
"unspent_coins_details_title": "Сведения о неизрасходованных монетах",
"unspent_coins_title": "Неизрасходованные монеты",

View file

@ -69,6 +69,7 @@
"avg_savings": "ประหยัดเฉลี่ย",
"awaitDAppProcessing": "โปรดรอให้ dApp ประมวลผลเสร็จสิ้น",
"awaiting_payment_confirmation": "รอการยืนยันการชำระเงิน",
"background_sync": "การซิงค์พื้นหลัง",
"background_sync_mode": "โหมดซิงค์พื้นหลัง",
"backup": "สำรองข้อมูล",
"backup_file": "ไฟล์สำรองข้อมูล",
@ -161,6 +162,7 @@
"confirm_passphrase": "ยืนยันวลีรหัสผ่าน",
"confirm_sending": "ยืนยันการส่ง",
"confirm_silent_payments_switch_node": "โหนดปัจจุบันของคุณไม่รองรับการชำระเงินแบบเงียบ \\ ncake กระเป๋าเงินจะเปลี่ยนเป็นโหนดที่เข้ากันได้เพียงเพื่อการสแกน",
"confirm_transaction": "ยืนยันการทำธุรกรรม",
"confirmations": "การยืนยัน",
"confirmed": "ยอดคงเหลือที่ยืนยันแล้ว",
"confirmed_tx": "ซึ่งยืนยันแล้ว",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ",
"generate_name": "สร้างชื่อ",
"generating_gift_card": "กำลังสร้างบัตรของขวัญ",
"generating_transaction": "การสร้างธุรกรรม",
"get_a": "รับ ",
"get_card_note": "ที่คุณสามารถเติมเงินด้วยสกุลเงินดิจิตอล ไม่จำเป็นต้องใส่ข้อมูลเพิ่มเติม!",
"get_your_yat": "รับ Yat ของคุณ",
@ -928,6 +931,8 @@
"understand": "ฉันเข้าใจ",
"unlock": "ปลดล็อค",
"unmatched_currencies": "สกุลเงินของกระเป๋าปัจจุบันของคุณไม่ตรงกับของ QR ที่สแกน",
"unrestricted_background_service": "บริการพื้นหลังที่ไม่ จำกัด",
"unrestricted_background_service_notice": "ในการเปิดใช้งานการซิงค์พื้นหลังคุณต้องเปิดใช้งานบริการพื้นหลังที่ไม่ จำกัด",
"unspent_change": "เปลี่ยน",
"unspent_coins_details_title": "รายละเอียดเหรียญที่ไม่ได้ใช้",
"unspent_coins_title": "เหรียญที่ไม่ได้ใช้",

View file

@ -69,6 +69,7 @@
"avg_savings": "Avg. Matitipid",
"awaitDAppProcessing": "Pakihintay na matapos ang pagproseso ng dApp.",
"awaiting_payment_confirmation": "Nanghihintay ng Kumpirmasyon sa Pagbabayad",
"background_sync": "Pag -sync ng background",
"background_sync_mode": "Background sync mode",
"backup": "Backup",
"backup_file": "Backup na file",
@ -161,6 +162,7 @@
"confirm_passphrase": "Kumpirma ang passphrase",
"confirm_sending": "Kumpirmahin ang pagpapadala",
"confirm_silent_payments_switch_node": "Ang iyong kasalukuyang node ay hindi sumusuporta sa tahimik na pagbabayad \\ nCake Wallet ay lilipat sa isang katugmang node, para lamang sa pag-scan",
"confirm_transaction": "Kumpirmahin ang transaksyon",
"confirmations": "Mga kumpirmasyon",
"confirmed": "Nakumpirma na Balanse",
"confirmed_tx": "Nakumpirma",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.",
"generate_name": "Bumuo ng pangalan",
"generating_gift_card": "Bumubuo ng Gift Card",
"generating_transaction": "Bumubuo ng transaksyon",
"get_a": "Kumuha ng ",
"get_card_note": " na maaari mong i-load gamit ang mga digital na pera. Walang karagdagang impormasyon na kailangan!",
"get_your_yat": "Kunin ang iyong Yat",
@ -928,6 +931,8 @@
"understand": "Naiitindihan ko",
"unlock": "I-unlock",
"unmatched_currencies": "Hindi tumutugma ang pera ng iyong kasalukuyang wallet sa na-scan na QR",
"unrestricted_background_service": "Hindi pinigilan na serbisyo sa background",
"unrestricted_background_service_notice": "Upang paganahin ang pag -sync ng background kailangan mong paganahin ang hindi pinigilan na serbisyo sa background",
"unspent_change": "Sukli",
"unspent_coins_details_title": "Mga detalye ng mga hindi nagastos na barya",
"unspent_coins_title": "Mga hindi nagamit na barya",

View file

@ -69,6 +69,7 @@
"avg_savings": "Ortalama Tasarruf",
"awaitDAppProcessing": "Lütfen dApp'in işlemeyi bitirmesini bekleyin.",
"awaiting_payment_confirmation": "Ödemenin onaylanması bekleniyor",
"background_sync": "Arka plan senkronizasyonu",
"background_sync_mode": "Arka Plan Senkronizasyon Modu",
"backup": "Yedek",
"backup_file": "Yedek dosyası",
@ -161,6 +162,7 @@
"confirm_passphrase": "Parola onaylayın",
"confirm_sending": "Göndermeyi onayla",
"confirm_silent_payments_switch_node": "Mevcut düğümünüz sessiz ödemeleri desteklemiyor \\ nCake cüzdanı, sadece tarama için uyumlu bir düğüme geçecektir",
"confirm_transaction": "İşlemi onaylayın",
"confirmations": "Onay",
"confirmed": "Onaylanmış Bakiye",
"confirmed_tx": "Onaylanmış",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.",
"generate_name": "İsim Oluştur",
"generating_gift_card": "Hediye Kartı Oluşturuluyor",
"generating_transaction": "İşlem Oluşturma",
"get_a": "Bir ",
"get_card_note": " dijital ve fiziksel ön ödemeli banka kartı edinin!",
"get_your_yat": "Yat'ını al",
@ -928,6 +931,8 @@
"understand": "Anladım",
"unlock": "Kilidini aç",
"unmatched_currencies": "Mevcut cüzdanınızın para birimi taranan QR ile eşleşmiyor",
"unrestricted_background_service": "Sınırsız arka plan hizmeti",
"unrestricted_background_service_notice": "Arka plan senkronizasyonunu etkinleştirmek için sınırsız arka plan hizmetini etkinleştirmeniz gerekir",
"unspent_change": "Değiştirmek",
"unspent_coins_details_title": "Harcanmamış koin detayları",
"unspent_coins_title": "Harcanmamış koinler",

View file

@ -69,6 +69,7 @@
"avg_savings": "Середня економія",
"awaitDAppProcessing": "Зачекайте, доки dApp завершить обробку.",
"awaiting_payment_confirmation": "Очікується підтвердження платежу",
"background_sync": "Фонове синхронізація",
"background_sync_mode": "Фоновий режим синхронізації",
"backup": "Резервна копія",
"backup_file": "Файл резервної копії",
@ -161,6 +162,7 @@
"confirm_passphrase": "Підтвердьте пасфрази",
"confirm_sending": "Підтвердити відправлення",
"confirm_silent_payments_switch_node": "Ваш поточний вузол не підтримує мовчазні платежі \\ ncake Wallet перейде на сумісний вузол, лише для сканування",
"confirm_transaction": "Підтвердити транзакцію",
"confirmations": "Підтвердження",
"confirmed": "Підтверджений баланс",
"confirmed_tx": "Підтверджений",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.",
"generate_name": "Згенерувати назву",
"generating_gift_card": "Створення подарункової картки",
"generating_transaction": "Генерування транзакції",
"get_a": "Отримати ",
"get_card_note": " яку можна перезавантажувати цифровими валютами. Додаткова інформація не потрібна!",
"get_your_yat": "Одержати свій Yat",
@ -929,6 +932,8 @@
"understand": "Зрозуміло",
"unlock": "Розблокувати",
"unmatched_currencies": "Валюта вашого гаманця не збігається з валютою сканованого QR-коду",
"unrestricted_background_service": "Необмежена фонова послуга",
"unrestricted_background_service_notice": "Для того, щоб увімкнути фонову синхронізацію, вам потрібно ввімкнути необмежену фонову послугу",
"unspent_change": "Зміна",
"unspent_coins_details_title": "Відомості про невитрачені монети",
"unspent_coins_title": "Невитрачені монети",

View file

@ -69,6 +69,7 @@
"avg_savings": "اوسط بچت",
"awaitDAppProcessing": "۔ﮟﯾﺮﮐ ﺭﺎﻈﺘﻧﺍ ﺎﮐ ﮯﻧﻮﮨ ﻞﻤﮑﻣ ﮓﻨﺴﯿﺳﻭﺮﭘ ﮯﮐ dApp ﻡﺮﮐ ﮦﺍﺮﺑ",
"awaiting_payment_confirmation": "ادائیگی کی تصدیق کے منتظر",
"background_sync": "پس منظر کی ہم آہنگی",
"background_sync_mode": "پس منظر کی مطابقت پذیری کا موڈ",
"backup": "بیک اپ",
"backup_file": "بیک اپ فائل",
@ -161,6 +162,7 @@
"confirm_passphrase": "پاسفریز کی تصدیق کریں",
"confirm_sending": "بھیجنے کی تصدیق کریں۔",
"confirm_silent_payments_switch_node": "آپ کا موجودہ نوڈ خاموش ادائیگیوں کی حمایت نہیں کرتا ہے۔",
"confirm_transaction": "لین دین کی تصدیق کریں",
"confirmations": "تصدیقات",
"confirmed": "تصدیق شدہ بیلنس",
"confirmed_tx": "تصدیق",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔",
"generate_name": "نام پیدا کریں۔",
"generating_gift_card": "گفٹ کارڈ تیار کرنا",
"generating_transaction": "ٹرانزیکشن پیدا کرنا",
"get_a": "حاصل",
"get_card_note": " جسے آپ ڈیجیٹل کرنسیوں کے ساتھ دوبارہ لوڈ کر سکتے ہیں۔ کوئی اضافی معلومات کی ضرورت نہیں!",
"get_your_yat": "اپنی Yat حاصل کریں۔",
@ -930,6 +933,8 @@
"understand": "میں سمجھتا ہوں۔",
"unlock": "غیر مقفل",
"unmatched_currencies": "آپ کے پرس کی موجودہ کرنسی اسکین شدہ QR سے مماثل نہیں ہے۔",
"unrestricted_background_service": "غیر محدود پس منظر کی خدمت",
"unrestricted_background_service_notice": "پس منظر کی مطابقت پذیری کو قابل بنانے کے ل you آپ کو غیر محدود پس منظر کی خدمت کو فعال کرنے کی ضرورت ہے",
"unspent_change": "تبدیل کریں",
"unspent_coins_details_title": "غیر خرچ شدہ سککوں کی تفصیلات",
"unspent_coins_title": "غیر خرچ شدہ سکے ۔",

View file

@ -69,6 +69,7 @@
"avg_savings": "Tiết kiệm trung bình",
"awaitDAppProcessing": "Vui lòng đợi ứng dụng phi tập trung hoàn thành xử lý.",
"awaiting_payment_confirmation": "Đang chờ xác nhận thanh toán",
"background_sync": "Đồng bộ nền",
"background_sync_mode": "Chế độ đồng bộ nền",
"backup": "Sao lưu",
"backup_file": "Tập tin sao lưu",
@ -160,6 +161,7 @@
"confirm_passphrase": "Xác nhận cụm mật khẩu",
"confirm_sending": "Xác nhận gửi",
"confirm_silent_payments_switch_node": "Nút hiện tại của bạn không hỗ trợ thanh toán im lặng\\nCake Wallet sẽ chuyển sang một nút tương thích chỉ để quét",
"confirm_transaction": "Xác nhận giao dịch",
"confirmations": "Xác nhận",
"confirmed": "Số dư đã xác nhận",
"confirmed_tx": "Đã xác nhận",
@ -343,6 +345,7 @@
"gas_exceeds_allowance": "Gas theo yêu cầu của giao dịch vượt quá trợ cấp.",
"generate_name": "Tạo tên",
"generating_gift_card": "Đang tạo thẻ quà tặng",
"generating_transaction": "Tạo giao dịch",
"get_a": "Nhận một ",
"get_card_note": " mà bạn có thể nạp lại bằng tiền điện tử. Không cần thêm thông tin!",
"get_your_yat": "Nhận Yat của bạn",
@ -925,6 +928,8 @@
"understand": "Tôi hiểu",
"unlock": "Mở khóa",
"unmatched_currencies": "Tiền tệ của ví hiện tại của bạn không khớp với QR đã quét",
"unrestricted_background_service": "Dịch vụ nền không giới hạn",
"unrestricted_background_service_notice": "Để cho phép đồng bộ hóa nền, bạn cần bật dịch vụ nền không giới hạn",
"unspent_change": "Tiền thối",
"unspent_coins_details_title": "Chi tiết các đồng tiền chưa chi tiêu",
"unspent_coins_title": "Các đồng tiền chưa chi tiêu",

View file

@ -69,6 +69,7 @@
"avg_savings": "Ìpamọ́ lóòrèkóòrè",
"awaitDAppProcessing": "Fi inurere duro fun dApp lati pari sisẹ.",
"awaiting_payment_confirmation": "À ń dúró de ìjẹ́rìísí àránṣẹ́",
"background_sync": "Imuṣiṣẹ Labẹ",
"background_sync_mode": "Ipo amuṣiṣẹpọ abẹlẹ",
"backup": "Ṣẹ̀dà",
"backup_file": "Ṣẹ̀dà akọsílẹ̀",
@ -161,6 +162,7 @@
"confirm_passphrase": "Jẹrisi kọwe",
"confirm_sending": "Jẹ́rìí sí ránṣẹ́",
"confirm_silent_payments_switch_node": "Ilode rẹ ti lọwọlọwọ ko ṣe atilẹyin awọn sisanwo ti o dakẹ \\ owet apamọwọ yoo yipada si oju-ọrọ ibaramu, o kan fun Scning",
"confirm_transaction": "Jẹrisi iṣowo naa",
"confirmations": "Àwọn ẹ̀rí",
"confirmed": "A ti jẹ́rìí ẹ̀",
"confirmed_tx": "Jẹrisi",
@ -345,6 +347,7 @@
"gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.",
"generate_name": "Ṣẹda Orukọ",
"generating_gift_card": "À ń dá káàdì ìrajà t'á lò nínú irú kan ìtajà",
"generating_transaction": "Ifọwọsi Iṣowo",
"get_a": "Gba ",
"get_card_note": " t'ẹ lè fikún owó ayélujára. Ẹ kò nílò ìṣofúnni àfikún!",
"get_your_yat": "Gba Yat yín",
@ -929,6 +932,8 @@
"understand": "Ó ye mi",
"unlock": "Sisalẹ",
"unmatched_currencies": "Irú owó ti àpamọ́wọ́ yín kì í ṣe irú ti yíya àmì ìlujá",
"unrestricted_background_service": "Iṣẹ ipilẹṣẹ ti ko nilẹ",
"unrestricted_background_service_notice": "Ni ibere lati mu ṣiṣẹpọ lẹhin ti o nilo lati ṣiṣẹ iṣẹ iṣẹ ti ko ni ibatan",
"unspent_change": "Yipada",
"unspent_coins_details_title": "Àwọn owó ẹyọ t'á kò tí ì san",
"unspent_coins_title": "Àwọn owó ẹyọ t'á kò tí ì san",

View file

@ -69,6 +69,7 @@
"avg_savings": "平均储蓄",
"awaitDAppProcessing": "请等待 dApp 处理完成。",
"awaiting_payment_confirmation": "等待付款确认",
"background_sync": "背景同步",
"background_sync_mode": "后台同步模式",
"backup": "备份",
"backup_file": "备份文件",
@ -161,6 +162,7 @@
"confirm_passphrase": "确认密码",
"confirm_sending": "确认发送",
"confirm_silent_payments_switch_node": "您当前的节点不支持无声付款\\ ncake钱包将切换到兼容节点仅用于扫描",
"confirm_transaction": "确认交易",
"confirmations": "确认",
"confirmed": "确认余额",
"confirmed_tx": "确认的",
@ -344,6 +346,7 @@
"gas_exceeds_allowance": "交易要求的气体超出了津贴。",
"generate_name": "生成名称",
"generating_gift_card": "生成礼品卡",
"generating_transaction": "生成交易",
"get_a": "得到一个",
"get_card_note": "你可以用数字货币重新加载。不需要额外的信息!",
"get_your_yat": "得到你的 Yat",
@ -928,6 +931,8 @@
"understand": "我已知晓",
"unlock": "开锁",
"unmatched_currencies": "您当前钱包的货币与扫描的 QR 的货币不匹配",
"unrestricted_background_service": "不受限制的背景服务",
"unrestricted_background_service_notice": "为了启用背景同步,您需要启用无限制的背景服务",
"unspent_change": "改变",
"unspent_coins_details_title": "未使用代幣詳情",
"unspent_coins_title": "未使用的硬幣",

View file

@ -1,3 +1,3 @@
{
"flutter": "3.24.0"
"flutter": "3.27.4"
}

View file

@ -4,7 +4,7 @@
FROM mcr.microsoft.com/windows/servercore:ltsc2022
ENV FLUTTER_VERSION=3.24.0
ENV FLUTTER_VERSION=3.27.4
ENV GIT_VERSION=2.47.1
ENV VS_INSTALLED_DIR="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools"
ENV PATH="C:\Users\ContainerAdministrator\.cargo\bin;C:\ProgramData\chocolatey\bin;C:\flutter\flutter\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Users\ContainerAdministrator\AppData\Local\Microsoft\WindowsApps"

View file

@ -47,7 +47,7 @@ Future<void> main() async {
if (localFilename.endsWith(".xz")) {
printV(" extracting $localFilename");
final inputStream = InputFileStream(localFilename);
final archive = XZDecoder().decodeBuffer(inputStream);
final archive = XZDecoder().decodeBytes(inputStream.toUint8List());
final outputStream = OutputFileStream(localFilename.replaceAll(".xz", ""));
outputStream.writeBytes(archive);
}