mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 09:19:22 +00:00
Merge branch 'tor' into monerodart_testing
This commit is contained in:
commit
86bd8f93c8
11 changed files with 433 additions and 180 deletions
216
docs/building.md
216
docs/building.md
|
@ -4,12 +4,12 @@ Here you will find instructions on how to install the necessary tools for buildi
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- The only OS supported for building Android and Linux desktop is Ubuntu 20.04. Windows build are completed using Ubuntu 20.04 on WSL2. Advanced users may also be able to build on other Debian-based distributions like Linux Mint.
|
- The only OS supported for building Android and Linux desktop is Ubuntu 20.04. Windows builds require using Ubuntu 20.04 on WSL2. macOS builds for itself and iOS. Advanced users may also be able to build on other Debian-based distributions like Linux Mint.
|
||||||
- Android setup ([Android Studio](https://developer.android.com/studio) and subsequent dependencies)
|
- Android setup ([Android Studio](https://developer.android.com/studio) and subsequent dependencies)
|
||||||
- 100 GB of storage
|
- 100 GB of storage
|
||||||
|
|
||||||
## Linux host
|
## Linux host
|
||||||
The following instructions are for building and running on a Linux host. Alternatively, see the [Windows](#Windows host) section.
|
The following instructions are for building and running on a Linux host. Alternatively, see the [Mac](#mac-host) and/or [Windows](#windows-host) section. This entire section (except for the Android Studio section) needs to be completed in WSL if building on a Windows host.
|
||||||
|
|
||||||
### Flutter
|
### Flutter
|
||||||
Install Flutter 3.19 beta (3.19.0-0.1.pre) by following these instructions: https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk. You can also clone https://github.com/flutter/flutter, check out the `3.19.0-0.1.pre` tag, and add its `flutter/bin` folder to your PATH. Run `flutter doctor` in a terminal to confirm its installation.
|
Install Flutter 3.19 beta (3.19.0-0.1.pre) by following these instructions: https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk. You can also clone https://github.com/flutter/flutter, check out the `3.19.0-0.1.pre` tag, and add its `flutter/bin` folder to your PATH. Run `flutter doctor` in a terminal to confirm its installation.
|
||||||
|
@ -23,25 +23,37 @@ sudo snap install android-studio --classic
|
||||||
```
|
```
|
||||||
|
|
||||||
Use `Tools > SDK Manager` to install:
|
Use `Tools > SDK Manager` to install:
|
||||||
- `SDK Tools > Android SDK (API 30)`
|
|
||||||
- `SDK Tools > NDK`
|
|
||||||
- `SDK Tools > Android SDK command line tools`
|
- `SDK Tools > Android SDK command line tools`
|
||||||
- `SDK Tools > CMake`
|
- `SDK Tools > CMake`
|
||||||
|
and for Android builds,
|
||||||
|
- `SDK Tools > Android SDK (API 30)`
|
||||||
|
- `SDK Tools > NDK`
|
||||||
|
|
||||||
Then in `File > Settings > Plugins`, install the **Flutter** and **Dart** plugins and restart the IDE. In `File > Settings > Languages & Frameworks > Flutter > Editor`, enable auto format on save to match the project's code style. If you have problems with the Dart SDK, make sure to run `flutter` in a terminal to download it (use `source ~/.bashrc` to update your environment variables if you're still using the same terminal from which you ran `setup.sh`). Run `flutter doctor` to install any missing dependencies and review and agree to any license agreements.
|
Then in `File > Settings > Plugins`, install the **Flutter** and **Dart** plugins and restart the IDE. In `File > Settings > Languages & Frameworks > Flutter > Editor`, enable auto format on save to match the project's code style. If you have problems with the Dart SDK, make sure to run `flutter` in a terminal to download it (use `source ~/.bashrc` to update your environment variables if you're still using the same terminal from which you ran `setup.sh`). Run `flutter doctor` to install any missing dependencies and review and agree to any license agreements.
|
||||||
|
|
||||||
Make a Pixel 4 (API 30) x86_64 emulator with 2GB of storage space for emulation
|
Make a Pixel 4 (API 30) x86_64 emulator with 2GB of storage space for emulation.
|
||||||
|
|
||||||
Install basic dependencies
|
|
||||||
```
|
|
||||||
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils g++ gcc gperf
|
|
||||||
```
|
|
||||||
|
|
||||||
The following *may* be needed for Android studio:
|
The following *may* be needed for Android studio:
|
||||||
```
|
```
|
||||||
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
|
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-1.0:i386
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Flutter
|
||||||
|
|
||||||
|
Flutter and the Dart SDK should have been set up by Android studio, but if running `flutter` doesn't work (try `flutter doctor`, too), follow the [guide to install Flutter on any of their supported platforms](https://docs.flutter.dev/get-started/install) or:
|
||||||
|
- `git clone https://github.com/flutter/flutter` somewhere it can live (`/var`, `/opt`, `~`)
|
||||||
|
- `git checkout 3.16.0` after navigating into the `flutter` directory, and
|
||||||
|
- add `flutter/bin` to your PATH (on Ubuntu, add `PATH=$PATH:path/to/flutter/bin` to `~/.profile`).
|
||||||
|
|
||||||
|
Run `flutter doctor` to install any missing dependencies and review and agree to any license agreements.
|
||||||
|
|
||||||
|
### Build dependencies
|
||||||
|
|
||||||
|
Install basic dependencies
|
||||||
|
```
|
||||||
|
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils g++ gcc gperf
|
||||||
|
```
|
||||||
|
|
||||||
Install [Rust](https://www.rust-lang.org/tools/install) with command:
|
Install [Rust](https://www.rust-lang.org/tools/install) with command:
|
||||||
```
|
```
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
@ -52,13 +64,15 @@ rustup default 1.67.1
|
||||||
|
|
||||||
Install the additional components for Rust:
|
Install the additional components for Rust:
|
||||||
```
|
```
|
||||||
cargo install cargo-ndk --version 2.12.7
|
cargo install cargo-ndk --version 2.12.7 --locked
|
||||||
```
|
```
|
||||||
|
|
||||||
Android specific dependencies:
|
Android specific dependencies:
|
||||||
```
|
```
|
||||||
sudo apt-get install libc6-dev-i386
|
sudo apt-get install libc6-dev-i386
|
||||||
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
|
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
|
||||||
```
|
```
|
||||||
|
|
||||||
Linux desktop specific dependencies:
|
Linux desktop specific dependencies:
|
||||||
```
|
```
|
||||||
sudo apt-get install clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev meson python3-pip libgirepository1.0-dev valac xsltproc docbook-xsl
|
sudo apt-get install clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev meson python3-pip libgirepository1.0-dev valac xsltproc docbook-xsl
|
||||||
|
@ -72,15 +86,25 @@ cd stack_wallet
|
||||||
git submodule update --init --recursive
|
git submodule update --init --recursive
|
||||||
```
|
```
|
||||||
|
|
||||||
Remove pre-installed system libraries for the following packages built by cryptography plugins in the crypto_plugins folder: `boost iconv libjson-dev libsecret openssl sodium unbound zmq`. You can use
|
Build the secure storage dependencies in order to target Linux (not needed for Windows or other platforms):
|
||||||
```
|
```
|
||||||
sudo apt list --installed | grep boost
|
cd scripts/linux
|
||||||
|
./build_secure_storage_deps.sh
|
||||||
|
// when finished go back to the root directory
|
||||||
|
cd ../..
|
||||||
```
|
```
|
||||||
for example to find which pre-installed packages you may need to remove with `sudo apt remove`. Be careful, as some packages (especially boost) are linked to GNOME (GUI) packages: when in doubt, remove `-dev` packages first like with
|
|
||||||
```
|
### Build coinlib
|
||||||
sudo apt-get remove '^libboost.*-dev.*'
|
Coinlib's native secp256k1 library must be built prior to running Stack Wallet. It can be built from within the root `stack_wallet` folder on a...
|
||||||
```
|
- Linux host for Linux targets: `dart run coinlib:build_linux`, or
|
||||||
<!-- TODO: configure compiler to prefer built over system libraries. Should already use them? -->
|
- Linux host for Windows targets: `dart run coinlib:build_windows_crosscompile`
|
||||||
|
- Windows host: `dart run coinlib:build_windows`
|
||||||
|
- WSL2 host: `dart run coinlib:build_wsl`
|
||||||
|
- macOS host: `dart run coinlib:build_macos`
|
||||||
|
|
||||||
|
To build coinlib on Linux, you will need `docker` (see [installation instructions](https://docs.docker.com/engine/install/ubuntu/)) or [`podman`](https://podman.io/docs/installation) (`sudo apt-get -y install podman`)
|
||||||
|
|
||||||
|
For Windows targets, you can use a `secp256k1.dll` produced by any of the three middle options if the first attempt doesn't succeed!
|
||||||
|
|
||||||
### Run prebuild script
|
### Run prebuild script
|
||||||
|
|
||||||
|
@ -107,6 +131,19 @@ cd scripts/linux
|
||||||
./build_all.sh
|
./build_all.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Remove system packages (may be needed for building flutter_libmonero)
|
||||||
|
[`flutter_libmonero`](https://github.com/cypherstack/flutter_libmonero) may have issues building due to conflicts with system packages: if so, follow this section.
|
||||||
|
|
||||||
|
Remove pre-installed system libraries for the following packages built by cryptography plugins in the crypto_plugins folder: `boost iconv libjson-dev libsecret openssl sodium unbound zmq`. You can use
|
||||||
|
```
|
||||||
|
sudo apt list --installed | grep boost
|
||||||
|
```
|
||||||
|
for example to find which pre-installed packages you may need to remove with `sudo apt remove`. Be careful, as some packages (especially boost) are linked to GNOME (GUI) packages: when in doubt, remove `-dev` packages first like with
|
||||||
|
```
|
||||||
|
sudo apt-get remove '^libboost.*-dev.*'
|
||||||
|
```
|
||||||
|
<!-- TODO: configure compiler to prefer built over system libraries. Should already use them? -->
|
||||||
|
|
||||||
#### Building plugins for Windows
|
#### Building plugins for Windows
|
||||||
```
|
```
|
||||||
cd scripts/windows
|
cd scripts/windows
|
||||||
|
@ -122,7 +159,7 @@ flutter pub get
|
||||||
flutter run android
|
flutter run android
|
||||||
```
|
```
|
||||||
|
|
||||||
Note on Emulators: Only x86_64 emulators are supported, x86 emulators will not work
|
Note on Emulators: Only x86_64 emulators are supported, x86 emulators will not work. You should [configure KVM](https://help.ubuntu.com/community/KVM/Installation) for much better performance.
|
||||||
|
|
||||||
#### Linux
|
#### Linux
|
||||||
Run the following commands or launch via Android Studio:
|
Run the following commands or launch via Android Studio:
|
||||||
|
@ -131,20 +168,100 @@ flutter pub get
|
||||||
flutter run linux
|
flutter run linux
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Mac host
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
XCode, Homebrew and several homebrew packages, Rust, and Flutter are required for Mac development with the Flutter SDK. Multiple IDEs may work, but Android Studio is recommended.
|
||||||
|
|
||||||
|
Download and install Xcode at https://developer.apple.com/xcode/, register your device (Mac or iPhone), and enable developer mode for your device as applicable. After installing XCode, make sure commandline tools are installed with `xcode-select --install`.
|
||||||
|
|
||||||
|
Download and install [Homebrew](https://brew.sh/). The following command can install it via script:
|
||||||
|
```
|
||||||
|
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
```
|
||||||
|
|
||||||
|
After installing Homebrew, install the following packages:
|
||||||
|
```
|
||||||
|
brew install autoconf automake boost berkeley-db ca-certificates cbindgen cmake cmake cocoapods curl git libssh2 make openssl@1.1 openssl@3 perl pkg-config rustup-init sodium unbound unzip xz zmq
|
||||||
|
```
|
||||||
|
|
||||||
|
The following brew formula *may* be needed:
|
||||||
|
```
|
||||||
|
brew install brotli cairo coreutils gdbm gettext glib gmp libevent libidn2 libnghttp2 libtool libunistring libx11 libxau libxcb libxdmcp libxext libxrender lzo m4 openldap pcre2 pixman procs rtmpdump tcl-tk xorgproto zstd
|
||||||
|
```
|
||||||
|
<!-- TODO: determine which of the above list are not needed at all. -->
|
||||||
|
|
||||||
|
Download and install [Rust](https://www.rust-lang.org/tools/install). [Rustup](https://rustup.rs/) is recommended for Rust setup. Use `rustc` to confirm successful installation. Install toolchains 1.67.1 and 1.72.0 and `cbindgen` and `cargo-lipo` too. You will also have to add the platform target(s) `aarch64-apple-ios` and/or `aarch64-apple-darwin`. You can use the command(s):
|
||||||
|
```
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||||
|
source ~/.bashrc
|
||||||
|
rustup install 1.67.1
|
||||||
|
rustup install 1.72.0
|
||||||
|
rustup default 1.67.1
|
||||||
|
cargo install cbindgen cargo-lipo
|
||||||
|
rustup target add aarch64-apple-ios aarch64-apple-darwin
|
||||||
|
```
|
||||||
|
|
||||||
|
Optionally download [Android Studio](https://developer.android.com/studio) as an IDE and activate its Dart and Flutter plugins. VS Code may work as an alternative, but this is not recommended.
|
||||||
|
|
||||||
|
### Flutter
|
||||||
|
Install [Flutter](https://docs.flutter.dev/get-started/install) 3.16.8 on your Mac host by following [these instructions](https://docs.flutter.dev/get-started/install/macos). Run `flutter doctor` in a terminal to confirm its installation.
|
||||||
|
|
||||||
|
### Build plugins
|
||||||
|
#### Building plugins for iOS
|
||||||
|
```
|
||||||
|
cd scripts/ios
|
||||||
|
./build_all.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Building plugins for macOS
|
||||||
|
```
|
||||||
|
cd scripts/macos
|
||||||
|
./build_all.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run prebuild script
|
||||||
|
|
||||||
|
Certain test wallet parameter and API key template files must be created in order to run Stack Wallet. These can be created by script as in
|
||||||
|
```
|
||||||
|
cd scripts
|
||||||
|
./prebuild.sh
|
||||||
|
// when finished go back to the root directory
|
||||||
|
cd ..
|
||||||
|
```
|
||||||
|
or manually by creating the files referenced in that script with the specified content.
|
||||||
|
|
||||||
|
### Running
|
||||||
|
#### iOS
|
||||||
|
Plug in your iOS device or use an emulato and then run the following commands:
|
||||||
|
```
|
||||||
|
flutter pub get
|
||||||
|
flutter run ios
|
||||||
|
```
|
||||||
|
|
||||||
|
#### macOS
|
||||||
|
Run the following commands or launch via Android Studio:
|
||||||
|
```
|
||||||
|
flutter pub get
|
||||||
|
flutter run macos
|
||||||
|
```
|
||||||
|
|
||||||
## Windows host
|
## Windows host
|
||||||
### Visual Studio
|
### Visual Studio
|
||||||
Visual Studio is required for Windows development with the Flutter SDK. Download it at https://visualstudio.microsoft.com/downloads/ and install the "Desktop development with C++" workload, including all of its default components.
|
Visual Studio is required for Windows development with the Flutter SDK. Download it at https://visualstudio.microsoft.com/downloads/ and install the "Desktop development with C++", "Linux development with C++", and "Visual C++ build tools" workloads. You may also need the Windows 10, 11, and/or Universal SDK workloads depending on your Windows version.
|
||||||
|
|
||||||
### Building libraries in WSL2
|
### Build plugins in WSL2
|
||||||
Set up Ubuntu 20.04 in WSL2. Follow the entire Linux host section in the WSL2 Ubuntu 20.04 host to get set up to build. You will also need to install Rust and MXE dependencies on the WSL2 Ubuntu 20.04 host:
|
Set up Ubuntu 20.04 in WSL2. Follow the entire Linux host section in the WSL2 Ubuntu 20.04 host to get set up to build. The Android Studio section may be skipped in WSL (it's only needed on the Windows host).
|
||||||
- [Install Rust](https://rustup.rs/)
|
|
||||||
```sh
|
Install the following libraries:
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
```
|
||||||
```
|
sudo apt-get install libgtk2.0-dev
|
||||||
- Install MXE by running `stack_wallet/scripts/windows/deps.sh`
|
```
|
||||||
```sh
|
|
||||||
./stack_wallet/scripts/windows/deps.sh
|
You will also need to install MXE on the WSL2 Ubuntu 20.04 host and can do so by running `stack_wallet/scripts/windows/deps.sh`:
|
||||||
```
|
```
|
||||||
|
./stack_wallet/scripts/windows/deps.sh
|
||||||
|
```
|
||||||
|
|
||||||
The WSL2 host may optionally be navigated to the `stack_wallet` repository on the Windows host in order to build the plugins in-place and skip the next section in which you copy the `dll`s from WSL2 to Windows. Then build windows `dll` libraries by running the following script on the WSL2 Ubuntu 20.04 host:
|
The WSL2 host may optionally be navigated to the `stack_wallet` repository on the Windows host in order to build the plugins in-place and skip the next section in which you copy the `dll`s from WSL2 to Windows. Then build windows `dll` libraries by running the following script on the WSL2 Ubuntu 20.04 host:
|
||||||
|
|
||||||
|
@ -160,10 +277,27 @@ Copy the resulting `dll`s to their respective positions on the Windows host:
|
||||||
-->
|
-->
|
||||||
<!-- TODO: script the copying or installation of libraries from WSL2 to the parent Windows host -->
|
<!-- TODO: script the copying or installation of libraries from WSL2 to the parent Windows host -->
|
||||||
|
|
||||||
### Install Flutter on Windows host
|
Frostdart will be built by the Windows host later.
|
||||||
Install Flutter 3.19 beta (3.19.0-0.1.pre) on your Windows host (not in WSL2) by following these instructions: https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk. You can also clone https://github.com/flutter/flutter, check out the `3.19.0-0.1.pre` tag, and add its `flutter/bin` folder to your PATH. Run `flutter doctor` in PowerShell to confirm its installation.
|
|
||||||
|
|
||||||
### Dependencies
|
### Install Flutter on Windows host
|
||||||
|
Install Flutter 3.19.5 on your Windows host (not in WSL2) by following these instructions: https://docs.flutter.dev/get-started/install/windows/desktop?tab=download#install-the-flutter-sdk. You can also clone https://github.com/flutter/flutter, check out the `3.19.5` tag, and add its `flutter/bin` folder to your PATH. Run `flutter doctor` in PowerShell to confirm its installation.
|
||||||
|
|
||||||
|
### Rust
|
||||||
|
Install [Rust](https://www.rust-lang.org/tools/install) on the Windows host (not in WSL2). Download the installer from [rustup.rs](https://rustup.rs), make sure it works on the commandline (you may need to open a new terminal), and install the following versions:
|
||||||
|
```
|
||||||
|
rustup install 1.72.0 # For frostdart and tor.
|
||||||
|
rustup install 1.67.1 # For flutter_libepiccash.
|
||||||
|
rustup default 1.67.1
|
||||||
|
```
|
||||||
|
<!--
|
||||||
|
You may also need to install `cargo-ndk`:
|
||||||
|
```
|
||||||
|
rustup install 1.73.0 # For cargo-ndk.
|
||||||
|
cargo install cargo-ndk --version 2.12.7 --locked
|
||||||
|
```
|
||||||
|
-->
|
||||||
|
|
||||||
|
### Windows SDK and Developer Mode
|
||||||
Install the Windows SDK: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ You may need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/), which can be installed [by Visual Studio](https://stackoverflow.com/a/73923899) (`Tools > Get Tools and Features... > Modify > Individual Components > Windows 10 SDK`).
|
Install the Windows SDK: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/ You may need to install the [Windows 10 SDK](https://developer.microsoft.com/en-us/windows/downloads/sdk-archive/), which can be installed [by Visual Studio](https://stackoverflow.com/a/73923899) (`Tools > Get Tools and Features... > Modify > Individual Components > Windows 10 SDK`).
|
||||||
|
|
||||||
Enable Developer Mode for symlink support,
|
Enable Developer Mode for symlink support,
|
||||||
|
@ -181,14 +315,22 @@ or [download the package](https://www.nuget.org/packages/Microsoft.Windows.CppWi
|
||||||
|
|
||||||
### Run prebuild script
|
### Run prebuild script
|
||||||
|
|
||||||
Certain test wallet parameter and API key template files must be created in order to run Stack Wallet. These can be created by script as in
|
Certain test wallet parameter and API key template files must be created in order to run Stack Wallet on Windows. These can be created by script using PowerShell on the Windows host as in
|
||||||
```
|
```
|
||||||
cd scripts
|
cd scripts
|
||||||
./prebuild.ps1
|
./prebuild.ps1
|
||||||
// when finished go back to the root directory
|
cd .. // When finished go back to the root directory.
|
||||||
cd ..
|
```
|
||||||
|
or manually by creating the files referenced in that script with the specified content.
|
||||||
|
|
||||||
|
### Build frostdart
|
||||||
|
|
||||||
|
In PowerShell on the Windows host, navigate to the `stack_wallet` folder:
|
||||||
|
```
|
||||||
|
cd crypto_plugins/frostdart
|
||||||
|
./build_all.bat
|
||||||
|
cd .. // When finished go back to the root directory.
|
||||||
```
|
```
|
||||||
or manually by creating the files referenced in that script with the specified content.
|
|
||||||
|
|
||||||
### Running
|
### Running
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,12 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
import 'package:stackwallet/networking/http.dart';
|
||||||
|
import 'package:stackwallet/services/tor_service.dart';
|
||||||
|
import 'package:stackwallet/utilities/prefs.dart';
|
||||||
|
|
||||||
class PayNymBot extends StatelessWidget {
|
class PayNymBot extends StatelessWidget {
|
||||||
const PayNymBot({
|
const PayNymBot({
|
||||||
|
@ -28,16 +32,37 @@ class PayNymBot extends StatelessWidget {
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
child: Image.network(
|
child: FutureBuilder<Uint8List>(
|
||||||
"https://paynym.is/$paymentCodeString/avatar",
|
future: _fetchImage(),
|
||||||
loadingBuilder: (context, child, loadingProgress) =>
|
builder: (context, snapshot) {
|
||||||
loadingProgress == null
|
if (snapshot.hasData) {
|
||||||
? child
|
return Image.memory(snapshot.data!);
|
||||||
: const Center(
|
} else if (snapshot.hasError) {
|
||||||
child: LoadingIndicator(),
|
return const Center(child: Icon(Icons.error));
|
||||||
),
|
} else {
|
||||||
|
return const Center(); // TODO [prio=low]: Make better loading indicator.
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Uint8List> _fetchImage() async {
|
||||||
|
final HTTP client = HTTP();
|
||||||
|
final Uri uri = Uri.parse("https://paynym.is/$paymentCodeString/avatar");
|
||||||
|
|
||||||
|
final response = await client.get(
|
||||||
|
url: uri,
|
||||||
|
proxyInfo: Prefs.instance.useTor
|
||||||
|
? TorService.sharedInstance.getProxyInfo()
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.code == 200) {
|
||||||
|
return Uint8List.fromList(response.bodyBytes);
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load image');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:solana/solana.dart';
|
import 'package:solana/solana.dart';
|
||||||
import 'package:stackwallet/models/node_model.dart';
|
import 'package:stackwallet/models/node_model.dart';
|
||||||
|
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart';
|
import 'package:stackwallet/wallets/crypto_currency/intermediate/bip39_currency.dart';
|
||||||
import 'package:stackwallet/utilities/default_nodes.dart';
|
|
||||||
|
|
||||||
class Solana extends Bip39Currency {
|
class Solana extends Bip39Currency {
|
||||||
Solana(super.network) {
|
Solana(super.network) {
|
||||||
|
@ -20,7 +20,8 @@ class Solana extends Bip39Currency {
|
||||||
switch (network) {
|
switch (network) {
|
||||||
case CryptoCurrencyNetwork.main:
|
case CryptoCurrencyNetwork.main:
|
||||||
return NodeModel(
|
return NodeModel(
|
||||||
host: "https://api.mainnet-beta.solana.com/", // TODO: Change this to stack wallet one
|
host:
|
||||||
|
"https://api.mainnet-beta.solana.com/", // TODO: Change this to stack wallet one
|
||||||
port: 443,
|
port: 443,
|
||||||
name: DefaultNodes.defaultName,
|
name: DefaultNodes.defaultName,
|
||||||
id: DefaultNodes.buildId(Coin.solana),
|
id: DefaultNodes.buildId(Coin.solana),
|
||||||
|
@ -38,11 +39,23 @@ class Solana extends Bip39Currency {
|
||||||
@override
|
@override
|
||||||
int get minConfirms => 21;
|
int get minConfirms => 21;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get torSupport => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool validateAddress(String address) {
|
bool validateAddress(String address) {
|
||||||
return isPointOnEd25519Curve(Ed25519HDPublicKey.fromBase58(address).toByteArray());
|
return isPointOnEd25519Curve(
|
||||||
|
Ed25519HDPublicKey.fromBase58(address).toByteArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get genesisHash => throw UnimplementedError();
|
String get genesisHash => throw UnimplementedError();
|
||||||
}
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is Solana && other.network == network;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(Solana, network);
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ class Stellar extends Bip39Currency {
|
||||||
@override
|
@override
|
||||||
int get minConfirms => 1;
|
int get minConfirms => 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get torSupport => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get genesisHash => throw UnimplementedError(
|
String get genesisHash => throw UnimplementedError(
|
||||||
"Not used for stellar",
|
"Not used for stellar",
|
||||||
|
|
|
@ -70,6 +70,9 @@ class Tezos extends Bip39Currency {
|
||||||
@override
|
@override
|
||||||
int get minConfirms => 1;
|
int get minConfirms => 1;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get torSupport => true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool validateAddress(String address) {
|
bool validateAddress(String address) {
|
||||||
return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address);
|
return RegExp(r"^tz[1-9A-HJ-NP-Za-km-z]{34}$").hasMatch(address);
|
||||||
|
|
|
@ -303,6 +303,7 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
Future<Address> _generateAndStoreReceivingAddressForIndex(
|
Future<Address> _generateAndStoreReceivingAddressForIndex(
|
||||||
int index,
|
int index,
|
||||||
) async {
|
) async {
|
||||||
|
|
||||||
Address? address = await getCurrentReceivingAddress();
|
Address? address = await getCurrentReceivingAddress();
|
||||||
EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig();
|
EpicBoxConfigModel epicboxConfig = await getEpicBoxConfig();
|
||||||
|
|
||||||
|
@ -311,6 +312,7 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
//Check if the address is the same as the current epicbox domain
|
//Check if the address is the same as the current epicbox domain
|
||||||
//Since we're only using one epicbpox now this doesn't apply but will be
|
//Since we're only using one epicbpox now this doesn't apply but will be
|
||||||
// useful in the future
|
// useful in the future
|
||||||
|
final encodedConfig = jsonEncode(epicboxConfig);
|
||||||
if (splitted[1] != epicboxConfig.host) {
|
if (splitted[1] != epicboxConfig.host) {
|
||||||
//Update the address
|
//Update the address
|
||||||
address = await thisWalletAddress(index, epicboxConfig);
|
address = await thisWalletAddress(index, epicboxConfig);
|
||||||
|
@ -318,6 +320,13 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
} else {
|
} else {
|
||||||
address = await thisWalletAddress(index, epicboxConfig);
|
address = await thisWalletAddress(index, epicboxConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.cachedReceivingAddress != address.value) {
|
||||||
|
await info.updateReceivingAddress(
|
||||||
|
newAddress: address.value,
|
||||||
|
isar: mainDB.isar,
|
||||||
|
);
|
||||||
|
}
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -346,7 +355,6 @@ class EpiccashWallet extends Bip39Wallet {
|
||||||
subType: AddressSubType.receiving,
|
subType: AddressSubType.receiving,
|
||||||
publicKey: [], // ??
|
publicKey: [], // ??
|
||||||
);
|
);
|
||||||
|
|
||||||
await mainDB.updateOrPutAddresses([address]);
|
await mainDB.updateOrPutAddresses([address]);
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ import 'package:stackwallet/services/tor_service.dart';
|
||||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
import 'package:stackwallet/utilities/default_nodes.dart';
|
import 'package:stackwallet/utilities/default_nodes.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart';
|
import 'package:stackwallet/wallets/crypto_currency/coins/solana.dart';
|
||||||
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
import 'package:stackwallet/wallets/crypto_currency/crypto_currency.dart';
|
||||||
|
@ -29,24 +28,30 @@ import 'package:tuple/tuple.dart';
|
||||||
class SolanaWallet extends Bip39Wallet<Solana> {
|
class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
SolanaWallet(CryptoCurrencyNetwork network) : super(Solana(network));
|
SolanaWallet(CryptoCurrencyNetwork network) : super(Solana(network));
|
||||||
|
|
||||||
|
static const String _addressDerivationPath = "m/44'/501'/0'/0'";
|
||||||
|
|
||||||
NodeModel? _solNode;
|
NodeModel? _solNode;
|
||||||
|
|
||||||
RpcClient? _rpcClient; // The Solana RpcClient.
|
RpcClient? _rpcClient; // The Solana RpcClient.
|
||||||
|
|
||||||
Future<Ed25519HDKeyPair> _getKeyPair() async {
|
Future<Ed25519HDKeyPair> _getKeyPair() async {
|
||||||
return Ed25519HDKeyPair.fromMnemonic(await getMnemonic(),
|
return Ed25519HDKeyPair.fromMnemonic(
|
||||||
account: 0, change: 0);
|
await getMnemonic(),
|
||||||
|
account: 0,
|
||||||
|
change: 0,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Address> _getCurrentAddress() async {
|
Future<Address> _generateAddress() async {
|
||||||
final addressStruct = Address(
|
final addressStruct = Address(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
value: (await _getKeyPair()).address,
|
value: (await _getKeyPair()).address,
|
||||||
publicKey: List<int>.empty(),
|
publicKey: List<int>.empty(),
|
||||||
derivationIndex: 0,
|
derivationIndex: 0,
|
||||||
derivationPath: DerivationPath()..value = "m/44'/501'/0'/0'",
|
derivationPath: DerivationPath()..value = _addressDerivationPath,
|
||||||
type: cryptoCurrency.coin.primaryAddressType,
|
type: cryptoCurrency.coin.primaryAddressType,
|
||||||
subType: AddressSubType.unknown);
|
subType: AddressSubType.receiving,
|
||||||
|
);
|
||||||
return addressStruct;
|
return addressStruct;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,7 +70,7 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
fundingAccount: pubKey,
|
fundingAccount: pubKey,
|
||||||
recipientAccount: pubKey,
|
recipientAccount: pubKey,
|
||||||
lamports: transferAmount.raw.toInt(),
|
lamports: transferAmount.raw.toInt(),
|
||||||
),
|
)
|
||||||
]).compile(
|
]).compile(
|
||||||
recentBlockhash: latestBlockhash!.value.blockhash,
|
recentBlockhash: latestBlockhash!.value.blockhash,
|
||||||
feePayer: pubKey,
|
feePayer: pubKey,
|
||||||
|
@ -83,18 +88,13 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
@override
|
@override
|
||||||
Future<void> checkSaveInitialReceivingAddress() async {
|
Future<void> checkSaveInitialReceivingAddress() async {
|
||||||
try {
|
try {
|
||||||
final address = (await _getKeyPair()).address;
|
Address? address = await getCurrentReceivingAddress();
|
||||||
|
|
||||||
await mainDB.updateOrPutAddresses([
|
if (address == null) {
|
||||||
Address(
|
address = await _generateAddress();
|
||||||
walletId: walletId,
|
|
||||||
value: address,
|
await mainDB.updateOrPutAddresses([address]);
|
||||||
publicKey: List<int>.empty(),
|
}
|
||||||
derivationIndex: 0,
|
|
||||||
derivationPath: DerivationPath()..value = "m/44'/501'/0'/0'",
|
|
||||||
type: cryptoCurrency.coin.primaryAddressType,
|
|
||||||
subType: AddressSubType.unknown)
|
|
||||||
]);
|
|
||||||
} catch (e, s) {
|
} catch (e, s) {
|
||||||
Logging.instance.log(
|
Logging.instance.log(
|
||||||
"$runtimeType checkSaveInitialReceivingAddress() failed: $e\n$s",
|
"$runtimeType checkSaveInitialReceivingAddress() failed: $e\n$s",
|
||||||
|
@ -118,24 +118,16 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
throw Exception("Insufficient available balance");
|
throw Exception("Insufficient available balance");
|
||||||
}
|
}
|
||||||
|
|
||||||
int feeAmount;
|
final feeAmount = await _getEstimatedNetworkFee(sendAmount);
|
||||||
final currentFees = await fees;
|
if (feeAmount == null) {
|
||||||
switch (txData.feeRateType) {
|
throw Exception(
|
||||||
case FeeRateType.fast:
|
"Failed to get fees, please check your node connection.");
|
||||||
feeAmount = currentFees.fast;
|
|
||||||
break;
|
|
||||||
case FeeRateType.slow:
|
|
||||||
feeAmount = currentFees.slow;
|
|
||||||
break;
|
|
||||||
case FeeRateType.average:
|
|
||||||
default:
|
|
||||||
feeAmount = currentFees.medium;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final address = await getCurrentReceivingAddress();
|
||||||
|
|
||||||
// Rent exemption of Solana
|
// Rent exemption of Solana
|
||||||
final accInfo =
|
final accInfo = await _rpcClient?.getAccountInfo(address!.value);
|
||||||
await _rpcClient?.getAccountInfo((await _getKeyPair()).address);
|
|
||||||
final int minimumRent =
|
final int minimumRent =
|
||||||
await _rpcClient?.getMinimumBalanceForRentExemption(
|
await _rpcClient?.getMinimumBalanceForRentExemption(
|
||||||
accInfo!.value!.data.toString().length) ??
|
accInfo!.value!.data.toString().length) ??
|
||||||
|
@ -145,7 +137,9 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
txData.amount!.raw.toInt() -
|
txData.amount!.raw.toInt() -
|
||||||
feeAmount)) {
|
feeAmount)) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Insufficient remaining balance for rent exemption, minimum rent: ${minimumRent / pow(10, cryptoCurrency.fractionDigits)}");
|
"Insufficient remaining balance for rent exemption, minimum rent: "
|
||||||
|
"${minimumRent / pow(10, cryptoCurrency.fractionDigits)}",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return txData.copyWith(
|
return txData.copyWith(
|
||||||
|
@ -179,7 +173,12 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
recipientAccount: recipientPubKey,
|
recipientAccount: recipientPubKey,
|
||||||
lamports: txData.amount!.raw.toInt()),
|
lamports: txData.amount!.raw.toInt()),
|
||||||
ComputeBudgetInstruction.setComputeUnitPrice(
|
ComputeBudgetInstruction.setComputeUnitPrice(
|
||||||
microLamports: txData.fee!.raw.toInt()),
|
microLamports: txData.fee!.raw.toInt() - 5000),
|
||||||
|
// 5000 lamports is the base fee for a transaction. This instruction adds the necessary fee on top of base fee if it is needed.
|
||||||
|
ComputeBudgetInstruction.setComputeUnitLimit(units: 1000000),
|
||||||
|
// 1000000 is the multiplication number to turn the compute unit price of microLamports to lamports.
|
||||||
|
// These instructions also help the user to not pay more than the shown fee.
|
||||||
|
// See: https://solanacookbook.com/references/basic-transactions.html#how-to-change-compute-budget-fee-priority-for-a-transaction
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -263,7 +262,7 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
@override
|
@override
|
||||||
Future<void> recover({required bool isRescan}) async {
|
Future<void> recover({required bool isRescan}) async {
|
||||||
await refreshMutex.protect(() async {
|
await refreshMutex.protect(() async {
|
||||||
final addressStruct = await _getCurrentAddress();
|
final addressStruct = await _generateAddress();
|
||||||
|
|
||||||
await mainDB.updateOrPutAddresses([addressStruct]);
|
await mainDB.updateOrPutAddresses([addressStruct]);
|
||||||
|
|
||||||
|
@ -285,13 +284,13 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
@override
|
@override
|
||||||
Future<void> updateBalance() async {
|
Future<void> updateBalance() async {
|
||||||
try {
|
try {
|
||||||
|
final address = await getCurrentReceivingAddress();
|
||||||
_checkClient();
|
_checkClient();
|
||||||
|
|
||||||
final balance = await _rpcClient?.getBalance(info.cachedReceivingAddress);
|
final balance = await _rpcClient?.getBalance(address!.value);
|
||||||
|
|
||||||
// Rent exemption of Solana
|
// Rent exemption of Solana
|
||||||
final accInfo =
|
final accInfo = await _rpcClient?.getAccountInfo(address!.value);
|
||||||
await _rpcClient?.getAccountInfo((await _getKeyPair()).address);
|
|
||||||
// TODO [prio=low]: handle null account info.
|
// TODO [prio=low]: handle null account info.
|
||||||
final int minimumRent =
|
final int minimumRent =
|
||||||
await _rpcClient?.getMinimumBalanceForRentExemption(
|
await _rpcClient?.getMinimumBalanceForRentExemption(
|
||||||
|
@ -374,12 +373,14 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
final txsList =
|
final txsList =
|
||||||
List<Tuple2<isar.Transaction, Address>>.empty(growable: true);
|
List<Tuple2<isar.Transaction, Address>>.empty(growable: true);
|
||||||
|
|
||||||
|
final myAddress = (await getCurrentReceivingAddress())!;
|
||||||
|
|
||||||
// TODO [prio=low]: Revisit null assertion below.
|
// TODO [prio=low]: Revisit null assertion below.
|
||||||
|
|
||||||
for (final tx in transactionsList!) {
|
for (final tx in transactionsList!) {
|
||||||
final senderAddress =
|
final senderAddress =
|
||||||
(tx.transaction as ParsedTransaction).message.accountKeys[0].pubkey;
|
(tx.transaction as ParsedTransaction).message.accountKeys[0].pubkey;
|
||||||
final receiverAddress =
|
var receiverAddress =
|
||||||
(tx.transaction as ParsedTransaction).message.accountKeys[1].pubkey;
|
(tx.transaction as ParsedTransaction).message.accountKeys[1].pubkey;
|
||||||
var txType = isar.TransactionType.unknown;
|
var txType = isar.TransactionType.unknown;
|
||||||
final txAmount = Amount(
|
final txAmount = Amount(
|
||||||
|
@ -388,12 +389,16 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
fractionDigits: cryptoCurrency.fractionDigits,
|
fractionDigits: cryptoCurrency.fractionDigits,
|
||||||
);
|
);
|
||||||
|
|
||||||
if ((senderAddress == (await _getKeyPair()).address) &&
|
if ((senderAddress == myAddress.value) &&
|
||||||
(receiverAddress == (await _getKeyPair()).address)) {
|
(receiverAddress == "11111111111111111111111111111111")) {
|
||||||
|
// The account that is only 1's are System Program accounts which
|
||||||
|
// means there is no receiver except the sender,
|
||||||
|
// see: https://explorer.solana.com/address/11111111111111111111111111111111
|
||||||
txType = isar.TransactionType.sentToSelf;
|
txType = isar.TransactionType.sentToSelf;
|
||||||
} else if (senderAddress == (await _getKeyPair()).address) {
|
receiverAddress = senderAddress;
|
||||||
|
} else if (senderAddress == myAddress.value) {
|
||||||
txType = isar.TransactionType.outgoing;
|
txType = isar.TransactionType.outgoing;
|
||||||
} else if (receiverAddress == (await _getKeyPair()).address) {
|
} else if (receiverAddress == myAddress.value) {
|
||||||
txType = isar.TransactionType.incoming;
|
txType = isar.TransactionType.incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,15 +423,16 @@ class SolanaWallet extends Bip39Wallet<Solana> {
|
||||||
);
|
);
|
||||||
|
|
||||||
final txAddress = Address(
|
final txAddress = Address(
|
||||||
walletId: walletId,
|
walletId: walletId,
|
||||||
value: receiverAddress,
|
value: receiverAddress,
|
||||||
publicKey: List<int>.empty(),
|
publicKey: List<int>.empty(),
|
||||||
derivationIndex: 0,
|
derivationIndex: 0,
|
||||||
derivationPath: DerivationPath()..value = "m/44'/501'/0'/0'",
|
derivationPath: DerivationPath()..value = _addressDerivationPath,
|
||||||
type: AddressType.solana,
|
type: AddressType.solana,
|
||||||
subType: txType == isar.TransactionType.outgoing
|
subType: txType == isar.TransactionType.outgoing
|
||||||
? AddressSubType.unknown
|
? AddressSubType.unknown
|
||||||
: AddressSubType.receiving);
|
: AddressSubType.receiving,
|
||||||
|
);
|
||||||
|
|
||||||
txsList.add(Tuple2(transaction, txAddress));
|
txsList.add(Tuple2(transaction, txAddress));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
|
import 'package:socks5_proxy/socks.dart';
|
||||||
import 'package:stackwallet/models/balance.dart';
|
import 'package:stackwallet/models/balance.dart';
|
||||||
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
|
import 'package:stackwallet/models/isar/models/blockchain_data/address.dart';
|
||||||
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
|
import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart';
|
||||||
|
@ -9,6 +12,10 @@ import 'package:stackwallet/models/isar/models/blockchain_data/v2/input_v2.dart'
|
||||||
import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart';
|
import 'package:stackwallet/models/isar/models/blockchain_data/v2/output_v2.dart';
|
||||||
import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
|
import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart';
|
||||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||||
|
import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart';
|
||||||
|
import 'package:stackwallet/services/event_bus/events/global/tor_status_changed_event.dart';
|
||||||
|
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
||||||
|
import 'package:stackwallet/services/tor_service.dart';
|
||||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
@ -20,11 +27,47 @@ import 'package:stackwallet/wallets/wallet/intermediate/bip39_wallet.dart';
|
||||||
import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart' as stellar;
|
import 'package:stellar_flutter_sdk/stellar_flutter_sdk.dart' as stellar;
|
||||||
|
|
||||||
class StellarWallet extends Bip39Wallet<Stellar> {
|
class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
StellarWallet(CryptoCurrencyNetwork network) : super(Stellar(network));
|
StellarWallet(CryptoCurrencyNetwork network) : super(Stellar(network)) {
|
||||||
|
final bus = GlobalEventBus.instance;
|
||||||
|
|
||||||
stellar.StellarSDK get stellarSdk {
|
// Listen for tor status changes.
|
||||||
if (_stellarSdk == null) {
|
_torStatusListener = bus.on<TorConnectionStatusChangedEvent>().listen(
|
||||||
_updateSdk();
|
(event) async {
|
||||||
|
switch (event.newStatus) {
|
||||||
|
case TorConnectionStatus.connecting:
|
||||||
|
if (!_torConnectingLock.isLocked) {
|
||||||
|
await _torConnectingLock.acquire();
|
||||||
|
}
|
||||||
|
_requireMutex = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TorConnectionStatus.connected:
|
||||||
|
case TorConnectionStatus.disconnected:
|
||||||
|
if (_torConnectingLock.isLocked) {
|
||||||
|
_torConnectingLock.release();
|
||||||
|
}
|
||||||
|
_requireMutex = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Listen for tor preference changes.
|
||||||
|
_torPreferenceListener = bus.on<TorPreferenceChangedEvent>().listen(
|
||||||
|
(event) async {
|
||||||
|
_stellarSdk?.httpClient.close();
|
||||||
|
_stellarSdk = null;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<stellar.StellarSDK> get stellarSdk async {
|
||||||
|
if (_requireMutex) {
|
||||||
|
await _torConnectingLock.protect(() async {
|
||||||
|
_stellarSdk ??= _getFreshSdk();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
_stellarSdk ??= _getFreshSdk();
|
||||||
}
|
}
|
||||||
return _stellarSdk!;
|
return _stellarSdk!;
|
||||||
}
|
}
|
||||||
|
@ -41,24 +84,60 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============== Private ====================================================
|
// ============== Private ====================================================
|
||||||
|
// add finalizer to cancel stream subscription when all references to an
|
||||||
|
// instance of this becomes inaccessible
|
||||||
|
final _ = Finalizer<StellarWallet>(
|
||||||
|
(p0) {
|
||||||
|
p0._torPreferenceListener?.cancel();
|
||||||
|
p0._torStatusListener?.cancel();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
StreamSubscription<TorConnectionStatusChangedEvent>? _torStatusListener;
|
||||||
|
StreamSubscription<TorPreferenceChangedEvent>? _torPreferenceListener;
|
||||||
|
|
||||||
|
final Mutex _torConnectingLock = Mutex();
|
||||||
|
bool _requireMutex = false;
|
||||||
|
|
||||||
stellar.StellarSDK? _stellarSdk;
|
stellar.StellarSDK? _stellarSdk;
|
||||||
|
|
||||||
Future<int> _getBaseFee() async {
|
Future<int> _getBaseFee() async {
|
||||||
final fees = await stellarSdk.feeStats.execute();
|
final fees = await (await stellarSdk).feeStats.execute();
|
||||||
return int.parse(fees.lastLedgerBaseFee);
|
return int.parse(fees.lastLedgerBaseFee);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateSdk() {
|
stellar.StellarSDK _getFreshSdk() {
|
||||||
final currentNode = getCurrentNode();
|
final currentNode = getCurrentNode();
|
||||||
_stellarSdk = stellar.StellarSDK("${currentNode.host}:${currentNode.port}");
|
HttpClient? _httpClient;
|
||||||
|
|
||||||
|
if (prefs.useTor) {
|
||||||
|
final ({InternetAddress host, int port}) proxyInfo =
|
||||||
|
TorService.sharedInstance.getProxyInfo();
|
||||||
|
|
||||||
|
_httpClient = HttpClient();
|
||||||
|
SocksTCPClient.assignToHttpClient(
|
||||||
|
_httpClient,
|
||||||
|
[
|
||||||
|
ProxySettings(
|
||||||
|
proxyInfo.host,
|
||||||
|
proxyInfo.port,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stellar.StellarSDK(
|
||||||
|
"${currentNode.host}:${currentNode.port}",
|
||||||
|
httpClient: _httpClient,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> _accountExists(String accountId) async {
|
Future<bool> _accountExists(String accountId) async {
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final receiverAccount = await stellarSdk.accounts.account(accountId);
|
final receiverAccount =
|
||||||
|
await (await stellarSdk).accounts.account(accountId);
|
||||||
if (receiverAccount.accountId != "") {
|
if (receiverAccount.accountId != "") {
|
||||||
exists = true;
|
exists = true;
|
||||||
}
|
}
|
||||||
|
@ -165,7 +244,8 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
@override
|
@override
|
||||||
Future<TxData> confirmSend({required TxData txData}) async {
|
Future<TxData> confirmSend({required TxData txData}) async {
|
||||||
final senderKeyPair = await _getSenderKeyPair(index: 0);
|
final senderKeyPair = await _getSenderKeyPair(index: 0);
|
||||||
final sender = await stellarSdk.accounts.account(senderKeyPair.accountId);
|
final sender =
|
||||||
|
await (await stellarSdk).accounts.account(senderKeyPair.accountId);
|
||||||
|
|
||||||
final address = txData.recipients!.first.address;
|
final address = txData.recipients!.first.address;
|
||||||
final amountToSend = txData.recipients!.first.amount;
|
final amountToSend = txData.recipients!.first.amount;
|
||||||
|
@ -203,7 +283,7 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
|
|
||||||
transaction.sign(senderKeyPair, stellarNetwork);
|
transaction.sign(senderKeyPair, stellarNetwork);
|
||||||
try {
|
try {
|
||||||
final response = await stellarSdk.submitTransaction(transaction);
|
final response = await (await stellarSdk).submitTransaction(transaction);
|
||||||
if (!response.success) {
|
if (!response.success) {
|
||||||
throw Exception("${response.extras?.resultCodes?.transactionResultCode}"
|
throw Exception("${response.extras?.resultCodes?.transactionResultCode}"
|
||||||
" ::: ${response.extras?.resultCodes?.operationsResultCodes}");
|
" ::: ${response.extras?.resultCodes?.operationsResultCodes}");
|
||||||
|
@ -230,7 +310,7 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<FeeObject> get fees async {
|
Future<FeeObject> get fees async {
|
||||||
int fee = await _getBaseFee();
|
final int fee = await _getBaseFee();
|
||||||
return FeeObject(
|
return FeeObject(
|
||||||
numberOfBlocksFast: 1,
|
numberOfBlocksFast: 1,
|
||||||
numberOfBlocksAverage: 1,
|
numberOfBlocksAverage: 1,
|
||||||
|
@ -268,7 +348,8 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
stellar.AccountResponse accountResponse;
|
stellar.AccountResponse accountResponse;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
accountResponse = await stellarSdk.accounts
|
accountResponse = await (await stellarSdk)
|
||||||
|
.accounts
|
||||||
.account((await getCurrentReceivingAddress())!.value)
|
.account((await getCurrentReceivingAddress())!.value)
|
||||||
.onError((error, stackTrace) => throw error!);
|
.onError((error, stackTrace) => throw error!);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -289,7 +370,7 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (stellar.Balance balance in accountResponse.balances) {
|
for (final stellar.Balance balance in accountResponse.balances) {
|
||||||
switch (balance.assetType) {
|
switch (balance.assetType) {
|
||||||
case stellar.Asset.TYPE_NATIVE:
|
case stellar.Asset.TYPE_NATIVE:
|
||||||
final swBalance = Balance(
|
final swBalance = Balance(
|
||||||
|
@ -326,7 +407,8 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
@override
|
@override
|
||||||
Future<void> updateChainHeight() async {
|
Future<void> updateChainHeight() async {
|
||||||
try {
|
try {
|
||||||
final height = await stellarSdk.ledgers
|
final height = await (await stellarSdk)
|
||||||
|
.ledgers
|
||||||
.order(stellar.RequestBuilderOrder.DESC)
|
.order(stellar.RequestBuilderOrder.DESC)
|
||||||
.limit(1)
|
.limit(1)
|
||||||
.execute()
|
.execute()
|
||||||
|
@ -344,7 +426,8 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> updateNode() async {
|
Future<void> updateNode() async {
|
||||||
_updateSdk();
|
_stellarSdk?.httpClient.close();
|
||||||
|
_stellarSdk = _getFreshSdk();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -352,10 +435,11 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
try {
|
try {
|
||||||
final myAddress = (await getCurrentReceivingAddress())!;
|
final myAddress = (await getCurrentReceivingAddress())!;
|
||||||
|
|
||||||
List<TransactionV2> transactionList = [];
|
final List<TransactionV2> transactionList = [];
|
||||||
stellar.Page<stellar.OperationResponse> payments;
|
stellar.Page<stellar.OperationResponse> payments;
|
||||||
try {
|
try {
|
||||||
payments = await stellarSdk.payments
|
payments = await (await stellarSdk)
|
||||||
|
.payments
|
||||||
.forAccount(myAddress.value)
|
.forAccount(myAddress.value)
|
||||||
.order(stellar.RequestBuilderOrder.DESC)
|
.order(stellar.RequestBuilderOrder.DESC)
|
||||||
.execute();
|
.execute();
|
||||||
|
@ -375,7 +459,7 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
rethrow;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (stellar.OperationResponse response in payments.records!) {
|
for (final stellar.OperationResponse response in payments.records!) {
|
||||||
// PaymentOperationResponse por;
|
// PaymentOperationResponse por;
|
||||||
if (response is stellar.PaymentOperationResponse) {
|
if (response is stellar.PaymentOperationResponse) {
|
||||||
final por = response;
|
final por = response;
|
||||||
|
@ -405,7 +489,8 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
final List<OutputV2> outputs = [];
|
final List<OutputV2> outputs = [];
|
||||||
final List<InputV2> inputs = [];
|
final List<InputV2> inputs = [];
|
||||||
|
|
||||||
OutputV2 output = OutputV2.isarCantDoRequiredInDefaultConstructor(
|
final OutputV2 output =
|
||||||
|
OutputV2.isarCantDoRequiredInDefaultConstructor(
|
||||||
scriptPubKeyHex: "00",
|
scriptPubKeyHex: "00",
|
||||||
valueStringSats: amount.raw.toString(),
|
valueStringSats: amount.raw.toString(),
|
||||||
addresses: [
|
addresses: [
|
||||||
|
@ -413,7 +498,7 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
],
|
],
|
||||||
walletOwns: addressTo == myAddress.value,
|
walletOwns: addressTo == myAddress.value,
|
||||||
);
|
);
|
||||||
InputV2 input = InputV2.isarCantDoRequiredInDefaultConstructor(
|
final InputV2 input = InputV2.isarCantDoRequiredInDefaultConstructor(
|
||||||
scriptSigHex: null,
|
scriptSigHex: null,
|
||||||
scriptSigAsm: null,
|
scriptSigAsm: null,
|
||||||
sequence: null,
|
sequence: null,
|
||||||
|
@ -433,8 +518,9 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
int height = 0;
|
int height = 0;
|
||||||
//Query the transaction linked to the payment,
|
//Query the transaction linked to the payment,
|
||||||
// por.transaction returns a null sometimes
|
// por.transaction returns a null sometimes
|
||||||
stellar.TransactionResponse tx =
|
final stellar.TransactionResponse tx = await (await stellarSdk)
|
||||||
await stellarSdk.transactions.transaction(por.transactionHash!);
|
.transactions
|
||||||
|
.transaction(por.transactionHash!);
|
||||||
|
|
||||||
if (tx.hash.isNotEmpty) {
|
if (tx.hash.isNotEmpty) {
|
||||||
fee = tx.feeCharged!;
|
fee = tx.feeCharged!;
|
||||||
|
@ -485,7 +571,8 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
final List<OutputV2> outputs = [];
|
final List<OutputV2> outputs = [];
|
||||||
final List<InputV2> inputs = [];
|
final List<InputV2> inputs = [];
|
||||||
|
|
||||||
OutputV2 output = OutputV2.isarCantDoRequiredInDefaultConstructor(
|
final OutputV2 output =
|
||||||
|
OutputV2.isarCantDoRequiredInDefaultConstructor(
|
||||||
scriptPubKeyHex: "00",
|
scriptPubKeyHex: "00",
|
||||||
valueStringSats: amount.raw.toString(),
|
valueStringSats: amount.raw.toString(),
|
||||||
addresses: [
|
addresses: [
|
||||||
|
@ -494,7 +581,7 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
],
|
],
|
||||||
walletOwns: caor.sourceAccount! == myAddress.value,
|
walletOwns: caor.sourceAccount! == myAddress.value,
|
||||||
);
|
);
|
||||||
InputV2 input = InputV2.isarCantDoRequiredInDefaultConstructor(
|
final InputV2 input = InputV2.isarCantDoRequiredInDefaultConstructor(
|
||||||
scriptSigHex: null,
|
scriptSigHex: null,
|
||||||
scriptSigAsm: null,
|
scriptSigAsm: null,
|
||||||
sequence: null,
|
sequence: null,
|
||||||
|
@ -515,8 +602,9 @@ class StellarWallet extends Bip39Wallet<Stellar> {
|
||||||
|
|
||||||
int fee = 0;
|
int fee = 0;
|
||||||
int height = 0;
|
int height = 0;
|
||||||
final tx =
|
final tx = await (await stellarSdk)
|
||||||
await stellarSdk.transactions.transaction(caor.transactionHash!);
|
.transactions
|
||||||
|
.transaction(caor.transactionHash!);
|
||||||
if (tx.hash.isNotEmpty) {
|
if (tx.hash.isNotEmpty) {
|
||||||
fee = tx.feeCharged!;
|
fee = tx.feeCharged!;
|
||||||
height = tx.ledger;
|
height = tx.ledger;
|
||||||
|
|
|
@ -30,7 +30,6 @@ import 'package:stackwallet/wallets/wallet/wallet.dart';
|
||||||
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
|
import 'package:stackwallet/wallets/wallet/wallet_mixin_interfaces/cw_based_interface.dart';
|
||||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
|
||||||
import 'package:stackwallet/widgets/dialogs/basic_dialog.dart';
|
import 'package:stackwallet/widgets/dialogs/basic_dialog.dart';
|
||||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
|
import 'package:stackwallet/widgets/wallet_info_row/wallet_info_row.dart';
|
||||||
|
@ -95,37 +94,6 @@ class SimpleWalletCard extends ConsumerWidget {
|
||||||
|
|
||||||
final wallet = ref.read(pWallets).getWallet(walletId);
|
final wallet = ref.read(pWallets).getWallet(walletId);
|
||||||
|
|
||||||
// If Tor enabled, show a warning if opening a wallet incompatible with Tor.
|
|
||||||
if (ref.read(prefsChangeNotifierProvider).useTor) {
|
|
||||||
if (!wallet.cryptoCurrency.torSupport) {
|
|
||||||
final shouldContinue = await showDialog<bool>(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => BasicDialog(
|
|
||||||
title: "Warning! Tor not supported.",
|
|
||||||
message: "Stacky is not compatible with Tor."
|
|
||||||
"\n\nBy using it, you will leak your IP address. Are you sure you "
|
|
||||||
"want to continue?",
|
|
||||||
// A PrimaryButton widget:
|
|
||||||
leftButton: PrimaryButton(
|
|
||||||
label: "Cancel",
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop(false);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
rightButton: SecondaryButton(
|
|
||||||
label: "Continue",
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.of(context).pop(true);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)) ??
|
|
||||||
false;
|
|
||||||
if (!shouldContinue) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
final Future<void> loadFuture;
|
final Future<void> loadFuture;
|
||||||
if (wallet is CwBasedInterface) {
|
if (wallet is CwBasedInterface) {
|
||||||
|
|
15
pubspec.lock
15
pubspec.lock
|
@ -1576,7 +1576,7 @@ packages:
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
socks_socket:
|
socks_socket:
|
||||||
dependency: "direct main"
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: master
|
ref: master
|
||||||
|
@ -1588,8 +1588,8 @@ packages:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "packages/solana"
|
path: "packages/solana"
|
||||||
ref: "0ada1f775c2a2c815de640424270a229f5e91e2f"
|
ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
||||||
resolved-ref: "0ada1f775c2a2c815de640424270a229f5e91e2f"
|
resolved-ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
||||||
url: "https://github.com/cypherstack/espresso-cash-public.git"
|
url: "https://github.com/cypherstack/espresso-cash-public.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.30.4"
|
version: "0.30.4"
|
||||||
|
@ -1661,10 +1661,11 @@ packages:
|
||||||
stellar_flutter_sdk:
|
stellar_flutter_sdk:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: stellar_flutter_sdk
|
path: "."
|
||||||
sha256: "4c55b1b6dfbde7f89bba59a422754280715fa3b5726cff5e7eeaed454d2c4b89"
|
ref: eca1d730e952cf6a6d64502f977cfc03876b75d4
|
||||||
url: "https://pub.dev"
|
resolved-ref: eca1d730e952cf6a6d64502f977cfc03876b75d4
|
||||||
source: hosted
|
url: "https://github.com/cypherstack/stellar_flutter_sdk.git"
|
||||||
|
source: git
|
||||||
version: "1.5.3"
|
version: "1.5.3"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
|
|
|
@ -156,11 +156,7 @@ dependencies:
|
||||||
desktop_drop: ^0.4.1
|
desktop_drop: ^0.4.1
|
||||||
nanodart: ^2.0.0
|
nanodart: ^2.0.0
|
||||||
basic_utils: ^5.5.4
|
basic_utils: ^5.5.4
|
||||||
stellar_flutter_sdk: ^1.5.3
|
stellar_flutter_sdk: ^1.7.8
|
||||||
socks_socket:
|
|
||||||
git:
|
|
||||||
url: https://github.com/cypherstack/socks_socket.git
|
|
||||||
ref: master
|
|
||||||
bip340: ^0.2.0
|
bip340: ^0.2.0
|
||||||
# tezart: ^2.0.5
|
# tezart: ^2.0.5
|
||||||
tezart:
|
tezart:
|
||||||
|
@ -180,7 +176,7 @@ dependencies:
|
||||||
solana:
|
solana:
|
||||||
git: # TODO [prio=low]: Revert to official package once Tor support is merged upstream.
|
git: # TODO [prio=low]: Revert to official package once Tor support is merged upstream.
|
||||||
url: https://github.com/cypherstack/espresso-cash-public.git
|
url: https://github.com/cypherstack/espresso-cash-public.git
|
||||||
ref: 0ada1f775c2a2c815de640424270a229f5e91e2f
|
ref: a83e375678eb22fe544dc125d29bbec0fb833882
|
||||||
path: packages/solana
|
path: packages/solana
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
Loading…
Reference in a new issue