diff --git a/.env b/.env index e84a7e1..64d0f79 100644 --- a/.env +++ b/.env @@ -1,2 +1,3 @@ -MONERO_C_TAG=v0.18.4.0-RC7 -COIN=monero +MONERO_C_TAG=99aa531f9c7180805e59dd52f6dde95d5c55ab0d +MONERO_C_PREBUILD_TAG=v0.18.4.6-RC2 +COIN=monero diff --git a/.fvmrc b/.fvmrc index c0ef54d..d80cf57 100644 --- a/.fvmrc +++ b/.fvmrc @@ -1,3 +1,3 @@ { - "flutter": "3.32.0" + "flutter": "3.41.9" } \ No newline at end of file diff --git a/.gitignore b/.gitignore index adb73b6..3a1f9ec 100644 --- a/.gitignore +++ b/.gitignore @@ -52,4 +52,6 @@ missing_translations.txt # FVM Version Cache .fvm/ -*.g.dart \ No newline at end of file +*.g.dart + +android/.kotlin/sessions/*.salive diff --git a/.vscode/settings.json b/.vscode/settings.json index 17f2bdf..6a5b098 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "dart.flutterSdkPath": ".fvm/versions/3.32.0" + "dart.flutterSdkPath": ".fvm/versions/3.41.9" } \ No newline at end of file diff --git a/Makefile b/Makefile index 7e220d8..34a3ad4 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,18 @@ include .env UNAME := $(shell uname) +MONERO_C_PREBUILD_TAG ?= $(MONERO_C_TAG) + +all: libs_android_build libs_ios_build prepare_dev + +init: + git submodule update --init --recursive libs_android_download: mwebd_android - ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet x86_64-linux-android --location android/app/src/main/jniLibs/x86_64 - ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a - ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet armv7a-linux-androideabi --location android/app/src/main/jniLibs/armeabi-v7a + ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --prebuild-tag ${MONERO_C_PREBUILD_TAG} --triplet x86_64-linux-android --location android/app/src/main/jniLibs/x86_64 + ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --prebuild-tag ${MONERO_C_PREBUILD_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a + ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --prebuild-tag ${MONERO_C_PREBUILD_TAG} --triplet armv7a-linux-androideabi --location android/app/src/main/jniLibs/armeabi-v7a libs_android_build: mwebd_android -ifneq ($(UNAME), Linux) - echo Only Linux hosts can build for android, try $(MAKE) libs_android_download - exit 1 -endif ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet x86_64-linux-android --location android/app/src/main/jniLibs/x86_64 ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet armv7a-linux-androideabi --location android/app/src/main/jniLibs/armeabi-v7a @@ -19,17 +21,13 @@ libs_android_build_ci: mwebd_android ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a libs_ios_download: mwebd_ios - ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-ios --location ios/native_libs/ios-arm64 - ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-iossimulator --location ios/native_libs/ios-arm64-simulator + ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --prebuild-tag ${MONERO_C_PREBUILD_TAG} --triplet aarch64-apple-ios --location ios/native_libs/ios-arm64 + ./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --prebuild-tag ${MONERO_C_PREBUILD_TAG} --triplet aarch64-apple-ios-simulator --location ios/native_libs/ios-arm64-simulator cd ios && ./gen_framework.sh libs_ios_build: mwebd_ios -ifneq ($(UNAME), Darwin) - echo Only Darwin hosts can build for iOS, try $(MAKE) libs_ios_download - exit 1 -endif ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-ios --location ios/native_libs/ios-arm64 - ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-iossimulator --location ios/native_libs/ios-arm64-simulator + ./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-ios-simulator --location ios/native_libs/ios-arm64-simulator cd ios && ./gen_framework.sh cupcake_android: diff --git a/README.md b/README.md index 8275383..bf4b29e 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,9 @@ To build: ```bash -$ make libs_android_build # or libs_android_download, libs_ios_build, libs_ios_download -$ make prepare_dev # load dev signing key (not required on iOS) +$ make init # fetch the submodules +$ make all # or libs_android_build, libs_android_download, libs_ios_build, libs_ios_download +$ make prepare_dev # not needed if ran `make all` $ make cupcake_android # or cupcake_ios ``` diff --git a/android/app/build.gradle b/android/app/build.gradle index 4accb32..8c6fcc1 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -51,7 +51,7 @@ android { applicationId "com.cakewallet.cupcake" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion 23 + minSdkVersion flutter.minSdkVersion targetSdkVersion 36 versionCode flutterVersionCode.toInteger() versionName flutterVersionName diff --git a/android/app/src/main/jniLibs/.gitignore b/android/app/src/main/jniLibs/.gitignore index 28bbbde..d60573a 100644 --- a/android/app/src/main/jniLibs/.gitignore +++ b/android/app/src/main/jniLibs/.gitignore @@ -1 +1 @@ -libmonero_libwallet2_api_c.so +libmonero_*wallet2_api_c.so diff --git a/android/gradle.properties b/android/gradle.properties index 598d13f..6cd1dbb 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,4 @@ -org.gradle.jvmargs=-Xmx4G +org.gradle.jvmargs=-Xmx6G android.useAndroidX=true android.enableJetifier=true +android.ndk.suppressMinSdkVersionError=21 diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index afa1e8e..efdcc4a 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip diff --git a/android/settings.gradle b/android/settings.gradle index d4383de..e79a8ea 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -19,7 +19,7 @@ pluginManagement { plugins { id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version '8.8.0' apply false + id "com.android.application" version '8.9.1' apply false id "org.jetbrains.kotlin.android" version "2.0.21" apply false } diff --git a/build_moneroc.sh b/build_moneroc.sh index 2c30bc7..375e3f6 100755 --- a/build_moneroc.sh +++ b/build_moneroc.sh @@ -1,11 +1,12 @@ #!/bin/bash # Script designed to build (or download) monero_c -# usage: -# ./build_moneroc.sh +# usage: +# ./build_moneroc.sh # --prebuild - allow downloads of prebuilds # --coin - monero/wownero -# --tag v0.18.3.3-RC45 - which tag to build / download +# --tag v0.18.3.3-RC45 - tag, branch, or commit to check out +# --prebuild-tag v0.18.4.6-RC2 - GitHub release to download libs from (defaults to --tag) # --triplet x86_64-linux-android - which triplet to build / download # --location android/app/src/main/jniLibs/x86_64 - where to but the libraries # source: github.com/mrcyjanek/unnamed_monero_wallet @@ -18,6 +19,7 @@ POSITIONAL_ARGS=() ARG_PREBUILD="" ARG_COIN="" ARG_TAG="" +ARG_PREBUILD_TAG="" ARG_TRIPLET="" ARG_LOCATION="" @@ -32,6 +34,11 @@ while [[ $# -gt 0 ]]; do shift shift ;; + --prebuild-tag) + ARG_PREBUILD_TAG="$2" + shift + shift + ;; --triplet) ARG_TRIPLET="$2" shift @@ -62,10 +69,21 @@ set -- "${POSITIONAL_ARGS[@]}" # restore positional parameters if [[ "x$ARG_TAG" == "x" || "x$ARG_TRIPLET" == "x" || "x$ARG_LOCATION" == "x" || "x$ARG_COIN" == "x" ]]; then - head -11 "$0" | tail -9 + head -12 "$0" | tail -10 exit 1 fi +# --branch only accepts tags/branches. Fetch the ref so commit SHAs work too. +function checkout_moneroc() { + local dest="$1" + rm -rf "${dest}" + mkdir -p "${dest}" + git -C "${dest}" init + git -C "${dest}" remote add origin https://github.com/mrcyjanek/monero_c + git -C "${dest}" fetch --depth=1 origin "${ARG_TAG}" + git -C "${dest}" checkout --force FETCH_HEAD +} + if [[ "${ARG_TRIPLET}" == *android* ]]; then lib_name_prefix=lib @@ -85,23 +103,81 @@ fi if [[ ! "x$ARG_PREBUILD" == "x" ]]; then + BUILD_DIR="$PWD/.cache/monero_c/${ARG_TAG}" + if [[ ! -d "${BUILD_DIR}/impls" ]]; + then + checkout_moneroc "${BUILD_DIR}" + fi + + RELEASE_TAG="${ARG_PREBUILD_TAG:-$ARG_TAG}" # download prebuild - GH_JSON="$(curl --retry 12 --retry-all-errors -L -o- 'https://api.github.com/repos/MrCyjaneK/monero_c/releases/tags/'"${ARG_TAG}" | tr -d '\r')" - for release_url in $(echo "$GH_JSON" | jq -r '.assets[].browser_download_url' | tr -d '\r' | xargs) + GH_JSON="$(curl --retry 12 --retry-all-errors -L -o- 'https://api.github.com/repos/MrCyjaneK/monero_c/releases/tags/'"${RELEASE_TAG}" | tr -d '\r')" + ASSET_URLS="$(echo "$GH_JSON" | jq -r '.assets[]?.browser_download_url' | tr -d '\r' | xargs)" + if [[ "x$ASSET_URLS" == "x" ]]; + then + echo "No release assets for tag '${RELEASE_TAG}'; --prebuild needs a GitHub release (set --prebuild-tag if --tag is a commit)" + exit 1 + fi + + BUNDLE_URL="" + for release_url in $ASSET_URLS do - asset_basename=$(urldecode $(basename $release_url) | tr -d '\r' | xargs) - if [[ "$asset_basename" == ${ARG_COIN}_${ARG_TRIPLET}* ]]; - then - if [[ "$asset_basename" == *libwallet2_api_c* ]]; + if [[ "$(basename $release_url)" == "release-bundle.zip" ]]; + then + BUNDLE_URL="$release_url" + fi + done + + if [[ ! "x$BUNDLE_URL" == "x" ]]; + then + BUNDLE_DIR="$PWD/.cache/monero_c/prebuild/${RELEASE_TAG}" + mkdir -p "$BUNDLE_DIR" + if [[ ! -f "$BUNDLE_DIR/release-bundle.zip" ]]; + then + curl --retry 12 --retry-all-errors -L "$BUNDLE_URL" -o "$BUNDLE_DIR/release-bundle.zip.part" + mv "$BUNDLE_DIR/release-bundle.zip.part" "$BUNDLE_DIR/release-bundle.zip" + fi + + rm -rf "$BUNDLE_DIR/${ARG_TRIPLET}" + unzip -q -o "$BUNDLE_DIR/release-bundle.zip" \ + "*/${ARG_TRIPLET}/lib${ARG_COIN}_wallet2_api_c.*" \ + -d "$BUNDLE_DIR/${ARG_TRIPLET}" || true + + FOUND="" + for release in "$BUNDLE_DIR/${ARG_TRIPLET}"/*/"${ARG_TRIPLET}"/lib${ARG_COIN}_wallet2_api_c.* + do + [[ -f "$release" ]] || continue + FOUND="ON" + asset_basename="$(basename $release)" + if [[ "${ARG_TRIPLET}" == *-apple-ios* ]]; then - curl -L "$release_url" > "$ARG_LOCATION/$lib_name_prefix${asset_basename/${ARG_TRIPLET}_/}" - unxz -f "$ARG_LOCATION/$lib_name_prefix${asset_basename/${ARG_TRIPLET}_/}" + cp "$release" "$ARG_LOCATION/${ARG_COIN}_libwallet2_api_c.${asset_basename##*.}" else - curl -L "$release_url" > "$ARG_LOCATION/${asset_basename/${ARG_COIN}_${ARG_TRIPLET}_/}" - unxz -f "$ARG_LOCATION/${asset_basename/${ARG_COIN}_${ARG_TRIPLET}_/}" + cp "$release" "$ARG_LOCATION/$asset_basename" fi + done + if [[ "x$FOUND" == "x" ]]; + then + echo "release-bundle.zip of '${RELEASE_TAG}' has no ${ARG_COIN} library for ${ARG_TRIPLET}" + exit 1 fi - done + else + for release_url in $ASSET_URLS + do + asset_basename=$(urldecode $(basename $release_url) | tr -d '\r' | xargs) + if [[ "$asset_basename" == ${ARG_COIN}_${ARG_TRIPLET}* ]]; + then + if [[ "$asset_basename" == *libwallet2_api_c* ]]; + then + curl -L "$release_url" > "$ARG_LOCATION/$lib_name_prefix${asset_basename/${ARG_TRIPLET}_/}" + unxz -f "$ARG_LOCATION/$lib_name_prefix${asset_basename/${ARG_TRIPLET}_/}" || true + else + curl -L "$release_url" > "$ARG_LOCATION/${asset_basename/${ARG_COIN}_${ARG_TRIPLET}_/}" + unxz -f "$ARG_LOCATION/${asset_basename/${ARG_COIN}_${ARG_TRIPLET}_/}" || true + fi + fi + done + fi else # build from source BUILD_DIR="$PWD/.cache/monero_c/${ARG_TAG}" @@ -120,23 +196,23 @@ else fi COPIED="" - if ! ls ${BUILD_DIR}/release/${ARG_COIN}/${ARG_TRIPLET}_libwallet2_api_c*.xz + if ! ls ${BUILD_DIR}/release/${ARG_COIN}/${ARG_TRIPLET}_libwallet2_api_c* then pushd "$BUILD_DIR" - ./build_single.sh ${ARG_COIN} ${ARG_TRIPLET} -j$(nproc) + env -i PATH="$PATH" HOME="$HOME" ./build_single.sh ${ARG_COIN} ${ARG_TRIPLET} -j$(nproc) popd fi - for release in ${BUILD_DIR}/release/${ARG_COIN}/${ARG_TRIPLET}_*.xz; + for release in ${BUILD_DIR}/release/${ARG_COIN}/${ARG_TRIPLET}_*; do asset_basename="$(basename $release)" if [[ "$asset_basename" == *libwallet2_api_c* ]]; then cp "$release" "$ARG_LOCATION/$lib_name_prefix${ARG_COIN}_${asset_basename/${ARG_TRIPLET}_/}" - unxz -f "$ARG_LOCATION/$lib_name_prefix${ARG_COIN}_${asset_basename/${ARG_TRIPLET}_/}" + unxz -f "$ARG_LOCATION/$lib_name_prefix${ARG_COIN}_${asset_basename/${ARG_TRIPLET}_/}" || true else cp "$release" "$ARG_LOCATION/${asset_basename/${ARG_TRIPLET}_/}" - unxz -f "$ARG_LOCATION/${asset_basename/${ARG_TRIPLET}_/}" + unxz -f "$ARG_LOCATION/${asset_basename/${ARG_TRIPLET}_/}" || true fi done -fi \ No newline at end of file +fi diff --git a/external/cake_wallet b/external/cake_wallet index e921365..df87bab 160000 --- a/external/cake_wallet +++ b/external/cake_wallet @@ -1 +1 @@ -Subproject commit e921365af73c1bdb8aaa736a15f774a90edaa6a4 +Subproject commit df87bab8367c5e712f668db3b2f9a32a87957a62 diff --git a/l10n.yaml b/l10n.yaml index fd3c83b..a712846 100644 --- a/l10n.yaml +++ b/l10n.yaml @@ -1,5 +1,4 @@ arb-dir: lib/l10n template-arb-file: app_en.arb output-localization-file: app_localizations.dart -synthetic-package: false -untranslated-messages-file: missing_translations.txt \ No newline at end of file +untranslated-messages-file: missing_translations.txt diff --git a/lib/coins/bitcoin/wallet.dart b/lib/coins/bitcoin/wallet.dart index 00711cb..616876c 100644 --- a/lib/coins/bitcoin/wallet.dart +++ b/lib/coins/bitcoin/wallet.dart @@ -10,6 +10,7 @@ import 'package:cupcake/coins/bitcoin/address.dart'; import 'package:cupcake/coins/bitcoin/amount.dart'; import 'package:cupcake/coins/bitcoin/coin.dart'; import 'package:cupcake/coins/bitcoin/wallet_info.dart'; +import 'package:cupcake/utils/psbt.dart'; import 'package:cupcake/utils/types.dart'; import 'package:cupcake/utils/urqr.dart'; import 'package:cupcake/views/animated_qr_page.dart'; @@ -43,6 +44,9 @@ class BDKWalletWrapper { wallet.sign( psbt: psbt, signOptions: SignOptions( + // Offline signer has no UTXO DB. + // Witness utxo is required to sign. + // Fee display warns when input amounts cannot be cross-checked. trustWitnessUtxo: true, allowAllSighashes: true, removePartialSigs: false, @@ -138,6 +142,7 @@ class BitcoinWallet implements CoinWallet { wallet: this, destMap: destMap, fee: BitcoinAmount(psbt.feeAmount()?.toInt() ?? -1), + warnings: psbtConfirmationWarnings(psbt.serialize()), confirmCallback: (final BuildContext context) async { final status = await wallet.sign(psbt: psbt); if (!status) throw Exception("Failed to sign"); diff --git a/lib/coins/debug/coin_test.dart b/lib/coins/debug/coin_test.dart new file mode 100644 index 0000000..e35c70f --- /dev/null +++ b/lib/coins/debug/coin_test.dart @@ -0,0 +1,78 @@ +typedef TestLog = void Function(String line); + +class CoinTestCase { + CoinTestCase(this.name, this.body); + final String name; + final Future Function(TestLog log) body; +} + +class TestFailure implements Exception { + TestFailure(this.message); + final String message; + + @override + String toString() => message; +} + +class TestSkipped implements Exception { + TestSkipped(this.reason); + final String reason; + + @override + String toString() => reason; +} + +void expectTrue(final bool value, final String what) { + if (!value) throw TestFailure(what); +} + +void expectEquals(final Object? actual, final Object? expected, final String what) { + if (!_deepEquals(actual, expected)) { + throw TestFailure("$what\n expected: $expected\n actual: $actual"); + } +} + +bool _deepEquals(final Object? a, final Object? b) { + if (a is List && b is List) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!_deepEquals(a[i], b[i])) return false; + } + return true; + } + return a == b; +} + +class CoinTestResults { + int passed = 0; + int failed = 0; + int skipped = 0; + + bool get ok => failed == 0; + + @override + String toString() => "$passed passed, $failed failed, $skipped skipped"; +} + +Future runCoinTests( + final List cases, + final TestLog log, + final CoinTestResults results, +) async { + for (final testCase in cases) { + final stopwatch = Stopwatch()..start(); + try { + await testCase.body(log); + results.passed++; + log("PASS ${testCase.name} (${stopwatch.elapsedMilliseconds}ms)"); + } on TestSkipped catch (e) { + results.skipped++; + log("SKIP ${testCase.name}: $e"); + } catch (e, s) { + results.failed++; + log("FAIL ${testCase.name} (${stopwatch.elapsedMilliseconds}ms)\n$e"); + if (e is! TestFailure) log(s.toString()); + } + await Future.delayed(Duration.zero); + } +} diff --git a/lib/coins/debug/fixtures.dart b/lib/coins/debug/fixtures.dart new file mode 100644 index 0000000..ec61cb0 --- /dev/null +++ b/lib/coins/debug/fixtures.dart @@ -0,0 +1,79 @@ +// BIP39 test vector seed, also used by BIP84 for its reference addresses. +const bip39TestSeed = + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; + +// m/84'/0'/0'/0/0, the BIP84 reference address for [bip39TestSeed]. +const bitcoinAddress = "bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu"; +const bitcoinXpub = + "xpub6CatWdiZiodmUeTDp8LT5or8nmbKNcuyvz7WyksVFkKB4RHwCD3XyuvPEbvqAQY3rAPshWcMLoP2fMFMKHPJ4ZeZXYVUhLv1VMrjPC7PW6V"; + +// Spends a fabricated P2WPKH utxo on m/84'/0'/0'/0/0 to m/84'/0'/0'/0/1. +const bitcoinUnsignedPsbt = + "cHNidP8BAFICAAAAAR8fKfDomQji4hOuyd1B9daUpObUp0dfOfqS4IyXHEC8AAAAAAD9////AZBfAQAAAAAAFgAUnJD5NOpR+g9lBBdwQ+CQjaaSmYMAAAAAAAEBH6CGAQAAAAAAFgAUwM681sPTyox13F7GLr5VMw75EOIiBgMw1U/Q3UIKbl+NNiT180gsrjUPedXwdTv1vu+cLZGvPBhzxdoKVAAAgAAAAIAAAACAAAAAAAAAAAAAIgID53X9UfDfuM2GXZ/xzKKhWM9lH+mX/cn+6cHTtemV6ncYc8XaClQAAIAAAACAAAAAgAAAAAABAAAAAA=="; + +// Witness data does not affect the txid, so a correctly signed transaction +// must still commit to exactly the payment that was requested. +const bitcoinExpectedTxid = "0ff7dabd7a9630099aedd328c789150ad087d2751094392027572e3cf94a0ee1"; +const bitcoinInputPubkey = "0330d54fd0dd420a6e5f8d3624f5f3482cae350f79d5f0753bf5beef9c2d91af3c"; + +// Same payment as [bitcoinUnsignedPsbt], but the input requests SIGHASH_NONE. +// A signature produced under that flag commits to no outputs, so an attacker +// can rewrite every recipient after the user confirms the benign-looking tx. +const bitcoinSighashNonePsbt = + "cHNidP8BAFICAAAAAR8fKfDomQji4hOuyd1B9daUpObUp0dfOfqS4IyXHEC8AAAAAAD9////AZBfAQAAAAAAFgAUnJD5NOpR+g9lBBdwQ+CQjaaSmYMAAAAAAAEBH6CGAQAAAAAAFgAUwM681sPTyox13F7GLr5VMw75EOIiBgMw1U/Q3UIKbl+NNiT180gsrjUPedXwdTv1vu+cLZGvPBhzxdoKVAAAgAAAAIAAAACAAAAAAAAAAAABAwQCAAAAACICA+d1/VHw37jNhl2f8cyioVjPZR/pl/3J/unB07Xplep3GHPF2gpUAACAAAAAgAAAAIAAAAAAAQAAAAA="; + +// PSBT v2, two inputs, no global unsigned tx. Only input 2 has SIGHASH_NONE. +const bitcoinV2MultiInputSighashNonePsbt = + "cHNidP8BAgQCAAAAAQMEAAAAAAEEAQIBBQEBAAEOIKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqAQ8EAAAAAAEQBP////8AAQ4gu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7sBDwQBAAAAARAE/////wEDBAIAAAAAAQMIUMMAAAAAAAABBBYAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="; + +// Shape of a normal Cake Wallet -> Cupcake Bitcoin PSBT after asPsbtV0: +// NON_WITNESS_UTXO + WITNESS_UTXO, BIP32 derivation, no SIGHASH_TYPE. +const bitcoinCakeWalletUnsignedPsbt = + "cHNidP8BAFICAAAAAaqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqAAAAAAABAAAAAZBfAQAAAAAAFgAUREREREREREREREREREREREREREQAAAAAAAEAUgIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/////AP////8BoIYBAAAAAAAWABQzMzMzMzMzMzMzMzMzMzMzMzMzMwAAAAABAR6ghgEAAAAAAAAUMzMzMzMzMzMzMzMzMzMzMzMzMzMiBgJVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVRjerb7vVAAAgAAAAIAAAACAAAAAAAAAAAAAAA=="; + +/// m/84'/2'/0'/0/0 for [bip39TestSeed]. +const litecoinAddress = "ltc1qjmxnz78nmc8nq77wuxh25n2es7rzm5c2rkk4wh"; + +// Must be a version 2 psbt: mwebd reads the recipients and rebuilds the +// transaction from the per input and per output fields, and ignores the +// unsigned transaction that a version 0 psbt carries in its global map. +const litecoinUnsignedPsbt = + "cHNidP8B+wQCAAAAAQIEAgAAAAEDBAAAAAABBAEBAQUBAQGSAQAAAQEfoIYBAAAAAAAWABSWzTF4894PMHvO4a6qTVmHhi3TCiIGAuScm5tdDxJyNdwmoMJSgUxS+zM9ZRqUZ3P1nXLC2pkEGHPF2gpUAACAAgAAgAAAAIAAAAAAAAAAAAEOIBwQp2anNzcJldK5tGtLqj6Rzl+YnOe58+WT3PIRPwSQAQ8EAAAAAAEQBP3///8AIgICHBdQ1KWtVDlnsw6UR+UNp6WHPovhM+sl8s4OpWOLnRcYc8XaClQAAIACAACAAAAAgAAAAAABAAAAAQMIkF8BAAAAAAABBBYAFHfyII4nK++A6YzpVuBdXtj1lvWjAA=="; + +const litecoinExpectedTxid = "d94e56263979b4ec61784d8a7d33d9bc03801d6dbb2a91a821a17e0d70c4ffc9"; +const litecoinInputPubkey = "02e49c9b9b5d0f127235dc26a0c252814c52fb333d651a946773f59d72c2da9904"; +const litecoinDestination = "ltc1qwlezpr3890hcp6vva9twqh27mr6edadreqvhnn"; +const litecoinDestinationAmount = 90000; +const litecoinFee = 10000; + +// The 25 word seed from monero's own cold signing functional test. +const moneroLegacySeed = + "velvet lymph giddy number token physics poetry unquoted nibs useful sabotage " + "limits benches lifestyle eden nitrogen anvil fewest avoid batch vials washing " + "fences goat unquoted"; +const moneroLegacyAddress = + "42ey1afDFnn4886T7196doS9GPMzexD9gXpsZJDwVjeRVdFCSoHnv7KPbBeGpzJBzHRCAs9UxqeoyFQMYbqSWYTfJJQAWDm"; + +// Polyseed wallet the signing fixtures below were captured from. +const moneroPolyseed = + "dentist never novel grain this patient globe extra deputy celery fossil mansion soft long sustain second"; +const moneroPolyseedAddress = + "434dZdLzhymcoNyGSBUJAqhDCLtBECN6698CGRMYByuEAYtpxXdbiibQb3t4qX3SiZi9vDWkxeiEF8kmDGmEoEZ4VMG8Nvh"; + +// Captured from a view-only wallet of [moneroPolyseed] with: +// monero-wallet-rpc export_outputs -> outputs_data_hex +// monero-wallet-rpc transfer -> unsigned_txset +// then hex decoded and stored base64. The cold signer wraps them back into a +// UR at runtime, which is byte for byte what a QR scan would have produced. +const moneroOutputsBase64 = + "TW9uZXJvIG91dHB1dCBleHBvcnQE9fEp/6bf/wEHJu5LlCaq9fKL7DgC4LEZaSxbn+RMKd7rki35tMtvFN416eIkouD0MaLsl/v9MRXEhvgvHbKnIdzmNmelmdCUV/zdmGNRF06siP1JhF9UtofVZl6PLF9TrSyEH4YgHuWZyy3DGDTk13FQZq0skluBdciKOd9lyVs7sJRaw0keUx0DCfZs2lrYl8EwEOoxPiZ3ZcXtUL9SuOpdOTg8CBxTyawB1emZwXKD2vFyQOusNOkb5tw17kHQivgVf/zZa0OBzh74Wwv3YCZ3kfQ0T3kQjr3GqdcN4XsG7wxZVW0U17pXLsQQgBIk7Dg2iTOyTmIktb0P9oFQljfGrbIzMqFhmRfbmyFraCC/8LLX4mqXH6b1uShx2UCDrm2JaEavbatXRcGEamUno8PWdpUTfI/7T4DAhhodjJU4iVwxEtbRrc6lCqmAY/crq5LvDQexBI8BW8+bz1KzGVo+LQinv9mNBAa1jcBWVrbkbwgyZfQN5wU="; + +const moneroUnsignedTxBase64 = + "TW9uZXJvIHVuc2lnbmVkIHR4IHNldAV0qTCTyTDZlPblP7Oc9L2gbfXuLo/GjN4u9Zep+7dtPLq6Q39sJenapmGq2pZ87K58158cHb3s6xal37cCPMEWrktZtHM3zSpMVLQS2j0DLDIHDONqLpcN/ZqEcL4FEDh+JKaDnOHBcgL6JqWEwxauEiqiDTNWydzVOxImKcPeETK+RclTn9t4Utj8VLJkJigTGhmdl1oKYtDG+/LkP4KbPXd/IH7vKOrq2Xn9F1wDfnPqZZBaUFHfCNfjtvvsIjPxc8JeSNl6/tiDZ3cdOqBY5L75XXqZXOiC+Dwhl7AHPcGOzT7xXkd5zN6vNOxFi+u/+lWN5o4+xVUJlx2bLdCwTmZy6zCDIJaz2rPo9kwTALcunFppj4+NjkfbB+x6nQS5wIZR82/AWbwvtFfBaCbC5Jvw6yq/8kzQ7KkHHHVTs1l5IlVU812Z/+IOy2U4qy8l9dbLoQQKYKNvT7S6wXYP63KvPlFjuczCbKqVpR5dq/4HWH8qICaUu9p76vryHDMiWPNmJYyTdDx/2yyNvGHxhI00TuFkvgWO0Q/wEIabCPrTpjwNtozEyazalvWbS9Qnmmoro61BFAPGneNT5nnyI7hFL1iSd4UqIK1Inp/HJ0tyoAg1AhF+0rt+PgJU3j7ALkh0+gViaLwhjjwurhUIZq0hBPn0zAp3I9BK4gKE7RgBKLbrApZt7E0Mvqgnb13/JZqfP/2s3cD2taePzoQcAqZuQR+uGAdNm9tx0dAJsy50oT9vJme6j+9IRtUJCU8uUe+bWztDXkcufzjapB4yOHLgv3R05UvyQLBVe4cXuEuGYGqKD3q6os540jbc0NGa0OFqd4jYA0lP3iF+uDp2sXr2ql3Fc6K/PHvTk9hKRstJhr7ngsDpNZ3i0so4xObEORHus5GHuh9OuOxQu9fhrawnANEf/x/wAJpTc9VWgkOIULcxAzCNVlegIhLe5GTySet4+pQIKGEAWPaX3qAvsMpbMRrGHC66v4Su1SQAS/vdO3iK5dN2V1dpsbJJmUHqFqciO3twjHFVPiMGtindKdxvzb2SQatgJzLVgReYKAo1Hyku1TqzfJoyuiQDWHH630ZxpwzvwqG24Nn2sQagC5dooSNR5uoRZrDLLoDiwWntAjA4+KFB41IbKPXafXSfDHAlIkQlPUG8OqQQ8URa3OI6SFjSTjrOfWtSpUr2iiDohfXqtTDXY5CQaBdW4iA1jf1BYQkYyyE6w4JTNrDdJSGQx1uwDmM63SQCD2Lb3CzPTVDOsVV6D0mAvFS4ydtUcc2nWs4zQ3rILJD+be6SnhfT412tf2VkVVo6EHQoCZSaMSkUpohq4RD/0GeIYrwfqzR6kTDS+fgCTYA7KUmldLA8XCUulwzQGiMDY+Z6MMy+n7jYksyGnutFyDo3Ioxh0bLrS0AceUjdl9QCF1EGg9fC+iAgnq7pc3SRdY11vSqIsLDMspg872Md6hi7zPxFiOwI0HbkTO527yh+G0bOeoMBzNWsnLhjMCzh5Bq8GydyPU6UmOvNXh+p3aBkDrxidVngEXy11LpBJBFaub3iahjUgMHEgaBS+M7qNyee9ftlmZ0KJO1+foc9CbS3gShhqZy+WjVM21VEQqdskwf2Vw9cod+DhaYhfLAk8Y2blCJZ/JDR8ZQ16tCXoTn18fBgRYOowHUevwS7GdoYo7v3KRTcknAUfVgrj4zujA827JfvLFfFYPbCkeTat1LhfcVb7acc6uEUonnWz+8f9aTiQ1DVBQ2pYue86rFwc5i+Osjm09LG5YPE//8bIdCJ2Cz3xaMxUWGqtZA+mTJNapeZ67ewMHQDyQhrunyL2na7Uv5n4UXMajMJRNu6UmwXd96J9NcuA+q0WBIhxdekWuN9eg8EUhDGoLz1Jc/UViujziijBs4FIf4AggXFDip0jE4QJUE7830cP1fkVcLBdL/hjsCmrEsUbZRROxFKuqfcTZ3fCvdVpICnkZYbr6HcyOgfvFpEDEG7QnzulXylBfL+0OaDOvu16QweCaMb1BL0o2v3LpGBvgoXvgGcwDooWYIVa+anHyKXSAyF1EQggqMge8bvl0E6mv7Gqc1Yj1hLWHiGXQeDuHfASEZBjZQjxmaNfvkYKlNvjj4o4mr3jUraNItPZ8ZlpizMCM72vUXYwTuxNi+dDf26PaV2o59L6iJ9r9tmB7wh0IOfTKBx8SnevigZMCFE83K60TlUHMi2s6h9GJO2whK67S1E1RhJVwZ1nVXFb9An7J+XMRS2Xz2BM2om7OGt+BrTiYZVK12Mq5BqvMGERxPvJXkhQC6Hl/boe7TGalLTdCVpZdAwqkftXxvWbnXbFIa0D4egcgzYIVzdgwPUBFPxHS9Xa/8TABomaPDArEb4kZLo/9nRDQ12zuCM4R2TcFaiZzXWHnIso2daLsYFJXlyYk8S7kazlH+t/fOEYK3E7Ut/MJAkt91kPOT6X4rBvevCe3aY1uxI7ozlHiEWQI6n9E93PVfXCyTPI2MUlxRrkEsxugqeju4p6qn2XPGXRoneIOXCMOcsnI70WN2o6/4+B5TGXPQpAyXmZ2golxsTq+tuofzxViId+l7S/yoadfEH"; + +// Destination and amounts of the prepared transaction, as the signer must +// display them before asking for confirmation. It is a self transfer, so the +// destination is the wallet's own primary address. +const moneroDestination = moneroPolyseedAddress; +const moneroAmount = 100000000; +const moneroFee = 122960000; diff --git a/lib/coins/debug/test_cases.dart b/lib/coins/debug/test_cases.dart new file mode 100644 index 0000000..7f1227e --- /dev/null +++ b/lib/coins/debug/test_cases.dart @@ -0,0 +1,290 @@ +import 'dart:convert'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:bdk_flutter/bdk_flutter.dart' as bdk; +import 'package:bitcoin_base/bitcoin_base.dart' show BtcTransaction, LitecoinAddress; +import 'package:blockchain_utils/blockchain_utils.dart' show BytesUtils; +import 'package:cupcake/coins/abstract/coin.dart'; +import 'package:cupcake/coins/abstract/wallet.dart'; +import 'package:cupcake/coins/bitcoin/coin.dart'; +import 'package:cupcake/coins/bitcoin/creation/common.dart'; +import 'package:cupcake/coins/bitcoin/wallet.dart'; +import 'package:cupcake/coins/debug/coin_test.dart'; +import 'package:cupcake/coins/debug/fixtures.dart'; +import 'package:cupcake/coins/litecoin/coin.dart'; +import 'package:cupcake/coins/litecoin/creation/common.dart'; +import 'package:cupcake/coins/litecoin/wallet.dart'; +import 'package:cupcake/coins/monero/coin.dart'; +import 'package:cupcake/coins/monero/creation/common.dart'; +import 'package:cupcake/coins/monero/wallet.dart'; +import 'package:cupcake/utils/config.dart'; +import 'package:cupcake/utils/psbt.dart'; +import 'package:cupcake/utils/types.dart'; +import 'package:cw_mweb/cw_mweb.dart'; +import 'package:cw_mweb/mwebd.pbgrpc.dart'; +import 'package:ur/cbor_lite.dart'; +import 'package:ur/ur.dart'; +import 'package:ur/ur_encoder.dart'; + +/// Wallets the suite creates for itself. They are wiped before and after use, +/// so a leftover here means a run was interrupted. +const _walletPrefix = "cupcake-test-"; +const _walletPassword = "cupcake-test"; + +List coinTestCases(final Coin coin) => switch (coin.type) { + Coins.monero => _moneroCases(), + Coins.bitcoin => _bitcoinCases(), + Coins.litecoin => _litecoinCases(), + Coins.unknown => [], + }; + +class _Holder { + CoinWallet? wallet; + + T require() { + final wallet = this.wallet; + if (wallet is! T) throw TestSkipped("the wallet could not be restored"); + return wallet; + } +} + +void _wipeWalletFiles(final String path) { + for (final file in [File(path), File("$path.keys"), File("$path.address.txt")]) { + if (file.existsSync()) file.deleteSync(); + } +} + +String _hex(final List bytes) => + bytes.map((final b) => b.toRadixString(16).padLeft(2, "0")).join(); + +/// Rebuilds the QR payload an online wallet would have shown, so that the +/// fixtures can be stored as the raw monero blobs they came from. +String _encodeUR(final String tag, final Uint8List payload) { + final cbor = CBOREncoder(); + cbor.encodeBytes(payload); + final encoder = UREncoder(UR(tag, cbor.getBytes()), 1000); + final parts = []; + while (!encoder.isComplete) { + parts.add(encoder.nextPart()); + } + return parts.join("\n"); +} + +List _bitcoinCases() { + const name = "${_walletPrefix}btc"; + final holder = _Holder(); + return [ + CoinTestCase("restore from seed", (final log) async { + final coin = Bitcoin(); + _wipeWalletFiles(coin.getPathForWallet(name)); + final creation = BitcoinWalletCreation(Coin.L); + await creation.wipe(); + creation.seed.ctrl.text = bip39TestSeed; + final outcome = await creation.create(CreateMethod.restore, name, _walletPassword); + expectTrue(outcome?.success ?? false, "restore failed: ${outcome?.message}"); + final wallet = outcome!.wallet! as BitcoinWallet; + holder.wallet = wallet; + log(" ${wallet.address.first.address}"); + expectEquals(wallet.address.first.address, bitcoinAddress, "bip84 address"); + expectEquals(wallet.wallet.xpub, bitcoinXpub, "account xpub"); + }), + CoinTestCase("sign prepared transaction", (final log) async { + final wallet = holder.require(); + final psbt = await bdk.PartiallySignedTransaction.fromString(bitcoinUnsignedPsbt); + expectEquals(psbt.txid(), bitcoinExpectedTxid, "unsigned txid"); + + expectTrue(await wallet.wallet.sign(psbt: psbt), "bdk did not sign the transaction"); + + final tx = psbt.extractTx(); + expectEquals(tx.txid(), bitcoinExpectedTxid, "signing changed the payment"); + final witness = tx.input().first.witness; + expectEquals(witness.length, 2, "expected a signature and a pubkey in the witness"); + expectEquals(_hex(witness[1]), bitcoinInputPubkey, "witness pubkey"); + expectEquals(witness[0].last, 0x01, "expected SIGHASH_ALL in signature"); + log(" signature: ${_hex(witness[0])}"); + }), + CoinTestCase("psbt confirmation warnings", (final log) async { + // Normal Cake -> Cupcake Bitcoin send: quiet. + expectEquals( + psbtConfirmationWarnings(base64.decode(bitcoinCakeWalletUnsignedPsbt)), + [], + "cake bitcoin", + ); + + // Witness-only amounts -> fee warning; no sighash field -> no sighash warning. + final witnessOnly = psbtConfirmationWarnings(base64.decode(bitcoinUnsignedPsbt)); + expectEquals(witnessOnly.length, 1, "witness-only: fee only"); + expectTrue(witnessOnly.single.contains('independently verified'), "fee text"); + + // Explicit SIGHASH_NONE (also witness-only -> fee + sighash). + final none = psbtConfirmationWarnings(base64.decode(bitcoinSighashNonePsbt)); + expectTrue(none.any((final w) => w.contains('SIGHASH_NONE')), "sighash none"); + expectTrue(none.any((final w) => w.contains('independently verified')), "fee too"); + + // v2 multi-input: only input 2 is flagged -> one sighash warning. + final v2 = psbtConfirmationWarnings(base64.decode(bitcoinV2MultiInputSighashNonePsbt)); + expectTrue( + v2.any((final w) => w.contains('SIGHASH_NONE') && w.contains('1 input')), + "input 2 only", + ); + + // Litecoin v2 (mwebd witness-only): fee warn, no sighash. + final ltc = psbtConfirmationWarnings(base64.decode(litecoinUnsignedPsbt)); + expectEquals(ltc.length, 1, "ltc: fee only"); + expectTrue(ltc.single.contains('independently verified'), "ltc fee text"); + log(" cake=[], witness/ltc=fee, sighash=NONE(+fee), v2=input2"); + }), + CoinTestCase("cleanup", (final log) async { + await holder.wallet?.close(); + _wipeWalletFiles(Bitcoin().getPathForWallet(name)); + }), + ]; +} + +List _litecoinCases() { + const name = "${_walletPrefix}ltc"; + final holder = _Holder(); + return [ + CoinTestCase("restore from seed", (final log) async { + final coin = Litecoin(); + _wipeWalletFiles(coin.getPathForWallet(name)); + final creation = LitecoinWalletCreation(Coin.L); + await creation.wipe(); + creation.seed.ctrl.text = bip39TestSeed; + final outcome = await creation.create(CreateMethod.restore, name, _walletPassword); + expectTrue(outcome?.success ?? false, "restore failed: ${outcome?.message}"); + final wallet = outcome!.wallet! as LitecoinWallet; + holder.wallet = wallet; + log(" ${wallet.getSegwitAddress}"); + expectEquals(wallet.getSegwitAddress, litecoinAddress, "bip84 address"); + }), + CoinTestCase("derive mweb address", (final log) async { + final wallet = holder.require(); + final address = wallet.getMwebAddress; + log(" $address"); + expectTrue(address.startsWith("ltcmweb1"), "unexpected mweb address: $address"); + }), + CoinTestCase("sign prepared transaction", (final log) async { + final wallet = holder.require(); + final recipients = await CwMweb.psbtGetRecipients( + PsbtGetRecipientsRequest(psbtB64: litecoinUnsignedPsbt), + ); + expectEquals(recipients.recipient.length, 1, "recipient count"); + expectEquals(recipients.recipient.first.address, litecoinDestination, "recipient address"); + expectEquals( + recipients.recipient.first.value.toInt(), + litecoinDestinationAmount, + "recipient amount", + ); + expectEquals(recipients.fee.toInt(), litecoinFee, "fee"); + + final inputProgram = + LitecoinAddress(recipients.inputAddress.first).baseAddress.addressProgram; + expectEquals(wallet.pubkeyMap.getExternalIndex(inputProgram), 0, "input address index"); + + var signed = await CwMweb.psbtSign( + PsbtSignRequest( + psbtB64: litecoinUnsignedPsbt, + scanSecret: wallet.scanSecret, + spendSecret: wallet.spendSecret, + ), + ); + signed = await CwMweb.psbtSignNonMweb( + PsbtSignNonMwebRequest( + psbtB64: signed.psbtB64, + privKey: wallet.wpkhHd.derivePath("0/0").privateKey.raw, + index: 0, + ), + ); + expectTrue(signed.psbtB64 != litecoinUnsignedPsbt, "the psbt came back unchanged"); + + final extracted = await CwMweb.psbtExtract(PsbtExtractRequest(psbtB64: signed.psbtB64)); + final tx = BtcTransaction.fromRaw(BytesUtils.toHexString(extracted.rawTx)); + expectEquals(tx.txId(), litecoinExpectedTxid, "signing changed the payment"); + final witness = tx.witnesses.first.stack; + expectEquals(witness.length, 2, "expected a signature and a pubkey in the witness"); + expectEquals(witness[1], litecoinInputPubkey, "witness pubkey"); + log(" signature: ${witness[0]}"); + }), + CoinTestCase("cleanup", (final log) async { + await holder.wallet?.close(); + _wipeWalletFiles(Litecoin().getPathForWallet(name)); + }), + ]; +} + +Future _restoreMonero(final String name, final String seed) async { + final coin = Monero(); + for (final open in Monero.wPtrList) { + Monero.wm.closeWallet(open, false); + } + Monero.wPtrList.clear(); + _wipeWalletFiles(coin.getPathForWallet(name)); + final creation = MoneroWalletCreation(Coin.L); + await creation.wipe(); + creation.seed.ctrl.text = seed; + final outcome = await creation.create(CreateMethod.restore, name, _walletPassword); + expectTrue(outcome.success, "restore failed: ${outcome.message}"); + return outcome.wallet! as MoneroWallet; +} + +List _moneroCases() { + const legacyName = "${_walletPrefix}xmr-legacy"; + const polyseedName = "${_walletPrefix}xmr"; + final holder = _Holder(); + return [ + CoinTestCase("restore from a 25 word seed", (final log) async { + final wallet = await _restoreMonero(legacyName, moneroLegacySeed); + log(" ${wallet.address.first.address}"); + expectEquals(wallet.address.first.address, moneroLegacyAddress, "primary address"); + expectEquals(wallet.legacySeed, moneroLegacySeed, "seed round trip"); + await wallet.close(); + }), + CoinTestCase("restore from a polyseed", (final log) async { + final wallet = await _restoreMonero(polyseedName, moneroPolyseed); + holder.wallet = wallet; + log(" ${wallet.address.first.address}"); + expectEquals(wallet.address.first.address, moneroPolyseedAddress, "primary address"); + expectEquals(wallet.polyseed, moneroPolyseed, "seed round trip"); + }), + CoinTestCase("import outputs and sign prepared transaction", (final log) async { + if (moneroOutputsBase64.isEmpty) { + throw TestSkipped("no captured transaction, see lib/coins/debug/fixtures.dart"); + } + final wallet = holder.require().wallet; + + wallet.importOutputsUR(_encodeUR("xmr-output", base64Decode(moneroOutputsBase64))); + expectEquals(wallet.status(), 0, "importOutputsUR: ${wallet.errorString()}"); + + final tx = wallet.loadUnsignedTxUR( + input: _encodeUR("xmr-txunsigned", base64Decode(moneroUnsignedTxBase64)), + ); + expectEquals(wallet.status(), 0, "loadUnsignedTxUR: ${wallet.errorString()}"); + expectEquals(tx.status(), 0, "unsigned transaction: ${tx.errorString()}"); + expectEquals(tx.txCount(), 1, "transaction count"); + expectEquals(tx.recipientAddress(), moneroDestination, "recipient"); + expectEquals(tx.amount(), "$moneroAmount", "amount"); + expectEquals(tx.fee(), "$moneroFee", "fee"); + + final signed = tx + .signUR(CupcakeConfig.instance.maxFragmentLength) + .split("\n") + .where((final part) => part.isNotEmpty) + .toList(); + expectEquals(wallet.status(), 0, "signUR: ${wallet.errorString()}"); + expectEquals(tx.status(), 0, "signed transaction: ${tx.errorString()}"); + expectTrue(signed.isNotEmpty, "signUR returned nothing"); + expectTrue( + signed.first.startsWith("ur:xmr-txsigned/"), + "unexpected UR fragment: ${signed.first}", + ); + log(" ${signed.length} signed UR fragment(s)"); + }), + CoinTestCase("cleanup", (final log) async { + await holder.wallet?.close(); + _wipeWalletFiles(Monero().getPathForWallet(legacyName)); + _wipeWalletFiles(Monero().getPathForWallet(polyseedName)); + }), + ]; +} diff --git a/lib/coins/litecoin/wallet.dart b/lib/coins/litecoin/wallet.dart index 4a714f8..66fa2db 100644 --- a/lib/coins/litecoin/wallet.dart +++ b/lib/coins/litecoin/wallet.dart @@ -13,6 +13,7 @@ import 'package:cupcake/coins/litecoin/address.dart'; import 'package:cupcake/coins/litecoin/amount.dart'; import 'package:cupcake/coins/litecoin/coin.dart'; import 'package:cupcake/coins/litecoin/wallet_info.dart'; +import 'package:cupcake/utils/psbt.dart'; import 'package:cupcake/utils/types.dart'; import 'package:cupcake/utils/urqr.dart'; import 'package:cupcake/views/animated_qr_page.dart'; @@ -66,8 +67,8 @@ class LitecoinWallet implements CoinWallet { bip39.mnemonicToSeed(seed, passphrase: passphrase), Bip44Conf.litecoinMainNet.altKeyNetVer, ).derivePath("m/84'/2'/0'") as Bip32Slip10Secp256k1; - final mwebHd = Bip32Slip10Secp256k1.fromSeed(bip39.mnemonicToSeed(seed)).derivePath("m/1000'") - as Bip32Slip10Secp256k1; + final mwebHd = Bip32Slip10Secp256k1.fromSeed(bip39.mnemonicToSeed(seed, passphrase: passphrase)) + .derivePath("m/1000'") as Bip32Slip10Secp256k1; final pubkeyMap = PubkeyIndexMap(wpkhHd); pubkeyMap.topupExternal(); @@ -159,6 +160,7 @@ class LitecoinWallet implements CoinWallet { wallet: this, destMap: destMap, fee: LitecoinAmount(resp.fee.toInt()), + warnings: psbtConfirmationWarnings(base64.decode(psbtB64)), confirmCallback: (final BuildContext context) async { Uint8List sourceBytes; try { diff --git a/lib/utils/psbt.dart b/lib/utils/psbt.dart new file mode 100644 index 0000000..eded773 --- /dev/null +++ b/lib/utils/psbt.dart @@ -0,0 +1,126 @@ +import 'dart:typed_data'; + +List psbtConfirmationWarnings(final Uint8List psbtBytes) { + try { + final (sighashes, feeOk) = _inspect(psbtBytes); + return [ + if (!feeOk) + 'The fee shown cannot be independently verified. ' + 'Input amounts come from the wallet that created this PSBT and may not ' + 'match what you actually pay.', + if (sighashes.isNotEmpty) + 'This transaction uses a non-standard signature type ' + '(${sighashes.map(_sighashName).join(', ')}) on ' + '${sighashes.length} input${sighashes.length == 1 ? '' : 's'}. ' + 'The signature may not commit to the outputs shown above. ' + 'Only continue if you trust the wallet that created this PSBT.', + ]; + } catch (_) { + return const [ + 'Could not verify this PSBT. Only continue if you trust the wallet that created it.', + ]; + } +} + +// ret: [non-standard sighash types in input order, fee independently verifiable] +(List, bool) _inspect(final Uint8List bytes) { + final r = _R(bytes); + if (bytes.length < 5 || + bytes[0] != 0x70 || + bytes[1] != 0x73 || + bytes[2] != 0x62 || + bytes[3] != 0x74 || + bytes[4] != 0xff) { + throw FormatException('bad magic'); + } + r.i = 5; + + final global = {}; + while (_entry(global, r)) {} + + final int nIn; + final int nOut; + if (global[0x00] case final tx?) { + (nIn, nOut) = _txCounts(tx); // v0 + } else { + nIn = _R(global[0x04]!).varint(); // v2 + nOut = _R(global[0x05]!).varint(); + } + if (nIn <= 0) throw FormatException('no inputs'); + + final sighashes = []; + var feeOk = true; + for (var i = 0; i < nIn; i++) { + final input = {}; + while (_entry(input, r)) {} + if (!input.containsKey(0x00)) feeOk = false; // NON_WITNESS_UTXO + final raw = input[0x03]; // SIGHASH_TYPE + if (raw != null && raw.length == 4) { + final type = ByteData.sublistView(raw).getUint32(0, Endian.little); + if (type != 0x01) sighashes.add(type); // anything but SIGHASH_ALL + } + } + for (var i = 0; i < nOut; i++) { + while (_entry(null, r)) {} + } + return (sighashes, feeOk); +} + +// read one PSBT key/value. Empty-keyData values are stored in [map] when non-null. +bool _entry(final Map? map, final _R r) { + final keyLen = r.varint(); + if (keyLen == 0) return false; + final keyType = r.u8(); + final keyData = r.take(keyLen - 1); + final value = r.take(r.varint()); + if (map != null && keyData.isEmpty) map[keyType] = value; + return true; +} + +(int, int) _txCounts(final Uint8List tx) { + final r = _R(tx)..i = 4; + if (r.left > 0 && r.data[r.i] == 0x00) { + r.u8(); + if (r.u8() != 0x01) throw FormatException('bad segwit marker'); + } + final vin = r.varint(); + for (var i = 0; i < vin; i++) { + r.take(36); + r.take(r.varint()); + r.take(4); + } + return (vin, r.varint()); +} + +String _sighashName(final int type) { + final base = switch (type & 0x1f) { + 0x00 => 'SIGHASH_DEFAULT', + 0x01 => 'SIGHASH_ALL', + 0x02 => 'SIGHASH_NONE', + 0x03 => 'SIGHASH_SINGLE', + _ => 'SIGHASH_$type', + }; + return (type & 0x80) != 0 ? '$base|ANYONECANPAY' : base; +} + +class _R { + _R(this.data); + final Uint8List data; + int i = 0; + + int get left => data.length - i; + int u8() => data[i++]; + Uint8List take(final int n) { + final out = data.sublist(i, i + n); + i += n; + return out; + } + + int varint() { + final b = u8(); + if (b < 0xfd) return b; + if (b == 0xfd) return u8() | (u8() << 8); + if (b == 0xfe) return u8() | (u8() << 8) | (u8() << 16) | (u8() << 24); + throw FormatException('varint too large'); + } +} diff --git a/lib/view_model/unconfirmed_transaction_view_model.dart b/lib/view_model/unconfirmed_transaction_view_model.dart index 045a746..c937963 100644 --- a/lib/view_model/unconfirmed_transaction_view_model.dart +++ b/lib/view_model/unconfirmed_transaction_view_model.dart @@ -17,6 +17,7 @@ abstract class UnconfirmedTransactionViewModelBase extends ViewModel with Store required this.wallet, required this.fee, required this.destMap, + required this.warnings, required final FutureOr Function(BuildContext context) confirmCallback, required final FutureOr Function(BuildContext context) cancelCallback, }) : _confirmCallback = confirmCallback, @@ -41,4 +42,5 @@ abstract class UnconfirmedTransactionViewModelBase extends ViewModel with Store final Amount fee; final Map destMap; + final List warnings; } diff --git a/lib/views/debug/coin_test_screen.dart b/lib/views/debug/coin_test_screen.dart new file mode 100644 index 0000000..d26b5c1 --- /dev/null +++ b/lib/views/debug/coin_test_screen.dart @@ -0,0 +1,93 @@ +import 'package:cupcake/coins/abstract/coin.dart'; +import 'package:cupcake/coins/debug/coin_test.dart'; +import 'package:cupcake/coins/debug/test_cases.dart'; +import 'package:cupcake/coins/list.dart'; +import 'package:cupcake/view_model/abstract.dart'; +import 'package:cupcake/views/abstract.dart'; +import 'package:cupcake/views/widgets/buttons/long_primary.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; + +class CoinTestViewModel extends ViewModel { + @override + String get screenName => "Coin tests"; + + final Observable status = Observable(""); + final Observable busy = Observable(false); + + void log(final String line) { + runInAction(() => status.value = "${status.value}\n$line".trimLeft()); + } + + Future run() async { + if (busy.value) return; + runInAction(() { + busy.value = true; + status.value = ""; + }); + + Coin.L = L; + final results = CoinTestResults(); + try { + for (final coin in walletCoins) { + log(""); + log("=== ${coin.strings.nameFull} ==="); + if (!coin.isEnabled) { + results.skipped++; + log("SKIP: native library unavailable"); + continue; + } + await runCoinTests(coinTestCases(coin), log, results); + } + } catch (e, s) { + results.failed++; + log("FAIL harness crashed: $e\n$s"); + } + log(""); + log(results.ok ? "ALL OK: $results" : "FAILURES: $results"); + runInAction(() => busy.value = false); + } +} + +class CoinTestScreen extends AbstractView { + CoinTestScreen({super.key}); + + @override + final CoinTestViewModel viewModel = CoinTestViewModel(); + + final ScrollController _scrollController = ScrollController(); + + @override + Widget? body(final BuildContext context) { + return Observer( + builder: (final BuildContext context) { + WidgetsBinding.instance.addPostFrameCallback((final _) { + if (!_scrollController.hasClients) return; + _scrollController.jumpTo(_scrollController.position.maxScrollExtent); + }); + return SingleChildScrollView( + controller: _scrollController, + padding: const EdgeInsets.symmetric(horizontal: 16), + child: SelectableText( + viewModel.status.value.isEmpty + ? "Restores known test wallets, checks the derived addresses and\n" + "signs prepared transactions offline." + : viewModel.status.value, + style: const TextStyle(fontFamily: "monospace", fontSize: 12), + ), + ); + }, + ); + } + + @override + Widget? bottomNavigationBar(final BuildContext context) { + return Observer( + builder: (final BuildContext context) => LongPrimaryButton( + text: viewModel.busy.value ? "Running..." : "Run all coin tests", + onPressed: viewModel.busy.value ? null : viewModel.run, + ), + ); + } +} diff --git a/lib/views/settings.dart b/lib/views/settings.dart index 289d012..9e348a2 100644 --- a/lib/views/settings.dart +++ b/lib/views/settings.dart @@ -2,6 +2,7 @@ import 'package:cupcake/coins/abstract/wallet.dart'; import 'package:cupcake/utils/secure_storage.dart'; import 'package:cupcake/view_model/settings_view_model.dart'; import 'package:cupcake/views/abstract.dart'; +import 'package:cupcake/views/debug/coin_test_screen.dart'; import 'package:cupcake/views/open_wallet.dart'; import 'package:cupcake/views/ui_playground.dart'; import 'package:cupcake/views/widgets/buttons/long_primary.dart'; @@ -110,6 +111,11 @@ class SettingsView extends AbstractView { onPressed: () => UIPlayground(wallet: viewModel.wallet).push(context), text: "UI Playground", ), + if (viewModel.debug) + LongPrimaryButton( + onPressed: () => CoinTestScreen().push(context), + text: "Coin tests", + ), if (viewModel.debug) ...List.generate( viewModel.wallet.coin.debugOptions.length, diff --git a/lib/views/ui_playground.dart b/lib/views/ui_playground.dart index 43fa8ca..0f47ee2 100644 --- a/lib/views/ui_playground.dart +++ b/lib/views/ui_playground.dart @@ -1,11 +1,14 @@ +import 'dart:convert'; import 'dart:math'; import 'package:cupcake/coins/abstract/amount.dart'; import 'package:cupcake/coins/abstract/address.dart'; import 'package:cupcake/coins/abstract/wallet.dart'; +import 'package:cupcake/coins/debug/fixtures.dart'; import 'package:cupcake/utils/alerts/basic.dart'; import 'package:cupcake/utils/config.dart'; import 'package:cupcake/utils/new_wallet/info_page.dart'; +import 'package:cupcake/utils/psbt.dart'; import 'package:cupcake/utils/types.dart'; import 'package:cupcake/view_model/create_wallet_view_model.dart'; import 'package:cupcake/view_model/ui_playground_view_model.dart'; @@ -190,6 +193,7 @@ class UIPlayground extends AbstractView { confirmCallback: (final BuildContext context) => {_alert(context, "confirmCallback")}, cancelCallback: (final BuildContext context) => _alert(context, "cancelCallback"), ).pushReplacement(context), + "UnconfirmedTransaction(SIGHASH_NONE warning)": () => _showSighashNoneConfirm(context), "VerifySeed(seedWords: 12, wordList: (4, 1000))": () => VerifySeedPage(seedWords: _genSeedWords(12), wordList: _genList(4, 1000)).push(context), "VerifySeed(seedWords: 16, wordList: (4, 1000))": () => @@ -202,6 +206,19 @@ class UIPlayground extends AbstractView { }; } + void _showSighashNoneConfirm(final BuildContext context) { + UnconfirmedTransactionView( + wallet: viewModel.wallet, + fee: Amount(10000), + destMap: { + Address(UnknownLabel(), "bc1qnjg0jd8228aq7egyzacy8cys3knf9xvrerkf9g"): Amount(90000), + }, + warnings: psbtConfirmationWarnings(base64.decode(bitcoinSighashNonePsbt)), + confirmCallback: (final BuildContext context) => {_alert(context, "confirmCallback")}, + cancelCallback: (final BuildContext context) => _alert(context, "cancelCallback"), + ).pushReplacement(context); + } + void _alert(final BuildContext context, final String message) { Navigator.of(context).pop(); showAlert(context: context, title: "callback", body: [message]); diff --git a/lib/views/unconfirmed_transaction.dart b/lib/views/unconfirmed_transaction.dart index f6b3cef..f7d1e78 100644 --- a/lib/views/unconfirmed_transaction.dart +++ b/lib/views/unconfirmed_transaction.dart @@ -8,6 +8,7 @@ import 'package:cupcake/l10n/app_localizations.dart'; import 'package:cupcake/utils/formatter_address.dart'; import 'package:cupcake/view_model/unconfirmed_transaction_view_model.dart'; import 'package:cupcake/views/widgets/guarded_gesture_detector.dart'; +import 'package:cupcake/views/widgets/yellow_warning.dart'; import 'package:flutter/material.dart'; class UnconfirmedTransactionView { @@ -17,14 +18,18 @@ class UnconfirmedTransactionView { required final Map destMap, required final FutureOr Function(BuildContext context) confirmCallback, required final FutureOr Function(BuildContext context) cancelCallback, + this.warnings = const [], }) : viewModel = UnconfirmedTransactionViewModel( wallet: wallet, fee: fee, destMap: destMap, + warnings: warnings, confirmCallback: confirmCallback, cancelCallback: cancelCallback, ); + final List warnings; + final UnconfirmedTransactionViewModel viewModel; AppLocalizations get L => viewModel.L; ThemeData get T => viewModel.T; @@ -138,6 +143,11 @@ class UnconfirmedTransactionView { child: Column( mainAxisSize: MainAxisSize.min, children: [ + for (final warning in viewModel.warnings) + YellowWarning( + text: warning, + padding: const EdgeInsets.only(bottom: 8), + ), _buildStandardTile( context, itemTitle: 'Fee', diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index a516dc4..0e3cb3b 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,23 +6,33 @@ import FlutterMacOS import Foundation import cw_mweb +import device_info_plus import fast_scanner +import file_picker +import file_selector_macos +import flutter_inappwebview_macos import flutter_secure_storage_macos import local_auth_darwin import package_info_plus -import path_provider_foundation +import rive_common import share_plus +import shared_preferences_foundation import sqlite3_flutter_libs import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { CwMwebPlugin.register(with: registry.registrar(forPlugin: "CwMwebPlugin")) + DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) LocalAuthPlugin.register(with: registry.registrar(forPlugin: "LocalAuthPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + RivePlugin.register(with: registry.registrar(forPlugin: "RivePlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/pubspec.lock b/pubspec.lock index 29861bd..f408877 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,23 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "16e298750b6d0af7ce8a3ba7c18c69c3785d11b15ec83f6dcd0ad2a0009b3cab" + sha256: "5b7468c326d2f8a4f630056404ca0d291ade42918f4a3c6233618e724f39da8e" url: "https://pub.dev" source: hosted - version: "76.0.0" - _macros: - dependency: transitive - description: dart - source: sdk - version: "0.3.3" + version: "92.0.0" analyzer: dependency: "direct main" description: name: analyzer - sha256: "1f14db053a8c23e260789e9b0980fa27f2680dd640932cae5e1137cce0e46e1e" + sha256: "70e4b1ef8003c64793a9e268a551a82869a8a96f39deb73dea28084b0e8bf75e" url: "https://pub.dev" source: hosted - version: "6.11.0" + version: "9.0.0" android_native_settings_properties: dependency: transitive description: @@ -31,6 +26,22 @@ packages: url: "https://github.com/mrcyjanek/flutter_android_native_settings_properties" source: git version: "0.0.1" + animated_reorderable_list: + dependency: transitive + description: + name: animated_reorderable_list + sha256: "5de5cca556a8c9c8f7b65234ae4b683593dc6e167db498744a5e389302f24d13" + url: "https://pub.dev" + source: hosted + version: "1.3.0" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "50e982d500bc863e1d703448afdbf9e5a72eb48840a4f766fa361ffd6877055f" + url: "https://pub.dev" + source: hosted + version: "2.0.3" applock: dependency: "direct main" description: @@ -44,10 +55,10 @@ packages: dependency: transitive description: name: archive - sha256: "2fde1607386ab523f7a36bb3e7edb43bd58e6edaf2ffb29d8a6d578b297fdbbd" + sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff url: "https://pub.dev" source: hosted - version: "4.0.7" + version: "4.0.9" args: dependency: transitive description: @@ -64,13 +75,21 @@ packages: url: "https://pub.dev" source: hosted version: "2.13.0" + awesome_dialog: + dependency: transitive + description: + name: awesome_dialog + sha256: "41c41ae4b30b5c7f26bb3d9f9c87010ed1cab0bb4d4ac0cc513e5799c37e9d82" + url: "https://pub.dev" + source: hosted + version: "3.2.1" bdk_flutter: dependency: "direct main" description: path: "." - ref: cfa95443f11e75625c5f7de986b1cc64b682ed3f - resolved-ref: cfa95443f11e75625c5f7de986b1cc64b682ed3f - url: "https://github.com/StaxoLotl/bdk-flutter/" + ref: "43532b1436f7f76d72ba67bd4428cd0a81cae145" + resolved-ref: "43532b1436f7f76d72ba67bd4428cd0a81cae145" + url: "https://github.com/MrCyjaneK/bdk-flutter.git" source: git version: "0.31.3" bip32: @@ -123,62 +142,54 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + bubble: + dependency: transitive + description: + name: bubble + sha256: "65b992b8f8ba2e7e2871190cbdfaa0818b6de2f340bef37cb5ee1b61debe0226" + url: "https://pub.dev" + source: hosted + version: "1.2.1" build: dependency: "direct main" description: name: build - sha256: "51dc711996cbf609b90cbe5b335bbce83143875a9d58e4b5c6d3c4f684d3dda7" + sha256: "275bf6bb2a00a9852c28d4e0b410da1d833a734d57d39d44f94bfc895a484ec3" url: "https://pub.dev" source: hosted - version: "2.5.4" + version: "4.0.4" build_cli_annotations: dependency: transitive description: name: build_cli_annotations - sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172 + sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95 url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.1" build_config: dependency: transitive description: name: build_config - sha256: "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33" + sha256: "4f64382b97504dc2fcdf487d5aae33418e08b4703fc21249e4db6d804a4d0187" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.2.0" build_daemon: dependency: transitive description: name: build_daemon - sha256: "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa" + sha256: bf05f6e12cfea92d3c09308d7bcdab1906cd8a179b023269eed00c071004b957 url: "https://pub.dev" source: hosted - version: "4.0.4" - build_resolvers: - dependency: transitive - description: - name: build_resolvers - sha256: ee4257b3f20c0c90e72ed2b57ad637f694ccba48839a821e87db762548c22a62 - url: "https://pub.dev" - source: hosted - version: "2.5.4" + version: "4.1.1" build_runner: dependency: "direct dev" description: name: build_runner - sha256: "382a4d649addbfb7ba71a3631df0ec6a45d5ab9b098638144faf27f02778eb53" - url: "https://pub.dev" - source: hosted - version: "2.5.4" - build_runner_core: - dependency: transitive - description: - name: build_runner_core - sha256: "85fbbb1036d576d966332a3f5ce83f2ce66a40bea1a94ad2d5fc29a19a0d3792" + sha256: "39ad4ca8a2876779737c60e4228b4bcd35d4352ef7e14e47514093edc012c734" url: "https://pub.dev" source: hosted - version: "9.1.2" + version: "2.11.1" built_collection: dependency: transitive description: @@ -191,18 +202,18 @@ packages: dependency: transitive description: name: built_value - sha256: a30f0a0e38671e89a492c44d005b5545b830a961575bbd8336d42869ff71066d + sha256: "6ae8a6435a8c6520c7077b107e77f1fb4ba7009633259a4d49a8afd8e7efc5e9" url: "https://pub.dev" source: hosted - version: "8.12.0" + version: "8.12.4" characters: dependency: transitive description: name: characters - sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" charcode: dependency: transitive description: @@ -215,10 +226,18 @@ packages: dependency: transitive description: name: checked_yaml - sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff + sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "2.0.4" + cli_config: + dependency: transitive + description: + name: cli_config + sha256: ac20a183a07002b700f0c25e61b7ee46b23c309d76ab7b7640a028f18e4d99ec + url: "https://pub.dev" + source: hosted + version: "0.2.0" cli_util: dependency: transitive description: @@ -235,14 +254,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.2" + code_assets: + dependency: transitive + description: + name: code_assets + sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" + url: "https://pub.dev" + source: hosted + version: "1.0.0" code_builder: dependency: transitive description: name: code_builder - sha256: "11654819532ba94c34de52ff5feb52bd81cba1de00ef2ed622fd50295f9d4243" + sha256: "6a6cab2ba4680d6423f34a9b972a4c9a94ebe1b62ecec4e1a1f2cba91fd1319d" url: "https://pub.dev" source: hosted - version: "4.11.0" + version: "4.11.1" collection: dependency: transitive description: @@ -267,22 +294,38 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + coverage: + dependency: transitive + description: + name: coverage + sha256: "5da775aa218eaf2151c721b16c01c7676fbfdd99cebba2bf64e8b807a28ff94d" + url: "https://pub.dev" + source: hosted + version: "1.15.0" cross_file: dependency: transitive description: name: cross_file - sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" url: "https://pub.dev" source: hosted - version: "0.3.4+2" + version: "0.3.5+2" crypto: dependency: "direct main" description: name: crypto - sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf + url: "https://pub.dev" + source: hosted + version: "3.0.7" + csslib: + dependency: transitive + description: + name: csslib + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "1.0.2" cupertino_icons: dependency: "direct main" description: @@ -310,10 +353,10 @@ packages: dependency: transitive description: name: dart_style - sha256: "7306ab8a2359a48d22310ad823521d723acfed60ee1f7e37388e8986853b6820" + sha256: a9c30492da18ff84efe2422ba2d319a89942d93e58eb0b73d32abe822ef54b7b url: "https://pub.dev" source: hosted - version: "2.3.8" + version: "3.1.3" dartx: dependency: transitive description: @@ -322,30 +365,94 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.0" + data_table_2: + dependency: transitive + description: + name: data_table_2 + sha256: cb31d465dcf1e1598a662d06d3d2c16c73700ae9e837a3d91588f1dda7519abc + url: "https://pub.dev" + source: hosted + version: "2.7.2" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" + decimal: + dependency: transitive + description: + name: decimal + sha256: fc706a5618b81e5b367b01dd62621def37abc096f2b46a9bd9068b64c1fa36d0 + url: "https://pub.dev" + source: hosted + version: "3.2.4" + device_info_plus: + dependency: transitive + description: + name: device_info_plus + sha256: "77f757b789ff68e4eaf9c56d1752309bd9f7ad557cb105b938a7f8eb89e59110" + url: "https://pub.dev" + source: hosted + version: "9.1.2" + device_info_plus_platform_interface: + dependency: transitive + description: + name: device_info_plus_platform_interface + sha256: e1ea89119e34903dca74b883d0dd78eb762814f97fb6c76f35e9ff74d261a18f + url: "https://pub.dev" + source: hosted + version: "7.0.3" drift: dependency: "direct main" description: name: drift - sha256: b584ddeb2b74436735dd2cf746d2d021e19a9a6770f409212fd5cbc2814ada85 + sha256: "970cd188fddb111b26ea6a9b07a62bf5c2432d74147b8122c67044ae3b97e99e" url: "https://pub.dev" source: hosted - version: "2.26.1" + version: "2.31.0" drift_dev: dependency: "direct dev" description: name: drift_dev - sha256: "0d3f8b33b76cf1c6a82ee34d9511c40957549c4674b8f1688609e6d6c7306588" + sha256: "917184b2fb867b70a548a83bf0d36268423b38d39968c06cce4905683da49587" url: "https://pub.dev" source: hosted - version: "2.26.0" + version: "2.31.0" drift_flutter: dependency: "direct main" description: name: drift_flutter - sha256: b7534bf320aac5213259aac120670ba67b63a1fd010505babc436ff86083818f + sha256: c07120854742a0cae2f7501a0da02493addde550db6641d284983c08762e60a7 + url: "https://pub.dev" + source: hosted + version: "0.2.8" + easy_debounce: + dependency: transitive + description: + name: easy_debounce + sha256: f082609cfb8f37defb9e37fc28bc978c6712dedf08d4c5a26f820fa10165a236 + url: "https://pub.dev" + source: hosted + version: "2.0.3" + easy_stepper: + dependency: transitive + description: + name: easy_stepper + sha256: "63f66314a509ec690c8152a41288961fd96ba9e92ef184299f068a5e78bd16ad" + url: "https://pub.dev" + source: hosted + version: "0.8.5+1" + equatable: + dependency: transitive + description: + name: equatable + sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" url: "https://pub.dev" source: hosted - version: "0.2.7" + version: "2.0.8" fake_async: dependency: transitive description: @@ -367,10 +474,10 @@ packages: dependency: transitive description: name: ffi - sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" file: dependency: transitive description: @@ -379,6 +486,54 @@ packages: url: "https://pub.dev" source: hosted version: "7.0.1" + file_picker: + dependency: transitive + description: + name: file_picker + sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343" + url: "https://pub.dev" + source: hosted + version: "10.3.10" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" + url: "https://pub.dev" + source: hosted + version: "0.9.4" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" + url: "https://pub.dev" + source: hosted + version: "0.9.5" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" + url: "https://pub.dev" + source: hosted + version: "2.7.0" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" + url: "https://pub.dev" + source: hosted + version: "0.9.3+5" + fixed: + dependency: transitive + description: + name: fixed + sha256: "9b67adeef364271501738a7ab452f45f3207b69a7d8d5692eaa22d038757b035" + url: "https://pub.dev" + source: hosted + version: "5.3.4" fixnum: dependency: transitive description: @@ -387,48 +542,136 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.1" + flex_color_scheme: + dependency: transitive + description: + name: flex_color_scheme + sha256: ab854146f201d2d62cc251fd525ef023b84182c4a0bfe4ae4c18ffc505b412d3 + url: "https://pub.dev" + source: hosted + version: "8.4.0" + flex_seed_scheme: + dependency: transitive + description: + name: flex_seed_scheme + sha256: a3183753bbcfc3af106224bff3ab3e1844b73f58062136b7499919f49f3667e7 + url: "https://pub.dev" + source: hosted + version: "4.0.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" - flutter_asset_generator: - dependency: "direct dev" - description: - name: flutter_asset_generator - sha256: "11ecacee3aeb83035572f86d37dff06e6925d4968cb768156aea711f6ea24ae9" - url: "https://pub.dev" - source: hosted - version: "1.2.0" flutter_driver: dependency: transitive description: flutter source: sdk version: "0.0.0" + flutter_form_builder: + dependency: transitive + description: + name: flutter_form_builder + sha256: "1233251b4bc1d5deb245745d2a89dcebf4cdd382e1ec3f21f1c6703b700e574f" + url: "https://pub.dev" + source: hosted + version: "10.3.0+2" flutter_gen: dependency: "direct main" description: name: flutter_gen - sha256: "4117a3ea6b26a910c715bd58abcc5a90447e70930a5b98249e94c41da9e849bb" + sha256: eac4863b65813aacbf16ecc07e7c271ab82fb2d95181825348f1fb7b03fd52da url: "https://pub.dev" source: hosted - version: "5.10.0" + version: "5.12.0" flutter_gen_core: dependency: transitive description: name: flutter_gen_core - sha256: "3eaa2d3d8be58267ac4cd5e215ac965dd23cae0410dc073de2e82e227be32bfc" + sha256: b6bafbbd981da2f964eb45bcb8b8a7676a281084f8922c0c75de4cfbaa849311 url: "https://pub.dev" source: hosted - version: "5.10.0" + version: "5.12.0" flutter_gen_runner: dependency: "direct dev" description: name: flutter_gen_runner - sha256: e74b4ead01df3e8f02e73a26ca856759dbbe8cb3fd60941ba9f4005cd0cd19c9 + sha256: "896aad224b96304e9a66a2468393fa7ffb66a631640d08940d7889cba65649c4" url: "https://pub.dev" source: hosted - version: "5.10.0" + version: "5.13.0" + flutter_hooks: + dependency: transitive + description: + name: flutter_hooks + sha256: "8ae1f090e5f4ef5cfa6670ce1ab5dddadd33f3533a7f9ba19d9f958aa2a89f42" + url: "https://pub.dev" + source: hosted + version: "0.21.3+1" + flutter_inappwebview: + dependency: transitive + description: + name: flutter_inappwebview + sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" + url: "https://pub.dev" + source: hosted + version: "6.1.5" + flutter_inappwebview_android: + dependency: transitive + description: + name: flutter_inappwebview_android + sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" + url: "https://pub.dev" + source: hosted + version: "1.1.3" + flutter_inappwebview_internal_annotations: + dependency: transitive + description: + name: flutter_inappwebview_internal_annotations + sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 + url: "https://pub.dev" + source: hosted + version: "1.3.0" + flutter_inappwebview_ios: + dependency: transitive + description: + name: flutter_inappwebview_ios + sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_macos: + dependency: transitive + description: + name: flutter_inappwebview_macos + sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_platform_interface: + dependency: transitive + description: + name: flutter_inappwebview_platform_interface + sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 + url: "https://pub.dev" + source: hosted + version: "1.3.0+1" + flutter_inappwebview_web: + dependency: transitive + description: + name: flutter_inappwebview_web + sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_inappwebview_windows: + dependency: transitive + description: + name: flutter_inappwebview_windows + sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" + url: "https://pub.dev" + source: hosted + version: "0.6.0" flutter_launcher_icons: dependency: "direct dev" description: @@ -458,22 +701,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + flutter_native_splash: + dependency: transitive + description: + name: flutter_native_splash + sha256: "4fb9f4113350d3a80841ce05ebf1976a36de622af7d19aca0ca9a9911c7ff002" + url: "https://pub.dev" + source: hosted + version: "2.4.7" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: c2fe1001710127dfa7da89977a08d591398370d099aacdaa6d44da7eb14b8476 + sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1 url: "https://pub.dev" source: hosted - version: "2.0.31" + version: "2.0.33" + flutter_riverpod: + dependency: transitive + description: + name: flutter_riverpod + sha256: e2026c72738a925a60db30258ff1f29974e40716749f3c9850aabf34ffc1a14c + url: "https://pub.dev" + source: hosted + version: "3.2.1" flutter_rust_bridge: dependency: transitive description: name: flutter_rust_bridge - sha256: "5a5c7a5deeef2cc2ffe6076a33b0429f4a20ceac22a397297aed2b1eb067e611" + sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e" url: "https://pub.dev" source: hosted - version: "2.9.0" + version: "2.11.1" flutter_secure_storage: dependency: "direct main" description: @@ -526,10 +785,10 @@ packages: dependency: "direct main" description: name: flutter_svg - sha256: b9c2ad5872518a27507ab432d1fb97e8813b05f0fc693f9d40fad06d073e0678 + sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.3" flutter_test: dependency: "direct dev" description: flutter @@ -540,6 +799,14 @@ packages: description: flutter source: sdk version: "0.0.0" + form_builder_validators: + dependency: transitive + description: + name: form_builder_validators + sha256: cd9a06b35abaed8bf050467c1239e3ee1c8795f42d4cb6568c08dbb8a4d6bd36 + url: "https://pub.dev" + source: hosted + version: "11.3.0" freezed_annotation: dependency: transitive description: @@ -561,6 +828,14 @@ packages: description: flutter source: sdk version: "0.0.0" + gap: + dependency: transitive + description: + name: gap + sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d + url: "https://pub.dev" + source: hosted + version: "3.0.1" glob: dependency: transitive description: @@ -569,6 +844,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + go_router: + dependency: transitive + description: + name: go_router + sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3 + url: "https://pub.dev" + source: hosted + version: "14.8.1" google_identity_services_web: dependency: transitive description: @@ -605,10 +888,10 @@ packages: dependency: "direct main" description: name: haptic_feedback - sha256: d3b5ad41858d18a35d317636c9cdc1cb8aef23c7b861ca5896273acc68e1a98a + sha256: "3422bf2a55c541c9e3f029197b9a94d262d2dda19191a022eb310e5dd922e9e0" url: "https://pub.dev" source: hosted - version: "0.5.1+1" + version: "0.5.1+2" hashcash_dart: dependency: transitive description: @@ -650,14 +933,38 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.0" + hooks: + dependency: transitive + description: + name: hooks + sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" + url: "https://pub.dev" + source: hosted + version: "1.0.1" + hooks_riverpod: + dependency: transitive + description: + name: hooks_riverpod + sha256: "402a0969af107ebb42d0300dd68aa48df136671dacb70593d164f04b30af43f4" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + html: + dependency: transitive + description: + name: html + sha256: "6d1264f2dffa1b1101c25a91dff0dc2daee4c18e87cd8538729773c073dbf602" + url: "https://pub.dev" + source: hosted + version: "0.15.6" http: dependency: transitive description: name: http - sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007 + sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" url: "https://pub.dev" source: hosted - version: "1.5.0" + version: "1.6.0" http2: dependency: transitive description: @@ -682,14 +989,86 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.2" + iconsax_flutter: + dependency: transitive + description: + name: iconsax_flutter + sha256: d14b4cec8586025ac15276bdd40f6eea308cb85748135965bb6255f14beb2564 + url: "https://pub.dev" + source: hosted + version: "1.0.1" image: dependency: transitive description: name: image - sha256: "4e973fcf4caae1a4be2fa0a13157aa38a8f9cb049db6529aa00b4d71abc4d928" + sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce + url: "https://pub.dev" + source: hosted + version: "4.8.0" + image_picker: + dependency: transitive + description: + name: image_picker + sha256: "784210112be18ea55f69d7076e2c656a4e24949fa9e76429fe53af0c0f4fa320" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: eda9b91b7e266d9041084a42d605a74937d996b87083395c5e47835916a86156 + url: "https://pub.dev" + source: hosted + version: "0.8.13+14" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" url: "https://pub.dev" source: hosted - version: "4.5.4" + version: "3.1.1" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 + url: "https://pub.dev" + source: hosted + version: "0.8.13+6" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" + url: "https://pub.dev" + source: hosted + version: "0.2.2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" + url: "https://pub.dev" + source: hosted + version: "2.11.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae + url: "https://pub.dev" + source: hosted + version: "0.2.2" image_size_getter: dependency: transitive description: @@ -731,34 +1110,34 @@ packages: dependency: transitive description: name: json_annotation - sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 url: "https://pub.dev" source: hosted - version: "4.9.0" + version: "4.11.0" leak_tracker: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "11.0.2" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" url: "https://pub.dev" source: hosted - version: "3.0.9" + version: "3.0.10" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" lints: dependency: transitive description: @@ -779,18 +1158,18 @@ packages: dependency: transitive description: name: local_auth_android - sha256: "48924f4a8b3cc45994ad5993e2e232d3b00788a305c1bf1c7db32cef281ce9a3" + sha256: a0bdfcc0607050a26ef5b31d6b4b254581c3d3ce3c1816ab4d4f4a9173e84467 url: "https://pub.dev" source: hosted - version: "1.0.52" + version: "1.0.56" local_auth_darwin: dependency: transitive description: name: local_auth_darwin - sha256: "0e9706a8543a4a2eee60346294d6a633dd7c3ee60fae6b752570457c4ff32055" + sha256: "699873970067a40ef2f2c09b4c72eb1cfef64224ef041b3df9fdc5c4c1f91f49" url: "https://pub.dev" source: hosted - version: "1.6.0" + version: "1.6.1" local_auth_platform_interface: dependency: transitive description: @@ -807,6 +1186,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.11" + logger: + dependency: transitive + description: + name: logger + sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 + url: "https://pub.dev" + source: hosted + version: "2.6.2" logging: dependency: transitive description: @@ -819,42 +1206,42 @@ packages: dependency: "direct main" description: name: lottie - sha256: c5fa04a80a620066c15cf19cc44773e19e9b38e989ff23ea32e5903ef1015950 + sha256: "8ae0be46dbd9e19641791dc12ee480d34e1fd3f84c749adc05f3ad9342b71b95" url: "https://pub.dev" source: hosted - version: "3.3.1" - macros: - dependency: transitive - description: - name: macros - sha256: "1d9e801cd66f7ea3663c45fc708450db1fa57f988142c64289142c9b7ee80656" - url: "https://pub.dev" - source: hosted - version: "0.1.3-main.0" + version: "3.3.2" matcher: dependency: transitive description: name: matcher - sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 url: "https://pub.dev" source: hosted - version: "0.12.17" + version: "0.12.19" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" + url: "https://pub.dev" + source: hosted + version: "0.13.0" + memoize: + dependency: transitive + description: + name: memoize + sha256: "51481d328c86cbdc59711369179bac88551ca0556569249be5317e66fc796cac" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "3.0.0" meta: dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.17.0" mime: dependency: transitive description: @@ -867,35 +1254,41 @@ packages: dependency: "direct main" description: name: mobx - sha256: bf1a90e5bcfd2851fc6984e20eef69557c65d9e4d0a88f5be4cf72c9819ce6b0 + sha256: "25ea9a3ee69243d578fb6288721d8eeb18550d0391c32f896d377d994154bff2" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.6.0" mobx_codegen: dependency: "direct dev" description: name: mobx_codegen - sha256: e0abbbc651a69550440f6b65c99ec222a1e2a4afd7baec8ba0f3088c7ca582a8 + sha256: "406051a76157fb0a562700110bd2bedd85c959b1cd2d3df740c706bc07539c33" url: "https://pub.dev" source: hosted - version: "2.7.1" + version: "2.7.6" mockito: dependency: transitive description: name: mockito - sha256: f99d8d072e249f719a5531735d146d8cf04c580d93920b04de75bef6dfb2daf6 + sha256: a45d1aa065b796922db7b9e7e7e45f921aed17adf3a8318a1f47097e7e695566 url: "https://pub.dev" source: hosted - version: "5.4.5" + version: "5.6.3" monero: dependency: "direct main" description: - path: "impls/monero.dart" - ref: "v0.18.4.0-RC4" - resolved-ref: a479a569bc25dd1e9701436404a46f0f509096a4 - url: "https://github.com/mrcyjanek/monero_c" - source: git + path: ".cache/monero_c/99aa531f9c7180805e59dd52f6dde95d5c55ab0d/impls/monero.dart" + relative: true + source: path version: "0.0.0" + native_toolchain_c: + dependency: transitive + description: + name: native_toolchain_c + sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" + url: "https://pub.dev" + source: hosted + version: "0.17.4" nested: dependency: transitive description: @@ -904,6 +1297,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + objective_c: + dependency: transitive + description: + name: objective_c + sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" + url: "https://pub.dev" + source: hosted + version: "9.3.0" package_config: dependency: transitive description: @@ -956,18 +1365,18 @@ packages: dependency: "direct main" description: name: path_provider_android - sha256: "3b4c1fc3aa55ddc9cd4aa6759984330d5c8e66aa7702a6223c61540dc6380c37" + sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e url: "https://pub.dev" source: hosted - version: "2.2.19" + version: "2.2.22" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "16eef174aacb07e09c351502740fa6254c165757638eba1e9116b0a781201bbd" + sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.6.0" path_provider_linux: dependency: transitive description: @@ -992,14 +1401,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.0" + pausable_timer: + dependency: transitive + description: + name: pausable_timer + sha256: "6ef1a95441ec3439de6fb63f39a011b67e693198e7dae14e20675c3c00e86074" + url: "https://pub.dev" + source: hosted + version: "3.1.0+3" petitparser: dependency: transitive description: name: petitparser - sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "7.0.2" pinenacl: dependency: transitive description: @@ -1052,18 +1469,18 @@ packages: dependency: transitive description: name: posix - sha256: "6323a5b0fa688b6a010df4905a56b00181479e6d10534cecfecede2aa55add61" + sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" url: "https://pub.dev" source: hosted - version: "6.0.3" + version: "6.5.0" process: dependency: transitive description: name: process - sha256: "107d8be718f120bbba9dcd1e95e3bd325b1b4a4f07db64154635ba03f2567a0d" + sha256: c6248e4526673988586e8c00bb22a49210c258dc91df5227d5da9748ecf79744 url: "https://pub.dev" source: hosted - version: "5.0.3" + version: "5.0.5" protobuf: dependency: transitive description: @@ -1112,6 +1529,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.0" + rational: + dependency: transitive + description: + name: rational + sha256: cb808fb6f1a839e6fc5f7d8cb3b0a10e1db48b3be102de73938c627f0b636336 + url: "https://pub.dev" + source: hosted + version: "2.2.3" recase: dependency: transitive description: @@ -1120,6 +1545,47 @@ packages: url: "https://pub.dev" source: hosted version: "4.1.0" + rive: + dependency: transitive + description: + name: rive + sha256: "2551a44fa766a7ed3f52aa2b94feda6d18d00edc25dee5f66e72e9b365bb6d6c" + url: "https://pub.dev" + source: hosted + version: "0.13.20" + rive_common: + dependency: transitive + description: + name: rive_common + sha256: "2ba42f80d37a4efd0696fb715787c4785f8a13361e8aea9227c50f1e78cf763a" + url: "https://pub.dev" + source: hosted + version: "0.4.15" + riverpod: + dependency: transitive + description: + name: riverpod + sha256: "8c22216be8ad3ef2b44af3a329693558c98eca7b8bd4ef495c92db0bba279f83" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + riverpod_annotation: + dependency: transitive + description: + name: riverpod_annotation + sha256: "16471a1260b94e939394d78f1c63a9350936ac4a68c9fbdab40be47268c0b04f" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + rlz: + dependency: transitive + description: + path: rust_builder + ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + resolved-ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + url: "https://github.com/cake-tech/zkool2" + source: git + version: "0.0.1" rxdart: dependency: transitive description: @@ -1128,6 +1594,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.28.0" + searchable_listview: + dependency: transitive + description: + name: searchable_listview + sha256: "902c0038a10e11aa4cc9305dc9e7ec339fad6e5a23c484283f784b67ae6cf7d1" + url: "https://pub.dev" + source: hosted + version: "2.19.4" sha3: dependency: transitive description: @@ -1152,6 +1626,62 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.2" + shared_preferences: + dependency: transitive + description: + name: shared_preferences + sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f + url: "https://pub.dev" + source: hosted + version: "2.4.20" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" + url: "https://pub.dev" + source: hosted + version: "2.5.6" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shelf: dependency: transitive description: @@ -1160,6 +1690,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.2" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 + url: "https://pub.dev" + source: hosted + version: "1.1.3" shelf_web_socket: dependency: transitive description: @@ -1182,53 +1728,61 @@ packages: source: sdk version: "0.0.0" source_gen: - dependency: "direct main" + dependency: transitive description: name: source_gen - sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" + sha256: "1d562a3c1f713904ebbed50d2760217fd8a51ca170ac4b05b0db490699dbac17" url: "https://pub.dev" source: hosted - version: "1.5.0" - source_span: + version: "4.2.0" + source_map_stack_trace: dependency: transitive description: - name: source_span - sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + name: source_map_stack_trace + sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b url: "https://pub.dev" source: hosted - version: "1.10.1" - sprintf: + version: "2.1.2" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "190222579a448b03896e0ca6eca5998fa810fda630c1d65e2f78b3f638f54812" + url: "https://pub.dev" + source: hosted + version: "0.10.13" + source_span: dependency: transitive description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + name: source_span + sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "1.10.2" sqlite3: dependency: transitive description: name: sqlite3 - sha256: f18fd9a72d7a1ad2920db61368f2a69368f1cc9b56b8233e9d83b47b0a8435aa + sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2" url: "https://pub.dev" source: hosted - version: "2.9.3" + version: "2.9.4" sqlite3_flutter_libs: dependency: transitive description: name: sqlite3_flutter_libs - sha256: "69c80d812ef2500202ebd22002cbfc1b6565e9ff56b2f971e757fac5d42294df" + sha256: "1e800ebe7f85a80a66adacaa6febe4d5f4d8b75f244e9838a27cb2ffc7aec08d" url: "https://pub.dev" source: hosted - version: "0.5.40" + version: "0.5.41" sqlparser: dependency: transitive description: name: sqlparser - sha256: "57090342af1ce32bb499aa641f4ecdd2d6231b9403cea537ac059e803cc20d67" + sha256: "337e9997f7141ffdd054259128553c348635fa318f7ca492f07a4ab76f850d19" url: "https://pub.dev" source: hosted - version: "0.41.2" + version: "0.43.1" stack_trace: dependency: transitive description: @@ -1237,6 +1791,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.12.1" + state_notifier: + dependency: transitive + description: + name: state_notifier + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb + url: "https://pub.dev" + source: hosted + version: "1.0.0" stream_channel: dependency: transitive description: @@ -1277,30 +1839,46 @@ packages: url: "https://pub.dev" source: hosted version: "1.2.2" + test: + dependency: transitive + description: + name: test + sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7" + url: "https://pub.dev" + source: hosted + version: "1.30.0" test_api: dependency: transitive description: name: test_api - sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" + url: "https://pub.dev" + source: hosted + version: "0.7.10" + test_core: + dependency: transitive + description: + name: test_core + sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51" url: "https://pub.dev" source: hosted - version: "0.7.4" + version: "0.6.16" time: dependency: transitive description: name: time - sha256: "370572cf5d1e58adcb3e354c47515da3f7469dac3a95b447117e728e7be6f461" + sha256: "46187cf30bffdab28c56be9a63861b36e4ab7347bf403297595d6a97e10c789f" url: "https://pub.dev" source: hosted - version: "2.1.5" - timing: + version: "2.1.6" + toastification: dependency: transitive description: - name: timing - sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" + name: toastification + sha256: "69db2bff425b484007409650d8bcd5ed1ce2e9666293ece74dcd917dacf23112" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "3.0.3" typed_data: dependency: transitive description: @@ -1309,6 +1887,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + universal_io: + dependency: transitive + description: + name: universal_io + sha256: f63cbc48103236abf48e345e07a03ce5757ea86285ed313a6a032596ed9301e2 + url: "https://pub.dev" + source: hosted + version: "2.3.1" unorm_dart: dependency: transitive description: @@ -1338,34 +1924,34 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "81777b08c498a292d93ff2feead633174c386291e35612f8da438d6e92c4447e" + sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" url: "https://pub.dev" source: hosted - version: "6.3.20" + version: "6.3.28" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: d80b3f567a617cb923546034cc94bfe44eb15f989fe670b37f26abdb9d939cb7 + sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" url: "https://pub.dev" source: hosted - version: "6.3.4" + version: "6.4.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.2.2" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: c043a77d6600ac9c38300567f33ef12b0ef4f4783a2c1f00231d2b1941fea13f + sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" url: "https://pub.dev" source: hosted - version: "3.2.3" + version: "3.2.5" url_launcher_platform_interface: dependency: transitive description: @@ -1378,26 +1964,26 @@ packages: dependency: transitive description: name: url_launcher_web - sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.2" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.5" uuid: dependency: transitive description: name: uuid - sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff + sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" url: "https://pub.dev" source: hosted - version: "4.5.1" + version: "4.5.3" vector_graphics: dependency: "direct main" description: @@ -1418,34 +2004,34 @@ packages: dependency: transitive description: name: vector_graphics_compiler - sha256: d354a7ec6931e6047785f4db12a1f61ec3d43b207fc0790f863818543f8ff0dc + sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" url: "https://pub.dev" source: hosted - version: "1.1.19" + version: "1.2.0" vector_math: dependency: transitive description: name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.2.0" vm_service: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "15.0.2" watcher: dependency: transitive description: name: watcher - sha256: "592ab6e2892f67760543fb712ff0177f4ec76c031f02f5b4ff8d3fc5eb9fb61a" + sha256: "1398c9f081a753f9226febe8900fce8f7d0a67163334e1c94a2438339d79d635" url: "https://pub.dev" source: hosted - version: "1.1.4" + version: "1.2.1" web: dependency: "direct overridden" description: @@ -1478,14 +2064,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" win32: dependency: transitive description: name: win32 - sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e url: "https://pub.dev" source: hosted - version: "5.13.0" + version: "5.15.0" + win32_registry: + dependency: transitive + description: + name: win32_registry + sha256: "21ec76dfc731550fd3e2ce7a33a9ea90b828fdf19a5c3bcf556fa992cfa99852" + url: "https://pub.dev" + source: hosted + version: "1.1.5" xdg_directories: dependency: transitive description: @@ -1498,10 +2100,10 @@ packages: dependency: transitive description: name: xml - sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" url: "https://pub.dev" source: hosted - version: "6.5.0" + version: "6.6.1" yaml: dependency: transitive description: @@ -1510,6 +2112,15 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.3" + zkool: + dependency: "direct main" + description: + path: "." + ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + resolved-ref: "36e72b530c274c4a54a6127aadb94886e84d67bf" + url: "https://github.com/cake-tech/zkool2" + source: git + version: "6.24.0" sdks: - dart: ">=3.7.0 <4.0.0" - flutter: ">=3.29.0" + dart: ">=3.10.3 <4.0.0" + flutter: ">=3.38.4" diff --git a/pubspec.yaml b/pubspec.yaml index 16ca8d4..7b522e3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -35,10 +35,7 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.6 monero: - git: - url: https://github.com/mrcyjanek/monero_c - ref: v0.18.4.0-RC4 - path: impls/monero.dart + path: .cache/monero_c/99aa531f9c7180805e59dd52f6dde95d5c55ab0d/impls/monero.dart path: ^1.9.0 path_provider: ^2.1.5 path_provider_android: ^2.2.12 @@ -61,9 +58,8 @@ dependencies: crypto: ^3.0.3 package_info_plus: ^8.1.0 local_auth: ^2.3.0 - analyzer: ^6.11.0 - build: ^2.4.2 - source_gen: ^1.0.0 + analyzer: ^9.0.0 + build: ^4.0.4 mobx: ^2.5.0 flutter_mobx: ^2.3.0 drift: ^2.26.1 @@ -90,6 +86,10 @@ dependencies: git: url: https://github.com/cake-tech/blockchain_utils ref: cake-update-v2 + zkool: + git: + url: https://github.com/cake-tech/zkool2 + ref: 36e72b530c274c4a54a6127aadb94886e84d67bf dev_dependencies: flutter_test: @@ -101,12 +101,11 @@ dev_dependencies: # package. See that file for information about deactivating specific lint # rules and activating additional ones. flutter_lints: ^5.0.0 - flutter_asset_generator: ^1.2.0 build_runner: ^2.4.15 - flutter_gen_runner: ^5.8.0 + flutter_gen_runner: ^5.12.0 integration_test: sdk: flutter - mobx_codegen: ^2.7.0 + mobx_codegen: ^2.7.6 drift_dev: ^2.26.0 flutter_launcher_icons: ^0.14.4 hashlib: 1.19.2 @@ -116,8 +115,8 @@ dependency_overrides: intl: 0.20.2 bdk_flutter: git: - url: https://github.com/StaxoLotl/bdk-flutter/ - ref: cfa95443f11e75625c5f7de986b1cc64b682ed3f + url: https://github.com/MrCyjaneK/bdk-flutter.git + ref: 43532b1436f7f76d72ba67bd4428cd0a81cae145 analyzer: exclude: