diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index e716b930ca..a8f387d3ee 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -48,6 +48,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Set version id: ver run: | @@ -125,6 +131,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Set version id: ver run: | @@ -252,7 +264,7 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -371,7 +383,7 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -453,7 +465,7 @@ jobs: toolchain: stable targets: aarch64-apple-ios - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -521,6 +533,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Set version id: ver run: | @@ -585,6 +603,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Set version id: ver run: | @@ -766,6 +790,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Set version id: ver run: | @@ -880,7 +910,7 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -895,8 +925,8 @@ jobs: - name: Install Rust toolchains run: | rustup toolchain install 1.85.1 - rustup toolchain install 1.89.0 - rustup default 1.89.0 + rustup toolchain install 1.91.0 + rustup default 1.91.0 - name: Configure app run: | @@ -969,7 +999,7 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -981,8 +1011,8 @@ jobs: - name: Install Rust toolchains run: | rustup toolchain install 1.85.1 - rustup toolchain install 1.89.0 - rustup default 1.89.0 + rustup toolchain install 1.91.0 + rustup default 1.91.0 - name: Configure app run: | @@ -1044,7 +1074,7 @@ jobs: toolchain: stable targets: aarch64-apple-ios - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -1056,10 +1086,10 @@ jobs: - name: Install additional Rust toolchains run: | rustup toolchain install 1.85.1 - rustup toolchain install 1.89.0 - rustup default 1.89.0 - rustup target add aarch64-apple-ios --toolchain 1.89.0 - rustup target add x86_64-apple-ios --toolchain 1.89.0 + rustup toolchain install 1.91.0 + rustup default 1.91.0 + rustup target add aarch64-apple-ios --toolchain 1.91.0 + rustup target add x86_64-apple-ios --toolchain 1.91.0 - name: Configure app run: | @@ -1224,6 +1254,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Set version id: ver run: | @@ -1338,7 +1374,7 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -1353,8 +1389,8 @@ jobs: - name: Install Rust toolchains run: | rustup toolchain install 1.85.1 - rustup toolchain install 1.89.0 - rustup default 1.89.0 + rustup toolchain install 1.91.0 + rustup default 1.91.0 - name: Configure app run: | @@ -1427,7 +1463,7 @@ jobs: echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "build_number=${BUILD_NUMBER}" >> $GITHUB_OUTPUT - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -1439,9 +1475,9 @@ jobs: - name: Install Rust toolchains run: | rustup toolchain install 1.85.1 - rustup toolchain install 1.89.0 - rustup default 1.89.0 - rustup target add aarch64-apple-darwin --toolchain 1.89.0 + rustup toolchain install 1.91.0 + rustup default 1.91.0 + rustup target add aarch64-apple-darwin --toolchain 1.91.0 cargo install cargo-lipo - name: Configure app @@ -1504,7 +1540,7 @@ jobs: toolchain: stable targets: aarch64-apple-ios - - uses: subosito/flutter-action@v2 + - uses: subosito/flutter-action@1a449444c387b1966244ae4d4f8c696479add0b2 # v2 with: flutter-version: '3.44.8' channel: 'stable' @@ -1516,10 +1552,10 @@ jobs: - name: Install additional Rust toolchains run: | rustup toolchain install 1.85.1 - rustup toolchain install 1.89.0 - rustup default 1.89.0 - rustup target add aarch64-apple-ios --toolchain 1.89.0 - rustup target add x86_64-apple-ios --toolchain 1.89.0 + rustup toolchain install 1.91.0 + rustup default 1.91.0 + rustup target add aarch64-apple-ios --toolchain 1.91.0 + rustup target add x86_64-apple-ios --toolchain 1.91.0 - name: Configure app run: | @@ -1667,4 +1703,3 @@ jobs: with: name: stack_duo-appimage-x86_64-${{ steps.ver.outputs.version }}.AppImage path: stack_duo-appimage-x86_64-${{ steps.ver.outputs.version }}.AppImage - diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index eca0145f8b..a855d00719 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -18,6 +18,12 @@ jobs: fetch-depth: 0 submodules: recursive + - name: Use Flutter 3.44.8 + run: | + git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 + flutter --version + - name: Configure app run: | cd scripts @@ -56,6 +62,10 @@ jobs: const kShopInBitPartnerSecret = ""; const kCakePayApiToken = ""; const kExolixApiKey = ""; + const kLetsExchangeId = ""; + const kLetsExchangeToken = ""; + const kCypherGoatApiKey = ""; + const kCypherGoatAffiliate = ""; EOF fi diff --git a/Dockerfile b/Dockerfile index 72e8cd3e2c..217fe2da4b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,9 +32,9 @@ ENV RUSTUP_HOME=/usr/local/rustup \ PATH=/usr/local/cargo/bin:$PATH RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ - | sh -s -- -y --default-toolchain 1.89.0 --profile minimal --no-modify-path \ + | sh -s -- -y --default-toolchain 1.91.0 --profile minimal --no-modify-path \ && rustup install 1.85.1 1.71.0 stable --profile minimal \ - && rustup target add x86_64-unknown-linux-gnu --toolchain 1.89.0 \ + && rustup target add x86_64-unknown-linux-gnu --toolchain 1.91.0 \ && cargo install cargo-ndk \ && chmod -R a+rwX "$CARGO_HOME" "$RUSTUP_HOME" @@ -83,7 +83,11 @@ RUN curl -fsSL https://go.dev/dl/go1.24.13.linux-amd64.tar.gz -o /tmp/go.tar.gz ENV FLUTTER_HOME=/opt/flutter \ PATH=/opt/flutter/bin:/opt/flutter/bin/cache/dart-sdk/bin:$PATH -RUN git clone --depth 1 --branch 3.44.8 https://github.com/flutter/flutter.git "$FLUTTER_HOME" \ +RUN git init "$FLUTTER_HOME" \ + && git -C "$FLUTTER_HOME" remote add origin https://github.com/flutter/flutter.git \ + && git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ + && git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ + && git -C "$FLUTTER_HOME" tag 3.44.8 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ && git config --global --add safe.directory '*' \ && flutter config --no-analytics \ && flutter precache --linux --android \ @@ -116,10 +120,10 @@ ENV RUSTUP_HOME=/usr/local/rustup \ PATH=/usr/local/cargo/bin:$PATH RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ - | sh -s -- -y --default-toolchain 1.89.0 --profile minimal --no-modify-path \ + | sh -s -- -y --default-toolchain 1.91.0 --profile minimal --no-modify-path \ && rustup target add \ aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android \ - --toolchain 1.89.0 \ + --toolchain 1.91.0 \ && cargo install cargo-ndk \ && chmod -R a+rwX "$CARGO_HOME" "$RUSTUP_HOME" @@ -168,7 +172,11 @@ RUN curl -fsSL https://go.dev/dl/go1.24.13.linux-amd64.tar.gz -o /tmp/go.tar.gz ENV FLUTTER_HOME=/opt/flutter \ PATH=/opt/flutter/bin:/opt/flutter/bin/cache/dart-sdk/bin:$PATH -RUN git clone --depth 1 --branch 3.44.8 https://github.com/flutter/flutter.git "$FLUTTER_HOME" \ +RUN git init "$FLUTTER_HOME" \ + && git -C "$FLUTTER_HOME" remote add origin https://github.com/flutter/flutter.git \ + && git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ + && git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ + && git -C "$FLUTTER_HOME" tag 3.44.8 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ && git config --global --add safe.directory '*' \ && flutter config --no-analytics \ && flutter precache --android \ @@ -200,7 +208,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ENV FLUTTER_HOME=/opt/flutter \ PATH=/opt/flutter/bin:/opt/flutter/bin/cache/dart-sdk/bin:$PATH -RUN git clone --depth 1 --branch 3.44.8 https://github.com/flutter/flutter.git "$FLUTTER_HOME" \ +RUN git init "$FLUTTER_HOME" \ + && git -C "$FLUTTER_HOME" remote add origin https://github.com/flutter/flutter.git \ + && git -C "$FLUTTER_HOME" fetch --depth 1 origin 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ + && git -C "$FLUTTER_HOME" checkout --detach 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ + && git -C "$FLUTTER_HOME" tag 3.44.8 058e0af2c2b57e369d905a03ac9748b0ebf543c6 \ && git config --global --add safe.directory '*' \ && flutter config --no-analytics \ && flutter precache --linux \ diff --git a/docs/building.md b/docs/building.md index af2d328a94..f2ba2c7b44 100644 --- a/docs/building.md +++ b/docs/building.md @@ -14,7 +14,7 @@ Here you will find instructions on how to install the necessary tools for buildi 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 -Install Flutter 3.38.5 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). Run `flutter doctor` in a terminal to confirm its installation. +Install Flutter 3.44.8 by [following their guide](https://docs.flutter.dev/get-started/install/linux/desktop?tab=download#install-the-flutter-sdk). Run `flutter doctor` in a terminal to confirm its installation. ### Android Studio Install Android Studio. Follow instructions here [https://developer.android.com/studio/install#linux](https://developer.android.com/studio/install#linux) or install via snap: @@ -51,8 +51,8 @@ Install [Rust](https://www.rust-lang.org/tools/install) via [rustup.rs](https:// ``` curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh source ~/.bashrc -rustup install 1.89.0 1.85.1 1.81.0 -rustup default 1.89.0 +rustup install 1.91.0 1.85.1 1.81.0 +rustup default 1.91.0 cargo install cargo-ndk ``` @@ -69,7 +69,7 @@ pip3 install --upgrade meson==0.64.1 markdown==3.4.1 markupsafe==2.1.1 jinja2==3 ``` ### Flutter -Install Flutter 3.38.5 by [following their guide](https://docs.flutter.dev/install/manual). +Install Flutter 3.44.8 by [following their guide](https://docs.flutter.dev/install/manual). Run `flutter doctor` in a terminal to confirm its installation. @@ -206,12 +206,12 @@ brew install brotli cairo coreutils gdbm gettext glib gmp libevent libidn2 libng ``` -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.81.0, 1.85.1, and 1.89.0 as well as `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): +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.81.0, 1.85.1, and 1.91.0 as well as `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.89.0 1.85.1 1.81.0 -rustup default 1.89.0 +rustup install 1.91.0 1.85.1 1.81.0 +rustup default 1.91.0 cargo install cargo-ndk cargo install cbindgen cargo-lipo rustup target add aarch64-apple-ios aarch64-apple-darwin @@ -220,7 +220,7 @@ 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 3.38.5 on your Mac host by [following their guide](https://docs.flutter.dev/install/manual). Run `flutter doctor` in a terminal to confirm its installation. +Install 3.44.8 on your Mac host by [following their guide](https://docs.flutter.dev/install/manual). Run `flutter doctor` in a terminal to confirm its installation. ### Build plugins and configure #### Building plugins for iOS @@ -302,13 +302,13 @@ If the DLLs were built on the WSL filesystem instead of on Windows, copy the res Frostdart will be built by the Windows host later. ### Install Flutter on Windows host -Install Flutter 3.38.5 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/install/manual). Run `flutter doctor` in PowerShell to confirm its installation. +Install Flutter 3.44.8 on your Windows host (not in WSL2) by [following their guide](https://docs.flutter.dev/install/manual). 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.89.0 1.85.1 1.81.0 -rustup default 1.89.0 +rustup install 1.91.0 1.85.1 1.81.0 +rustup default 1.91.0 cargo install cargo-ndk ``` diff --git a/lib/hive_registrar.g.dart b/lib/hive_registrar.g.dart new file mode 100644 index 0000000000..65261eb4aa --- /dev/null +++ b/lib/hive_registrar.g.dart @@ -0,0 +1,27 @@ +// Generated by Hive CE +// Do not modify +// Check in to version control + +import 'package:hive_ce/hive_ce.dart'; +import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart'; +import 'package:stackwallet/models/exchange/response_objects/trade.dart'; +import 'package:stackwallet/models/mwcmqs_config_model.dart'; +import 'package:stackwallet/models/mwcmqs_server_model.dart'; + +extension HiveRegistrar on HiveInterface { + void registerAdapters() { + registerAdapter(ExchangeTransactionStatusAdapter()); + registerAdapter(MwcMqsConfigModelAdapter()); + registerAdapter(MwcMqsServerModelAdapter()); + registerAdapter(TradeAdapter()); + } +} + +extension IsolatedHiveRegistrar on IsolatedHiveInterface { + void registerAdapters() { + registerAdapter(ExchangeTransactionStatusAdapter()); + registerAdapter(MwcMqsConfigModelAdapter()); + registerAdapter(MwcMqsServerModelAdapter()); + registerAdapter(TradeAdapter()); + } +} diff --git a/lib/models/isar/exchange_cache/currency.g.dart b/lib/models/isar/exchange_cache/currency.g.dart index 20865c68c6..b450b3f68f 100644 --- a/lib/models/isar/exchange_cache/currency.g.dart +++ b/lib/models/isar/exchange_cache/currency.g.dart @@ -117,7 +117,7 @@ const CurrencySchema = CollectionSchema( getId: _currencyGetId, getLinks: _currencyGetLinks, attach: _currencyAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _currencyEstimateSize( diff --git a/lib/models/isar/exchange_cache/pair.g.dart b/lib/models/isar/exchange_cache/pair.g.dart index 81479ec618..2d25e5a541 100644 --- a/lib/models/isar/exchange_cache/pair.g.dart +++ b/lib/models/isar/exchange_cache/pair.g.dart @@ -82,7 +82,7 @@ const PairSchema = CollectionSchema( getId: _pairGetId, getLinks: _pairGetLinks, attach: _pairAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _pairEstimateSize( diff --git a/lib/models/isar/models/address_label.g.dart b/lib/models/isar/models/address_label.g.dart index 077359ac8c..803b5f579f 100644 --- a/lib/models/isar/models/address_label.g.dart +++ b/lib/models/isar/models/address_label.g.dart @@ -75,7 +75,7 @@ const AddressLabelSchema = CollectionSchema( getId: _addressLabelGetId, getLinks: _addressLabelGetLinks, attach: _addressLabelAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _addressLabelEstimateSize( diff --git a/lib/models/isar/models/block_explorer.g.dart b/lib/models/isar/models/block_explorer.g.dart index 4265524c41..09258dca60 100644 --- a/lib/models/isar/models/block_explorer.g.dart +++ b/lib/models/isar/models/block_explorer.g.dart @@ -48,7 +48,7 @@ const TransactionBlockExplorerSchema = CollectionSchema( getId: _transactionBlockExplorerGetId, getLinks: _transactionBlockExplorerGetLinks, attach: _transactionBlockExplorerAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _transactionBlockExplorerEstimateSize( diff --git a/lib/models/isar/models/blockchain_data/address.g.dart b/lib/models/isar/models/blockchain_data/address.g.dart index 2878d16402..6bd5857045 100644 --- a/lib/models/isar/models/blockchain_data/address.g.dart +++ b/lib/models/isar/models/blockchain_data/address.g.dart @@ -128,7 +128,7 @@ const AddressSchema = CollectionSchema( getId: _addressGetId, getLinks: _addressGetLinks, attach: _addressAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _addressEstimateSize( diff --git a/lib/models/isar/models/blockchain_data/transaction.g.dart b/lib/models/isar/models/blockchain_data/transaction.g.dart index c87673a99a..32de2b9bc3 100644 --- a/lib/models/isar/models/blockchain_data/transaction.g.dart +++ b/lib/models/isar/models/blockchain_data/transaction.g.dart @@ -151,7 +151,7 @@ const TransactionSchema = CollectionSchema( getId: _transactionGetId, getLinks: _transactionGetLinks, attach: _transactionAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _transactionEstimateSize( diff --git a/lib/models/isar/models/blockchain_data/utxo.g.dart b/lib/models/isar/models/blockchain_data/utxo.g.dart index b338040982..1d8cee5043 100644 --- a/lib/models/isar/models/blockchain_data/utxo.g.dart +++ b/lib/models/isar/models/blockchain_data/utxo.g.dart @@ -127,7 +127,7 @@ const UTXOSchema = CollectionSchema( getId: _uTXOGetId, getLinks: _uTXOGetLinks, attach: _uTXOAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _uTXOEstimateSize( diff --git a/lib/models/isar/models/blockchain_data/v2/transaction_v2.g.dart b/lib/models/isar/models/blockchain_data/v2/transaction_v2.g.dart index c604f36f7c..37b2df0af9 100644 --- a/lib/models/isar/models/blockchain_data/v2/transaction_v2.g.dart +++ b/lib/models/isar/models/blockchain_data/v2/transaction_v2.g.dart @@ -157,7 +157,7 @@ const TransactionV2Schema = CollectionSchema( getId: _transactionV2GetId, getLinks: _transactionV2GetLinks, attach: _transactionV2Attach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _transactionV2EstimateSize( diff --git a/lib/models/isar/models/contact_entry.g.dart b/lib/models/isar/models/contact_entry.g.dart index 99b745c3a7..699565528f 100644 --- a/lib/models/isar/models/contact_entry.g.dart +++ b/lib/models/isar/models/contact_entry.g.dart @@ -68,7 +68,7 @@ const ContactEntrySchema = CollectionSchema( getId: _contactEntryGetId, getLinks: _contactEntryGetLinks, attach: _contactEntryAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _contactEntryEstimateSize( diff --git a/lib/models/isar/models/encrypted_string_value.g.dart b/lib/models/isar/models/encrypted_string_value.g.dart index 2b99600117..6af468faf8 100644 --- a/lib/models/isar/models/encrypted_string_value.g.dart +++ b/lib/models/isar/models/encrypted_string_value.g.dart @@ -48,7 +48,7 @@ const EncryptedStringValueSchema = CollectionSchema( getId: _encryptedStringValueGetId, getLinks: _encryptedStringValueGetLinks, attach: _encryptedStringValueAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _encryptedStringValueEstimateSize( diff --git a/lib/models/isar/models/ethereum/eth_contract.g.dart b/lib/models/isar/models/ethereum/eth_contract.g.dart index b5b3aadbc2..8933e27e81 100644 --- a/lib/models/isar/models/ethereum/eth_contract.g.dart +++ b/lib/models/isar/models/ethereum/eth_contract.g.dart @@ -56,7 +56,7 @@ const EthContractSchema = CollectionSchema( getId: _ethContractGetId, getLinks: _ethContractGetLinks, attach: _ethContractAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _ethContractEstimateSize( diff --git a/lib/models/isar/models/log.g.dart b/lib/models/isar/models/log.g.dart index 358c9c6b15..65a8c75059 100644 --- a/lib/models/isar/models/log.g.dart +++ b/lib/models/isar/models/log.g.dart @@ -57,7 +57,7 @@ const LogSchema = CollectionSchema( getId: _logGetId, getLinks: _logGetLinks, attach: _logAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _logEstimateSize( diff --git a/lib/models/isar/models/sent_to_address.g.dart b/lib/models/isar/models/sent_to_address.g.dart index 354b03038e..f43267deb7 100644 --- a/lib/models/isar/models/sent_to_address.g.dart +++ b/lib/models/isar/models/sent_to_address.g.dart @@ -71,7 +71,7 @@ const SentToAddressSchema = CollectionSchema( getId: _sentToAddressGetId, getLinks: _sentToAddressGetLinks, attach: _sentToAddressAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _sentToAddressEstimateSize( diff --git a/lib/models/isar/models/solana/sol_contract.g.dart b/lib/models/isar/models/solana/sol_contract.g.dart index b75906e254..79a2a1948a 100644 --- a/lib/models/isar/models/solana/sol_contract.g.dart +++ b/lib/models/isar/models/solana/sol_contract.g.dart @@ -55,7 +55,7 @@ const SolContractSchema = CollectionSchema( getId: _solContractGetId, getLinks: _solContractGetLinks, attach: _solContractAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _solContractEstimateSize( diff --git a/lib/models/isar/models/transaction_note.g.dart b/lib/models/isar/models/transaction_note.g.dart index 9a16ae190c..76f39a5ade 100644 --- a/lib/models/isar/models/transaction_note.g.dart +++ b/lib/models/isar/models/transaction_note.g.dart @@ -70,7 +70,7 @@ const TransactionNoteSchema = CollectionSchema( getId: _transactionNoteGetId, getLinks: _transactionNoteGetLinks, attach: _transactionNoteAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _transactionNoteEstimateSize( diff --git a/lib/models/isar/ordinal.g.dart b/lib/models/isar/ordinal.g.dart index 09ba404340..f1da74039c 100644 --- a/lib/models/isar/ordinal.g.dart +++ b/lib/models/isar/ordinal.g.dart @@ -77,7 +77,7 @@ const OrdinalSchema = CollectionSchema( getId: _ordinalGetId, getLinks: _ordinalGetLinks, attach: _ordinalAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _ordinalEstimateSize( diff --git a/lib/models/isar/stack_theme.g.dart b/lib/models/isar/stack_theme.g.dart index 71f51800fa..adeb670265 100644 --- a/lib/models/isar/stack_theme.g.dart +++ b/lib/models/isar/stack_theme.g.dart @@ -857,7 +857,7 @@ const StackThemeSchema = CollectionSchema( getId: _stackThemeGetId, getLinks: _stackThemeGetLinks, attach: _stackThemeAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _stackThemeEstimateSize( diff --git a/lib/wallets/isar/models/frost_wallet_info.g.dart b/lib/wallets/isar/models/frost_wallet_info.g.dart index 459bff7e17..f2c0c9bbdb 100644 --- a/lib/wallets/isar/models/frost_wallet_info.g.dart +++ b/lib/wallets/isar/models/frost_wallet_info.g.dart @@ -66,7 +66,7 @@ const FrostWalletInfoSchema = CollectionSchema( getId: _frostWalletInfoGetId, getLinks: _frostWalletInfoGetLinks, attach: _frostWalletInfoAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _frostWalletInfoEstimateSize( diff --git a/lib/wallets/isar/models/spark_coin.g.dart b/lib/wallets/isar/models/spark_coin.g.dart index adbb522c6b..f41cab69bb 100644 --- a/lib/wallets/isar/models/spark_coin.g.dart +++ b/lib/wallets/isar/models/spark_coin.g.dart @@ -110,7 +110,7 @@ const SparkCoinSchema = CollectionSchema( getId: _sparkCoinGetId, getLinks: _sparkCoinGetLinks, attach: _sparkCoinAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _sparkCoinEstimateSize( diff --git a/lib/wallets/isar/models/token_wallet_info.g.dart b/lib/wallets/isar/models/token_wallet_info.g.dart index 7e07112243..d64cc4872e 100644 --- a/lib/wallets/isar/models/token_wallet_info.g.dart +++ b/lib/wallets/isar/models/token_wallet_info.g.dart @@ -70,7 +70,7 @@ const TokenWalletInfoSchema = CollectionSchema( getId: _tokenWalletInfoGetId, getLinks: _tokenWalletInfoGetLinks, attach: _tokenWalletInfoAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _tokenWalletInfoEstimateSize( diff --git a/lib/wallets/isar/models/wallet_info.g.dart b/lib/wallets/isar/models/wallet_info.g.dart index 1db7d04fcf..0667a4feb0 100644 --- a/lib/wallets/isar/models/wallet_info.g.dart +++ b/lib/wallets/isar/models/wallet_info.g.dart @@ -112,7 +112,7 @@ const WalletInfoSchema = CollectionSchema( getId: _walletInfoGetId, getLinks: _walletInfoGetLinks, attach: _walletInfoAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _walletInfoEstimateSize( diff --git a/lib/wallets/isar/models/wallet_info_meta.g.dart b/lib/wallets/isar/models/wallet_info_meta.g.dart index 4ec63249e3..9bf7a93c6e 100644 --- a/lib/wallets/isar/models/wallet_info_meta.g.dart +++ b/lib/wallets/isar/models/wallet_info_meta.g.dart @@ -55,7 +55,7 @@ const WalletInfoMetaSchema = CollectionSchema( getId: _walletInfoMetaGetId, getLinks: _walletInfoMetaGetLinks, attach: _walletInfoMetaAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _walletInfoMetaEstimateSize( diff --git a/lib/wallets/isar/models/wallet_solana_token_info.g.dart b/lib/wallets/isar/models/wallet_solana_token_info.g.dart index bd83700810..d4e1c7f9a8 100644 --- a/lib/wallets/isar/models/wallet_solana_token_info.g.dart +++ b/lib/wallets/isar/models/wallet_solana_token_info.g.dart @@ -71,7 +71,7 @@ const WalletSolanaTokenInfoSchema = CollectionSchema( getId: _walletSolanaTokenInfoGetId, getLinks: _walletSolanaTokenInfoGetLinks, attach: _walletSolanaTokenInfoAttach, - version: '3.3.0-dev.2', + version: '3.3.2', ); int _walletSolanaTokenInfoEstimateSize( diff --git a/lib/wallets/wallet/impl/xelis_transaction_mapper.dart b/lib/wallets/wallet/impl/xelis_transaction_mapper.dart new file mode 100644 index 0000000000..009f880b3b --- /dev/null +++ b/lib/wallets/wallet/impl/xelis_transaction_mapper.dart @@ -0,0 +1,237 @@ +import 'dart:convert'; + +import '../../../models/isar/models/blockchain_data/transaction.dart'; +import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; +import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; +import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; +import '../../../utilities/amount/amount.dart'; +import '../../../wl_gen/interfaces/lib_xelis_interface.dart'; + +TransactionV2 mapXelisTransactionEntry({ + required TransactionEntryWrapper transactionEntry, + required String walletId, + required String walletAddress, + required int fractionDigits, +}) { + final inputs = []; + final outputs = []; + final otherData = {}; + final entry = transactionEntry.entryType; + + InputV2 walletInput(int value) => + InputV2.isarCantDoRequiredInDefaultConstructor( + scriptSigHex: null, + scriptSigAsm: null, + sequence: null, + outpoint: null, + addresses: [walletAddress], + valueStringSats: value.toString(), + witness: null, + innerRedeemScriptAsm: null, + coinbase: null, + walletOwns: true, + ); + + OutputV2 output(int value, String address, {required bool walletOwns}) => + OutputV2.isarCantDoRequiredInDefaultConstructor( + scriptPubKeyHex: '', + valueStringSats: value.toString(), + addresses: [address], + walletOwns: walletOwns, + ); + + void setFee(int fee) { + otherData['overrideFee'] = Amount( + rawValue: BigInt.from(fee), + fractionDigits: fractionDigits, + ).toJsonString(); + } + + void addIncomingContractTransfers(Map> transfers) { + for (final contractEntry in transfers.entries) { + for (final assetEntry in contractEntry.value.entries) { + outputs.add(output(assetEntry.value, walletAddress, walletOwns: true)); + } + } + } + + final TransactionType transactionType; + int? nonce; + + switch (entry) { + case CoinbaseEntryWrapper(:final reward): + transactionType = TransactionType.incoming; + outputs.add(output(reward, walletAddress, walletOwns: true)); + otherData['xelisEntryType'] = 'coinbase'; + setFee(0); + + case BurnEntryWrapper(:final amount, :final fee, :final asset): + transactionType = TransactionType.outgoing; + nonce = entry.nonce; + inputs.add(walletInput(amount + fee)); + outputs.add(output(amount, 'burn', walletOwns: false)); + otherData['xelisEntryType'] = 'burn'; + otherData['burnAsset'] = asset; + setFee(fee); + + case IncomingEntryWrapper(:final from, :final transfers): + transactionType = from == walletAddress + ? TransactionType.sentToSelf + : TransactionType.incoming; + for (final transfer in transfers) { + outputs.add(output(transfer.amount, walletAddress, walletOwns: true)); + otherData['asset_${transfer.asset}'] = transfer.amount.toString(); + if (transfer.extraData != null) { + otherData['extraData_${transfer.asset}'] = transfer.extraData; + } + } + otherData['xelisEntryType'] = 'incoming'; + otherData['from'] = from; + setFee(0); + + case OutgoingEntryWrapper(:final fee, :final transfers): + transactionType = TransactionType.outgoing; + nonce = entry.nonce; + inputs.add(walletInput(fee)); + for (final transfer in transfers) { + inputs.add(walletInput(transfer.amount)); + outputs.add( + output(transfer.amount, transfer.destination, walletOwns: false), + ); + otherData['asset_${transfer.asset}_amount'] = transfer.amount + .toString(); + if (transfer.extraData != null) { + otherData['extraData_${transfer.asset}'] = transfer.extraData; + } + } + otherData['xelisEntryType'] = 'outgoing'; + setFee(fee); + + case MultisigEntryWrapper( + :final participants, + :final threshold, + :final fee, + ): + transactionType = TransactionType.outgoing; + nonce = entry.nonce; + inputs.add(walletInput(fee)); + for (final participant in participants) { + outputs.add(output(0, participant, walletOwns: false)); + } + otherData['xelisEntryType'] = 'multisig'; + otherData['participants'] = participants; + otherData['threshold'] = threshold; + setFee(fee); + + case InvokeContractEntryWrapper( + :final contract, + :final deposits, + :final received, + :final chunkId, + :final fee, + :final maxGas, + ): + transactionType = TransactionType.outgoing; + nonce = entry.nonce; + inputs.add(walletInput(fee)); + for (final deposit in deposits.entries) { + inputs.add(walletInput(deposit.value)); + outputs.add(output(deposit.value, contract, walletOwns: false)); + } + addIncomingContractTransfers(received); + otherData['xelisEntryType'] = 'invokeContract'; + otherData['contract'] = contract; + otherData['deposits'] = deposits; + otherData['received'] = received; + otherData['chunkId'] = chunkId; + otherData['maxGas'] = maxGas; + setFee(fee); + + case DeployContractEntryWrapper(:final fee, :final invoke): + transactionType = TransactionType.outgoing; + nonce = entry.nonce; + inputs.add(walletInput(fee)); + if (invoke != null) { + for (final deposit in invoke.deposits.entries) { + inputs.add(walletInput(deposit.value)); + outputs.add( + output(deposit.value, 'contract-deployment', walletOwns: false), + ); + } + } + otherData['xelisEntryType'] = 'deployContract'; + if (invoke != null) { + otherData['invoke'] = { + 'maxGas': invoke.maxGas, + 'deposits': invoke.deposits, + }; + } + setFee(fee); + + case IncomingContractEntryWrapper(:final transfers): + transactionType = TransactionType.incoming; + addIncomingContractTransfers(transfers); + otherData['xelisEntryType'] = 'incomingContract'; + otherData['transfers'] = transfers; + setFee(0); + + case OutgoingBlobEntryWrapper(:final destinations, :final fee, :final data): + transactionType = TransactionType.outgoing; + nonce = entry.nonce; + inputs.add(walletInput(fee)); + for (final destination in destinations) { + outputs.add(output(0, destination, walletOwns: false)); + } + otherData['xelisEntryType'] = 'outgoingBlob'; + otherData['destinations'] = destinations; + otherData['data'] = data; + setFee(fee); + + case IncomingBlobEntryWrapper( + :final from, + :final destinations, + :final data, + ): + transactionType = from == walletAddress + ? TransactionType.sentToSelf + : TransactionType.incoming; + for (final destination in destinations) { + outputs.add( + output(0, destination, walletOwns: destination == walletAddress), + ); + } + otherData['xelisEntryType'] = 'incomingBlob'; + otherData['from'] = from; + otherData['destinations'] = destinations; + otherData['data'] = data; + setFee(0); + + case UnknownEntryWrapper(:final entryType, :final data): + transactionType = TransactionType.unknown; + otherData['xelisEntryType'] = entryType; + if (data != null) { + otherData['data'] = data; + } + setFee(0); + } + + if (nonce != null) { + otherData['nonce'] = nonce; + } + + return TransactionV2( + walletId: walletId, + blockHash: '', + hash: transactionEntry.hash, + txid: transactionEntry.hash, + timestamp: + (transactionEntry.timestamp?.millisecondsSinceEpoch ?? 0) ~/ 1000, + height: transactionEntry.topoheight, + inputs: List.unmodifiable(inputs), + outputs: List.unmodifiable(outputs), + version: -1, + type: transactionType, + subType: TransactionSubType.none, + otherData: jsonEncode(otherData), + ); +} diff --git a/lib/wallets/wallet/impl/xelis_wallet.dart b/lib/wallets/wallet/impl/xelis_wallet.dart index 66b551bb8e..20f42591d8 100644 --- a/lib/wallets/wallet/impl/xelis_wallet.dart +++ b/lib/wallets/wallet/impl/xelis_wallet.dart @@ -8,9 +8,6 @@ import 'package:stack_wallet_backup/generate_password.dart'; import '../../../models/balance.dart'; import '../../../models/isar/models/blockchain_data/address.dart'; -import '../../../models/isar/models/blockchain_data/transaction.dart'; -import '../../../models/isar/models/blockchain_data/v2/input_v2.dart'; -import '../../../models/isar/models/blockchain_data/v2/output_v2.dart'; import '../../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; import '../../../models/paymint/fee_object_model.dart'; import '../../../services/event_bus/events/global/wallet_sync_status_changed_event.dart'; @@ -23,6 +20,10 @@ import '../../crypto_currency/crypto_currency.dart'; import '../../models/tx_data.dart'; import '../intermediate/lib_xelis_wallet.dart'; import '../wallet.dart'; +import 'xelis_transaction_mapper.dart'; + +const _defaultFeeEstimateAddress = + 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m'; class XelisWallet extends LibXelisWallet { Completer? _initCompleter; @@ -57,7 +58,7 @@ class XelisWallet extends LibXelisWallet { seed: mnemonic, network: cryptoCurrency.network, precomputedTablesPath: tablePath, - stack_l1Low: tableState.currentSize.isLow, + stackL1Low: tableState.currentSize.isLow, ); await secureStorageInterface.write( @@ -91,7 +92,7 @@ class XelisWallet extends LibXelisWallet { password: password, network: cryptoCurrency.network, precomputedTablesPath: tablePath, - stack_l1Low: tableState.currentSize.isLow, + stackL1Low: tableState.currentSize.isLow, ); final mnemonic = await libXelis.getSeed(wallet); @@ -123,7 +124,7 @@ class XelisWallet extends LibXelisWallet { password: password!, network: cryptoCurrency.network, precomputedTablesPath: tablePath, - stack_l1Low: tableState.currentSize.isLow, + stackL1Low: tableState.currentSize.isLow, ); await _finishInit(); @@ -381,191 +382,11 @@ class XelisWallet extends LibXelisWallet { continue; // Skip already processed transactions } - final List outputs = []; - final List inputs = []; - TransactionType? txType; - const TransactionSubType txSubType = TransactionSubType.none; - int? nonce; - Amount fee = Amount( - rawValue: BigInt.zero, - fractionDigits: cryptoCurrency.fractionDigits, - ); - final Map otherData = {}; - - final entryType = transactionEntry.entryType; - - if (entryType is CoinbaseEntryWrapper) { - final coinbase = entryType; - txType = TransactionType.incoming; - - final int decimals = await libXelis.getAssetDecimals( - wallet!, - asset: libXelis.xelisAsset, - ); - - fee = Amount( - rawValue: BigInt.zero, - fractionDigits: cryptoCurrency.fractionDigits, - ); - - outputs.add( - OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "", - valueStringSats: coinbase.reward.toString(), - addresses: [thisAddress], - walletOwns: true, - ), - ); - otherData['overrideFee'] = fee.toJsonString(); - } else if (entryType is BurnEntryWrapper) { - final burn = entryType; - txType = TransactionType.outgoing; - - final int decimals = await libXelis.getAssetDecimals( - wallet!, - asset: burn.asset, - ); - - fee = Amount( - rawValue: BigInt.from(burn.fee), - fractionDigits: cryptoCurrency.fractionDigits, - ); - - inputs.add( - InputV2.isarCantDoRequiredInDefaultConstructor( - scriptSigAsm: null, - scriptSigHex: null, - sequence: null, - outpoint: null, - valueStringSats: burn.amount.toString(), - addresses: [thisAddress], - witness: null, - innerRedeemScriptAsm: null, - coinbase: null, - walletOwns: true, - ), - ); - - outputs.add( - OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "", - valueStringSats: burn.amount.toString(), - addresses: ['burn'], - walletOwns: false, - ), - ); - - otherData['burnAsset'] = burn.asset; - } else if (entryType is IncomingEntryWrapper) { - final incoming = entryType; - txType = incoming.from == thisAddress - ? TransactionType.sentToSelf - : TransactionType.incoming; - - for (final transfer in incoming.transfers) { - final int decimals = await libXelis.getAssetDecimals( - wallet!, - asset: transfer.asset, - ); - - fee = Amount( - rawValue: BigInt.zero, - fractionDigits: cryptoCurrency.fractionDigits, - ); - - outputs.add( - OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "", - valueStringSats: transfer.amount.toString(), - addresses: [thisAddress], - walletOwns: true, - ), - ); - - otherData['asset_${transfer.asset}'] = transfer.amount.toString(); - if (transfer.extraData != null) { - otherData['extraData_${transfer.asset}'] = transfer.extraData!; - } - otherData['overrideFee'] = fee.toJsonString(); - } - } else if (entryType is OutgoingEntryWrapper) { - final outgoing = entryType; - txType = TransactionType.outgoing; - nonce = outgoing.nonce; - - fee = Amount( - rawValue: BigInt.from(outgoing.fee), - fractionDigits: cryptoCurrency.fractionDigits, - ); - - inputs.add( - InputV2.isarCantDoRequiredInDefaultConstructor( - scriptSigHex: null, - scriptSigAsm: null, - sequence: null, - outpoint: null, - addresses: [thisAddress], - valueStringSats: (outgoing.fee).toString(), - witness: null, - innerRedeemScriptAsm: null, - coinbase: null, - walletOwns: true, - ), - ); - - for (final transfer in outgoing.transfers) { - inputs.add( - InputV2.isarCantDoRequiredInDefaultConstructor( - scriptSigHex: null, - scriptSigAsm: null, - sequence: null, - outpoint: null, - addresses: [thisAddress], - valueStringSats: (transfer.amount).toString(), - witness: null, - innerRedeemScriptAsm: null, - coinbase: null, - walletOwns: true, - ), - ); - - outputs.add( - OutputV2.isarCantDoRequiredInDefaultConstructor( - scriptPubKeyHex: "", - valueStringSats: transfer.amount.toString(), - addresses: [transfer.destination], - walletOwns: false, - ), - ); - - otherData['asset_${transfer.asset}_amount'] = transfer.amount - .toString(); - if (transfer.extraData != null) { - otherData['extraData_${transfer.asset}'] = transfer.extraData!; - } - } - } else { - // Skip unknown entry types - continue; - } - - final txn = TransactionV2( + final txn = mapXelisTransactionEntry( + transactionEntry: transactionEntry, walletId: walletId, - blockHash: "", // Not provided in Xelis data - hash: transactionEntry.hash, - txid: transactionEntry.hash, - timestamp: - (transactionEntry.timestamp?.millisecondsSinceEpoch ?? 0) ~/ 1000, - height: transactionEntry.topoheight, - inputs: List.unmodifiable(inputs), - outputs: List.unmodifiable(outputs), - version: -1, // Version not provided - type: txType, - subType: txSubType, - otherData: jsonEncode({ - ...otherData, - if (nonce != null) 'nonce': nonce, - }), + walletAddress: thisAddress, + fractionDigits: cryptoCurrency.fractionDigits, ); // Logging.instance.log( @@ -728,13 +549,13 @@ class XelisWallet extends LibXelisWallet { final defaultDecimals = cryptoCurrency.fractionDigits; final defaultFee = BigInt.from(0); - // Use default address if recipients list is empty to ensure basic fee estimates are readily available + // Use a default address when no recipient is available so basic fee + // estimates can still be calculated. final effectiveRecipients = recipients.isNotEmpty ? recipients : [ TxRecipient( - address: - 'xel:xz9574c80c4xegnvurazpmxhw5dlg2n0g9qm60uwgt75uqyx3pcsqzzra9m', + address: _defaultFeeEstimateAddress, amount: amount, isChange: false, addressType: AddressType.xelis, @@ -905,10 +726,7 @@ class XelisWallet extends LibXelisWallet { Future handleNewTransaction(TransactionEntryWrapper tx) async { try { final txList = [tx]; - final newTxIds = await updateTransactions( - isRescan: false, - objTransactions: txList, - ); + await updateTransactions(isRescan: false, objTransactions: txList); await updateBalance(); diff --git a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart index eb818021a6..55a840b75e 100644 --- a/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart +++ b/lib/wallets/wallet/intermediate/lib_xelis_wallet.dart @@ -229,7 +229,7 @@ extension XelisTableManagement on LibXelisWallet { final tablePath = await getPrecomputedTablesPath(); await libXelis.updateTables( precomputedTablesPath: tablePath, - stack_l1Low: state.desiredSize.isLow, + stackL1Low: state.desiredSize.isLow, ); await setTableState( diff --git a/lib/wl_gen/interfaces/lib_xelis_interface.dart b/lib/wl_gen/interfaces/lib_xelis_interface.dart index 4674347e3b..477c62da68 100644 --- a/lib/wl_gen/interfaces/lib_xelis_interface.dart +++ b/lib/wl_gen/interfaces/lib_xelis_interface.dart @@ -36,7 +36,7 @@ abstract class LibXelisInterface { Future updateTables({ required String precomputedTablesPath, - required bool stack_l1Low, + required bool stackL1Low, }); Future getSeed(OpaqueXelisWallet wallet); @@ -50,7 +50,7 @@ abstract class LibXelisInterface { String? seed, String? privateKey, String? precomputedTablesPath, - bool? stack_l1Low, + bool? stackL1Low, }); Future openXelisWallet( @@ -60,7 +60,7 @@ abstract class LibXelisInterface { required String password, required CryptoCurrencyNetwork network, String? precomputedTablesPath, - bool? stack_l1Low, + bool? stackL1Low, }); String getAddress(OpaqueXelisWallet wallet); @@ -183,11 +183,13 @@ class BurnEntryWrapper extends EntryWrapper { final int amount; final int fee; final String asset; + final int nonce; const BurnEntryWrapper({ required this.amount, required this.fee, required this.asset, + required this.nonce, }); } @@ -219,7 +221,97 @@ class OutgoingEntryWrapper extends EntryWrapper { }); } -class UnknownEntryWrapper extends EntryWrapper {} +class MultisigEntryWrapper extends EntryWrapper { + final List participants; + final int threshold; + final int fee; + final int nonce; + + const MultisigEntryWrapper({ + required this.participants, + required this.threshold, + required this.fee, + required this.nonce, + }); +} + +class InvokeContractEntryWrapper extends EntryWrapper { + final String contract; + final Map deposits; + final Map> received; + final int chunkId; + final int fee; + final int maxGas; + final int nonce; + + const InvokeContractEntryWrapper({ + required this.contract, + required this.deposits, + required this.received, + required this.chunkId, + required this.fee, + required this.maxGas, + required this.nonce, + }); +} + +class DeployInvokeWrapper { + final int maxGas; + final Map deposits; + + const DeployInvokeWrapper({required this.maxGas, required this.deposits}); +} + +class DeployContractEntryWrapper extends EntryWrapper { + final int fee; + final int nonce; + final DeployInvokeWrapper? invoke; + + const DeployContractEntryWrapper({ + required this.fee, + required this.nonce, + required this.invoke, + }); +} + +class IncomingContractEntryWrapper extends EntryWrapper { + final Map> transfers; + + const IncomingContractEntryWrapper({required this.transfers}); +} + +class OutgoingBlobEntryWrapper extends EntryWrapper { + final List destinations; + final int fee; + final int nonce; + final Map data; + + const OutgoingBlobEntryWrapper({ + required this.destinations, + required this.fee, + required this.nonce, + required this.data, + }); +} + +class IncomingBlobEntryWrapper extends EntryWrapper { + final String from; + final List destinations; + final Map data; + + const IncomingBlobEntryWrapper({ + required this.from, + required this.destinations, + required this.data, + }); +} + +class UnknownEntryWrapper extends EntryWrapper { + final String entryType; + final Map? data; + + const UnknownEntryWrapper({required this.entryType, this.data}); +} // ============================================================================= @@ -257,6 +349,7 @@ class XelisTableState { this.isGenerating = false, this.currentSize = XelisTableSize.low, XelisTableSize desiredSize = XelisTableSize.full, + // ignore: prefer_initializing_formals }) : _desiredSize = desiredSize; XelisTableState copyWith({ diff --git a/pubspec.lock b/pubspec.lock index 156164fd48..d487f766fe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "0eb33edbbe99a02e73b8bbeb6f2b65972023d902117ee8d1bf0ea1a79f83aa7b" + sha256: "8d7ff3948166b8ec5da0fbb5962000926b8e02f2ed9b3e51d1738905fbd4c98d" url: "https://pub.dev" source: hosted - version: "90.0.0" + version: "93.0.0" analyzer: dependency: "direct dev" description: name: analyzer - sha256: "711e3a890bb529bf55f07d73b8706f4b7504ad77e90d2f205626b116c048583f" + sha256: "92584d8f77b0095cb0cc7041dd4baea8bb3ec1a5a5f84037c93b1cf414942633" url: "https://pub.dev" source: hosted - version: "8.3.0" + version: "10.0.0" another_flushbar: dependency: "direct main" description: @@ -163,10 +163,10 @@ packages: dependency: transitive description: name: build - sha256: ce76b1d48875e3233fde17717c23d1f60a91cc631597e49a400c89b475395b1d + sha256: "45d14a0fb23e018d8287c32fc98d726ce466b231928ed9b9200f29bd3ccd39ae" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.0.7" build_cli_annotations: dependency: transitive description: @@ -191,30 +191,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.1" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: d1d57f7807debd7349b4726a19fd32ec8bc177c71ad0febf91a20f84cd2d4b46 - url: "https://pub.dev" - source: hosted - version: "3.0.3" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b24597fceb695969d47025c958f3837f9f0122e237c6a22cb082a5ac66c3ca30 + sha256: "39ad4ca8a2876779737c60e4228b4bcd35d4352ef7e14e47514093edc012c734" url: "https://pub.dev" source: hosted - version: "2.7.1" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "066dda7f73d8eb48ba630a55acb50c4a84a2e6b453b1cb4567f581729e794f7b" - url: "https://pub.dev" - source: hosted - version: "9.3.1" + version: "2.11.1" built_collection: dependency: transitive description: @@ -737,10 +721,10 @@ packages: dependency: transitive description: name: dart_style - sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b + sha256: "29f7ecc274a86d32920b1d9cfc7502fa87220da41ec60b55f329559d5732e2b2" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.7" dartx: dependency: transitive description: @@ -1292,10 +1276,10 @@ packages: dependency: "direct dev" description: name: hive_ce_generator - sha256: a169feeff2da9cc2c417ce5ae9bcebf7c8a95d7a700492b276909016ad70a786 + sha256: c9a7cda57823ffec35846c051637ddcd105eafa253e7395d9c8c0ed5e87fbb72 url: "https://pub.dev" source: hosted - version: "1.9.3" + version: "1.11.1" hive_test: dependency: "direct dev" description: @@ -1385,26 +1369,26 @@ packages: dependency: "direct main" description: name: isar_community - sha256: eae4a7e659bec0f92fc953afb8738512062df6a2ff99fe838cb53f9ed4fa6e97 + sha256: "683fd093956eac3a660776afb70d65d50a3391b3587b40b89e3d12586b8cc47f" url: "https://pub.dev" source: hosted - version: "3.3.0-dev.2" + version: "3.3.2" isar_community_flutter_libs: dependency: "direct main" description: name: isar_community_flutter_libs - sha256: e8e6668d2c20ed61af9422bddc0bc3d1f6db91e3a5dae4406379a1426c06fbff + sha256: c44340fa38c81ef16d924202d443bbe799cde4826be9a31a9dc92ee612e1966f url: "https://pub.dev" source: hosted - version: "3.3.0-dev.2" + version: "3.3.2" isar_community_generator: dependency: "direct dev" description: name: isar_community_generator - sha256: "9da90eafaecf2ec482f50854373e37f3d9e33387830dbc0265bcdb74d9036e74" + sha256: fd5a2a5df2aac2fccba82425005bf47fd2a48f34190536d0c9fd732dc7303fb3 url: "https://pub.dev" source: hosted - version: "3.3.0-dev.2" + version: "3.3.2" isolate_channel: dependency: transitive description: @@ -2091,18 +2075,18 @@ packages: dependency: transitive description: name: source_gen - sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" + sha256: a603f1fb984a7391ae5978d1b92bfaaa08b350dca5c825256f925818f7943bf5 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "4.2.4" source_helper: dependency: transitive description: name: source_helper - sha256: "6a3c6cc82073a8797f8c4dc4572146114a39652851c157db37e964d9c7038723" + sha256: "5e6f216fdf6376c9f3852381ae037499797a3385377d388b011dac98d303c67c" url: "https://pub.dev" source: hosted - version: "1.3.8" + version: "1.3.13" source_map_stack_trace: dependency: transitive description: @@ -2281,14 +2265,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.4" - timing: - dependency: transitive - description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" - url: "https://pub.dev" - source: hosted - version: "1.0.2" tint: dependency: transitive description: @@ -2616,11 +2592,11 @@ packages: dependency: "direct main" description: path: "." - ref: f67a02c6fff7c3c269f4497e077c7cf419076a60 - resolved-ref: f67a02c6fff7c3c269f4497e077c7cf419076a60 - url: "https://github.com/xelis-project/xelis-flutter-ffi.git" + ref: "3b122aaea48daee2e1844f17650e2f1ad31d8bcb" + resolved-ref: "3b122aaea48daee2e1844f17650e2f1ad31d8bcb" + url: "https://github.com/ManyMath/xelis-flutter-ffi.git" source: git - version: "0.2.0" + version: "0.3.1" xml: dependency: transitive description: @@ -2671,4 +2647,4 @@ packages: version: "0.2.4" sdks: dart: ">=3.12.0 <4.0.0" - flutter: ">=3.44.0 <4.0.0" + flutter: ">=3.44.8 <4.0.0" diff --git a/scripts/app_config/templates/pubspec.template.yaml b/scripts/app_config/templates/pubspec.template.yaml index 1ddf61ea7f..cba5bc7bf0 100644 --- a/scripts/app_config/templates/pubspec.template.yaml +++ b/scripts/app_config/templates/pubspec.template.yaml @@ -15,7 +15,7 @@ version: PLACEHOLDER_V+PLACEHOLDER_B environment: sdk: ">=3.12.0 <4.0.0" - flutter: ^3.44.0 + flutter: ^3.44.8 dependencies: flutter: @@ -33,11 +33,11 @@ dependencies: # xelis_dart_sdk: 0.35.1 ## git: ## url: https://github.com/xelis-project/xelis-dart-sdk.git -## ref: f1da98f8bad8b9ad3645661a23f9efb83e44b0c9 +## ref: a07489e6ed10355ad34f08445dcd9441202393c1 # xelis_flutter: # git: -# url: https://github.com/xelis-project/xelis-flutter-ffi.git -# ref: f67a02c6fff7c3c269f4497e077c7cf419076a60 +# url: https://github.com/ManyMath/xelis-flutter-ffi.git +# ref: 3b122aaea48daee2e1844f17650e2f1ad31d8bcb # %%END_ENABLE_XEL%% # %%ENABLE_FIRO%% @@ -187,8 +187,8 @@ dependencies: lottie: ^3.3.2 file_picker: ^10.3.3 connectivity_plus: ^4.0.1 - isar_community: 3.3.0-dev.2 - isar_community_flutter_libs: 3.3.0-dev.2 + isar_community: 3.3.2 + isar_community_flutter_libs: 3.3.2 dropdown_button2: ^2.1.3 string_validator: ^0.3.0 equatable: ^2.0.5 @@ -282,15 +282,15 @@ dev_dependencies: sdk: flutter build_runner: ^2.5.4 flutter_launcher_icons: ^0.13.1 - hive_ce_generator: ^1.9.3 + hive_ce_generator: 1.11.1 dependency_validator: ^5.0.2 hive_test: ^1.0.1 mockito: ^5.4.6 mockingjay: ^0.2.0 - analyzer: ^8.2.2 + analyzer: 10.0.0 import_sorter: ^4.6.0 flutter_lints: ^3.0.1 - isar_community_generator: 3.3.0-dev.2 + isar_community_generator: 3.3.2 drift_dev: ^2.28.3 flutter_native_splash: @@ -348,9 +348,6 @@ dependency_overrides: # required to override solana's lower version decimal: ^3.2.4 - # pin analyzer below 8.4.0 to avoid source_gen 3.1.0 incompatibility (getInvocation() removed in 8.4.0+) - analyzer: ">=8.2.0 <8.4.0" - # xelis override json_rpc_2: ^4.0.0 freezed: ^3.1.0 diff --git a/scripts/rust_version.sh b/scripts/rust_version.sh index 68c52d6b97..4c66d8c047 100755 --- a/scripts/rust_version.sh +++ b/scripts/rust_version.sh @@ -2,19 +2,19 @@ set_rust_to_everything_else() { - if rustup toolchain list | grep -q "1.85.1"; then - rustup default 1.89.0 + if rustup toolchain list | grep -q "1.91.0"; then + rustup default 1.91.0 else - echo "Rust version 1.89.0 is not installed. Please install it using 'rustup install 1.89.0'." >&2 + echo "Rust version 1.91.0 is not installed. Please install it using 'rustup install 1.91.0'." >&2 exit 1 fi } set_rust_version_for_libepiccash() { - if rustup toolchain list | grep -q "1.89.0"; then - rustup default 1.89.0 + if rustup toolchain list | grep -q "1.91.0"; then + rustup default 1.91.0 else - echo "Rust version 1.89.0 is not installed. Please install it using 'rustup install 1.89.0'." >&2 + echo "Rust version 1.91.0 is not installed. Please install it using 'rustup install 1.91.0'." >&2 exit 1 fi } @@ -26,4 +26,4 @@ set_rust_version_for_libmwc() { echo "Rust version 1.85.1 is not installed. Please install it using 'rustup install 1.85.1'." >&2 exit 1 fi -} \ No newline at end of file +} diff --git a/test/fixtures/isar_3_3_0_dev_2/README.md b/test/fixtures/isar_3_3_0_dev_2/README.md new file mode 100644 index 0000000000..b756ef91c0 --- /dev/null +++ b/test/fixtures/isar_3_3_0_dev_2/README.md @@ -0,0 +1,22 @@ +# Isar 3.3.0-dev.2 migration fixture + +The fixtures contain databases created by `isar_community` 3.3.0-dev.2 using +schemas that match Stack Wallet 2.3.4: + +- `isar_3_3_0_dev_2_wallet_data.isar.gz` contains a `TransactionV2` with an + input, outpoint, and output. Its collection schema ID is + `-4280912949179256257`, matching Stack Wallet's current wallet database. +- `isar_3_3_0_dev_2_log.isar.gz` contains one legacy Stack Wallet `Log` record. + Its collection schema ID is `7425915233166922082`. + +The committed fixture is gzip-compressed without a filename or timestamp. Its +SHA-256 digest is: + +```text +c7bd6db8215a61d888c78c42a18b10541274d340c3c5377a5424bdcb595ad126 isar_3_3_0_dev_2_log.isar.gz +6a0ce2f29c58875985d32253acb54469632fd55111812c39e1a41a87cf93f22a isar_3_3_0_dev_2_wallet_data.isar.gz +``` + +Use `tool/isar_migration_fixture_generator` to regenerate it. The migration +tests open temporary copies using Isar 3.3.2, verify the databases and indexed +records, write current records, close the databases, and reopen them. diff --git a/test/fixtures/isar_3_3_0_dev_2/isar_3_3_0_dev_2_log.isar.gz b/test/fixtures/isar_3_3_0_dev_2/isar_3_3_0_dev_2_log.isar.gz new file mode 100644 index 0000000000..937cdfc907 Binary files /dev/null and b/test/fixtures/isar_3_3_0_dev_2/isar_3_3_0_dev_2_log.isar.gz differ diff --git a/test/fixtures/isar_3_3_0_dev_2/isar_3_3_0_dev_2_wallet_data.isar.gz b/test/fixtures/isar_3_3_0_dev_2/isar_3_3_0_dev_2_wallet_data.isar.gz new file mode 100644 index 0000000000..d99a116e8a Binary files /dev/null and b/test/fixtures/isar_3_3_0_dev_2/isar_3_3_0_dev_2_wallet_data.isar.gz differ diff --git a/test/isar_community_migration_test.dart b/test/isar_community_migration_test.dart new file mode 100644 index 0000000000..4a49f33828 --- /dev/null +++ b/test/isar_community_migration_test.dart @@ -0,0 +1,199 @@ +import 'dart:convert'; +import 'dart:ffi'; +import 'dart:io'; + +import 'package:crypto/crypto.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:isar_community/isar.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/v2/transaction_v2.dart'; +import 'package:stackwallet/models/isar/models/log.dart'; +import 'package:stackwallet/utilities/enums/log_level_enum.dart'; + +Future _isarCoreLibraryPath() async { + final packageConfigFile = File('.dart_tool/package_config.json'); + final packageConfig = + jsonDecode(await packageConfigFile.readAsString()) + as Map; + final packages = packageConfig['packages'] as List; + final package = packages.cast?>().firstWhere( + (entry) => entry?['name'] == 'isar_community_flutter_libs', + orElse: () => null, + ); + if (package == null) { + throw StateError('Could not resolve isar_community_flutter_libs'); + } + + final libraryRelativePath = switch (Platform.operatingSystem) { + 'macos' => 'macos/libisar.dylib', + 'linux' => 'linux/libisar.so', + 'windows' => 'windows/libisar.dll', + final platform => throw UnsupportedError( + 'Isar migration test is not supported on $platform', + ), + }; + + final resolvedPackageRoot = packageConfigFile.uri.resolve( + package['rootUri'] as String, + ); + final packageRoot = resolvedPackageRoot.replace( + path: '${resolvedPackageRoot.path}/', + ); + return File.fromUri(packageRoot.resolve(libraryRelativePath)).path; +} + +void main() { + test('opens and updates an Isar 3.3.0-dev.2 database with 3.3.2', () async { + final temporaryDirectory = await Directory.systemTemp.createTemp( + 'stack-wallet-isar-migration-', + ); + Isar? isar; + + try { + await Isar.initializeIsarCore( + libraries: {Abi.current(): await _isarCoreLibraryPath()}, + ); + + final fixture = File( + 'test/fixtures/isar_3_3_0_dev_2/' + 'isar_3_3_0_dev_2_log.isar.gz', + ); + final fixtureBytes = await fixture.readAsBytes(); + expect( + sha256.convert(fixtureBytes).toString(), + 'c7bd6db8215a61d888c78c42a18b10541274d340c3c5377a5424bdcb595ad126', + reason: 'The migration fixture must only change intentionally', + ); + final databaseFile = File( + '${temporaryDirectory.path}/isar_3_3_0_dev_2_log.isar', + ); + await databaseFile.writeAsBytes(gzip.decode(fixtureBytes), flush: true); + + isar = await Isar.open( + [LogSchema], + directory: temporaryDirectory.path, + name: 'isar_3_3_0_dev_2_log', + ); + // ignore: experimental_member_use + await isar.verify(); + + final migratedLog = await isar.logs + .where() + .timestampInMillisUTCEqualTo(1722470400000) + .findFirst(); + expect(migratedLog, isNotNull); + expect(migratedLog!.message, 'created by isar_community 3.3.0-dev.2'); + expect(migratedLog.logLevel, LogLevel.Warning); + + await isar.writeTxn(() async { + await isar!.logs.put( + Log() + ..message = 'written by isar_community 3.3.2' + ..timestampInMillisUTC = 1722470401000 + ..logLevel = LogLevel.Info, + ); + }); + await isar.close(); + isar = null; + + isar = await Isar.open( + [LogSchema], + directory: temporaryDirectory.path, + name: 'isar_3_3_0_dev_2_log', + ); + // ignore: experimental_member_use + await isar.verify(); + expect(await isar.logs.count(), 2); + } finally { + await isar?.close(); + await temporaryDirectory.delete(recursive: true); + } + }); + + test( + 'opens and updates an Isar 3.3.0-dev.2 wallet database with 3.3.2', + () async { + final temporaryDirectory = await Directory.systemTemp.createTemp( + 'stack-wallet-isar-wallet-migration-', + ); + Isar? isar; + + try { + await Isar.initializeIsarCore( + libraries: {Abi.current(): await _isarCoreLibraryPath()}, + ); + + final fixture = File( + 'test/fixtures/isar_3_3_0_dev_2/' + 'isar_3_3_0_dev_2_wallet_data.isar.gz', + ); + final fixtureBytes = await fixture.readAsBytes(); + expect( + sha256.convert(fixtureBytes).toString(), + '6a0ce2f29c58875985d32253acb54469632fd55111812c39e1a41a87cf93f22a', + reason: 'The migration fixture must only change intentionally', + ); + final databaseFile = File( + '${temporaryDirectory.path}/isar_3_3_0_dev_2_wallet_data.isar', + ); + await databaseFile.writeAsBytes(gzip.decode(fixtureBytes), flush: true); + + isar = await Isar.open( + [TransactionV2Schema], + directory: temporaryDirectory.path, + name: 'isar_3_3_0_dev_2_wallet_data', + ); + // ignore: experimental_member_use + await isar.verify(); + + final migratedTransaction = await isar.transactionV2s + .where() + .txidWalletIdEqualTo('migration-transaction', 'migration-wallet') + .findFirst(); + expect(migratedTransaction, isNotNull); + expect(migratedTransaction!.type, TransactionType.outgoing); + expect(migratedTransaction.nonce, 7); + expect(migratedTransaction.inputs.single.valueStringSats, '101'); + expect( + migratedTransaction.inputs.single.outpoint!.txid, + 'previous-transaction', + ); + expect(migratedTransaction.outputs.single.valueStringSats, '100'); + expect(migratedTransaction.outputs.single.addresses, ['xel:recipient']); + + await isar.writeTxn(() async { + await isar!.transactionV2s.put( + TransactionV2( + walletId: 'migration-wallet', + blockHash: 'current-block-hash', + hash: 'current-transaction', + txid: 'current-transaction', + timestamp: 1722470401, + height: 43, + inputs: const [], + outputs: const [], + version: -1, + type: TransactionType.incoming, + subType: TransactionSubType.none, + otherData: jsonEncode({'nonce': 8}), + ), + ); + }); + await isar.close(); + isar = null; + + isar = await Isar.open( + [TransactionV2Schema], + directory: temporaryDirectory.path, + name: 'isar_3_3_0_dev_2_wallet_data', + ); + // ignore: experimental_member_use + await isar.verify(); + expect(await isar.transactionV2s.count(), 2); + } finally { + await isar?.close(); + await temporaryDirectory.delete(recursive: true); + } + }, + ); +} diff --git a/test/screen_tests/onboarding/create_pin_view_screen_test.dart b/test/screen_tests/onboarding/create_pin_view_screen_test.dart index 455d347c45..9029e84792 100644 --- a/test/screen_tests/onboarding/create_pin_view_screen_test.dart +++ b/test/screen_tests/onboarding/create_pin_view_screen_test.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -10,7 +12,6 @@ import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/themes/theme_service.dart'; import 'package:stackwallet/utilities/biometrics.dart'; -import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/widgets/custom_pin_put/pin_keyboard.dart'; import '../../sample_data/theme_json.dart'; @@ -132,7 +133,7 @@ void main() { expect(await platformOverrides.secureStorage.read(key: kPinKey), '1234'); expect(platformOverrides.secureStorage.writes, 1); - expect(biometrics.calls, 0); + expect(biometrics.calls, Platform.isLinux ? 0 : 1); verify(prefs.useBiometrics = false).called(1); verify(prefs.hasPin = true).called(1); diff --git a/test/xelis_dependency_smoke_test.dart b/test/xelis_dependency_smoke_test.dart new file mode 100644 index 0000000000..036aeab401 --- /dev/null +++ b/test/xelis_dependency_smoke_test.dart @@ -0,0 +1,88 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/wl_gen/interfaces/lib_xelis_interface.dart'; +import 'package:xelis_dart_sdk/xelis_dart_sdk.dart' as xelis_sdk; +import 'package:xelis_flutter/src/api/network.dart' as xelis_ffi; +import 'package:xelis_flutter/src/api/precomputed_tables.dart' as xelis_ffi; + +void main() { + test('updated Xelis dependencies expose the APIs used by Stack Wallet', () { + expect( + xelis_sdk.WalletEvent.fromStr('new_transaction'), + xelis_sdk.WalletEvent.newTransaction, + ); + expect( + xelis_sdk.WalletEvent.fromStr('new_pending_transaction'), + xelis_sdk.WalletEvent.newPendingTransaction, + ); + expect(xelis_ffi.Network.mainnet.name, 'mainnet'); + expect( + const xelis_ffi.PrecomputedTableType.l1Low(), + isA(), + ); + }); + + test('all Xelis SDK transaction variants have Stack Wallet wrappers', () { + const extraData = xelis_sdk.ExtraData( + data: 'payload', + flag: xelis_sdk.Flag.public, + ); + final entries = [ + const xelis_sdk.TransactionEntryType.coinbase(reward: 1), + const xelis_sdk.TransactionEntryType.burn( + asset: 'asset', + amount: 2, + fee: 3, + nonce: 4, + ), + const xelis_sdk.TransactionEntryType.incoming( + from: 'from', + transfers: [], + ), + const xelis_sdk.TransactionEntryType.outgoing( + fee: 1, + nonce: 2, + transfers: [], + ), + const xelis_sdk.TransactionEntryType.multisig( + participants: ['participant'], + threshold: 1, + fee: 2, + nonce: 3, + ), + const xelis_sdk.TransactionEntryType.invokeContract( + contract: 'contract', + deposits: {'asset': 1}, + received: {}, + chunkId: 2, + fee: 3, + maxGas: 4, + nonce: 5, + ), + const xelis_sdk.TransactionEntryType.deployContract(fee: 1, nonce: 2), + const xelis_sdk.TransactionEntryType.incomingContract( + transfers: { + 'contract': {'asset': 1}, + }, + ), + const xelis_sdk.TransactionEntryType.outgoingBlob( + destinations: ['destination'], + fee: 1, + nonce: 2, + data: extraData, + ), + const xelis_sdk.TransactionEntryType.incomingBlob( + from: 'from', + destinations: ['destination'], + data: extraData, + ), + ]; + + final wrappers = entries.map(xelisEntryTypeToWrapper).toList(); + + expect(wrappers, hasLength(entries.length)); + expect(wrappers.whereType(), isEmpty); + expect(wrappers[7], isA()); + expect(wrappers[8], isA()); + expect(wrappers[9], isA()); + }); +} diff --git a/test/xelis_transaction_mapper_test.dart b/test/xelis_transaction_mapper_test.dart new file mode 100644 index 0000000000..42a892b603 --- /dev/null +++ b/test/xelis_transaction_mapper_test.dart @@ -0,0 +1,287 @@ +import 'dart:convert'; + +import 'package:flutter_test/flutter_test.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/transaction.dart'; +import 'package:stackwallet/wallets/wallet/impl/xelis_transaction_mapper.dart'; +import 'package:stackwallet/wl_gen/interfaces/lib_xelis_interface.dart'; + +void main() { + const walletAddress = 'xel:wallet'; + + TransactionEntryWrapper transaction(EntryWrapper entry) => + TransactionEntryWrapper( + entry, + entryType: entry, + hash: 'hash-${entry.runtimeType}', + timestamp: DateTime.fromMillisecondsSinceEpoch(1234000), + topoheight: 42, + ); + + test('maps coinbase rewards', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction(const CoinbaseEntryWrapper(reward: 50)), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.incoming); + expect(result.outputs.single.valueStringSats, '50'); + expect(result.outputs.single.walletOwns, isTrue); + expect(result.getFee(fractionDigits: 8).raw, BigInt.zero); + }); + + test('maps incoming transfers and sent-to-self history', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const IncomingEntryWrapper( + from: walletAddress, + transfers: [ + ( + amount: 15, + asset: 'asset-a', + extraData: {'flag': 'public', 'data': 'memo'}, + ), + ], + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + final otherData = jsonDecode(result.otherData!) as Map; + expect(result.type, TransactionType.sentToSelf); + expect(result.outputs.single.valueStringSats, '15'); + expect(otherData['asset_asset-a'], '15'); + expect(otherData['extraData_asset-a']['data'], 'memo'); + }); + + test('maps outgoing transfers, fee, and nonce', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const OutgoingEntryWrapper( + nonce: 3, + fee: 2, + transfers: [ + ( + destination: 'xel:recipient', + amount: 40, + asset: 'asset-a', + extraData: null, + ), + ], + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.outgoing); + expect(result.getFee(fractionDigits: 8).raw, BigInt.from(2)); + expect(result.nonce, 3); + expect( + result + .getAmountSentFromThisWallet(fractionDigits: 8, subtractFee: true) + .raw, + BigInt.from(40), + ); + }); + + test('maps incoming contract transfers into wallet-owned outputs', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const IncomingContractEntryWrapper( + transfers: { + 'contract-a': {'asset-a': 12, 'asset-b': 34}, + 'contract-b': {'asset-a': 56}, + }, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.incoming); + expect(result.outputs.map((e) => e.valueStringSats), ['12', '34', '56']); + expect(result.outputs.every((e) => e.walletOwns), isTrue); + expect(jsonDecode(result.otherData!)['xelisEntryType'], 'incomingContract'); + }); + + test('maps outgoing blob fee and participants without dropping history', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const OutgoingBlobEntryWrapper( + destinations: ['xel:one', 'xel:two'], + fee: 17, + nonce: 9, + data: {'flag': 'public', 'data': 'hello'}, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.outgoing); + expect(result.getFee(fractionDigits: 8).raw, BigInt.from(17)); + expect(result.outputs.expand((e) => e.addresses), ['xel:one', 'xel:two']); + expect(result.nonce, 9); + }); + + test('maps incoming blob as a zero-value incoming transaction', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const IncomingBlobEntryWrapper( + from: 'xel:sender', + destinations: [walletAddress], + data: {'flag': 'private', 'data': 'payload'}, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.incoming); + expect(result.outputs.single.valueStringSats, '0'); + expect(result.outputs.single.walletOwns, isTrue); + }); + + test('maps multisig metadata and fee', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const MultisigEntryWrapper( + participants: ['xel:one', 'xel:two'], + threshold: 2, + fee: 5, + nonce: 6, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + final otherData = jsonDecode(result.otherData!) as Map; + expect(result.type, TransactionType.outgoing); + expect(result.getFee(fractionDigits: 8).raw, BigInt.from(5)); + expect(result.nonce, 6); + expect(otherData['threshold'], 2); + expect(result.outputs, hasLength(2)); + }); + + test('maps contract deposits and received transfers', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const InvokeContractEntryWrapper( + contract: 'contract-a', + deposits: {'asset-a': 20}, + received: { + 'contract-a': {'asset-b': 30}, + }, + chunkId: 7, + fee: 3, + maxGas: 50, + nonce: 8, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + final otherData = jsonDecode(result.otherData!) as Map; + expect(result.type, TransactionType.outgoing); + expect(result.getFee(fractionDigits: 8).raw, BigInt.from(3)); + expect(result.inputs.map((e) => e.valueStringSats), ['3', '20']); + expect(result.outputs.map((e) => e.valueStringSats), ['20', '30']); + expect(result.outputs.map((e) => e.walletOwns), [false, true]); + expect(otherData['chunkId'], 7); + expect(otherData['maxGas'], 50); + }); + + test('maps deploy invocation deposits', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const DeployContractEntryWrapper( + fee: 4, + nonce: 10, + invoke: DeployInvokeWrapper(maxGas: 100, deposits: {'asset-a': 25}), + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.outgoing); + expect(result.getFee(fractionDigits: 8).raw, BigInt.from(4)); + expect(result.inputs.map((e) => e.valueStringSats), ['4', '25']); + expect(result.outputs.single.addresses, ['contract-deployment']); + expect(result.nonce, 10); + }); + + test('maps deploys without an invocation', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const DeployContractEntryWrapper(fee: 4, nonce: 10, invoke: null), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.outgoing); + expect(result.inputs.single.valueStringSats, '4'); + expect(result.outputs, isEmpty); + expect(result.nonce, 10); + }); + + test('preserves future unknown entries instead of dropping them', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const UnknownEntryWrapper( + entryType: 'futureEntry', + data: {'value': 123}, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.type, TransactionType.unknown); + final otherData = jsonDecode(result.otherData!) as Map; + expect(otherData['xelisEntryType'], 'futureEntry'); + expect(otherData['data'], {'value': 123}); + expect(otherData['overrideFee'], isA()); + }); + + test('accounts for both burn amount and fee', () { + final result = mapXelisTransactionEntry( + transactionEntry: transaction( + const BurnEntryWrapper( + amount: 100, + fee: 7, + asset: 'asset-a', + nonce: 11, + ), + ), + walletId: 'wallet-id', + walletAddress: walletAddress, + fractionDigits: 8, + ); + + expect(result.getFee(fractionDigits: 8).raw, BigInt.from(7)); + expect(result.nonce, 11); + expect( + result + .getAmountSentFromThisWallet(fractionDigits: 8, subtractFee: true) + .raw, + BigInt.from(100), + ); + }); +} diff --git a/tool/isar_migration_fixture_generator/.gitignore b/tool/isar_migration_fixture_generator/.gitignore new file mode 100644 index 0000000000..22b503f473 --- /dev/null +++ b/tool/isar_migration_fixture_generator/.gitignore @@ -0,0 +1 @@ +lib/*.g.dart diff --git a/tool/isar_migration_fixture_generator/README.md b/tool/isar_migration_fixture_generator/README.md new file mode 100644 index 0000000000..e97dab56bc --- /dev/null +++ b/tool/isar_migration_fixture_generator/README.md @@ -0,0 +1,22 @@ +# Isar migration fixture generator + +This standalone Dart package intentionally pins the Isar version used before +Stack Wallet's 3.3.2 upgrade. Its `Log` model must remain structurally identical +to `lib/models/isar/models/log.dart`, and its `TransactionV2` plus embedded +models must remain structurally identical to the production wallet schema. + +From this directory, regenerate the fixture with: + +```sh +dart pub get --enforce-lockfile +dart run build_runner build --delete-conflicting-outputs +dart run bin/generate.dart ../../test/fixtures/isar_3_3_0_dev_2 \ + /path/to/isar_community_flutter_libs-3.3.0-dev.2//libisar +``` + +On macOS the library is `macos/libisar.dylib`; Linux uses +`linux/libisar.so`; Windows uses `windows/libisar.dll`. + +Isar may vary internal database bytes between generations. Regenerating the +fixture therefore requires an intentional review and update of the SHA-256 in +the fixture README and migration test. diff --git a/tool/isar_migration_fixture_generator/bin/generate.dart b/tool/isar_migration_fixture_generator/bin/generate.dart new file mode 100644 index 0000000000..1e89fe8669 --- /dev/null +++ b/tool/isar_migration_fixture_generator/bin/generate.dart @@ -0,0 +1,109 @@ +import 'dart:ffi'; +import 'dart:io'; + +import 'package:isar_community/isar.dart'; +import 'package:stack_wallet_isar_fixture_generator/log.dart'; +import 'package:stack_wallet_isar_fixture_generator/transaction_v2.dart'; + +Future main(List args) async { + if (args.length != 2) { + stderr.writeln('Usage: generate '); + exitCode = 64; + return; + } + + final outputDirectory = Directory(args[0])..createSync(recursive: true); + await Isar.initializeIsarCore(libraries: {Abi.current(): args[1]}); + + await _generateLogFixture(outputDirectory); + await _generateWalletDataFixture(outputDirectory); +} + +Future _generateLogFixture(Directory outputDirectory) async { + const databaseName = 'isar_3_3_0_dev_2_log'; + final isar = await Isar.open( + [LogSchema], + directory: outputDirectory.path, + name: databaseName, + ); + await isar.writeTxn(() async { + await isar.logs.put( + Log() + ..message = 'created by isar_community 3.3.0-dev.2' + ..timestampInMillisUTC = 1722470400000 + ..logLevel = LogLevel.Warning, + ); + }); + await isar.close(); + + await _compressDatabase(outputDirectory, databaseName); +} + +Future _generateWalletDataFixture(Directory outputDirectory) async { + const databaseName = 'isar_3_3_0_dev_2_wallet_data'; + final isar = await Isar.open( + [TransactionV2Schema], + directory: outputDirectory.path, + name: databaseName, + ); + await isar.writeTxn(() async { + final outpoint = OutpointV2() + ..txid = 'previous-transaction' + ..vout = 1; + final input = InputV2() + ..scriptSigHex = '00' + ..scriptSigAsm = null + ..sequence = 42 + ..outpoint = outpoint + ..addresses = ['xel:sender'] + ..valueStringSats = '101' + ..coinbase = null + ..witness = null + ..innerRedeemScriptAsm = null + ..walletOwns = true; + final output = OutputV2() + ..scriptPubKeyHex = '51' + ..scriptPubKeyAsm = null + ..valueStringSats = '100' + ..addresses = ['xel:recipient'] + ..walletOwns = false; + + await isar.transactionV2s.put( + TransactionV2( + walletId: 'migration-wallet', + blockHash: 'block-hash', + hash: 'migration-transaction', + txid: 'migration-transaction', + timestamp: 1722470400, + height: 42, + inputs: [input], + outputs: [output], + version: -1, + type: TransactionType.outgoing, + subType: TransactionSubType.none, + otherData: '{"nonce":7}', + ), + ); + }); + await isar.close(); + + await _compressDatabase(outputDirectory, databaseName); +} + +Future _compressDatabase( + Directory outputDirectory, + String databaseName, +) async { + final databaseFile = File('${outputDirectory.path}/$databaseName.isar'); + final compressedFile = File('${databaseFile.path}.gz'); + await compressedFile.writeAsBytes( + gzip.encode(await databaseFile.readAsBytes()), + flush: true, + ); + await databaseFile.delete(); + + final lockFile = File('${databaseFile.path}-lck'); + if (await lockFile.exists()) { + await lockFile.delete(); + } +} diff --git a/tool/isar_migration_fixture_generator/lib/log.dart b/tool/isar_migration_fixture_generator/lib/log.dart new file mode 100644 index 0000000000..88bb2266e0 --- /dev/null +++ b/tool/isar_migration_fixture_generator/lib/log.dart @@ -0,0 +1,18 @@ +import 'package:isar_community/isar.dart'; + +part 'log.g.dart'; + +enum LogLevel { Info, Warning, Error, Fatal, Debug } + +@Collection() +class Log { + Id id = Isar.autoIncrement; + + late String message; + + @Index() + late int timestampInMillisUTC; + + @Enumerated(EnumType.name) + late LogLevel logLevel; +} diff --git a/tool/isar_migration_fixture_generator/lib/transaction_v2.dart b/tool/isar_migration_fixture_generator/lib/transaction_v2.dart new file mode 100644 index 0000000000..a8ab82f999 --- /dev/null +++ b/tool/isar_migration_fixture_generator/lib/transaction_v2.dart @@ -0,0 +1,123 @@ +import 'dart:convert'; + +import 'package:isar_community/isar.dart'; + +part 'transaction_v2.g.dart'; + +enum TransactionType { outgoing, incoming, sentToSelf, unknown } + +enum TransactionSubType { + none, + bip47Notification, + mint, + join, + ethToken, + cashFusion, + sparkMint, + sparkSpend, + ordinal, + mweb, + splToken, +} + +@Embedded() +class OutpointV2 { + late final String txid; + late final int vout; + + OutpointV2(); + + @override + int get hashCode => Object.hash(txid, vout); +} + +@Embedded() +class InputV2 { + late final String? scriptSigHex; + late final String? scriptSigAsm; + late final int? sequence; + late final OutpointV2? outpoint; + late final List addresses; + late final String valueStringSats; + late final String? coinbase; + late final String? witness; + late final String? innerRedeemScriptAsm; + late final bool walletOwns; + + InputV2(); +} + +@Embedded() +class OutputV2 { + late final String scriptPubKeyHex; + late final String? scriptPubKeyAsm; + late final String valueStringSats; + late final List addresses; + late final bool walletOwns; + + OutputV2(); +} + +@Collection() +class TransactionV2 { + TransactionV2({ + required this.walletId, + required this.blockHash, + required this.hash, + required this.txid, + required this.timestamp, + required this.height, + required this.inputs, + required this.outputs, + required this.version, + required this.type, + required this.subType, + required this.otherData, + }); + + Id id = Isar.autoIncrement; + + @Index() + final String walletId; + + @Index(unique: true, composite: [CompositeIndex('walletId')]) + final String txid; + + final String hash; + + @Index() + late final int timestamp; + + final int? height; + final String? blockHash; + final int version; + final List inputs; + final List outputs; + + @enumerated + final TransactionType type; + + @enumerated + final TransactionSubType subType; + + final String? otherData; + + Map get _decodedOtherData => + jsonDecode(otherData ?? '{}') as Map; + + bool get isEpiccashTransaction => + _decodedOtherData['isEpiccashTransaction'] == true; + + int? get numberOfMessages => _decodedOtherData['numberOfMessages'] as int?; + + String? get slateId => _decodedOtherData['slateId'] as String?; + + String? get onChainNote => _decodedOtherData['onChainNote'] as String?; + + bool get isCancelled => _decodedOtherData['isCancelled'] == true; + + String? get contractAddress => + _decodedOtherData['contractAddress'] as String?; + + int? get nonce => _decodedOtherData['nonce'] as int?; +} diff --git a/tool/isar_migration_fixture_generator/pubspec.lock b/tool/isar_migration_fixture_generator/pubspec.lock new file mode 100644 index 0000000000..321acea4d9 --- /dev/null +++ b/tool/isar_migration_fixture_generator/pubspec.lock @@ -0,0 +1,509 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: da0d9209ca76bde579f2da330aeb9df62b6319c834fa7baae052021b0462401f + url: "https://pub.dev" + source: hosted + version: "85.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: f4ad0fea5f102201015c9aae9d93bc02f75dd9491529a8c21f88d17a8523d44c + url: "https://pub.dev" + source: hosted + version: "7.6.0" + args: + dependency: transitive + description: + name: args + sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + async: + dependency: transitive + description: + name: async + sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 + url: "https://pub.dev" + source: hosted + version: "2.13.1" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + build: + dependency: transitive + description: + name: build + sha256: ce76b1d48875e3233fde17717c23d1f60a91cc631597e49a400c89b475395b1d + url: "https://pub.dev" + source: hosted + version: "3.1.0" + build_config: + dependency: transitive + description: + name: build_config + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + sha256: "79e05eaf15a48d7230b053a4363b8eaac0cc234bbd0134c3229455481f55cbc6" + url: "https://pub.dev" + source: hosted + version: "4.1.5" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + sha256: d1d57f7807debd7349b4726a19fd32ec8bc177c71ad0febf91a20f84cd2d4b46 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + build_runner: + dependency: "direct dev" + description: + name: build_runner + sha256: b24597fceb695969d47025c958f3837f9f0122e237c6a22cb082a5ac66c3ca30 + url: "https://pub.dev" + source: hosted + version: "2.7.1" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + sha256: "066dda7f73d8eb48ba630a55acb50c4a84a2e6b453b1cb4567f581729e794f7b" + url: "https://pub.dev" + source: hosted + version: "9.3.1" + built_collection: + dependency: transitive + description: + name: built_collection + sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100" + url: "https://pub.dev" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + sha256: "31b24be6615ec7fcf70b3aa5a7469fe35826485e639a16dd7eb83ba30e4cc6a8" + url: "https://pub.dev" + source: hosted + version: "8.12.7" + characters: + dependency: transitive + description: + name: characters + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b + url: "https://pub.dev" + source: hosted + version: "1.4.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" + url: "https://pub.dev" + source: hosted + version: "2.0.4" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + code_builder: + dependency: transitive + description: + name: code_builder + sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" + url: "https://pub.dev" + source: hosted + version: "4.11.1" + collection: + dependency: transitive + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + convert: + dependency: transitive + description: + name: convert + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + dart_style: + dependency: transitive + description: + name: dart_style + sha256: "8a0e5fba27e8ee025d2ffb4ee820b4e6e2cf5e4246a6b1a477eb66866947e0bb" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + dartx: + dependency: transitive + description: + name: dartx + sha256: "8b25435617027257d43e6508b5fe061012880ddfdaa75a71d607c3de2a13d244" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + ffi: + dependency: transitive + description: + name: ffi + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de + url: "https://pub.dev" + source: hosted + version: "2.1.3" + graphs: + dependency: transitive + description: + name: graphs + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8 + url: "https://pub.dev" + source: hosted + version: "3.2.2" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + io: + dependency: transitive + description: + name: io + sha256: dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b + url: "https://pub.dev" + source: hosted + version: "1.0.5" + isar_community: + dependency: "direct main" + description: + name: isar_community + sha256: eae4a7e659bec0f92fc953afb8738512062df6a2ff99fe838cb53f9ed4fa6e97 + url: "https://pub.dev" + source: hosted + version: "3.3.0-dev.2" + isar_community_generator: + dependency: "direct dev" + description: + name: isar_community_generator + sha256: "9da90eafaecf2ec482f50854373e37f3d9e33387830dbc0265bcdb74d9036e74" + url: "https://pub.dev" + source: hosted + version: "3.3.0-dev.2" + js: + dependency: transitive + description: + name: js + sha256: "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc" + url: "https://pub.dev" + source: hosted + version: "0.7.2" + json_annotation: + dependency: transitive + description: + name: json_annotation + sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" + url: "https://pub.dev" + source: hosted + version: "4.12.0" + logging: + dependency: transitive + description: + name: logging + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: "31bd099b47c10cd1aeb55146a2d46ce0277630ecef3f7dae54ad7873f36696cd" + url: "https://pub.dev" + source: hosted + version: "0.12.20" + meta: + dependency: transitive + description: + name: meta + sha256: "307249ce4ff29d58a18e97f6345f539382eb9c9c29ecda628900f31de0443dd9" + url: "https://pub.dev" + source: hosted + version: "1.19.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + package_config: + dependency: transitive + description: + name: package_config + sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc + url: "https://pub.dev" + source: hosted + version: "2.2.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + pool: + dependency: transitive + description: + name: pool + sha256: "978783255c543aa3586a1b3c21f6e9d720eb315376a915872c61ef8b5c20177d" + url: "https://pub.dev" + source: hosted + version: "1.5.2" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" + url: "https://pub.dev" + source: hosted + version: "2.2.0" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + sha256: "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082" + url: "https://pub.dev" + source: hosted + version: "1.5.0" + shelf: + dependency: transitive + description: + name: shelf + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 + url: "https://pub.dev" + source: hosted + version: "1.4.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925" + url: "https://pub.dev" + source: hosted + version: "3.0.0" + source_gen: + dependency: transitive + description: + name: source_gen + sha256: "7b19d6ba131c6eb98bfcbf8d56c1a7002eba438af2e7ae6f8398b2b0f4f381e3" + url: "https://pub.dev" + source: hosted + version: "3.1.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" + url: "https://pub.dev" + source: hosted + version: "1.10.2" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + stream_transform: + dependency: transitive + description: + name: stream_transform + sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871 + url: "https://pub.dev" + source: hosted + version: "2.1.1" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: "475610b2aa23c19687cce2961e44b0cc57cafe220f67c2b80201231b2a07fbe7" + url: "https://pub.dev" + source: hosted + version: "0.7.13" + time: + dependency: transitive + description: + name: time + sha256: "46187cf30bffdab28c56be9a63861b36e4ab7347bf403297595d6a97e10c789f" + url: "https://pub.dev" + source: hosted + version: "2.1.6" + timing: + dependency: transitive + description: + name: timing + sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + url: "https://pub.dev" + source: hosted + version: "1.0.2" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8 + url: "https://pub.dev" + source: hosted + version: "3.0.3" + xxh3: + dependency: transitive + description: + name: xxh3 + sha256: "399a0438f5d426785723c99da6b16e136f4953fb1e9db0bf270bd41dd4619916" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + yaml: + dependency: transitive + description: + name: yaml + sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce + url: "https://pub.dev" + source: hosted + version: "3.1.3" +sdks: + dart: ">=3.11.0 <4.0.0" diff --git a/tool/isar_migration_fixture_generator/pubspec.yaml b/tool/isar_migration_fixture_generator/pubspec.yaml new file mode 100644 index 0000000000..a84592ead2 --- /dev/null +++ b/tool/isar_migration_fixture_generator/pubspec.yaml @@ -0,0 +1,12 @@ +name: stack_wallet_isar_fixture_generator +publish_to: none + +environment: + sdk: ">=3.6.0 <4.0.0" + +dependencies: + isar_community: 3.3.0-dev.2 + +dev_dependencies: + build_runner: 2.7.1 + isar_community_generator: 3.3.0-dev.2 diff --git a/tool/wl_templates/XEL_lib_xelis_interface_impl.template.dart b/tool/wl_templates/XEL_lib_xelis_interface_impl.template.dart index df1d41ac5d..6504dfe0f2 100644 --- a/tool/wl_templates/XEL_lib_xelis_interface_impl.template.dart +++ b/tool/wl_templates/XEL_lib_xelis_interface_impl.template.dart @@ -164,13 +164,15 @@ final class _LibXelisInterfaceImpl extends LibXelisInterface { yield NewTransaction( TransactionEntryWrapper( tx, - entryType: _entryTypeConversion(tx.txEntryType), + entryType: xelisEntryTypeToWrapper(tx.txEntryType), hash: tx.hash, timestamp: tx.timestamp, topoheight: tx.topoheight, ), ); case xelis_sdk.WalletEvent.newPendingTransaction: + // Stack Wallet's transaction model requires a finalized + // topoheight, so refresh this entry after it is finalized. continue; case xelis_sdk.WalletEvent.balanceChanged: final data = xelis_sdk.BalanceChangedEvent.fromJson( @@ -219,12 +221,12 @@ final class _LibXelisInterfaceImpl extends LibXelisInterface { @override Future updateTables({ required String precomputedTablesPath, - required bool stack_l1Low, + required bool stackL1Low, }) async { // TODO: add more granular table size management interface // for now, just patching the old system into the new FFI API - x_tables.PrecomputedTableType tableType = stack_l1Low + x_tables.PrecomputedTableType tableType = stackL1Low ? x_tables.PrecomputedTableType.l1Low() : x_tables.PrecomputedTableType.l1Full(); @@ -247,12 +249,12 @@ final class _LibXelisInterfaceImpl extends LibXelisInterface { String? seed, String? privateKey, String? precomputedTablesPath, - bool? stack_l1Low, + bool? stackL1Low, }) async { // TODO: add more granular table size management interface // for now, just patching the old system into the new FFI API - x_tables.PrecomputedTableType tableType = stack_l1Low ?? false + x_tables.PrecomputedTableType tableType = stackL1Low ?? false ? x_tables.PrecomputedTableType.l1Low() : x_tables.PrecomputedTableType.l1Full(); @@ -278,12 +280,12 @@ final class _LibXelisInterfaceImpl extends LibXelisInterface { required String password, required CryptoCurrencyNetwork network, String? precomputedTablesPath, - bool? stack_l1Low, + bool? stackL1Low, }) async { // TODO: add more granular table size management interface // for now, just patching the old system into the new FFI API - x_tables.PrecomputedTableType tableType = (stack_l1Low ?? false) + x_tables.PrecomputedTableType tableType = (stackL1Low ?? false) ? x_tables.PrecomputedTableType.l1Low() : x_tables.PrecomputedTableType.l1Full(); @@ -320,7 +322,7 @@ final class _LibXelisInterfaceImpl extends LibXelisInterface { final tx = _checkDecodeJsonStringTxEntry(e); return TransactionEntryWrapper( tx, - entryType: _entryTypeConversion(tx.txEntryType), + entryType: xelisEntryTypeToWrapper(tx.txEntryType), hash: tx.hash, timestamp: tx.timestamp, topoheight: tx.topoheight, @@ -444,7 +446,7 @@ extension _CryptoCurrencyNetworkConversion on x_network.Network { } } -EntryWrapper _entryTypeConversion(xelis_sdk.TransactionEntryType entryType) { +EntryWrapper xelisEntryTypeToWrapper(xelis_sdk.TransactionEntryType entryType) { if (entryType is xelis_sdk.CoinbaseEntry) { return CoinbaseEntryWrapper(reward: entryType.reward); } else if (entryType is xelis_sdk.BurnEntry) { @@ -452,6 +454,7 @@ EntryWrapper _entryTypeConversion(xelis_sdk.TransactionEntryType entryType) { amount: entryType.amount, fee: entryType.fee, asset: entryType.asset, + nonce: entryType.nonce, ); } else if (entryType is xelis_sdk.IncomingEntry) { return IncomingEntryWrapper( @@ -481,8 +484,55 @@ EntryWrapper _entryTypeConversion(xelis_sdk.TransactionEntryType entryType) { ) .toList(), ); + } else if (entryType is xelis_sdk.MultisigEntry) { + return MultisigEntryWrapper( + participants: entryType.participants, + threshold: entryType.threshold, + fee: entryType.fee, + nonce: entryType.nonce, + ); + } else if (entryType is xelis_sdk.InvokeContractEntry) { + return InvokeContractEntryWrapper( + contract: entryType.contract, + deposits: entryType.deposits, + received: entryType.received, + chunkId: entryType.chunkId, + fee: entryType.fee, + maxGas: entryType.maxGas, + nonce: entryType.nonce, + ); + } else if (entryType is xelis_sdk.DeployContractEntry) { + final invoke = entryType.invoke; + return DeployContractEntryWrapper( + fee: entryType.fee, + nonce: entryType.nonce, + invoke: invoke == null + ? null + : DeployInvokeWrapper( + maxGas: invoke.maxGas, + deposits: invoke.deposits, + ), + ); + } else if (entryType is xelis_sdk.IncomingContractEntry) { + return IncomingContractEntryWrapper(transfers: entryType.transfers); + } else if (entryType is xelis_sdk.OutgoingBlobEntry) { + return OutgoingBlobEntryWrapper( + destinations: entryType.destinations, + fee: entryType.fee, + nonce: entryType.nonce, + data: entryType.data.toJson(), + ); + } else if (entryType is xelis_sdk.IncomingBlobEntry) { + return IncomingBlobEntryWrapper( + from: entryType.from, + destinations: entryType.destinations, + data: entryType.data.toJson(), + ); } else { - return UnknownEntryWrapper(); + return UnknownEntryWrapper( + entryType: entryType.runtimeType.toString(), + data: entryType.toJson(), + ); } }