mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 11:39:22 +00:00
Merge branch 'breez' of https://github.com/cake-tech/cake_wallet into wownero_breez
Conflicts: configure_cake_wallet.sh cw_core/lib/amount_converter.dart cw_core/lib/wallet_type.dart cw_monero/lib/monero_wallet.dart lib/view_model/unspent_coins/unspent_coins_list_view_model.dart scripts/android/pubspec_gen.sh scripts/ios/app_config.sh scripts/macos/app_config.sh tool/configure.dart
This commit is contained in:
commit
90508b8726
133 changed files with 4714 additions and 459 deletions
3
.github/workflows/pr_test_build.yml
vendored
3
.github/workflows/pr_test_build.yml
vendored
|
@ -158,6 +158,9 @@ jobs:
|
|||
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
echo "const breezApiKey = '${{ secrets.BREEZ_API_KEY }}';" >> cw_lightning/lib/.secrets.g.dart
|
||||
echo "const greenlightCert = '${{ secrets.GREENLIGHT_CERTIFICATE }}';" >> cw_lightning/lib/.secrets.g.dart
|
||||
echo "const greenlightKey = '${{ secrets.GREENLIGHT_KEY }}';" >> cw_lightning/lib/.secrets.g.dart
|
||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||
echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -128,6 +128,7 @@ cw_haven/android/.externalNativeBuild/
|
|||
cw_haven/android/.cxx/
|
||||
|
||||
lib/bitcoin/bitcoin.dart
|
||||
lib/lightning/lightning.dart
|
||||
lib/monero/monero.dart
|
||||
lib/haven/haven.dart
|
||||
lib/ethereum/ethereum.dart
|
||||
|
|
|
@ -23,6 +23,7 @@ if (flutterVersionName == null) {
|
|||
|
||||
apply plugin: 'com.android.application'
|
||||
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
|
||||
apply plugin: 'kotlinx-serialization'
|
||||
|
||||
def keystoreProperties = new Properties()
|
||||
def keystorePropertiesFile = rootProject.file('key.properties')
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
|
||||
<!--bibo01 : hardware option-->
|
||||
|
@ -69,6 +71,9 @@
|
|||
<data android:scheme="bitcoin" />
|
||||
<data android:scheme="bitcoin-wallet" />
|
||||
<data android:scheme="bitcoin_wallet" />
|
||||
<data android:scheme="lightning" />
|
||||
<data android:scheme="lightning-wallet" />
|
||||
<data android:scheme="lightning_wallet" />
|
||||
<data android:scheme="monero" />
|
||||
<data android:scheme="monero-wallet" />
|
||||
<data android:scheme="monero_wallet" />
|
||||
|
@ -115,6 +120,24 @@
|
|||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
|
||||
<!-- service to handle messaging events -->
|
||||
<!-- commented out until we decide what to do -->
|
||||
<!-- <service
|
||||
android:name=".NotificationFcmService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service> -->
|
||||
|
||||
<!-- service to handle the foreground service -->
|
||||
<service
|
||||
android:name=".NotificationForegroundService"
|
||||
android:foregroundServiceType="shortService"
|
||||
android:exported="false"
|
||||
android:stopWithTask="false">
|
||||
</service>
|
||||
</application>
|
||||
|
||||
<queries>
|
||||
|
|
|
@ -9,6 +9,7 @@ buildscript {
|
|||
classpath 'com.android.tools.build:gradle:7.3.0'
|
||||
classpath 'com.google.gms:google-services:4.3.8'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
BIN
assets/images/lightning_logo.png
Normal file
BIN
assets/images/lightning_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.4 KiB |
10
assets/images/lightning_logo.svg
Normal file
10
assets/images/lightning_logo.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!-- Generator: Adobe Fireworks 10, Export SVG Extension by Aaron Beall (http://fireworks.abeall.com) . Version: 0.6.1 -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg id="bitcoin_lightning_icon.fw-Page%201" viewBox="0 0 280 280" style="background-color:#ffffff00" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
|
||||
x="0px" y="0px" width="280px" height="280px"
|
||||
>
|
||||
<path id="Ellipse" d="M 7 140.5 C 7 66.769 66.769 7 140.5 7 C 214.231 7 274 66.769 274 140.5 C 274 214.231 214.231 274 140.5 274 C 66.769 274 7 214.231 7 140.5 Z" fill="#f7931a"/>
|
||||
<path d="M 161.1943 51.5 C 153.2349 72.1607 145.2756 94.4107 135.7244 116.6607 C 135.7244 116.6607 135.7244 119.8393 138.9081 119.8393 L 204.1747 119.8393 C 204.1747 119.8393 204.1747 121.4286 205.7667 123.0179 L 110.2545 229.5 C 108.6626 227.9107 108.6626 226.3214 108.6626 224.7321 L 142.0919 153.2143 L 142.0919 146.8571 L 75.2333 146.8571 L 75.2333 140.5 L 156.4187 51.5 L 161.1943 51.5 Z" fill="#ffffff"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/warning.png
Normal file
BIN
assets/images/warning.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
|
@ -31,5 +31,4 @@ source ./app_env.sh cakewallet
|
|||
./app_config.sh
|
||||
cd ../.. && flutter pub get
|
||||
#flutter packages pub run tool/generate_localization.dart
|
||||
./model_generator.sh
|
||||
#cd macos && pod install
|
||||
./model_generator.sh
|
|
@ -3,12 +3,13 @@ import 'package:cw_core/crypto_amount_format.dart';
|
|||
|
||||
const bitcoinAmountLength = 8;
|
||||
const bitcoinAmountDivider = 100000000;
|
||||
const lightningAmountDivider = 1;
|
||||
final bitcoinAmountFormat = NumberFormat()
|
||||
..maximumFractionDigits = bitcoinAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
|
||||
String bitcoinAmountToString({required int amount}) => bitcoinAmountFormat.format(
|
||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||
String bitcoinAmountToString({required int amount}) =>
|
||||
bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider));
|
||||
|
||||
double bitcoinAmountToDouble({required int amount}) =>
|
||||
cryptoAmountToDouble(amount: amount, divider: bitcoinAmountDivider);
|
||||
|
@ -24,3 +25,9 @@ int stringDoubleToBitcoinAmount(String amount) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
String bitcoinAmountToLightningString({required int amount}) {
|
||||
String formattedAmount = bitcoinAmountFormat
|
||||
.format(cryptoAmountToDouble(amount: amount, divider: lightningAmountDivider));
|
||||
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ abstract class ElectrumWalletBase
|
|||
getAccountHDWallet(currency, networkType, seedBytes, xpub, walletInfo.derivationInfo),
|
||||
syncStatus = NotConnectedSyncStatus(),
|
||||
_password = password,
|
||||
_mnemonic = mnemonic,
|
||||
_feeRates = <int>[],
|
||||
_isTransactionUpdating = false,
|
||||
isEnabledAutoGenerateSubaddress = true,
|
||||
|
@ -91,7 +92,6 @@ abstract class ElectrumWalletBase
|
|||
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||
this.network = _getNetwork(networkType, currency),
|
||||
this.isTestnet = networkType == bitcoin.testnet,
|
||||
this._mnemonic = mnemonic,
|
||||
super(walletInfo) {
|
||||
this.electrumClient = electrumClient ?? ElectrumClient();
|
||||
this.walletInfo = walletInfo;
|
||||
|
@ -1138,7 +1138,7 @@ abstract class ElectrumWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
Future<void> close({bool? switchingToSameWalletType}) async {
|
||||
try {
|
||||
await electrumClient.close();
|
||||
} catch (_) {}
|
||||
|
|
|
@ -33,15 +33,16 @@ abstract class LitecoinWalletBase extends ElectrumWallet with Store {
|
|||
Map<String, int>? initialRegularAddressIndex,
|
||||
Map<String, int>? initialChangeAddressIndex,
|
||||
}) : super(
|
||||
mnemonic: mnemonic,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: litecoinNetwork,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
currency: CryptoCurrency.ltc) {
|
||||
mnemonic: mnemonic,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: litecoinNetwork,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
currency: CryptoCurrency.ltc,
|
||||
) {
|
||||
walletAddresses = LitecoinWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
|
|
|
@ -27,7 +27,7 @@ dependencies:
|
|||
git:
|
||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||
ref: Add-Support-For-OP-Return-data
|
||||
rxdart: ^0.27.5
|
||||
rxdart: ^0.28.0
|
||||
cryptography: ^2.0.5
|
||||
bitcoin_base:
|
||||
git:
|
||||
|
@ -53,7 +53,7 @@ dev_dependencies:
|
|||
build_runner: ^2.4.7
|
||||
build_resolvers: ^2.0.9
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -35,15 +35,16 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
|
|||
Map<String, int>? initialRegularAddressIndex,
|
||||
Map<String, int>? initialChangeAddressIndex,
|
||||
}) : super(
|
||||
mnemonic: mnemonic,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: bitcoin.bitcoin,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
currency: CryptoCurrency.bch) {
|
||||
mnemonic: mnemonic,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: bitcoin.bitcoin,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
currency: CryptoCurrency.bch,
|
||||
) {
|
||||
walletAddresses = BitcoinCashWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
|
|
|
@ -43,7 +43,7 @@ dev_dependencies:
|
|||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -6,6 +6,7 @@ class AmountConverter {
|
|||
static const _moneroAmountDivider = 1000000000000;
|
||||
static const _wowneroAmountLength = 11;
|
||||
static const _wowneroAmountDivider = 100000000000;
|
||||
static const _ethereumAmountDivider = 1000000000000000000;
|
||||
static const _bitcoinAmountDivider = 100000000;
|
||||
static const _bitcoinAmountLength = 8;
|
||||
static final _bitcoinAmountFormat = NumberFormat()
|
||||
|
@ -18,6 +19,30 @@ class AmountConverter {
|
|||
..maximumFractionDigits = _wowneroAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
|
||||
static int amountStringToInt(CryptoCurrency cryptoCurrency, String amount) {
|
||||
switch (cryptoCurrency) {
|
||||
case CryptoCurrency.xmr:
|
||||
return _moneroParseAmount(amount);
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
case CryptoCurrency.xaud:
|
||||
case CryptoCurrency.xbtc:
|
||||
case CryptoCurrency.xcad:
|
||||
case CryptoCurrency.xchf:
|
||||
case CryptoCurrency.xcny:
|
||||
case CryptoCurrency.xeur:
|
||||
case CryptoCurrency.xgbp:
|
||||
case CryptoCurrency.xjpy:
|
||||
case CryptoCurrency.xnok:
|
||||
case CryptoCurrency.xnzd:
|
||||
case CryptoCurrency.xusd:
|
||||
return _moneroParseAmount(amount);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static String amountIntToString(CryptoCurrency cryptoCurrency, int amount) {
|
||||
switch (cryptoCurrency) {
|
||||
case CryptoCurrency.xmr:
|
||||
|
@ -28,6 +53,8 @@ class AmountConverter {
|
|||
case CryptoCurrency.bch:
|
||||
case CryptoCurrency.ltc:
|
||||
return _bitcoinAmountToString(amount);
|
||||
case CryptoCurrency.btcln:
|
||||
return _lightningAmountToString(amount);
|
||||
case CryptoCurrency.xhv:
|
||||
case CryptoCurrency.xag:
|
||||
case CryptoCurrency.xau:
|
||||
|
@ -57,6 +84,11 @@ class AmountConverter {
|
|||
static String _bitcoinAmountToString(int amount) => _bitcoinAmountFormat
|
||||
.format(cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));
|
||||
|
||||
static String _lightningAmountToString(int amount) {
|
||||
String formattedAmount = _bitcoinAmountFormat.format(amount);
|
||||
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||
}
|
||||
|
||||
static String _wowneroAmountToString(int amount) => _wowneroAmountFormat
|
||||
.format(cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider));
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
CryptoCurrency.kaspa,
|
||||
CryptoCurrency.digibyte,
|
||||
CryptoCurrency.usdtSol,
|
||||
CryptoCurrency.btcln,
|
||||
CryptoCurrency.usdcTrc20,
|
||||
CryptoCurrency.tbtc,
|
||||
CryptoCurrency.wow,
|
||||
|
@ -190,7 +191,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png', decimals: 6);
|
||||
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png', decimals: 18);
|
||||
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png', decimals: 8);
|
||||
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png', decimals: 8);
|
||||
static const btcln = CryptoCurrency(title: 'sats', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'sats', iconPath: 'assets/images/lightning_logo.png', decimals: 8);
|
||||
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png', decimals: 18);
|
||||
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png', decimals: 18);
|
||||
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/images/arb_icon.png', decimals: 18);
|
||||
|
@ -224,7 +225,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
static const tbtc = CryptoCurrency(title: 'tBTC', fullName: 'Testnet Bitcoin', raw: 93, name: 'tbtc', iconPath: 'assets/images/tbtc.png', decimals: 8);
|
||||
static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 94, name: 'wow', iconPath: 'assets/images/wownero_icon.png', decimals: 11);
|
||||
|
||||
|
||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {
|
||||
acc.addAll({item.raw: item});
|
||||
|
|
|
@ -8,6 +8,8 @@ CryptoCurrency currencyForWalletType(WalletType type, {bool? isTestnet}) {
|
|||
return CryptoCurrency.tbtc;
|
||||
}
|
||||
return CryptoCurrency.btc;
|
||||
case WalletType.lightning:
|
||||
return CryptoCurrency.btcln;
|
||||
case WalletType.monero:
|
||||
return CryptoCurrency.xmr;
|
||||
case WalletType.litecoin:
|
||||
|
|
|
@ -80,7 +80,7 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
|
|||
|
||||
Future<void> rescan({required int height});
|
||||
|
||||
void close();
|
||||
void close({bool? switchingToSameWalletType});
|
||||
|
||||
Future<void> changePassword(String password);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ part 'wallet_type.g.dart';
|
|||
const walletTypes = [
|
||||
WalletType.monero,
|
||||
WalletType.bitcoin,
|
||||
WalletType.lightning,
|
||||
WalletType.litecoin,
|
||||
WalletType.haven,
|
||||
WalletType.ethereum,
|
||||
|
@ -16,6 +17,7 @@ const walletTypes = [
|
|||
WalletType.polygon,
|
||||
WalletType.solana,
|
||||
WalletType.tron,
|
||||
WalletType.wownero,
|
||||
];
|
||||
|
||||
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
|
||||
|
@ -58,6 +60,9 @@ enum WalletType {
|
|||
|
||||
@HiveField(12)
|
||||
wownero,
|
||||
|
||||
@HiveField(13)
|
||||
lightning,
|
||||
}
|
||||
|
||||
int serializeToInt(WalletType type) {
|
||||
|
@ -86,6 +91,8 @@ int serializeToInt(WalletType type) {
|
|||
return 10;
|
||||
case WalletType.wownero:
|
||||
return 11;
|
||||
case WalletType.lightning:
|
||||
return 12;
|
||||
case WalletType.none:
|
||||
return -1;
|
||||
}
|
||||
|
@ -117,6 +124,8 @@ WalletType deserializeFromInt(int raw) {
|
|||
return WalletType.tron;
|
||||
case 11:
|
||||
return WalletType.wownero;
|
||||
case 12:
|
||||
return WalletType.lightning;
|
||||
default:
|
||||
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
|
||||
}
|
||||
|
@ -142,6 +151,8 @@ String walletTypeToString(WalletType type) {
|
|||
return 'Banano';
|
||||
case WalletType.polygon:
|
||||
return 'Polygon';
|
||||
case WalletType.lightning:
|
||||
return 'Lightning';
|
||||
case WalletType.solana:
|
||||
return 'Solana';
|
||||
case WalletType.tron:
|
||||
|
@ -173,6 +184,8 @@ String walletTypeToDisplayName(WalletType type) {
|
|||
return 'Banano (BAN)';
|
||||
case WalletType.polygon:
|
||||
return 'Polygon (MATIC)';
|
||||
case WalletType.lightning:
|
||||
return 'Bitcoin (Lightning)';
|
||||
case WalletType.solana:
|
||||
return 'Solana (SOL)';
|
||||
case WalletType.tron:
|
||||
|
@ -207,6 +220,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type, {bool isTestnet = fal
|
|||
return CryptoCurrency.banano;
|
||||
case WalletType.polygon:
|
||||
return CryptoCurrency.maticpoly;
|
||||
case WalletType.lightning:
|
||||
return CryptoCurrency.btcln;
|
||||
case WalletType.solana:
|
||||
return CryptoCurrency.sol;
|
||||
case WalletType.tron:
|
||||
|
|
|
@ -191,7 +191,7 @@ abstract class EVMChainWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
void close() {
|
||||
void close({bool? switchingToSameWalletType}) {
|
||||
_client.stop();
|
||||
_transactionsUpdateTimer?.cancel();
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ dev_dependencies:
|
|||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
flutter_lints: ^2.0.0
|
||||
|
||||
flutter:
|
||||
|
|
|
@ -106,7 +106,7 @@ abstract class HavenWalletBase
|
|||
Future<void>? updateBalance() => null;
|
||||
|
||||
@override
|
||||
void close() {
|
||||
void close({bool? switchingToSameWalletType}) {
|
||||
_listener?.stop();
|
||||
_onAccountChangeReaction?.reaction.dispose();
|
||||
_autoSaveTimer?.cancel();
|
||||
|
|
|
@ -27,7 +27,7 @@ dev_dependencies:
|
|||
build_runner: ^2.4.7
|
||||
mobx_codegen: ^2.0.7
|
||||
build_resolvers: ^2.0.9
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
74
cw_lightning/.gitignore
vendored
Normal file
74
cw_lightning/.gitignore
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
# Miscellaneous
|
||||
*.class
|
||||
*.log
|
||||
*.pyc
|
||||
*.swp
|
||||
.DS_Store
|
||||
.atom/
|
||||
.buildlog/
|
||||
.history
|
||||
.svn/
|
||||
|
||||
# IntelliJ related
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
.idea/
|
||||
|
||||
# The .vscode folder contains launch configuration and tasks you configure in
|
||||
# VS Code which you may wish to be included in version control, so this line
|
||||
# is commented out by default.
|
||||
#.vscode/
|
||||
|
||||
# Flutter/Dart/Pub related
|
||||
**/doc/api/
|
||||
.dart_tool/
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
.packages
|
||||
.pub-cache/
|
||||
.pub/
|
||||
build/
|
||||
|
||||
# Android related
|
||||
**/android/**/gradle-wrapper.jar
|
||||
**/android/.gradle
|
||||
**/android/captures/
|
||||
**/android/gradlew
|
||||
**/android/gradlew.bat
|
||||
**/android/local.properties
|
||||
**/android/**/GeneratedPluginRegistrant.java
|
||||
|
||||
# iOS/XCode related
|
||||
**/ios/**/*.mode1v3
|
||||
**/ios/**/*.mode2v3
|
||||
**/ios/**/*.moved-aside
|
||||
**/ios/**/*.pbxuser
|
||||
**/ios/**/*.perspectivev3
|
||||
**/ios/**/*sync/
|
||||
**/ios/**/.sconsign.dblite
|
||||
**/ios/**/.tags*
|
||||
**/ios/**/.vagrant/
|
||||
**/ios/**/DerivedData/
|
||||
**/ios/**/Icon?
|
||||
**/ios/**/Pods/
|
||||
**/ios/**/.symlinks/
|
||||
**/ios/**/profile
|
||||
**/ios/**/xcuserdata
|
||||
**/ios/.generated/
|
||||
**/ios/Flutter/App.framework
|
||||
**/ios/Flutter/Flutter.framework
|
||||
**/ios/Flutter/Flutter.podspec
|
||||
**/ios/Flutter/Generated.xcconfig
|
||||
**/ios/Flutter/app.flx
|
||||
**/ios/Flutter/app.zip
|
||||
**/ios/Flutter/flutter_assets/
|
||||
**/ios/Flutter/flutter_export_environment.sh
|
||||
**/ios/ServiceDefinitions.json
|
||||
**/ios/Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!**/ios/**/default.mode1v3
|
||||
!**/ios/**/default.mode2v3
|
||||
!**/ios/**/default.pbxuser
|
||||
!**/ios/**/default.perspectivev3
|
10
cw_lightning/.metadata
Normal file
10
cw_lightning/.metadata
Normal file
|
@ -0,0 +1,10 @@
|
|||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
|
||||
version:
|
||||
revision: b1395592de68cc8ac4522094ae59956dd21a91db
|
||||
channel: stable
|
||||
|
||||
project_type: package
|
3
cw_lightning/CHANGELOG.md
Normal file
3
cw_lightning/CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
## [0.0.1] - TODO: Add release date.
|
||||
|
||||
* TODO: Describe initial release.
|
1
cw_lightning/LICENSE
Normal file
1
cw_lightning/LICENSE
Normal file
|
@ -0,0 +1 @@
|
|||
TODO: Add your license here.
|
14
cw_lightning/README.md
Normal file
14
cw_lightning/README.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
# cw_bitcoin
|
||||
|
||||
A new Flutter package project.
|
||||
|
||||
## Getting Started
|
||||
|
||||
This project is a starting point for a Dart
|
||||
[package](https://flutter.dev/developing-packages/),
|
||||
a library module containing code that can be shared easily across
|
||||
multiple Flutter or Dart projects.
|
||||
|
||||
For help getting started with Flutter, view our
|
||||
[online documentation](https://flutter.dev/docs), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
7
cw_lightning/lib/cw_lightning.dart
Normal file
7
cw_lightning/lib/cw_lightning.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
library cw_lightning;
|
||||
|
||||
/// A Calculator.
|
||||
class Calculator {
|
||||
/// Returns [value] plus 1.
|
||||
int addOne(int value) => value + 1;
|
||||
}
|
45
cw_lightning/lib/lightning_balance.dart
Normal file
45
cw_lightning/lib/lightning_balance.dart
Normal file
|
@ -0,0 +1,45 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||
import 'package:cw_bitcoin/electrum_balance.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
|
||||
class LightningBalance extends ElectrumBalance {
|
||||
LightningBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
|
||||
: super(
|
||||
confirmed: confirmed,
|
||||
unconfirmed: unconfirmed,
|
||||
frozen: frozen,
|
||||
);
|
||||
|
||||
static LightningBalance? fromJSON(String? jsonSource) {
|
||||
if (jsonSource == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final decoded = json.decode(jsonSource) as Map;
|
||||
|
||||
return LightningBalance(
|
||||
confirmed: decoded['confirmed'] as int? ?? 0,
|
||||
unconfirmed: decoded['unconfirmed'] as int? ?? 0,
|
||||
frozen: decoded['frozen'] as int? ?? 0);
|
||||
}
|
||||
|
||||
final int confirmed;
|
||||
final int unconfirmed;
|
||||
final int frozen;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => bitcoinAmountToLightningString(amount: confirmed);
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance => bitcoinAmountToLightningString(amount: unconfirmed);
|
||||
|
||||
@override
|
||||
String get formattedUnAvailableBalance {
|
||||
final frozenFormatted = bitcoinAmountToLightningString(amount: frozen);
|
||||
return frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||
}
|
||||
|
||||
String toJSON() =>
|
||||
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
|
||||
}
|
19
cw_lightning/lib/lightning_receive_page_option.dart
Normal file
19
cw_lightning/lib/lightning_receive_page_option.dart
Normal file
|
@ -0,0 +1,19 @@
|
|||
import 'package:cw_core/receive_page_option.dart';
|
||||
|
||||
class LightningReceivePageOption implements ReceivePageOption {
|
||||
static const lightningOnchain = LightningReceivePageOption._('lightningOnchain');
|
||||
static const lightningInvoice = LightningReceivePageOption._('lightningInvoice');
|
||||
|
||||
const LightningReceivePageOption._(this.value);
|
||||
|
||||
final String value;
|
||||
|
||||
String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
static const all = [
|
||||
LightningReceivePageOption.lightningInvoice,
|
||||
LightningReceivePageOption.lightningOnchain
|
||||
];
|
||||
}
|
57
cw_lightning/lib/lightning_transaction_info.dart
Normal file
57
cw_lightning/lib/lightning_transaction_info.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
import 'package:cw_bitcoin/bitcoin_amount_format.dart';
|
||||
import 'package:cw_bitcoin/electrum_transaction_info.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/format_amount.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class LightningTransactionInfo extends ElectrumTransactionInfo {
|
||||
LightningTransactionInfo({
|
||||
required String id,
|
||||
required int amount,
|
||||
int? fee,
|
||||
required TransactionDirection direction,
|
||||
required bool isPending,
|
||||
required DateTime date,
|
||||
}) : super(
|
||||
WalletType.lightning,
|
||||
amount: amount,
|
||||
fee: fee,
|
||||
direction: direction,
|
||||
date: date,
|
||||
isPending: isPending,
|
||||
id: id,
|
||||
confirmations: 0,
|
||||
height: 0,
|
||||
) {}
|
||||
|
||||
@override
|
||||
String amountFormatted() =>
|
||||
'${formatAmount(bitcoinAmountToLightningString(amount: amount))} ${walletTypeToCryptoCurrency(type).title}';
|
||||
|
||||
@override
|
||||
String? feeFormatted() => fee != null
|
||||
? '${formatAmount(bitcoinAmountToLightningString(amount: fee!))} ${walletTypeToCryptoCurrency(type).title}'
|
||||
: '';
|
||||
|
||||
factory LightningTransactionInfo.fromJson(Map<String, dynamic> data, WalletType type) {
|
||||
return LightningTransactionInfo(
|
||||
id: data['id'] as String,
|
||||
amount: data['amount'] as int,
|
||||
fee: data['fee'] as int,
|
||||
direction: parseTransactionDirectionFromInt(data['direction'] as int),
|
||||
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
|
||||
isPending: data['isPending'] as bool,
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final m = <String, dynamic>{};
|
||||
m['id'] = id;
|
||||
m['amount'] = amount;
|
||||
m['direction'] = direction.index;
|
||||
m['date'] = date.millisecondsSinceEpoch;
|
||||
m['isPending'] = isPending;
|
||||
m['fee'] = fee;
|
||||
return m;
|
||||
}
|
||||
}
|
422
cw_lightning/lib/lightning_wallet.dart
Normal file
422
cw_lightning/lib/lightning_wallet.dart
Normal file
|
@ -0,0 +1,422 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:bitbox/bitbox.dart';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:breez_sdk/breez_sdk.dart';
|
||||
import 'package:breez_sdk/bridge_generated.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet_snapshot.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_direction.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_lightning/lightning_balance.dart';
|
||||
import 'package:cw_lightning/lightning_transaction_info.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_address_record.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet_addresses.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:cw_lightning/.secrets.g.dart' as secrets;
|
||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
|
||||
part 'lightning_wallet.g.dart';
|
||||
|
||||
class LightningWallet = LightningWalletBase with _$LightningWallet;
|
||||
|
||||
abstract class LightningWalletBase extends ElectrumWallet with Store {
|
||||
bool _isTransactionUpdating;
|
||||
|
||||
@override
|
||||
@observable
|
||||
SyncStatus syncStatus;
|
||||
|
||||
LightningWalletBase({
|
||||
required String mnemonic,
|
||||
required String password,
|
||||
required WalletInfo walletInfo,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
required Uint8List seedBytes,
|
||||
String? addressPageType,
|
||||
List<BitcoinAddressRecord>? initialAddresses,
|
||||
LightningBalance? initialBalance,
|
||||
Map<String, int>? initialRegularAddressIndex,
|
||||
Map<String, int>? initialChangeAddressIndex,
|
||||
}) : _isTransactionUpdating = false,
|
||||
syncStatus = NotConnectedSyncStatus(),
|
||||
_balance = ObservableMap<CryptoCurrency, LightningBalance>(),
|
||||
mnemonic = mnemonic,
|
||||
super(
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
networkType: bitcoin.bitcoin,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
currency: CryptoCurrency.btcln,
|
||||
) {
|
||||
_balance[CryptoCurrency.btcln] =
|
||||
initialBalance ?? LightningBalance(confirmed: 0, unconfirmed: 0, frozen: 0);
|
||||
String derivationPath = walletInfo.derivationInfo!.derivationPath!;
|
||||
String sideDerivationPath = derivationPath.substring(0, derivationPath.length - 1) + "1";
|
||||
final hd = bitcoin.HDWallet.fromSeed(seedBytes, network: networkType);
|
||||
walletAddresses = BitcoinWalletAddresses(
|
||||
walletInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
mainHd: hd.derivePath(derivationPath),
|
||||
sideHd: hd.derivePath(sideDerivationPath),
|
||||
network: network,
|
||||
);
|
||||
|
||||
// initialize breez:
|
||||
try {
|
||||
setupBreez(seedBytes);
|
||||
} catch (e) {
|
||||
print("Error initializing Breez: $e");
|
||||
}
|
||||
|
||||
autorun((_) {
|
||||
this.walletAddresses.isEnabledAutoGenerateSubaddress = this.isEnabledAutoGenerateSubaddress;
|
||||
});
|
||||
}
|
||||
|
||||
late final ObservableMap<CryptoCurrency, LightningBalance> _balance;
|
||||
StreamSubscription<List<Payment>>? _paymentsSub;
|
||||
StreamSubscription<NodeState?>? _nodeStateSub;
|
||||
StreamSubscription<LogEntry>? _logStream;
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableMap<CryptoCurrency, LightningBalance> get balance => _balance;
|
||||
|
||||
static Future<LightningWallet> create(
|
||||
{required String mnemonic,
|
||||
required String password,
|
||||
required WalletInfo walletInfo,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
String? addressPageType,
|
||||
List<BitcoinAddressRecord>? initialAddresses,
|
||||
LightningBalance? initialBalance,
|
||||
Map<String, int>? initialRegularAddressIndex,
|
||||
Map<String, int>? initialChangeAddressIndex}) async {
|
||||
late final Uint8List seedBytes;
|
||||
// electrum:
|
||||
if (validateMnemonic(mnemonic)) {
|
||||
seedBytes = await mnemonicToSeedBytes(mnemonic);
|
||||
// bip39:
|
||||
} else if (bip39.validateMnemonic(mnemonic)) {
|
||||
seedBytes = await bip39.mnemonicToSeed(mnemonic);
|
||||
} else {
|
||||
throw Exception("Invalid mnemonic!");
|
||||
}
|
||||
return LightningWallet(
|
||||
mnemonic: mnemonic,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
initialAddresses: initialAddresses,
|
||||
initialBalance: initialBalance,
|
||||
seedBytes: seedBytes,
|
||||
initialRegularAddressIndex: initialRegularAddressIndex,
|
||||
initialChangeAddressIndex: initialChangeAddressIndex,
|
||||
addressPageType: addressPageType,
|
||||
);
|
||||
}
|
||||
|
||||
static Future<LightningWallet> open({
|
||||
required String name,
|
||||
required WalletInfo walletInfo,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
required String password,
|
||||
}) async {
|
||||
final snp =
|
||||
await ElectrumWalletSnapshot.load(name, walletInfo.type, password, BitcoinNetwork.mainnet);
|
||||
|
||||
print("OPENING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||
return LightningWallet(
|
||||
mnemonic: snp.mnemonic!,
|
||||
password: password,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfo,
|
||||
initialAddresses: snp.addresses,
|
||||
initialBalance: LightningBalance(
|
||||
confirmed: snp.balance.confirmed,
|
||||
unconfirmed: snp.balance.unconfirmed,
|
||||
frozen: snp.balance.frozen,
|
||||
),
|
||||
seedBytes: await Mnemonic.toSeed(snp.mnemonic!),
|
||||
initialRegularAddressIndex: snp.regularAddressIndex,
|
||||
initialChangeAddressIndex: snp.changeAddressIndex,
|
||||
addressPageType: snp.addressPageType,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleNodeState(NodeState? nodeState) async {
|
||||
if (nodeState == null) return;
|
||||
_balance[CryptoCurrency.btcln] = LightningBalance(
|
||||
confirmed: nodeState.maxPayableMsat ~/ 1000,
|
||||
unconfirmed: nodeState.maxReceivableMsat ~/ 1000,
|
||||
frozen: 0,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handlePayments(List<Payment> payments) async {
|
||||
_isTransactionUpdating = true;
|
||||
final txs = convertToTxInfo(payments);
|
||||
transactionHistory.addMany(txs);
|
||||
_isTransactionUpdating = false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> renameWalletFiles(String newWalletName) async {
|
||||
await stopBreez(true);
|
||||
await super.renameWalletFiles(newWalletName);
|
||||
await setupBreez(await Mnemonic.toSeed(mnemonic));
|
||||
}
|
||||
|
||||
void _logSdkEntries(LogEntry entry) {
|
||||
switch (entry.level) {
|
||||
case "ERROR":
|
||||
case "WARN":
|
||||
case "INFO":
|
||||
// case "DEBUG":
|
||||
// case "TRACE":
|
||||
print("BREEZ:${entry.level}: ${entry.line}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> setupBreez(Uint8List seedBytes) async {
|
||||
final sdk = await BreezSDK();
|
||||
_logStream?.cancel();
|
||||
_logStream = sdk.logStream.listen(_logSdkEntries);
|
||||
|
||||
try {
|
||||
if (!(await sdk.isInitialized())) {
|
||||
sdk.initialize();
|
||||
}
|
||||
} catch (e) {
|
||||
print("Error initializing Breez: $e");
|
||||
return;
|
||||
}
|
||||
|
||||
GreenlightCredentials greenlightCredentials = GreenlightCredentials(
|
||||
developerKey: base64.decode(secrets.greenlightKey),
|
||||
developerCert: base64.decode(secrets.greenlightCert),
|
||||
);
|
||||
|
||||
NodeConfig breezNodeConfig = NodeConfig.greenlight(
|
||||
config: GreenlightNodeConfig(
|
||||
partnerCredentials: greenlightCredentials,
|
||||
inviteCode: null,
|
||||
),
|
||||
);
|
||||
Config breezConfig = await sdk.defaultConfig(
|
||||
envType: EnvironmentType.Production,
|
||||
apiKey: secrets.breezApiKey,
|
||||
nodeConfig: breezNodeConfig,
|
||||
);
|
||||
|
||||
String workingDir = await pathForWalletDir(name: walletInfo.name, type: type);
|
||||
workingDir = "$workingDir/breez/";
|
||||
|
||||
new Directory(workingDir).createSync(recursive: true);
|
||||
breezConfig = breezConfig.copyWith(workingDir: workingDir);
|
||||
|
||||
// disconnect if already connected
|
||||
try {
|
||||
if (await sdk.isInitialized()) {
|
||||
await sdk.disconnect();
|
||||
}
|
||||
} catch (e, s) {
|
||||
print("ERROR disconnecting from Breez: $e\n$s");
|
||||
}
|
||||
|
||||
try {
|
||||
await sdk.connect(
|
||||
req: ConnectRequest(
|
||||
config: breezConfig,
|
||||
seed: seedBytes,
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
print("Error connecting to Breez: $e\n$s");
|
||||
}
|
||||
|
||||
await _nodeStateSub?.cancel();
|
||||
_nodeStateSub = sdk.nodeStateStream.listen((event) {
|
||||
_handleNodeState(event);
|
||||
});
|
||||
await _handleNodeState(await sdk.nodeInfo());
|
||||
|
||||
await _paymentsSub?.cancel();
|
||||
_paymentsSub = sdk.paymentsStream.listen((List<Payment> payments) {
|
||||
_handlePayments(payments);
|
||||
});
|
||||
await _handlePayments(await sdk.listPayments(req: ListPaymentsRequest()));
|
||||
|
||||
print("initialized breez: ${(await sdk.isInitialized())}");
|
||||
}
|
||||
|
||||
Future<void> stopBreez(bool disconnect) async {
|
||||
if (disconnect) {
|
||||
final sdk = await BreezSDK();
|
||||
if (await sdk.isInitialized()) {
|
||||
await sdk.disconnect();
|
||||
}
|
||||
}
|
||||
await _nodeStateSub?.cancel();
|
||||
await _paymentsSub?.cancel();
|
||||
}
|
||||
|
||||
@action
|
||||
@override
|
||||
Future<void> startSync() async {
|
||||
try {
|
||||
syncStatus = AttemptingSyncStatus();
|
||||
await updateTransactions();
|
||||
syncStatus = SyncedSyncStatus();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
syncStatus = FailedSyncStatus();
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) {
|
||||
throw UnimplementedError("changePassword");
|
||||
}
|
||||
|
||||
@action
|
||||
@override
|
||||
Future<void> connectToNode({required Node node}) async {
|
||||
try {
|
||||
syncStatus = ConnectingSyncStatus();
|
||||
await updateTransactions();
|
||||
syncStatus = ConnectedSyncStatus();
|
||||
} catch (e) {
|
||||
print(e);
|
||||
syncStatus = FailedSyncStatus();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
throw UnimplementedError("createTransaction");
|
||||
}
|
||||
|
||||
Future<bool> updateTransactions() async {
|
||||
try {
|
||||
if (_isTransactionUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_isTransactionUpdating = true;
|
||||
final transactions = await fetchTransactions();
|
||||
transactionHistory.addMany(transactions);
|
||||
await transactionHistory.save();
|
||||
_isTransactionUpdating = false;
|
||||
return true;
|
||||
} catch (_) {
|
||||
_isTransactionUpdating = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, LightningTransactionInfo> convertToTxInfo(List<Payment> payments) {
|
||||
Map<String, LightningTransactionInfo> transactions = {};
|
||||
|
||||
for (Payment tx in payments) {
|
||||
if (tx.paymentType == PaymentType.ClosedChannel) {
|
||||
continue;
|
||||
}
|
||||
bool isSend = tx.paymentType == PaymentType.Sent;
|
||||
transactions[tx.id] = LightningTransactionInfo(
|
||||
isPending: false,
|
||||
id: tx.id,
|
||||
amount: tx.amountMsat ~/ 1000,
|
||||
fee: tx.feeMsat ~/ 1000,
|
||||
date: DateTime.fromMillisecondsSinceEpoch(tx.paymentTime * 1000),
|
||||
direction: isSend ? TransactionDirection.outgoing : TransactionDirection.incoming,
|
||||
);
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Map<String, LightningTransactionInfo>> fetchTransactions() async {
|
||||
final sdk = await BreezSDK();
|
||||
|
||||
final payments = await sdk.listPayments(req: ListPaymentsRequest());
|
||||
final transactions = convertToTxInfo(payments);
|
||||
|
||||
return transactions;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rescan({
|
||||
required int height,
|
||||
int? chainTip,
|
||||
ScanData? scanData,
|
||||
bool? doSingleScan,
|
||||
bool? usingElectrs,
|
||||
}) async {
|
||||
updateTransactions();
|
||||
}
|
||||
|
||||
Future<void> init() async {
|
||||
await walletAddresses.init();
|
||||
await transactionHistory.init();
|
||||
await save();
|
||||
}
|
||||
|
||||
String toJSON() => json.encode({
|
||||
'mnemonic': mnemonic,
|
||||
'account_index': walletAddresses.currentReceiveAddressIndexByType,
|
||||
'change_address_index': walletAddresses.currentChangeAddressIndexByType,
|
||||
'addresses': walletAddresses.allAddresses.map((addr) => addr.toJSON()).toList(),
|
||||
'address_page_type': walletInfo.addressPageType == null
|
||||
? SegwitAddresType.p2wpkh.toString()
|
||||
: walletInfo.addressPageType.toString(),
|
||||
'balance': balance[currency]?.toJSON(),
|
||||
'network_type': network == BitcoinNetwork.testnet ? 'testnet' : 'mainnet',
|
||||
});
|
||||
|
||||
Future<void> updateBalance() async {
|
||||
// balance is updated automatically
|
||||
}
|
||||
|
||||
@override
|
||||
String mnemonic;
|
||||
|
||||
@override
|
||||
String get seed => mnemonic;
|
||||
|
||||
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
|
||||
|
||||
@override
|
||||
Future<void> close({bool? switchingToSameWalletType}) async {
|
||||
try {
|
||||
await electrumClient.close();
|
||||
} catch (_) {}
|
||||
try {
|
||||
bool shouldDisconnect = switchingToSameWalletType == null || !switchingToSameWalletType;
|
||||
await stopBreez(shouldDisconnect);
|
||||
} catch (e, s) {
|
||||
print("Error stopping breez: $e\n$s");
|
||||
}
|
||||
}
|
||||
}
|
134
cw_lightning/lib/lightning_wallet_service.dart
Normal file
134
cw_lightning/lib/lightning_wallet_service.dart
Normal file
|
@ -0,0 +1,134 @@
|
|||
import 'dart:io';
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_mnemonic.dart';
|
||||
import 'package:cw_bitcoin/mnemonic_is_incorrect_exception.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_lightning/lightning_wallet.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:bip39/bip39.dart' as bip39;
|
||||
|
||||
class LightningWalletService extends WalletService<
|
||||
BitcoinNewWalletCredentials,
|
||||
BitcoinRestoreWalletFromSeedCredentials,
|
||||
BitcoinRestoreWalletFromWIFCredentials,
|
||||
BitcoinRestoreWalletFromHardware> {
|
||||
LightningWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||
|
||||
@override
|
||||
WalletType getType() => WalletType.lightning;
|
||||
|
||||
@override
|
||||
Future<LightningWallet> create(BitcoinNewWalletCredentials credentials, {bool? isTestnet}) async {
|
||||
final wallet = await LightningWalletBase.create(
|
||||
mnemonic: bip39.generateMnemonic(),
|
||||
password: credentials.password!,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
);
|
||||
await wallet.save();
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isWalletExit(String name) async =>
|
||||
File(await pathForWallet(name: name, type: getType())).existsSync();
|
||||
|
||||
@override
|
||||
Future<LightningWallet> openWallet(String name, String password) async {
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhereOrNull((info) => info.id == WalletBase.idFor(name, getType()))!;
|
||||
try {
|
||||
final wallet = await LightningWalletBase.open(
|
||||
password: password,
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
);
|
||||
await wallet.init();
|
||||
saveBackup(name);
|
||||
return wallet;
|
||||
} catch (_) {
|
||||
await restoreWalletFilesFromBackup(name);
|
||||
final wallet = await LightningWalletBase.open(
|
||||
password: password,
|
||||
name: name,
|
||||
walletInfo: walletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
);
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LightningWallet> restoreFromHardwareWallet(BitcoinRestoreWalletFromHardware credentials,
|
||||
{bool? isTestnet}) {
|
||||
throw UnimplementedError(
|
||||
"Restoring a Lightning wallet from a hardware wallet is not yet supported!");
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> remove(String wallet) async {
|
||||
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
|
||||
final walletInfo = walletInfoSource.values
|
||||
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
|
||||
await walletInfoSource.delete(walletInfo.key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> rename(String currentName, String password, String newName) async {
|
||||
final currentWalletInfo = walletInfoSource.values
|
||||
.firstWhereOrNull((info) => info.id == WalletBase.idFor(currentName, getType()))!;
|
||||
final currentWallet = await LightningWalletBase.open(
|
||||
password: password,
|
||||
name: currentName,
|
||||
walletInfo: currentWalletInfo,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
await saveBackup(newName);
|
||||
|
||||
final newWalletInfo = currentWalletInfo;
|
||||
newWalletInfo.id = WalletBase.idFor(newName, getType());
|
||||
newWalletInfo.name = newName;
|
||||
|
||||
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LightningWallet> restoreFromKeys(BitcoinRestoreWalletFromWIFCredentials credentials,
|
||||
{bool? isTestnet}) async =>
|
||||
throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<LightningWallet> restoreFromSeed(BitcoinRestoreWalletFromSeedCredentials credentials,
|
||||
{bool? isTestnet}) async {
|
||||
if (!bip39.validateMnemonic(credentials.mnemonic) && !validateMnemonic(credentials.mnemonic)) {
|
||||
throw BitcoinMnemonicIsIncorrectException();
|
||||
}
|
||||
|
||||
final network = isTestnet == true ? BitcoinNetwork.testnet : BitcoinNetwork.mainnet;
|
||||
credentials.walletInfo?.network = network.value;
|
||||
|
||||
final wallet = await LightningWalletBase.create(
|
||||
password: credentials.password!,
|
||||
mnemonic: credentials.mnemonic,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
);
|
||||
await wallet.save();
|
||||
await wallet.init();
|
||||
return wallet;
|
||||
}
|
||||
}
|
920
cw_lightning/pubspec.lock
Normal file
920
cw_lightning/pubspec.lock
Normal file
|
@ -0,0 +1,920 @@
|
|||
# Generated by pub
|
||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||
packages:
|
||||
_fe_analyzer_shared:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: _fe_analyzer_shared
|
||||
sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "61.0.0"
|
||||
analyzer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: analyzer
|
||||
sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.13.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "20071638cbe4e5964a427cfa0e86dce55d060bc7d82d56f3554095d7239a8765"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.2"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
sha256: "139d809800a412ebb26a3892da228b2d0ba36f0ef5d9a82166e5e52ec8d61611"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.2"
|
||||
asn1lib:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: asn1lib
|
||||
sha256: ab96a1cb3beeccf8145c52e449233fe68364c9641623acd3adad66f8184f1039
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.11.0"
|
||||
bech32:
|
||||
dependency: transitive
|
||||
description:
|
||||
path: "."
|
||||
ref: "cake-0.2.2"
|
||||
resolved-ref: "05755063b593aa6cca0a4820a318e0ce17de6192"
|
||||
url: "https://github.com/cake-tech/bech32.git"
|
||||
source: git
|
||||
version: "0.2.2"
|
||||
bip32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bip32
|
||||
sha256: "54787cd7a111e9d37394aabbf53d1fc5e2e0e0af2cd01c459147a97c0e3f8a97"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
bip39:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bip39
|
||||
sha256: de1ee27ebe7d96b84bb3a04a4132a0a3007dcdd5ad27dd14aa87a29d97c45edc
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.6"
|
||||
bitbox:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: Add-Support-For-OP-Return-data
|
||||
resolved-ref: "57b78afb85bd2c30d3cdb9f7884f3878a62be442"
|
||||
url: "https://github.com/cake-tech/bitbox-flutter.git"
|
||||
source: git
|
||||
version: "1.0.1"
|
||||
bitcoin_base:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: cake-update-v2
|
||||
resolved-ref: "3fd81d238b990bb767fc7a4fdd5053a22a142e2e"
|
||||
url: "https://github.com/cake-tech/bitcoin_base.git"
|
||||
source: git
|
||||
version: "4.2.0"
|
||||
bitcoin_flutter:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: cake-update-v4
|
||||
resolved-ref: e19ffb7e7977278a75b27e0479b3c6f4034223b3
|
||||
url: "https://github.com/cake-tech/bitcoin_flutter.git"
|
||||
source: git
|
||||
version: "2.1.0"
|
||||
blockchain_utils:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: blockchain_utils
|
||||
sha256: "38ef5f4a22441ac4370aed9071dc71c460acffc37c79b344533f67d15f24c13c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
breez_sdk:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "v0.4.0-rc2"
|
||||
resolved-ref: "8762a59b1f823d3c37ee04b95bfe4eb88ea4eb6c"
|
||||
url: "https://github.com/breez/breez-sdk-flutter.git"
|
||||
source: git
|
||||
version: "0.4.0-rc2"
|
||||
bs58check:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: bs58check
|
||||
sha256: c4a164d42b25c2f6bc88a8beccb9fc7d01440f3c60ba23663a20a70faf484ea9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
build:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build
|
||||
sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
build_cli_annotations:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_cli_annotations
|
||||
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
sha256: bf80fcfb46a29945b423bd9aad884590fb1dc69b330a4d4700cac476af1708d1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_daemon
|
||||
sha256: "6bc5544ea6ce4428266e7ea680e945c68806c4aae2da0eb5e9ccf38df8d6acbf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
build_resolvers:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_resolvers
|
||||
sha256: "687cf90a3951affac1bd5f9ecb5e3e90b60487f3d9cdc359bb310f8876bb02a6"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.10"
|
||||
build_runner:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: build_runner
|
||||
sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.3"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
sha256: "14febe0f5bac5ae474117a36099b4de6f1dbc52df6c5e55534b3da9591bf4292"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.2.7"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_collection
|
||||
sha256: "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.1"
|
||||
built_value:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: built_value
|
||||
sha256: "169565c8ad06adb760c3645bf71f00bff161b00002cace266cad42c5d22a7725"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "8.4.3"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: characters
|
||||
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
checked_yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: checked_yaml
|
||||
sha256: "3d1505d91afa809d177efd4eed5bb0eb65805097a1463abdd2add076effae311"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
clock:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: clock
|
||||
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
code_builder:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: code_builder
|
||||
sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.4.0"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.18.0"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: convert
|
||||
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: crypto
|
||||
sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
cryptography:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cryptography
|
||||
sha256: e0e37f79665cd5c86e8897f9abe1accfe813c0cc5299dab22256e22fddc1fef8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
cw_bitcoin:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../cw_bitcoin"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
cw_core:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "../cw_core"
|
||||
relative: true
|
||||
source: path
|
||||
version: "0.0.1"
|
||||
dart_style:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: dart_style
|
||||
sha256: "7a03456c3490394c8e7665890333e91ae8a49be43542b616e414449ac358acd4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.4"
|
||||
encrypt:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: encrypt
|
||||
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.0.1"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fake_async
|
||||
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
ffi:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: ffi
|
||||
sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file
|
||||
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.4"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: fixnum
|
||||
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_mobx:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_mobx
|
||||
sha256: "0da4add0016387a7bf309a0d0c41d36c6b3ae25ed7a176409267f166509e723e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.6+5"
|
||||
flutter_rust_bridge:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_rust_bridge
|
||||
sha256: "02720226035257ad0b571c1256f43df3e1556a499f6bcb004849a0faaa0e87f0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.82.6"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
freezed:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: freezed
|
||||
sha256: "57247f692f35f068cae297549a46a9a097100685c6780fe67177503eea5ed4e5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.7"
|
||||
freezed_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: freezed_annotation
|
||||
sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.4.1"
|
||||
frontend_server_client:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: frontend_server_client
|
||||
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
glob:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: glob
|
||||
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
graphs:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: graphs
|
||||
sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.0"
|
||||
hex:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hex
|
||||
sha256: "4e7cd54e4b59ba026432a6be2dd9d96e4c5205725194997193bf871703b82c4a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
hive:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: hive
|
||||
sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.3"
|
||||
hive_generator:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: hive_generator
|
||||
sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_multi_server
|
||||
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.1"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.18.1"
|
||||
io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: io
|
||||
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: js
|
||||
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
json_annotation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: json_annotation
|
||||
sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.8.0"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker
|
||||
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "10.0.0"
|
||||
leak_tracker_flutter_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_flutter_testing
|
||||
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
leak_tracker_testing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: leak_tracker_testing
|
||||
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: logging
|
||||
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: matcher
|
||||
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.12.16+1"
|
||||
material_color_utilities:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: material_color_utilities
|
||||
sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.0"
|
||||
meta:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: meta
|
||||
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.0"
|
||||
mime:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
mobx:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mobx
|
||||
sha256: f1862bd92c6a903fab67338f27e2f731117c3cb9ea37cee1a487f9e4e0de314a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3+1"
|
||||
mobx_codegen:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
name: mobx_codegen
|
||||
sha256: "86122e410d8ea24dda0c69adb5c2a6ccadd5ce02ad46e144764e0d0184a06181"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: package_config
|
||||
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path
|
||||
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.9.0"
|
||||
path_provider:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: path_provider
|
||||
sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
path_provider_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_android
|
||||
sha256: e595b98692943b4881b219f0a9e3945118d3c16bd7e2813f98ec6e532d905f72
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_foundation:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_foundation
|
||||
sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.1"
|
||||
path_provider_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_linux
|
||||
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
path_provider_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_platform_interface
|
||||
sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
path_provider_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: path_provider_windows
|
||||
sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.2.1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: petitparser
|
||||
sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.4.0"
|
||||
platform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: platform
|
||||
sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
plugin_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: plugin_platform_interface
|
||||
sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
pointycastle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pointycastle
|
||||
sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.6.2"
|
||||
pool:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pool
|
||||
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.5.1"
|
||||
process:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: process
|
||||
sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.4"
|
||||
pub_semver:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pub_semver
|
||||
sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
pubspec_parse:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pubspec_parse
|
||||
sha256: "75f6614d6dde2dc68948dffbaa4fe5dae32cd700eb9fb763fe11dfb45a3c4d0a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
puppeteer:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: puppeteer
|
||||
sha256: "59e723cc5b69537159a7c34efd645dc08a6a1ac4647d7d7823606802c0f93cdb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
rxdart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: rxdart
|
||||
sha256: "0c7c0cedd93788d996e33041ffecda924cc54389199cde4e6a34b440f50044cb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.27.7"
|
||||
shelf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf
|
||||
sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
shelf_static:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_static
|
||||
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shelf_web_socket
|
||||
sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.3"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.99"
|
||||
socks5_proxy:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: socks5_proxy
|
||||
sha256: "1d21b5606169654bbf4cfb904e8e6ed897e9f763358709f87310c757096d909a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_gen
|
||||
sha256: "2d79738b6bbf38a43920e2b8d189e9a3ce6cc201f4b8fc76be5e4fe377b1c38d"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.6"
|
||||
source_helper:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_helper
|
||||
sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.3"
|
||||
source_span:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: source_span
|
||||
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.10.0"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sprintf
|
||||
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stack_trace
|
||||
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.11.1"
|
||||
stream_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_channel
|
||||
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
stream_transform:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: stream_transform
|
||||
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
string_scanner:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: string_scanner
|
||||
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
term_glyph:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: term_glyph
|
||||
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.1"
|
||||
test_api:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: test_api
|
||||
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.6.1"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: timing
|
||||
sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.1"
|
||||
tuple:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: tuple
|
||||
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
unorm_dart:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: unorm_dart
|
||||
sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0"
|
||||
uuid:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: uuid
|
||||
sha256: "22c94e5ad1e75f9934b766b53c742572ee2677c56bc871d850a57dad0f82127f"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.2.2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vector_math
|
||||
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
vm_service:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: vm_service
|
||||
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "13.0.0"
|
||||
watcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: watcher
|
||||
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.2"
|
||||
web_socket_channel:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: web_socket_channel
|
||||
sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
win32:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: win32
|
||||
sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.3"
|
||||
xdg_directories:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: xdg_directories
|
||||
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.0+3"
|
||||
yaml:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: yaml
|
||||
sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.1"
|
||||
sdks:
|
||||
dart: ">=3.3.0 <4.0.0"
|
||||
flutter: ">=3.19.0"
|
88
cw_lightning/pubspec.yaml
Normal file
88
cw_lightning/pubspec.yaml
Normal file
|
@ -0,0 +1,88 @@
|
|||
name: cw_lightning
|
||||
description: A new Flutter package project.
|
||||
version: 0.0.1
|
||||
publish_to: none
|
||||
author: Cake Wallet
|
||||
homepage: https://cakewallet.com
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.5 <3.0.0"
|
||||
flutter: ">=1.20.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
path_provider: ^2.0.11
|
||||
http: ^1.1.0
|
||||
mobx: ^2.0.7+4
|
||||
flutter_mobx: ^2.0.6+1
|
||||
intl: ^0.18.0
|
||||
cw_core:
|
||||
path: ../cw_core
|
||||
cw_bitcoin:
|
||||
path: ../cw_bitcoin
|
||||
bitcoin_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/bitcoin_flutter.git
|
||||
ref: cake-update-v4
|
||||
bitbox:
|
||||
git:
|
||||
url: https://github.com/cake-tech/bitbox-flutter.git
|
||||
ref: Add-Support-For-OP-Return-data
|
||||
breez_sdk:
|
||||
git:
|
||||
url: https://github.com/breez/breez-sdk-flutter.git
|
||||
ref: v0.4.3-rc1
|
||||
cryptography: ^2.0.5
|
||||
bitcoin_base:
|
||||
git:
|
||||
url: https://github.com/cake-tech/bitcoin_base
|
||||
ref: cake-update-v3
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.1.11
|
||||
build_resolvers: ^2.0.9
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
||||
# For information on the generic Dart part of this file, see the
|
||||
# following page: https://dart.dev/tools/pub/pubspec
|
||||
|
||||
# The following section is specific to Flutter.
|
||||
flutter:
|
||||
|
||||
# To add assets to your package, add an assets section, like this:
|
||||
# assets:
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
#
|
||||
# For details regarding assets in packages, see
|
||||
# https://flutter.dev/assets-and-images/#from-packages
|
||||
#
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||
|
||||
# To add custom fonts to your package, add a fonts section here,
|
||||
# in this "flutter" section. Each entry in this list should have a
|
||||
# "family" key with the font family name, and a "fonts" key with a
|
||||
# list giving the asset and other descriptors for the font. For
|
||||
# example:
|
||||
# fonts:
|
||||
# - family: Schyler
|
||||
# fonts:
|
||||
# - asset: fonts/Schyler-Regular.ttf
|
||||
# - asset: fonts/Schyler-Italic.ttf
|
||||
# style: italic
|
||||
# - family: Trajan Pro
|
||||
# fonts:
|
||||
# - asset: fonts/TrajanPro.ttf
|
||||
# - asset: fonts/TrajanPro_Bold.ttf
|
||||
# weight: 700
|
||||
#
|
||||
# For details regarding fonts in packages, see
|
||||
# https://flutter.dev/custom-fonts/#from-packages
|
12
cw_lightning/test/cw_lightning_test.dart
Normal file
12
cw_lightning/test/cw_lightning_test.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
import 'package:cw_lightning/cw_lightning.dart';
|
||||
|
||||
void main() {
|
||||
test('adds one to input values', () {
|
||||
final calculator = Calculator();
|
||||
expect(calculator.addOne(2), 3);
|
||||
expect(calculator.addOne(-7), -6);
|
||||
expect(calculator.addOne(0), 1);
|
||||
});
|
||||
}
|
|
@ -161,7 +161,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
Future<void>? updateBalance() => null;
|
||||
|
||||
@override
|
||||
void close() async {
|
||||
void close({bool? switchingToSameWalletType}) {
|
||||
_listener?.stop();
|
||||
_onAccountChangeReaction?.reaction.dispose();
|
||||
_autoSaveTimer?.cancel();
|
||||
|
|
|
@ -34,7 +34,7 @@ dev_dependencies:
|
|||
build_runner: ^2.4.7
|
||||
build_resolvers: ^2.0.9
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -138,7 +138,7 @@ abstract class NanoWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
void close() {
|
||||
void close({bool? switchingToSameWalletType}) {
|
||||
_client.stop();
|
||||
_receiveTimer?.cancel();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ dev_dependencies:
|
|||
sdk: flutter
|
||||
build_runner: ^2.4.7
|
||||
mobx_codegen: ^2.0.7
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
|
||||
dependency_overrides:
|
||||
watcher: ^1.1.0
|
||||
|
|
|
@ -165,7 +165,7 @@ abstract class SolanaWalletBase
|
|||
Future<void> changePassword(String password) => throw UnimplementedError("changePassword");
|
||||
|
||||
@override
|
||||
void close() {
|
||||
void close({bool? switchingToSameWalletType}) {
|
||||
_client.stop();
|
||||
_transactionsUpdateTimer?.cancel();
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ abstract class TronWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
void close() {
|
||||
void close({bool? switchingToSameWalletType}) {
|
||||
_transactionsUpdateTimer?.cancel();
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,26 @@
|
|||
<string>bitcoin-wallet</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>lightning</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>lightning</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLName</key>
|
||||
<string>lightning-wallet</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>lightning-wallet</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
|
|
|
@ -36,4 +36,10 @@ class CWBitcoinCash extends BitcoinCash {
|
|||
@override
|
||||
TransactionPriority getBitcoinCashTransactionPrioritySlow() =>
|
||||
BitcoinCashTransactionPriority.slow;
|
||||
|
||||
@override
|
||||
String getMnemonic(int? strength) => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Uint8List getSeedFromMnemonic(String seed) => throw UnimplementedError();
|
||||
}
|
||||
|
|
|
@ -279,7 +279,8 @@ class AddressValidator extends TextValidator {
|
|||
'|([^0-9a-zA-Z]|^)((bc|tb)1q[ac-hj-np-z02-9]{40,80})([^0-9a-zA-Z]|\$)' //P2wshAddress type
|
||||
'|([^0-9a-zA-Z]|^)((bc|tb)1p([ac-hj-np-z02-9]{39}|[ac-hj-np-z02-9]{59}|[ac-hj-np-z02-9]{8,89}))([^0-9a-zA-Z]|\$)' //P2trAddress type
|
||||
'|${SilentPaymentAddress.regex.pattern}\$';
|
||||
|
||||
case CryptoCurrency.btcln:
|
||||
return '(lnbc|LNBC)([0-9]{1,}[a-zA-Z0-9]+)([^0-9a-zA-Z]|\$)';
|
||||
case CryptoCurrency.ltc:
|
||||
return '([^0-9a-zA-Z]|^)^L[a-zA-Z0-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)[LM][a-km-zA-HJ-NP-Z1-9]{26,33}([^0-9a-zA-Z]|\$)'
|
||||
|
|
|
@ -24,7 +24,7 @@ class SeedValidator extends Validator<MnemonicItem> {
|
|||
static List<String> getWordList({required WalletType type, required String language}) {
|
||||
switch (type) {
|
||||
case WalletType.bitcoin:
|
||||
return getBitcoinWordList(language);
|
||||
case WalletType.lightning:
|
||||
case WalletType.litecoin:
|
||||
return getBitcoinWordList(language);
|
||||
case WalletType.monero:
|
||||
|
|
|
@ -79,6 +79,7 @@ class WalletCreationService {
|
|||
case WalletType.polygon:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
case WalletType.lightning:
|
||||
return true;
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
|
|
112
lib/di.dart
112
lib/di.dart
|
@ -1,3 +1,4 @@
|
|||
import 'package:breez_sdk/bridge_generated.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/anonpay/anonpay_api.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
|
||||
|
@ -28,16 +29,24 @@ import 'package:cake_wallet/entities/contact.dart';
|
|||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cw_core/nano_account.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
import 'package:cake_wallet/entities/template.dart';
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_template.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/haven/haven.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -77,12 +86,16 @@ import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
|||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/lightning_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/lightning_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||
import 'package:cake_wallet/src/screens/send/lightning_send_confirm_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/lightning_send_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/fullscreen_qr_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
|
@ -122,13 +135,14 @@ import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart';
|
||||
import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
|
||||
import 'package:cake_wallet/cake_pay/cake_pay_api.dart';
|
||||
import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
|
||||
import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
|
||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart';
|
||||
|
@ -136,6 +150,7 @@ import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_cr
|
|||
import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/seed_type_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
|
@ -148,13 +163,12 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_i
|
|||
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
|
||||
import 'package:cw_core/nano_account.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
|
||||
|
@ -174,7 +188,6 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart';
|
|||
import 'package:cake_wallet/store/templates/send_template_store.dart';
|
||||
import 'package:cake_wallet/store/wallet_list_store.dart';
|
||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/view_model/auth_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/backup_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
|
||||
|
@ -188,7 +201,6 @@ import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
|
||||
|
@ -217,8 +229,6 @@ import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
@ -376,17 +386,19 @@ Future<void> setup({
|
|||
fiatConvertationStore: getIt.get<FiatConversionStore>()));
|
||||
|
||||
getIt.registerFactory(() => DashboardViewModel(
|
||||
balanceViewModel: getIt.get<BalanceViewModel>(),
|
||||
appStore: getIt.get<AppStore>(),
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
tradeFilterStore: getIt.get<TradeFilterStore>(),
|
||||
transactionFilterStore: getIt.get<TransactionFilterStore>(),
|
||||
settingsStore: settingsStore,
|
||||
yatStore: getIt.get<YatStore>(),
|
||||
ordersStore: getIt.get<OrdersStore>(),
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
keyService: getIt.get<KeyService>()));
|
||||
balanceViewModel: getIt.get<BalanceViewModel>(),
|
||||
appStore: getIt.get<AppStore>(),
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
tradeFilterStore: getIt.get<TradeFilterStore>(),
|
||||
transactionFilterStore: getIt.get<TransactionFilterStore>(),
|
||||
settingsStore: settingsStore,
|
||||
yatStore: getIt.get<YatStore>(),
|
||||
ordersStore: getIt.get<OrdersStore>(),
|
||||
anonpayTransactionsStore: getIt.get<AnonpayTransactionsStore>(),
|
||||
sharedPreferences: getIt.get<SharedPreferences>(),
|
||||
keyService: getIt.get<KeyService>(),
|
||||
lightningViewModel: getIt.get<LightningViewModel>(),
|
||||
));
|
||||
|
||||
getIt.registerFactory<AuthService>(
|
||||
() => AuthService(
|
||||
|
@ -624,7 +636,6 @@ Future<void> setup({
|
|||
authService: getIt.get<AuthService>(),
|
||||
initialPaymentRequest: initialPaymentRequest,
|
||||
));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => SendTemplatePage(sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));
|
||||
|
||||
|
@ -905,6 +916,8 @@ Future<void> setup({
|
|||
return nano!.createNanoWalletService(_walletInfoSource);
|
||||
case WalletType.polygon:
|
||||
return polygon!.createPolygonWalletService(_walletInfoSource);
|
||||
case WalletType.lightning:
|
||||
return lightning!.createLightningWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||
case WalletType.solana:
|
||||
return solana!.createSolanaWalletService(_walletInfoSource);
|
||||
case WalletType.tron:
|
||||
|
@ -1192,5 +1205,62 @@ Future<void> setup({
|
|||
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
|
||||
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>()));
|
||||
|
||||
getIt.registerFactory<LightningViewModel>(
|
||||
() => LightningViewModel(),
|
||||
);
|
||||
|
||||
getIt.registerFactory<LightningSendViewModel>(
|
||||
() => LightningSendViewModel(
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
fiatConversionStore: getIt.get<FiatConversionStore>(),
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactoryParam<LightningInvoicePageViewModel, void, void>((_, __) {
|
||||
return LightningInvoicePageViewModel(
|
||||
getIt.get<SettingsStore>(),
|
||||
getIt.get<AppStore>().wallet!,
|
||||
getIt.get<SharedPreferences>(),
|
||||
getIt.get<LightningViewModel>(),
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<LightningReceiveOnchainPage, void, void>((_, __) {
|
||||
return LightningReceiveOnchainPage(
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
lightningViewModel: getIt.get<LightningViewModel>(),
|
||||
receiveOptionViewModel:
|
||||
getIt.get<ReceiveOptionViewModel>(param1: lightning!.getOptionOnchain()),
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<LightningInvoicePage, void, void>((_, __) {
|
||||
return LightningInvoicePage(
|
||||
lightningInvoicePageViewModel: getIt.get<LightningInvoicePageViewModel>(),
|
||||
receiveOptionViewModel:
|
||||
getIt.get<ReceiveOptionViewModel>(param1: lightning!.getOptionInvoice()),
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactory<LightningSendPage>(() {
|
||||
return LightningSendPage(
|
||||
output: Output(
|
||||
getIt.get<AppStore>().wallet!,
|
||||
getIt.get<SettingsStore>(),
|
||||
getIt.get<FiatConversionStore>(),
|
||||
() => CryptoCurrency.btcln,
|
||||
),
|
||||
authService: getIt.get<AuthService>(),
|
||||
lightningSendViewModel: getIt.get<LightningSendViewModel>(),
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<LightningSendConfirmPage, LNInvoice, void>((LNInvoice invoice, _) {
|
||||
return LightningSendConfirmPage(
|
||||
invoice: invoice,
|
||||
lightningSendViewModel: getIt.get<LightningSendViewModel>(),
|
||||
);
|
||||
});
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MainActions {
|
||||
|
@ -11,8 +13,7 @@ class MainActions {
|
|||
|
||||
final bool Function(DashboardViewModel viewModel)? isEnabled;
|
||||
final bool Function(DashboardViewModel viewModel)? canShow;
|
||||
final Future<void> Function(
|
||||
BuildContext context, DashboardViewModel viewModel) onTap;
|
||||
final Future<void> Function(BuildContext context, DashboardViewModel viewModel) onTap;
|
||||
|
||||
MainActions._({
|
||||
required this.name,
|
||||
|
@ -55,6 +56,10 @@ class MainActions {
|
|||
name: (context) => S.of(context).receive,
|
||||
image: 'assets/images/received.png',
|
||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||
if (viewModel.wallet.type == WalletType.lightning) {
|
||||
Navigator.pushNamed(context, Routes.lightningInvoice);
|
||||
return;
|
||||
}
|
||||
Navigator.pushNamed(context, Routes.addressPage);
|
||||
},
|
||||
);
|
||||
|
@ -75,6 +80,10 @@ class MainActions {
|
|||
name: (context) => S.of(context).send,
|
||||
image: 'assets/images/upload.png',
|
||||
onTap: (BuildContext context, DashboardViewModel viewModel) async {
|
||||
if (viewModel.wallet.type == WalletType.lightning) {
|
||||
Navigator.pushNamed(context, Routes.lightningSend);
|
||||
return;
|
||||
}
|
||||
Navigator.pushNamed(context, Routes.send);
|
||||
},
|
||||
);
|
||||
|
@ -114,4 +123,4 @@ class MainActions {
|
|||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ class ProvidersHelper {
|
|||
ProviderType.moonpay,
|
||||
];
|
||||
case WalletType.none:
|
||||
case WalletType.lightning:
|
||||
case WalletType.haven:
|
||||
return [];
|
||||
}
|
||||
|
@ -113,6 +114,7 @@ class ProvidersHelper {
|
|||
case WalletType.monero:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
case WalletType.lightning:
|
||||
case WalletType.none:
|
||||
case WalletType.haven:
|
||||
case WalletType.wownero:
|
||||
|
|
|
@ -11,6 +11,14 @@ import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
double lightningDoubleToBitcoinDouble({required double amount}) {
|
||||
return amount / 100000000;
|
||||
}
|
||||
|
||||
double bitcoinDoubleToLightningDouble({required double amount}) {
|
||||
return amount * 100000000;
|
||||
}
|
||||
|
||||
class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}})
|
||||
: _lastUsedRateId = '',
|
||||
|
@ -106,6 +114,14 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final coinJson = responseJSON.first as Map<String, dynamic>;
|
||||
|
||||
// trocador treats btcln as just bitcoin amounts:
|
||||
if (from == CryptoCurrency.btcln) {
|
||||
return Limits(
|
||||
min: bitcoinDoubleToLightningDouble(amount: (coinJson['minimum'] as double)),
|
||||
max: bitcoinDoubleToLightningDouble(amount: (coinJson['maximum'] as double)),
|
||||
);
|
||||
}
|
||||
|
||||
return Limits(
|
||||
min: coinJson['minimum'] as double,
|
||||
max: coinJson['maximum'] as double,
|
||||
|
@ -122,14 +138,20 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
try {
|
||||
if (amount == 0) return 0.0;
|
||||
|
||||
double amt = amount;
|
||||
|
||||
if (from == CryptoCurrency.btcln) {
|
||||
amt = lightningDoubleToBitcoinDouble(amount: amount);
|
||||
}
|
||||
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'ticker_from': _normalizeCurrency(from),
|
||||
'ticker_to': _normalizeCurrency(to),
|
||||
'network_from': _networkFor(from),
|
||||
'network_to': _networkFor(to),
|
||||
if (!isFixedRateMode) 'amount_from': amount.toString(),
|
||||
if (isFixedRateMode) 'amount_to': amount.toString(),
|
||||
if (!isFixedRateMode) 'amount_from': amt.toString(),
|
||||
if (isFixedRateMode) 'amount_to': amt.toString(),
|
||||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
'min_kycrating': 'C',
|
||||
'markup': markup,
|
||||
|
@ -160,6 +182,14 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
required bool isFixedRateMode,
|
||||
required bool isSendAll,
|
||||
}) async {
|
||||
double fromAmt = double.parse(request.fromAmount);
|
||||
double toAmt = double.parse(request.toAmount);
|
||||
if (request.fromCurrency == CryptoCurrency.btcln) {
|
||||
fromAmt = lightningDoubleToBitcoinDouble(amount: fromAmt);
|
||||
}
|
||||
if (request.toCurrency == CryptoCurrency.btcln) {
|
||||
toAmt = lightningDoubleToBitcoinDouble(amount: toAmt);
|
||||
}
|
||||
final params = {
|
||||
'api_key': apiKey,
|
||||
'ticker_from': _normalizeCurrency(request.fromCurrency),
|
||||
|
@ -169,17 +199,22 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
'min_kycrating': 'C',
|
||||
'markup': markup,
|
||||
if (!isFixedRateMode) 'amount_from': request.fromAmount,
|
||||
if (isFixedRateMode) 'amount_to': request.toAmount,
|
||||
if (!isFixedRateMode) 'amount_from': fromAmt.toString(),
|
||||
if (isFixedRateMode) 'amount_to': toAmt.toString(),
|
||||
'address': request.toAddress,
|
||||
'refund': request.refundAddress
|
||||
};
|
||||
|
||||
double amt = double.tryParse(request.toAmount) ?? 0;
|
||||
if (request.fromCurrency == CryptoCurrency.btcln) {
|
||||
amt = lightningDoubleToBitcoinDouble(amount: amt);
|
||||
}
|
||||
|
||||
if (isFixedRateMode) {
|
||||
await fetchRate(
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
amount: double.tryParse(request.toAmount) ?? 0,
|
||||
amount: amt,
|
||||
isFixedRateMode: true,
|
||||
isReceiveAmount: true,
|
||||
);
|
||||
|
@ -225,6 +260,13 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
final providerId = responseJSON['id_provider'] as String;
|
||||
final providerName = responseJSON['provider'] as String;
|
||||
|
||||
String? responseAmount = responseJSON['amount_from']?.toString();
|
||||
if (request.fromCurrency == CryptoCurrency.btcln && responseAmount != null) {
|
||||
responseAmount =
|
||||
bitcoinDoubleToLightningDouble(amount: double.parse(responseAmount)).toString();
|
||||
}
|
||||
responseAmount ??= fromAmt.toString();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: request.fromCurrency,
|
||||
|
@ -237,7 +279,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
createdAt: DateTime.tryParse(date)?.toLocal(),
|
||||
amount: responseJSON['amount_from']?.toString() ?? request.fromAmount,
|
||||
amount: responseAmount,
|
||||
payoutAddress: payoutAddress,
|
||||
isSendAll: isSendAll);
|
||||
}
|
||||
|
@ -290,6 +332,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
return 'MATIC';
|
||||
case CryptoCurrency.zec:
|
||||
return 'Mainnet';
|
||||
case CryptoCurrency.btcln:
|
||||
return 'Lightning';
|
||||
default:
|
||||
return currency.tag != null ? _normalizeTag(currency.tag!) : 'Mainnet';
|
||||
}
|
||||
|
@ -301,6 +345,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
return 'zec';
|
||||
case CryptoCurrency.usdcEPoly:
|
||||
return 'usdce';
|
||||
case CryptoCurrency.btcln:
|
||||
return 'btc';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
|
69
lib/lightning/cw_lightning.dart
Normal file
69
lib/lightning/cw_lightning.dart
Normal file
|
@ -0,0 +1,69 @@
|
|||
part of 'lightning.dart';
|
||||
|
||||
class CWLightning extends Lightning {
|
||||
|
||||
@override
|
||||
String formatterLightningAmountToString({required int amount}) =>
|
||||
bitcoinAmountToString(amount: amount * 100000000);
|
||||
|
||||
@override
|
||||
double formatterLightningAmountToDouble({required int amount}) =>
|
||||
bitcoinAmountToDouble(amount: amount * 100000000);
|
||||
|
||||
@override
|
||||
int formatterStringDoubleToLightningAmount(String amount) =>
|
||||
stringDoubleToBitcoinAmount(amount * 100000000);
|
||||
|
||||
WalletService createLightningWalletService(
|
||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
||||
return LightningWalletService(walletInfoSource, unspentCoinSource);
|
||||
}
|
||||
|
||||
@override
|
||||
List<LightningReceivePageOption> getLightningReceivePageOptions() =>
|
||||
LightningReceivePageOption.all;
|
||||
|
||||
@override
|
||||
ReceivePageOption getOptionInvoice() => LightningReceivePageOption.lightningInvoice;
|
||||
|
||||
@override
|
||||
ReceivePageOption getOptionOnchain() => LightningReceivePageOption.lightningOnchain;
|
||||
|
||||
@override
|
||||
String satsToLightningString(int sats) {
|
||||
const bitcoinAmountLength = 8;
|
||||
const bitcoinAmountDivider = 100000000;
|
||||
const lightningAmountDivider = 1;
|
||||
final bitcoinAmountFormat = NumberFormat()
|
||||
..maximumFractionDigits = bitcoinAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
|
||||
String formattedAmount = bitcoinAmountFormat.format(sats);
|
||||
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||
}
|
||||
|
||||
@override
|
||||
String bitcoinAmountToLightningString({required int amount}) {
|
||||
final bitcoinAmountFormat = NumberFormat()
|
||||
..maximumFractionDigits = bitcoinAmountLength
|
||||
..minimumFractionDigits = 1;
|
||||
String formattedAmount =
|
||||
bitcoinAmountFormat.format(cryptoAmountToDouble(amount: amount, divider: 1));
|
||||
return formattedAmount.substring(0, formattedAmount.length - 2);
|
||||
}
|
||||
|
||||
@override
|
||||
int bitcoinAmountToLightningAmount({required int amount}) {
|
||||
return amount * 100000000;
|
||||
}
|
||||
|
||||
@override
|
||||
double bitcoinDoubleToLightningDouble({required double amount}) {
|
||||
return amount * 100000000;
|
||||
}
|
||||
|
||||
@override
|
||||
double lightningDoubleToBitcoinDouble({required double amount}) {
|
||||
return amount / 100000000;
|
||||
}
|
||||
}
|
|
@ -30,46 +30,49 @@ Future<void> startFiatRateUpdate(
|
|||
|
||||
if (appStore.wallet!.type == WalletType.haven) {
|
||||
await updateHavenRate(fiatConversionStore);
|
||||
} else {
|
||||
fiatConversionStore.prices[appStore.wallet!.currency] =
|
||||
await FiatConversionService.fetchPrice(
|
||||
crypto: appStore.wallet!.currency,
|
||||
fiat: settingsStore.fiatCurrency,
|
||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
||||
return;
|
||||
}
|
||||
|
||||
Iterable<CryptoCurrency>? currencies;
|
||||
if (appStore.wallet!.type == WalletType.ethereum) {
|
||||
currencies =
|
||||
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||
Iterable<CryptoCurrency>? currencies = [];
|
||||
switch (appStore.wallet!.type) {
|
||||
case WalletType.ethereum:
|
||||
currencies =
|
||||
ethereum!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||
break;
|
||||
case WalletType.polygon:
|
||||
currencies =
|
||||
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||
break;
|
||||
case WalletType.solana:
|
||||
currencies =
|
||||
solana!.getSPLTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||
break;
|
||||
case WalletType.tron:
|
||||
currencies =
|
||||
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||
break;
|
||||
case WalletType.lightning:
|
||||
currencies = [CryptoCurrency.btc];
|
||||
break;
|
||||
default:
|
||||
currencies = [appStore.wallet!.currency];
|
||||
break;
|
||||
}
|
||||
|
||||
if (appStore.wallet!.type == WalletType.polygon) {
|
||||
currencies =
|
||||
polygon!.getERC20Currencies(appStore.wallet!).where((element) => element.enabled);
|
||||
for (final currency in currencies) {
|
||||
() async {
|
||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||
crypto: currency,
|
||||
fiat: settingsStore.fiatCurrency,
|
||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly,
|
||||
);
|
||||
}.call();
|
||||
}
|
||||
|
||||
if (appStore.wallet!.type == WalletType.solana) {
|
||||
currencies =
|
||||
solana!.getSPLTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||
}
|
||||
|
||||
if (appStore.wallet!.type == WalletType.tron) {
|
||||
currencies =
|
||||
tron!.getTronTokenCurrencies(appStore.wallet!).where((element) => element.enabled);
|
||||
}
|
||||
|
||||
|
||||
if (currencies != null) {
|
||||
for (final currency in currencies) {
|
||||
() async {
|
||||
fiatConversionStore.prices[currency] = await FiatConversionService.fetchPrice(
|
||||
crypto: currency,
|
||||
fiat: settingsStore.fiatCurrency,
|
||||
torOnly: settingsStore.fiatApiMode == FiatApiMode.torOnly);
|
||||
}.call();
|
||||
}
|
||||
}
|
||||
// keep btcln price in sync with btc (since the fiat api only returns btc and not btcln)
|
||||
// (btcln price is just the btc price divided by 100000000)
|
||||
fiatConversionStore.prices[CryptoCurrency.btcln] =
|
||||
(fiatConversionStore.prices[CryptoCurrency.btc] ?? 0) / 100000000;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
|
|
@ -73,7 +73,8 @@ void startCurrentWalletChangeReaction(
|
|||
if (wallet.type == WalletType.monero ||
|
||||
wallet.type == WalletType.bitcoin ||
|
||||
wallet.type == WalletType.litecoin ||
|
||||
wallet.type == WalletType.bitcoinCash) {
|
||||
wallet.type == WalletType.bitcoinCash ||
|
||||
wallet.type == WalletType.lightning) {
|
||||
_setAutoGenerateSubaddressStatus(wallet, settingsStore);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@ import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart';
|
|||
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/lightning_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/lightning_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||
import 'package:cake_wallet/src/screens/order_details/order_details_page.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
|
@ -53,6 +56,8 @@ import 'package:cake_wallet/src/screens/restore/restore_from_backup_page.dart';
|
|||
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/sweeping_wallet_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||
import 'package:cake_wallet/src/screens/send/lightning_send_confirm_page.dart';
|
||||
import 'package:cake_wallet/src/screens/send/lightning_send_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
|
||||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
|
@ -651,6 +656,25 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
case Routes.torPage:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<TorPage>());
|
||||
|
||||
case Routes.lightningSend:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<LightningSendPage>());
|
||||
|
||||
case Routes.lightningSendConfirm:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<LightningSendConfirmPage>(param1: settings.arguments));
|
||||
|
||||
case Routes.lightningReceiveOnchain:
|
||||
final args = settings.arguments as List;
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<LightningReceiveOnchainPage>(param1: args));
|
||||
|
||||
case Routes.lightningInvoice:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<LightningInvoicePage>());
|
||||
|
||||
case Routes.connectDevices:
|
||||
final params = settings.arguments as ConnectDevicePageParams;
|
||||
return MaterialPageRoute<void>(
|
||||
|
|
|
@ -101,5 +101,10 @@ class Routes {
|
|||
static const nftDetailsPage = '/nft_details_page';
|
||||
static const importNFTPage = '/import_nft_page';
|
||||
static const torPage = '/tor_page';
|
||||
static const lightningSend = '/lightning_send';
|
||||
static const lightningSendConfirm = '/lightning_send_confirm';
|
||||
static const lightningInvoice = '/lightning_invoice';
|
||||
static const lightningReceiveOnchain = '/lightning_receive_onchain';
|
||||
static const lightningSettings = '/lightning_settings';
|
||||
static const connectDevices = '/device/connect';
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ class DesktopWalletSelectionDropDown extends StatefulWidget {
|
|||
class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionDropDown> {
|
||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final lightningIcon = Image.asset('assets/images/lightning_logo.png', height: 24, width: 24);
|
||||
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||
final havenIcon = Image.asset('assets/images/haven_logo.png', height: 24, width: 24);
|
||||
|
@ -150,6 +151,8 @@ class _DesktopWalletSelectionDropDownState extends State<DesktopWalletSelectionD
|
|||
return tBitcoinIcon;
|
||||
}
|
||||
return bitcoinIcon;
|
||||
case WalletType.lightning:
|
||||
return lightningIcon;
|
||||
case WalletType.monero:
|
||||
return moneroIcon;
|
||||
case WalletType.litecoin:
|
||||
|
|
|
@ -186,6 +186,20 @@ class CryptoBalanceWidget extends StatelessWidget {
|
|||
),
|
||||
],
|
||||
)),
|
||||
Observer(builder: (_) {
|
||||
final serviceMessage = dashboardViewModel.serviceMessage;
|
||||
if (serviceMessage.isEmpty) {
|
||||
return const SizedBox();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
onTap: () => null,
|
||||
title: S.of(context).warning,
|
||||
subTitle: serviceMessage,
|
||||
),
|
||||
);
|
||||
}),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (dashboardViewModel.balanceViewModel.isShowCard &&
|
||||
|
|
|
@ -28,6 +28,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
this.fromBottomEdge = 25,
|
||||
this.moneroIcon = Image.asset('assets/images/monero_menu.png'),
|
||||
this.bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png'),
|
||||
this.lightningIcon = Image.asset('assets/images/lightning_logo.png'),
|
||||
this.litecoinIcon = Image.asset('assets/images/litecoin_menu.png'),
|
||||
this.havenIcon = Image.asset('assets/images/haven_menu.png'),
|
||||
this.ethereumIcon = Image.asset('assets/images/eth_icon.png'),
|
||||
|
@ -52,6 +53,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
|
||||
Image moneroIcon;
|
||||
Image bitcoinIcon;
|
||||
Image lightningIcon;
|
||||
Image litecoinIcon;
|
||||
Image havenIcon;
|
||||
Image ethereumIcon;
|
||||
|
@ -103,6 +105,7 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
color: Theme.of(context).extension<CakeMenuTheme>()!.iconColor);
|
||||
bitcoinIcon = Image.asset('assets/images/bitcoin_menu.png',
|
||||
color: Theme.of(context).extension<CakeMenuTheme>()!.iconColor);
|
||||
lightningIcon = Image.asset('assets/images/lightning_logo.png');
|
||||
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
@ -220,6 +223,8 @@ class MenuWidgetState extends State<MenuWidget> {
|
|||
return moneroIcon;
|
||||
case WalletType.bitcoin:
|
||||
return bitcoinIcon;
|
||||
case WalletType.lightning:
|
||||
return lightningIcon;
|
||||
case WalletType.litecoin:
|
||||
return litecoinIcon;
|
||||
case WalletType.haven:
|
||||
|
|
|
@ -638,6 +638,7 @@ class ExchangePage extends BasePage {
|
|||
initialIsAddressEditable: exchangeViewModel.isDepositAddressEnabled,
|
||||
isAmountEstimated: false,
|
||||
hasRefundAddress: true,
|
||||
hasAddress: exchangeViewModel.hasAddress,
|
||||
isMoneroWallet: exchangeViewModel.isMoneroWallet,
|
||||
currencies: exchangeViewModel.depositCurrencies,
|
||||
onCurrencySelected: (currency) {
|
||||
|
|
|
@ -33,6 +33,7 @@ class ExchangeCard extends StatefulWidget {
|
|||
this.title = '',
|
||||
this.initialIsAddressEditable = true,
|
||||
this.hasRefundAddress = false,
|
||||
this.hasAddress = true,
|
||||
this.isMoneroWallet = false,
|
||||
this.currencyButtonColor = Colors.transparent,
|
||||
this.addressButtonsColor = Colors.transparent,
|
||||
|
@ -57,6 +58,7 @@ class ExchangeCard extends StatefulWidget {
|
|||
final bool initialIsAddressEditable;
|
||||
final bool isAmountEstimated;
|
||||
final bool hasRefundAddress;
|
||||
final bool hasAddress;
|
||||
final bool isMoneroWallet;
|
||||
final Image imageArrow;
|
||||
final Color currencyButtonColor;
|
||||
|
@ -272,9 +274,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
color: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.hintTextColor),
|
||||
validator: _isAmountEditable
|
||||
? widget.currencyValueValidator
|
||||
: null),
|
||||
validator: _isAmountEditable ? widget.currencyValueValidator : null),
|
||||
),
|
||||
),
|
||||
if (widget.hasAllAmount)
|
||||
|
@ -330,138 +330,142 @@ class ExchangeCardState extends State<ExchangeCard> {
|
|||
: Offstage(),
|
||||
])),
|
||||
),
|
||||
!_isAddressEditable && widget.hasRefundAddress
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||
))
|
||||
: Offstage(),
|
||||
_isAddressEditable
|
||||
? FocusTraversalOrder(
|
||||
order: NumericFocusOrder(2),
|
||||
child: Padding(
|
||||
if (widget.hasAddress) ...[
|
||||
!_isAddressEditable && widget.hasRefundAddress
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
onURIScanned: (uri) {
|
||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||
addressController.text = paymentRequest.address;
|
||||
child: Text(
|
||||
S.of(context).refund_address,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||
))
|
||||
: Offstage(),
|
||||
_isAddressEditable
|
||||
? FocusTraversalOrder(
|
||||
order: NumericFocusOrder(2),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: AddressTextField(
|
||||
focusNode: widget.addressFocusNode,
|
||||
controller: addressController,
|
||||
onURIScanned: (uri) {
|
||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||
addressController.text = paymentRequest.address;
|
||||
|
||||
if (amountController.text.isNotEmpty) {
|
||||
_showAmountPopup(context, paymentRequest);
|
||||
return;
|
||||
}
|
||||
widget.amountFocusNode?.requestFocus();
|
||||
amountController.text = paymentRequest.amount;
|
||||
},
|
||||
placeholder: widget.hasRefundAddress ? S.of(context).refund_address : null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
],
|
||||
isBorderExist: false,
|
||||
textStyle:
|
||||
TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
onPushPasteButton: widget.onPushPasteButton,
|
||||
onPushAddressBookButton: widget.onPushAddressBookButton,
|
||||
selectedCurrency: _selectedCurrency),
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Builder(
|
||||
builder: (context) => Stack(children: <Widget>[
|
||||
FocusTraversalOrder(
|
||||
order: NumericFocusOrder(3),
|
||||
child: BaseTextFormField(
|
||||
controller: addressController,
|
||||
borderColor: Colors.transparent,
|
||||
suffixIcon: SizedBox(width: _isMoneroWallet ? 80 : 36),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: widget.addressTextFieldValidator),
|
||||
),
|
||||
Positioned(
|
||||
top: 2,
|
||||
right: 0,
|
||||
child: SizedBox(
|
||||
width: _isMoneroWallet ? 80 : 36,
|
||||
child: Row(children: <Widget>[
|
||||
if (_isMoneroWallet)
|
||||
if (amountController.text.isNotEmpty) {
|
||||
_showAmountPopup(context, paymentRequest);
|
||||
return;
|
||||
}
|
||||
widget.amountFocusNode?.requestFocus();
|
||||
amountController.text = paymentRequest.amount;
|
||||
},
|
||||
placeholder: widget.hasRefundAddress ? S.of(context).refund_address : null,
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook,
|
||||
],
|
||||
isBorderExist: false,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||
buttonColor: widget.addressButtonsColor,
|
||||
validator: widget.addressTextFieldValidator,
|
||||
onPushPasteButton: widget.onPushPasteButton,
|
||||
onPushAddressBookButton: widget.onPushAddressBookButton,
|
||||
selectedCurrency: _selectedCurrency),
|
||||
),
|
||||
)
|
||||
: Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Builder(
|
||||
builder: (context) => Stack(children: <Widget>[
|
||||
FocusTraversalOrder(
|
||||
order: NumericFocusOrder(3),
|
||||
child: BaseTextFormField(
|
||||
controller: addressController,
|
||||
borderColor: Colors.transparent,
|
||||
suffixIcon: SizedBox(width: _isMoneroWallet ? 80 : 36),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white),
|
||||
validator: widget.addressTextFieldValidator),
|
||||
),
|
||||
Positioned(
|
||||
top: 2,
|
||||
right: 0,
|
||||
child: SizedBox(
|
||||
width: _isMoneroWallet ? 80 : 36,
|
||||
child: Row(children: <Widget>[
|
||||
if (_isMoneroWallet)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: Semantics(
|
||||
label: S.of(context).address_book,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final contact =
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.pickerAddressBook,
|
||||
arguments: widget.initialCurrency,
|
||||
);
|
||||
|
||||
if (contact is ContactBase) {
|
||||
setState(() =>
|
||||
addressController.text = contact.address);
|
||||
widget.onPushAddressBookButton?.call(context);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.addressButtonsColor,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/open_book.png',
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor,
|
||||
)),
|
||||
),
|
||||
)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: Semantics(
|
||||
label: S.of(context).address_book,
|
||||
child: InkWell(
|
||||
onTap: () async {
|
||||
final contact =
|
||||
await Navigator.of(context).pushNamed(
|
||||
Routes.pickerAddressBook,
|
||||
arguments: widget.initialCurrency,
|
||||
);
|
||||
|
||||
if (contact is ContactBase) {
|
||||
setState(() =>
|
||||
addressController.text = contact.address);
|
||||
widget.onPushAddressBookButton?.call(context);
|
||||
}
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: widget.addressButtonsColor,
|
||||
borderRadius:
|
||||
BorderRadius.all(Radius.circular(6))),
|
||||
child: Image.asset(
|
||||
'assets/images/open_book.png',
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor,
|
||||
)),
|
||||
),
|
||||
)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 2),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: Semantics(
|
||||
label: S.of(context).copy_address,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: addressController.text));
|
||||
showBar<void>(
|
||||
context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.fromLTRB(8, 8, 0, 8),
|
||||
color: Colors.transparent,
|
||||
child: copyImage),
|
||||
),
|
||||
)))
|
||||
])))
|
||||
])),
|
||||
),
|
||||
padding: EdgeInsets.only(left: 2),
|
||||
child: Container(
|
||||
width: 34,
|
||||
height: 34,
|
||||
padding: EdgeInsets.only(top: 0),
|
||||
child: Semantics(
|
||||
label: S.of(context).copy_address,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(
|
||||
text: addressController.text));
|
||||
showBar<void>(
|
||||
context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.fromLTRB(8, 8, 0, 8),
|
||||
color: Colors.transparent,
|
||||
child: copyImage),
|
||||
),
|
||||
)))
|
||||
])))
|
||||
])),
|
||||
),
|
||||
],
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,22 +24,17 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
|||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
|
||||
void showInformation(
|
||||
ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) {
|
||||
void showInformation(ExchangeTradeViewModel exchangeTradeViewModel, BuildContext context) {
|
||||
final trade = exchangeTradeViewModel.trade;
|
||||
final walletName = exchangeTradeViewModel.wallet.name;
|
||||
|
||||
final information = exchangeTradeViewModel.isSendable
|
||||
? S.current.exchange_result_confirm(
|
||||
trade.amount, trade.from.toString(), walletName) +
|
||||
exchangeTradeViewModel.extraInfo
|
||||
: S.current.exchange_result_description(
|
||||
trade.amount, trade.from.toString()) +
|
||||
exchangeTradeViewModel.extraInfo;
|
||||
? S.current.exchange_result_confirm(trade.amount, trade.from.toString(), walletName) +
|
||||
exchangeTradeViewModel.extraInfo
|
||||
: S.current.exchange_result_description(trade.amount, trade.from.toString()) +
|
||||
exchangeTradeViewModel.extraInfo;
|
||||
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (_) => InformationPage(information: information));
|
||||
showPopUp<void>(context: context, builder: (_) => InformationPage(information: information));
|
||||
}
|
||||
|
||||
class ExchangeTradePage extends BasePage {
|
||||
|
@ -72,8 +67,7 @@ class ExchangeTradePage extends BasePage {
|
|||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
ExchangeTradeForm(exchangeTradeViewModel);
|
||||
Widget body(BuildContext context) => ExchangeTradeForm(exchangeTradeViewModel);
|
||||
}
|
||||
|
||||
class ExchangeTradeForm extends StatefulWidget {
|
||||
|
@ -138,7 +132,9 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor),
|
||||
color: Theme.of(context)
|
||||
.extension<TransactionTradeTheme>()!
|
||||
.detailsTitlesColor),
|
||||
),
|
||||
if (trade.expiredAt != null)
|
||||
TimerWidget(trade.expiredAt!,
|
||||
|
@ -159,9 +155,9 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.qrCodeColor
|
||||
)
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.qrCodeColor)),
|
||||
child: QrImage(data: trade.inputAddress ?? fetchingLabel),
|
||||
)))),
|
||||
Spacer(flex: 3)
|
||||
|
@ -192,10 +188,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
? Builder(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(
|
||||
ClipboardData(text: value));
|
||||
showBar<void>(context,
|
||||
S.of(context).copied_to_clipboard);
|
||||
Clipboard.setData(ClipboardData(text: value));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: content,
|
||||
))
|
||||
|
@ -209,17 +203,14 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
bottomSectionPadding: EdgeInsets.fromLTRB(24, 0, 24, 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
final trade = widget.exchangeTradeViewModel.trade;
|
||||
final sendingState =
|
||||
widget.exchangeTradeViewModel.sendViewModel.state;
|
||||
final sendingState = widget.exchangeTradeViewModel.sendViewModel.state;
|
||||
|
||||
return widget.exchangeTradeViewModel.isSendable &&
|
||||
!(sendingState is TransactionCommitted)
|
||||
? LoadingPrimaryButton(
|
||||
isDisabled: trade.inputAddress == null ||
|
||||
trade.inputAddress!.isEmpty,
|
||||
isDisabled: trade.inputAddress == null || trade.inputAddress!.isEmpty,
|
||||
isLoading: sendingState is IsExecutingState,
|
||||
onPressed: () =>
|
||||
widget.exchangeTradeViewModel.confirmSending(),
|
||||
onPressed: () => widget.exchangeTradeViewModel.confirmSending(),
|
||||
text: S.of(context).confirm,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white)
|
||||
|
@ -257,27 +248,26 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
return ConfirmSendingAlert(
|
||||
alertTitle: S.of(popupContext).confirm_sending,
|
||||
amount: S.of(popupContext).send_amount,
|
||||
amountValue: widget.exchangeTradeViewModel.sendViewModel
|
||||
.pendingTransaction!.amountFormatted,
|
||||
amountValue: widget
|
||||
.exchangeTradeViewModel.sendViewModel.pendingTransaction!.amountFormatted,
|
||||
fee: S.of(popupContext).send_fee,
|
||||
feeValue: widget.exchangeTradeViewModel.sendViewModel
|
||||
.pendingTransaction!.feeFormatted,
|
||||
feeRate: widget.exchangeTradeViewModel.sendViewModel.pendingTransaction!.feeRate,
|
||||
feeValue: widget
|
||||
.exchangeTradeViewModel.sendViewModel.pendingTransaction!.feeFormatted,
|
||||
feeRate:
|
||||
widget.exchangeTradeViewModel.sendViewModel.pendingTransaction!.feeRate,
|
||||
rightButtonText: S.of(popupContext).send,
|
||||
leftButtonText: S.of(popupContext).cancel,
|
||||
actionRightButton: () async {
|
||||
Navigator.of(popupContext).pop();
|
||||
await widget.exchangeTradeViewModel.sendViewModel
|
||||
.commitTransaction();
|
||||
await widget.exchangeTradeViewModel.sendViewModel.commitTransaction();
|
||||
transactionStatePopup();
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(popupContext).pop(),
|
||||
feeFiatAmount: widget.exchangeTradeViewModel
|
||||
.pendingTransactionFeeFiatAmountFormatted,
|
||||
fiatAmountValue: widget.exchangeTradeViewModel
|
||||
.pendingTransactionFiatAmountValueFormatted,
|
||||
outputs: widget.exchangeTradeViewModel.sendViewModel
|
||||
.outputs);
|
||||
feeFiatAmount:
|
||||
widget.exchangeTradeViewModel.pendingTransactionFeeFiatAmountFormatted,
|
||||
fiatAmountValue:
|
||||
widget.exchangeTradeViewModel.pendingTransactionFiatAmountValueFormatted,
|
||||
outputs: widget.exchangeTradeViewModel.sendViewModel.outputs);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -305,85 +295,26 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
void transactionStatePopup() {
|
||||
if (this.mounted) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext popupContext) {
|
||||
return Observer(builder: (_) {
|
||||
final state = widget
|
||||
.exchangeTradeViewModel.sendViewModel.state;
|
||||
context: context,
|
||||
builder: (BuildContext popupContext) {
|
||||
return Observer(builder: (_) {
|
||||
final state = widget.exchangeTradeViewModel.sendViewModel.state;
|
||||
|
||||
if (state is TransactionCommitted) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Theme.of(popupContext).colorScheme.background,
|
||||
child: Center(
|
||||
child: Image.asset(
|
||||
'assets/images/birthday_cake.png'),
|
||||
),
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
top: 220, left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(popupContext).send_success(widget
|
||||
.exchangeTradeViewModel
|
||||
.wallet
|
||||
.currency
|
||||
.toString()),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(popupContext).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
if (state is TransactionCommitted) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Theme.of(popupContext).colorScheme.background,
|
||||
child: Center(
|
||||
child: Image.asset('assets/images/birthday_cake.png'),
|
||||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 24,
|
||||
right: 24,
|
||||
bottom: 24,
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
popupContext,
|
||||
Routes.dashboard,
|
||||
(route) => false,
|
||||
);
|
||||
RequestReviewHandler.requestReview();
|
||||
},
|
||||
text: S.of(popupContext).got_it,
|
||||
color: Theme.of(popupContext).primaryColor,
|
||||
textColor: Colors.white))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Theme.of(popupContext).colorScheme.background,
|
||||
child: Center(
|
||||
child: Image.asset(
|
||||
'assets/images/birthday_cake.png'),
|
||||
),
|
||||
),
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(
|
||||
sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(popupContext)
|
||||
.colorScheme
|
||||
.background
|
||||
.withOpacity(0.25)),
|
||||
child: Center(
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 220),
|
||||
padding: EdgeInsets.only(top: 220, left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(popupContext).send_sending,
|
||||
S.of(popupContext).send_success(
|
||||
widget.exchangeTradeViewModel.wallet.currency.toString()),
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
|
@ -394,12 +325,60 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
),
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 24,
|
||||
right: 24,
|
||||
bottom: 24,
|
||||
child: PrimaryButton(
|
||||
onPressed: () {
|
||||
Navigator.pushNamedAndRemoveUntil(
|
||||
popupContext,
|
||||
Routes.dashboard,
|
||||
(route) => false,
|
||||
);
|
||||
RequestReviewHandler.requestReview();
|
||||
},
|
||||
text: S.of(popupContext).got_it,
|
||||
color: Theme.of(popupContext).primaryColor,
|
||||
textColor: Colors.white))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
color: Theme.of(popupContext).colorScheme.background,
|
||||
child: Center(
|
||||
child: Image.asset('assets/images/birthday_cake.png'),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(popupContext).colorScheme.background.withOpacity(0.25)),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 220),
|
||||
child: Text(
|
||||
S.of(popupContext).send_sending,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(popupContext).extension<CakeTextTheme>()!.titleColor,
|
||||
decoration: TextDecoration.none,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
340
lib/src/screens/receive/lightning_invoice_page.dart
Normal file
340
lib/src/screens/receive/lightning_invoice_page.dart
Normal file
|
@ -0,0 +1,340 @@
|
|||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/lightning_input_form.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||
|
||||
class LightningInvoicePage extends BasePage {
|
||||
LightningInvoicePage({
|
||||
required this.lightningInvoicePageViewModel,
|
||||
required this.receiveOptionViewModel,
|
||||
}) : _amountFocusNode = FocusNode() {}
|
||||
|
||||
final _descriptionController = TextEditingController();
|
||||
final _amountController = TextEditingController();
|
||||
final FocusNode _amountFocusNode;
|
||||
|
||||
final LightningInvoicePageViewModel lightningInvoicePageViewModel;
|
||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
bool effectsInstalled = false;
|
||||
|
||||
@override
|
||||
bool get gradientAll => true;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) => PresentReceiveOptionPicker(
|
||||
receiveOptionViewModel: receiveOptionViewModel, color: titleColor(context));
|
||||
|
||||
@override
|
||||
Widget trailing(BuildContext context) => TrailButton(
|
||||
caption: S.of(context).clear,
|
||||
onPressed: () {
|
||||
_formKey.currentState?.reset();
|
||||
});
|
||||
|
||||
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||
onClose(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () => _onNavigateBack(context),
|
||||
child: KeyboardActions(
|
||||
disableScroll: true,
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: _amountFocusNode,
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
),
|
||||
]),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.firstGradientTopPanelColor,
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.secondGradientTopPanelColor,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||
child: LightningInvoiceForm(
|
||||
descriptionController: _descriptionController,
|
||||
amountController: _amountController,
|
||||
depositAmountFocus: _amountFocusNode,
|
||||
formKey: _formKey,
|
||||
lightningInvoicePageViewModel: lightningInvoicePageViewModel,
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 12, bottom: 12, right: 6),
|
||||
margin: const EdgeInsets.only(left: 24, right: 24, bottom: 48),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
color: Color.fromARGB(255, 170, 147, 30),
|
||||
border: Border.all(
|
||||
color: Color.fromARGB(178, 223, 214, 0),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
margin: EdgeInsets.only(left: 12, bottom: 48, right: 20),
|
||||
child: Image.asset(
|
||||
"assets/images/warning.png",
|
||||
color: Color.fromARGB(128, 255, 255, 255),
|
||||
),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: lightningInvoicePageViewModel.lightningViewModel
|
||||
.invoiceSoftLimitsSats(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Expanded(
|
||||
child:
|
||||
Container(child: Center(child: CircularProgressIndicator())));
|
||||
}
|
||||
late String finalText;
|
||||
InvoiceSoftLimitsResult limits = snapshot.data as InvoiceSoftLimitsResult;
|
||||
if (limits.inboundLiquidity == 0) {
|
||||
finalText = S.of(context).lightning_invoice_min(
|
||||
limits.feePercent.toString(),
|
||||
lightning!.satsToLightningString(limits.minFee));
|
||||
} else {
|
||||
finalText = S.of(context).lightning_invoice_min_max(
|
||||
limits.feePercent.toString(),
|
||||
lightning!.satsToLightningString(limits.minFee),
|
||||
lightning!.satsToLightningString(limits.inboundLiquidity),
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Text(
|
||||
finalText,
|
||||
maxLines: 5,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
text: S.of(context).create_invoice,
|
||||
onPressed: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
lightningInvoicePageViewModel.setRequestParams(
|
||||
inputAmount: _amountController.text,
|
||||
inputDescription: _descriptionController.text,
|
||||
);
|
||||
lightningInvoicePageViewModel.createInvoice();
|
||||
},
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
isLoading: lightningInvoicePageViewModel.state is IsExecutingState,
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _setReactions(BuildContext context) {
|
||||
if (effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) async {
|
||||
if (option == lightning!.getOptionOnchain()) {
|
||||
Navigator.popAndPushNamed(
|
||||
context,
|
||||
Routes.lightningReceiveOnchain,
|
||||
arguments: [lightning!.getOptionOnchain()],
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => lightningInvoicePageViewModel.state, (ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).invoice_created,
|
||||
alertContent: '',
|
||||
contentWidget: Column(
|
||||
children: [
|
||||
Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
child: QrImage(
|
||||
data: state.payload as String,
|
||||
version: 14,
|
||||
errorCorrectionLevel: qr.QrErrorCorrectLevel.L,
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 12, bottom: 12, right: 6),
|
||||
margin: const EdgeInsets.only(top: 32),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
color: Color.fromARGB(255, 170, 147, 30),
|
||||
border: Border.all(
|
||||
color: Color.fromARGB(178, 223, 214, 0),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
margin: EdgeInsets.only(left: 12, bottom: 48, right: 12),
|
||||
child: Image.asset(
|
||||
"assets/images/warning.png",
|
||||
color: Color.fromARGB(128, 255, 255, 255),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Material(
|
||||
color: Colors.transparent,
|
||||
child: Text(
|
||||
S.of(context).lightning_invoice_warning,
|
||||
maxLines: 5,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
rightButtonText: S.of(context).ok,
|
||||
actionRightButton: () => Navigator.of(context).pop(),
|
||||
actionLeftButton: () async {
|
||||
Clipboard.setData(ClipboardData(text: state.payload as String));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
leftButtonText: S.of(context).copy,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
if (state is FailureState) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: state.error.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
effectsInstalled = true;
|
||||
}
|
||||
}
|
252
lib/src/screens/receive/lightning_receive_page.dart
Normal file
252
lib/src/screens/receive/lightning_receive_page.dart
Normal file
|
@ -0,0 +1,252 @@
|
|||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/qr_code_theme.dart';
|
||||
import 'package:cake_wallet/utils/brightness_util.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
class LightningReceiveOnchainPage extends BasePage {
|
||||
LightningReceiveOnchainPage(
|
||||
{required this.addressListViewModel,
|
||||
required this.receiveOptionViewModel,
|
||||
required this.lightningViewModel})
|
||||
: _amountController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>() {
|
||||
_amountController.addListener(() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
addressListViewModel.changeAmount(_amountController.text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final WalletAddressListViewModel addressListViewModel;
|
||||
final ReceiveOptionViewModel receiveOptionViewModel;
|
||||
final LightningViewModel lightningViewModel;
|
||||
final TextEditingController _amountController;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
|
||||
bool effectsInstalled = false;
|
||||
|
||||
@override
|
||||
String get title => S.current.receive;
|
||||
|
||||
@override
|
||||
bool get gradientBackground => true;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => true;
|
||||
|
||||
@override
|
||||
Widget middle(BuildContext context) => PresentReceiveOptionPicker(
|
||||
color: titleColor(context), receiveOptionViewModel: receiveOptionViewModel);
|
||||
|
||||
@override
|
||||
Widget Function(BuildContext, Widget) get rootWrapper =>
|
||||
(BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _setReactions(context));
|
||||
final copyImage = Image.asset('assets/images/copy_address.png',
|
||||
color: Theme.of(context).extension<QRCodeTheme>()!.qrWidgetCopyButtonColor);
|
||||
String heroTag = "lightning_receive";
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
FutureBuilder(
|
||||
future: lightningViewModel.receiveOnchain(),
|
||||
builder: ((context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return CircularProgressIndicator();
|
||||
}
|
||||
ReceiveOnchainResult results = snapshot.data as ReceiveOnchainResult;
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Text(
|
||||
S.of(context).qr_fullscreen,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Spacer(flex: 3),
|
||||
Observer(
|
||||
builder: (_) => Flexible(
|
||||
flex: 5,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
BrightnessUtil.changeBrightnessForFunction(
|
||||
() async {
|
||||
await Navigator.pushNamed(context, Routes.fullscreenQR,
|
||||
arguments: QrViewData(
|
||||
data: results.bitcoinAddress,
|
||||
heroTag: heroTag,
|
||||
));
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: Key(heroTag),
|
||||
child: Center(
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.textColor,
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(
|
||||
width: 3,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
child: QrImage(data: results.bitcoinAddress)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Spacer(flex: 3)
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 8, left: 24, right: 24),
|
||||
child: Builder(
|
||||
builder: (context) => Observer(
|
||||
builder: (context) => GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: results.bitcoinAddress));
|
||||
showBar<void>(context, S.of(context).copied_to_clipboard);
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Text(
|
||||
results.bitcoinAddress,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.textColor),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 12),
|
||||
child: copyImage,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.only(top: 24, bottom: 24, right: 6),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15)),
|
||||
color: Color.fromARGB(255, 170, 147, 30),
|
||||
border: Border.all(
|
||||
color: Color.fromARGB(178, 223, 214, 0),
|
||||
width: 2,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
width: 48,
|
||||
height: 48,
|
||||
margin: EdgeInsets.only(left: 12, bottom: 48, right: 20),
|
||||
child: Image.asset(
|
||||
"assets/images/warning.png",
|
||||
color: Color.fromARGB(128, 255, 255, 255),
|
||||
),
|
||||
),
|
||||
FutureBuilder(
|
||||
future: lightningViewModel.receiveOnchain(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.data == null) {
|
||||
return Expanded(
|
||||
child: Container(child: Center(child: CircularProgressIndicator())));
|
||||
}
|
||||
ReceiveOnchainResult results = snapshot.data as ReceiveOnchainResult;
|
||||
return Expanded(
|
||||
child: Text(
|
||||
S.of(context).lightning_receive_limits(
|
||||
lightning!.satsToLightningString(results.minAllowedDeposit),
|
||||
lightning!.satsToLightningString(results.maxAllowedDeposit),
|
||||
results.feePercent.toString(),
|
||||
lightning!.satsToLightningString(results.fee),
|
||||
),
|
||||
maxLines: 10,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _setReactions(BuildContext context) {
|
||||
if (effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
reaction((_) => receiveOptionViewModel.selectedReceiveOption, (ReceivePageOption option) async {
|
||||
if (option == lightning!.getOptionInvoice()) {
|
||||
Navigator.popAndPushNamed(
|
||||
context,
|
||||
Routes.lightningInvoice,
|
||||
arguments: [lightning!.getOptionInvoice()],
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
effectsInstalled = true;
|
||||
}
|
||||
}
|
|
@ -7,15 +7,16 @@ import 'package:flutter/services.dart';
|
|||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
|
||||
class AnonpayCurrencyInputField extends StatelessWidget {
|
||||
const AnonpayCurrencyInputField(
|
||||
{super.key,
|
||||
required this.onTapPicker,
|
||||
required this.selectedCurrency,
|
||||
required this.focusNode,
|
||||
required this.controller,
|
||||
required this.minAmount,
|
||||
required this.maxAmount});
|
||||
final Function() onTapPicker;
|
||||
const AnonpayCurrencyInputField({
|
||||
super.key,
|
||||
this.onTapPicker,
|
||||
required this.selectedCurrency,
|
||||
required this.focusNode,
|
||||
required this.controller,
|
||||
required this.minAmount,
|
||||
required this.maxAmount,
|
||||
});
|
||||
final Function()? onTapPicker;
|
||||
final Currency selectedCurrency;
|
||||
final FocusNode focusNode;
|
||||
final TextEditingController controller;
|
||||
|
@ -23,6 +24,7 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
|||
final String maxAmount;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool hasDecimals = selectedCurrency.name.toLowerCase() != "sats";
|
||||
final arrowBottomPurple = Image.asset(
|
||||
'assets/images/arrow_bottom_purple_icon.png',
|
||||
color: Colors.white,
|
||||
|
@ -34,40 +36,50 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
|||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color:
|
||||
Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderBottomPanelColor,
|
||||
color: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.textFieldBorderBottomPanelColor,
|
||||
width: 1)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
height: 32,
|
||||
child: InkWell(
|
||||
onTap: onTapPicker,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 5),
|
||||
child: arrowBottomPurple,
|
||||
),
|
||||
Text(selectedCurrency.name.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white))
|
||||
]),
|
||||
),
|
||||
),
|
||||
if (onTapPicker != null)
|
||||
Container(
|
||||
padding: EdgeInsets.only(right: 8),
|
||||
height: 32,
|
||||
child: InkWell(
|
||||
onTap: onTapPicker,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: EdgeInsets.only(right: 5),
|
||||
child: arrowBottomPurple,
|
||||
),
|
||||
Text(selectedCurrency.name.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 16,
|
||||
color: Colors.white))
|
||||
]),
|
||||
),
|
||||
)
|
||||
else
|
||||
Text(selectedCurrency.name.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600, fontSize: 16, color: Colors.white)),
|
||||
selectedCurrency.tag != null
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 3.0),
|
||||
child: Container(
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(6))),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
|
@ -77,7 +89,9 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
|||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
|
||||
color: Theme.of(context)
|
||||
.extension<SendPageTheme>()!
|
||||
.textFieldButtonIconColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -102,20 +116,21 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
|||
textInputAction: TextInputAction.next,
|
||||
enabled: true,
|
||||
textAlign: TextAlign.left,
|
||||
keyboardType:
|
||||
TextInputType.numberWithOptions(signed: false, decimal: true),
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: hasDecimals),
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]'))
|
||||
FilteringTextInputFormatter.deny(RegExp('[\\-|\\ ]')),
|
||||
if (!hasDecimals) FilteringTextInputFormatter.deny(RegExp('[\.,]')),
|
||||
],
|
||||
hintText: '0.0000',
|
||||
hintText: hasDecimals ? '0.0000' : '0',
|
||||
borderColor: Colors.transparent,
|
||||
//widget.borderColor,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
color:
|
||||
Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
validator: null,
|
||||
),
|
||||
|
@ -131,19 +146,23 @@ class AnonpayCurrencyInputField extends StatelessWidget {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).min_value(minAmount, selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||
),
|
||||
SizedBox(width: 10),
|
||||
Text(S.of(context).max_value(maxAmount, selectedCurrency.toString()),
|
||||
if (minAmount.isNotEmpty) ...[
|
||||
Text(
|
||||
S.of(context).min_value(minAmount, selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor)),
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor),
|
||||
),
|
||||
],
|
||||
SizedBox(width: 10),
|
||||
if (maxAmount.isNotEmpty) ...[
|
||||
Text(S.of(context).max_value(maxAmount, selectedCurrency.toString()),
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
height: 1.2,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor))
|
||||
],
|
||||
],
|
||||
),
|
||||
)
|
||||
|
|
81
lib/src/screens/receive/widgets/lightning_input_form.dart
Normal file
81
lib/src/screens/receive/widgets/lightning_input_form.dart
Normal file
|
@ -0,0 +1,81 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_currency_input_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/typography.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_invoice_page_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
|
||||
class LightningInvoiceForm extends StatelessWidget {
|
||||
LightningInvoiceForm({
|
||||
super.key,
|
||||
required this.formKey,
|
||||
required this.lightningInvoicePageViewModel,
|
||||
required this.amountController,
|
||||
required this.descriptionController,
|
||||
required this.depositAmountFocus,
|
||||
}) : _descriptionFocusNode = FocusNode() {
|
||||
amountController.text = lightningInvoicePageViewModel.amount;
|
||||
descriptionController.text = lightningInvoicePageViewModel.description;
|
||||
}
|
||||
|
||||
final TextEditingController amountController;
|
||||
final TextEditingController descriptionController;
|
||||
final LightningInvoicePageViewModel lightningInvoicePageViewModel;
|
||||
final FocusNode depositAmountFocus;
|
||||
final FocusNode _descriptionFocusNode;
|
||||
final GlobalKey<FormState> formKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Form(
|
||||
key: formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).invoice_details,
|
||||
style: textMediumSemiBold(),
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
return AnonpayCurrencyInputField(
|
||||
controller: amountController,
|
||||
focusNode: depositAmountFocus,
|
||||
maxAmount: '',
|
||||
minAmount: (lightningInvoicePageViewModel.minimum != null)
|
||||
? lightning!
|
||||
.satsToLightningString(lightningInvoicePageViewModel.minimum!.round())
|
||||
: '...',
|
||||
selectedCurrency: CryptoCurrency.btcln,
|
||||
);
|
||||
}),
|
||||
SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
BaseTextFormField(
|
||||
controller: descriptionController,
|
||||
focusNode: _descriptionFocusNode,
|
||||
textInputAction: TextInputAction.next,
|
||||
borderColor:
|
||||
Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderTopPanelColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
hintText: S.of(context).optional_description,
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
textStyle: TextStyle(fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(
|
||||
height: 52,
|
||||
),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
|
||||
class QrImage extends StatelessWidget {
|
||||
QrImage({
|
||||
|
@ -23,7 +24,9 @@ class QrImage extends StatelessWidget {
|
|||
return qr.QrImageView(
|
||||
data: data,
|
||||
errorCorrectionLevel: errorCorrectionLevel,
|
||||
version: version ?? 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
// Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
// changed from 9 to auto
|
||||
version: version ?? QrVersions.auto,
|
||||
size: size,
|
||||
foregroundColor: foregroundColor,
|
||||
backgroundColor: backgroundColor,
|
||||
|
|
|
@ -270,7 +270,8 @@ class WalletRestorePage extends BasePage {
|
|||
|
||||
// bip39:
|
||||
const validSeedLengths = [12, 18, 24];
|
||||
if (walletRestoreViewModel.type == WalletType.bitcoin &&
|
||||
final type = walletRestoreViewModel.type;
|
||||
if ((type == WalletType.bitcoin || type == WalletType.lightning) &&
|
||||
!(validSeedLengths.contains(seedWords.length))) {
|
||||
return false;
|
||||
}
|
||||
|
|
311
lib/src/screens/send/lightning_send_confirm_page.dart
Normal file
311
lib/src/screens/send/lightning_send_confirm_page.dart
Normal file
|
@ -0,0 +1,311 @@
|
|||
import 'package:breez_sdk/breez_sdk.dart';
|
||||
import 'package:breez_sdk/bridge_generated.dart' as BZG;
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_currency_input_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class LightningSendConfirmPage extends BasePage {
|
||||
LightningSendConfirmPage({required this.invoice, required this.lightningSendViewModel})
|
||||
: _formKey = GlobalKey<FormState>() {
|
||||
initialSatAmount = ((invoice.amountMsat ?? 0) ~/ 1000);
|
||||
_amountController = TextEditingController();
|
||||
_fiatAmountController = TextEditingController();
|
||||
_amountController.text = initialSatAmount.toString();
|
||||
_fiatAmountController.text = lightningSendViewModel.formattedFiatAmount(initialSatAmount);
|
||||
}
|
||||
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final controller = PageController(initialPage: 0);
|
||||
|
||||
BZG.LNInvoice invoice;
|
||||
late int initialSatAmount;
|
||||
late TextEditingController _amountController;
|
||||
late TextEditingController _fiatAmountController;
|
||||
final FocusNode _depositAmountFocus = FocusNode();
|
||||
final LightningSendViewModel lightningSendViewModel;
|
||||
|
||||
bool _effectsInstalled = false;
|
||||
|
||||
@override
|
||||
String get title => S.current.send;
|
||||
|
||||
@override
|
||||
bool get gradientAll => true;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@override
|
||||
Widget? leading(BuildContext context) {
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: titleColor(context),
|
||||
size: 16,
|
||||
);
|
||||
final _closeButton =
|
||||
currentTheme.type == ThemeType.dark ? closeButtonImageDarkTheme : closeButtonImage;
|
||||
|
||||
bool isMobileView = responsiveLayoutUtil.shouldRenderMobileUI;
|
||||
|
||||
return MergeSemantics(
|
||||
child: SizedBox(
|
||||
height: isMobileView ? 37 : 45,
|
||||
width: isMobileView ? 37 : 45,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: !isMobileView ? S.of(context).close : S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
|
||||
),
|
||||
onPressed: () => onClose(context),
|
||||
child: !isMobileView ? _closeButton : _backButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
void onClose(BuildContext context) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
_setEffects(context);
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () => _onNavigateBack(context),
|
||||
child: KeyboardActions(
|
||||
disableScroll: true,
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: FocusNode(),
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
),
|
||||
]),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.firstGradientTopPanelColor,
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.secondGradientTopPanelColor,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Observer(builder: (_) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||
child: Column(
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
enabled: false,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.textFieldBorderTopPanelColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
initialValue: "${S.of(context).invoice}: ${invoice.bolt11}",
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
if (invoice.amountMsat == null)
|
||||
Observer(builder: (_) {
|
||||
return AnonpayCurrencyInputField(
|
||||
controller: _amountController,
|
||||
focusNode: _depositAmountFocus,
|
||||
maxAmount: '',
|
||||
minAmount: '',
|
||||
selectedCurrency: CryptoCurrency.btcln,
|
||||
);
|
||||
})
|
||||
else
|
||||
BaseTextFormField(
|
||||
enabled: false,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.textFieldBorderTopPanelColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
initialValue:
|
||||
"sats: ${lightning!.bitcoinAmountToLightningString(amount: initialSatAmount)}",
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
BaseTextFormField(
|
||||
enabled: false,
|
||||
controller: _fiatAmountController,
|
||||
prefixIcon: Padding(
|
||||
padding: EdgeInsets.only(top: 9),
|
||||
child: Text(
|
||||
lightningSendViewModel.fiat.title + ':',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
borderColor: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.textFieldBorderTopPanelColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
if (invoice.description?.isNotEmpty ?? false) ...[
|
||||
BaseTextFormField(
|
||||
enabled: false,
|
||||
initialValue: "${S.of(context).description}: ${invoice.description}",
|
||||
textInputAction: TextInputAction.next,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.textFieldBorderTopPanelColor,
|
||||
suffixIcon: SizedBox(width: 36),
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).extension<ExchangePageTheme>()!.hintTextColor,
|
||||
),
|
||||
textStyle: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w600, color: Colors.white),
|
||||
validator: null,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
LoadingPrimaryButton(
|
||||
text: S.of(context).send,
|
||||
onPressed: () async {
|
||||
try {
|
||||
await lightningSendViewModel.send(
|
||||
invoice,
|
||||
int.parse(_amountController.text)
|
||||
);
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent:
|
||||
S.of(context).send_success(CryptoCurrency.btc.toString()),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () {
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
});
|
||||
} catch (e) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: e.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
},
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
isLoading: lightningSendViewModel.loading,
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||
onClose(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
if (_effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
_amountController.addListener(() {
|
||||
final amount = _amountController.text;
|
||||
_fiatAmountController.text = lightningSendViewModel.formattedFiatAmount(int.parse(amount));
|
||||
});
|
||||
|
||||
_effectsInstalled = true;
|
||||
}
|
||||
}
|
233
lib/src/screens/send/lightning_send_page.dart
Normal file
233
lib/src/screens/send/lightning_send_page.dart
Normal file
|
@ -0,0 +1,233 @@
|
|||
import 'package:breez_sdk/breez_sdk.dart';
|
||||
import 'package:breez_sdk/bridge_generated.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/trail_button.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class LightningSendPage extends BasePage {
|
||||
LightningSendPage({
|
||||
required this.output,
|
||||
required this.authService,
|
||||
required this.lightningSendViewModel,
|
||||
}) : _formKey = GlobalKey<FormState>();
|
||||
|
||||
final Output output;
|
||||
final AuthService authService;
|
||||
final LightningSendViewModel lightningSendViewModel;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
|
||||
final bolt11Controller = TextEditingController();
|
||||
final bolt11FocusNode = FocusNode();
|
||||
|
||||
bool _effectsInstalled = false;
|
||||
|
||||
@override
|
||||
String get title => S.current.send;
|
||||
|
||||
@override
|
||||
bool get gradientAll => true;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomInset => false;
|
||||
|
||||
@override
|
||||
bool get extendBodyBehindAppBar => true;
|
||||
|
||||
@override
|
||||
Widget? leading(BuildContext context) {
|
||||
final _backButton = Icon(
|
||||
Icons.arrow_back_ios,
|
||||
color: titleColor(context),
|
||||
size: 16,
|
||||
);
|
||||
final _closeButton =
|
||||
currentTheme.type == ThemeType.dark ? closeButtonImageDarkTheme : closeButtonImage;
|
||||
|
||||
bool isMobileView = responsiveLayoutUtil.shouldRenderMobileUI;
|
||||
|
||||
return MergeSemantics(
|
||||
child: SizedBox(
|
||||
height: isMobileView ? 37 : 45,
|
||||
width: isMobileView ? 37 : 45,
|
||||
child: ButtonTheme(
|
||||
minWidth: double.minPositive,
|
||||
child: Semantics(
|
||||
label: !isMobileView ? S.of(context).close : S.of(context).seed_alert_back,
|
||||
child: TextButton(
|
||||
style: ButtonStyle(
|
||||
overlayColor: MaterialStateColor.resolveWith((states) => Colors.transparent),
|
||||
),
|
||||
onPressed: () => onClose(context),
|
||||
child: !isMobileView ? _closeButton : _backButton,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
@override
|
||||
void onClose(BuildContext context) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget trailing(context) => TrailButton(
|
||||
caption: S.of(context).clear,
|
||||
onPressed: () {
|
||||
_formKey.currentState?.reset();
|
||||
});
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
_setEffects(context);
|
||||
|
||||
return WillPopScope(
|
||||
onWillPop: () => _onNavigateBack(context),
|
||||
child: KeyboardActions(
|
||||
disableScroll: true,
|
||||
config: KeyboardActionsConfig(
|
||||
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
|
||||
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
|
||||
nextFocus: false,
|
||||
actions: [
|
||||
KeyboardActionsItem(
|
||||
focusNode: FocusNode(),
|
||||
toolbarButtons: [(_) => KeyboardDoneButton()],
|
||||
),
|
||||
]),
|
||||
child: Container(
|
||||
color: Theme.of(context).colorScheme.background,
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
decoration: responsiveLayoutUtil.shouldRenderMobileUI
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(
|
||||
colors: [
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.firstGradientTopPanelColor,
|
||||
Theme.of(context)
|
||||
.extension<ExchangePageTheme>()!
|
||||
.secondGradientTopPanelColor,
|
||||
],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||
child: Column(
|
||||
children: [
|
||||
AddressTextField(
|
||||
focusNode: bolt11FocusNode,
|
||||
controller: bolt11Controller,
|
||||
onURIScanned: (uri) {
|
||||
final paymentRequest = PaymentRequest.fromUri(uri);
|
||||
bolt11Controller.text = paymentRequest.address;
|
||||
},
|
||||
options: [
|
||||
AddressTextFieldOption.paste,
|
||||
AddressTextFieldOption.qrCode,
|
||||
AddressTextFieldOption.addressBook
|
||||
],
|
||||
buttonColor:
|
||||
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
||||
borderColor:
|
||||
Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
|
||||
textStyle:
|
||||
TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white),
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldHintColor),
|
||||
onPushPasteButton: (context) async {
|
||||
output.resetParsedAddress();
|
||||
await output.fetchParsedAddress(context);
|
||||
await send(context);
|
||||
},
|
||||
onPushAddressBookButton: (context) async {
|
||||
output.resetParsedAddress();
|
||||
},
|
||||
onSelectedContact: (contact) {
|
||||
output.loadContact(contact);
|
||||
},
|
||||
selectedCurrency: CryptoCurrency.btc,
|
||||
),
|
||||
SizedBox(height: 24),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
|
||||
bottomSection: Column(
|
||||
children: <Widget>[
|
||||
PrimaryButton(
|
||||
text: S.of(context).send,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
onPressed: () => send(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> send(BuildContext context) async {
|
||||
try {
|
||||
await lightningSendViewModel.processInput(context, bolt11Controller.text);
|
||||
} catch (e) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: e.toString(),
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> _onNavigateBack(BuildContext context) async {
|
||||
onClose(context);
|
||||
return false;
|
||||
}
|
||||
|
||||
void _setEffects(BuildContext context) {
|
||||
if (_effectsInstalled) {
|
||||
return;
|
||||
}
|
||||
|
||||
_effectsInstalled = true;
|
||||
}
|
||||
}
|
|
@ -90,14 +90,22 @@ class ConnectionSyncPage extends BasePage {
|
|||
}),
|
||||
],
|
||||
],
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.manage_nodes,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
|
||||
Observer(
|
||||
builder: (context) {
|
||||
if (!dashboardViewModel.hasNodes) return const SizedBox();
|
||||
return Column(
|
||||
children: [
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.manage_nodes,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
Observer(
|
||||
builder: (context) {
|
||||
if (!dashboardViewModel.hasPowNodes) return const SizedBox();
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
SettingsCellWithArrow(
|
||||
|
|
|
@ -96,6 +96,7 @@ class WalletListBody extends StatefulWidget {
|
|||
class WalletListBodyState extends State<WalletListBody> {
|
||||
final moneroIcon = Image.asset('assets/images/monero_logo.png', height: 24, width: 24);
|
||||
final bitcoinIcon = Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final lightningIcon = Image.asset('assets/images/lightning_logo.png', height: 24, width: 24);
|
||||
final tBitcoinIcon = Image.asset('assets/images/tbtc.png', height: 24, width: 24);
|
||||
final litecoinIcon = Image.asset('assets/images/litecoin_icon.png', height: 24, width: 24);
|
||||
final nonWalletTypeIcon = Image.asset('assets/images/close.png', height: 24, width: 24);
|
||||
|
@ -309,6 +310,8 @@ class WalletListBodyState extends State<WalletListBody> {
|
|||
return tBitcoinIcon;
|
||||
}
|
||||
return bitcoinIcon;
|
||||
case WalletType.lightning:
|
||||
return lightningIcon;
|
||||
case WalletType.monero:
|
||||
return moneroIcon;
|
||||
case WalletType.litecoin:
|
||||
|
|
|
@ -10,6 +10,7 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
|||
required this.rightButtonText,
|
||||
required this.actionLeftButton,
|
||||
required this.actionRightButton,
|
||||
this.contentWidget,
|
||||
this.alertBarrierDismissible = true,
|
||||
this.isDividerExist = false,
|
||||
// this.leftActionColor,
|
||||
|
@ -20,6 +21,7 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
|||
final String alertContent;
|
||||
final String leftButtonText;
|
||||
final String rightButtonText;
|
||||
final Widget? contentWidget;
|
||||
final VoidCallback actionLeftButton;
|
||||
final VoidCallback actionRightButton;
|
||||
final bool alertBarrierDismissible;
|
||||
|
@ -47,4 +49,9 @@ class AlertWithTwoActions extends BaseAlertDialog {
|
|||
// Color get rightButtonColor => rightActionColor;
|
||||
@override
|
||||
bool get isDividerExists => isDividerExist;
|
||||
|
||||
@override
|
||||
Widget content(BuildContext context) {
|
||||
return contentWidget ?? super.content(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import 'package:cake_wallet/di.dart';
|
|||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -37,7 +38,8 @@ abstract class AppStoreBase with Store {
|
|||
@action
|
||||
Future<void> changeCurrentWallet(
|
||||
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet) async {
|
||||
this.wallet?.close();
|
||||
bool switchingToSameWalletType = this.wallet?.type == wallet.type;
|
||||
this.wallet?.close(switchingToSameWalletType: switchingToSameWalletType);
|
||||
this.wallet = wallet;
|
||||
this.wallet!.setExceptionHandler(ExceptionHandler.onError);
|
||||
|
||||
|
|
|
@ -956,6 +956,7 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
if (bitcoinElectrumServer != null) {
|
||||
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
||||
nodes[WalletType.lightning] = bitcoinElectrumServer;
|
||||
}
|
||||
|
||||
if (litecoinElectrumServer != null) {
|
||||
|
@ -1320,6 +1321,7 @@ abstract class SettingsStoreBase with Store {
|
|||
|
||||
if (bitcoinElectrumServer != null) {
|
||||
nodes[WalletType.bitcoin] = bitcoinElectrumServer;
|
||||
nodes[WalletType.lightning] = bitcoinElectrumServer;
|
||||
}
|
||||
|
||||
if (litecoinElectrumServer != null) {
|
||||
|
|
|
@ -48,6 +48,7 @@ abstract class AdvancedPrivacySettingsViewModelBase with Store {
|
|||
case WalletType.haven:
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
case WalletType.lightning:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,9 @@ abstract class BalanceViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
double get price {
|
||||
final price = fiatConvertationStore.prices[appStore.wallet!.currency];
|
||||
CryptoCurrency currency = appStore.wallet!.currency;
|
||||
|
||||
final price = fiatConvertationStore.prices[currency];
|
||||
|
||||
if (price == null) {
|
||||
// price should update on next fetch:
|
||||
|
@ -153,6 +155,8 @@ abstract class BalanceViewModelBase with Store {
|
|||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return S.current.receivable_balance;
|
||||
case WalletType.lightning:
|
||||
return S.current.max_receivable;
|
||||
default:
|
||||
return S.current.unconfirmed;
|
||||
}
|
||||
|
@ -249,6 +253,7 @@ abstract class BalanceViewModelBase with Store {
|
|||
asset: key,
|
||||
formattedAssetTitle: _formatterAsset(key)));
|
||||
}
|
||||
|
||||
final fiatCurrency = settingsStore.fiatCurrency;
|
||||
final price = fiatConvertationStore.prices[key] ?? 0;
|
||||
|
||||
|
@ -262,7 +267,7 @@ abstract class BalanceViewModelBase with Store {
|
|||
' ' +
|
||||
_getFiatBalance(price: price, cryptoAmount: value.formattedAdditionalBalance));
|
||||
|
||||
final availableFiatBalance = isFiatDisabled
|
||||
var availableFiatBalance = isFiatDisabled
|
||||
? ''
|
||||
: (fiatCurrency.toString() +
|
||||
' ' +
|
||||
|
@ -397,6 +402,7 @@ abstract class BalanceViewModelBase with Store {
|
|||
}
|
||||
|
||||
String _getFiatBalance({required double price, String? cryptoAmount}) {
|
||||
cryptoAmount = cryptoAmount?.replaceAll(',', '');// fix for amounts > 1000
|
||||
if (cryptoAmount == null || cryptoAmount.isEmpty || double.tryParse(cryptoAmount) == null) {
|
||||
return '0.00';
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:breez_sdk/bridge_generated.dart';
|
||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||
|
@ -29,6 +30,7 @@ import 'package:cake_wallet/view_model/dashboard/formatted_item_list.dart';
|
|||
import 'package:cake_wallet/view_model/dashboard/order_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
|
@ -54,19 +56,20 @@ part 'dashboard_view_model.g.dart';
|
|||
class DashboardViewModel = DashboardViewModelBase with _$DashboardViewModel;
|
||||
|
||||
abstract class DashboardViewModelBase with Store {
|
||||
DashboardViewModelBase(
|
||||
{required this.balanceViewModel,
|
||||
required this.appStore,
|
||||
required this.tradesStore,
|
||||
required this.tradeFilterStore,
|
||||
required this.transactionFilterStore,
|
||||
required this.settingsStore,
|
||||
required this.yatStore,
|
||||
required this.ordersStore,
|
||||
required this.anonpayTransactionsStore,
|
||||
required this.sharedPreferences,
|
||||
required this.keyService})
|
||||
: hasSellAction = false,
|
||||
DashboardViewModelBase({
|
||||
required this.balanceViewModel,
|
||||
required this.appStore,
|
||||
required this.tradesStore,
|
||||
required this.tradeFilterStore,
|
||||
required this.transactionFilterStore,
|
||||
required this.settingsStore,
|
||||
required this.yatStore,
|
||||
required this.ordersStore,
|
||||
required this.anonpayTransactionsStore,
|
||||
required this.sharedPreferences,
|
||||
required this.keyService,
|
||||
required this.lightningViewModel,
|
||||
}) : hasSellAction = false,
|
||||
hasBuyAction = false,
|
||||
hasExchangeAction = false,
|
||||
isShowFirstYatIntroduction = false,
|
||||
|
@ -345,6 +348,8 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
TransactionFilterStore transactionFilterStore;
|
||||
|
||||
LightningViewModel lightningViewModel;
|
||||
|
||||
Map<String, List<FilterItem>> filterItems;
|
||||
|
||||
BuyProvider? get defaultBuyProvider => ProvidersHelper.getProviderByType(
|
||||
|
@ -383,7 +388,12 @@ abstract class DashboardViewModelBase with Store {
|
|||
void furtherShowYatPopup(bool shouldShow) => settingsStore.shouldShowYatPopup = shouldShow;
|
||||
|
||||
@computed
|
||||
bool get isEnabledExchangeAction => settingsStore.exchangeStatus != ExchangeApiMode.disabled;
|
||||
bool get isEnabledExchangeAction {
|
||||
if (wallet.type == WalletType.lightning) {
|
||||
return false;
|
||||
}
|
||||
return settingsStore.exchangeStatus != ExchangeApiMode.disabled;
|
||||
}
|
||||
|
||||
@observable
|
||||
bool hasExchangeAction;
|
||||
|
@ -407,9 +417,26 @@ abstract class DashboardViewModelBase with Store {
|
|||
|
||||
ReactionDisposer? _onMoneroBalanceChangeReaction;
|
||||
|
||||
@computed
|
||||
bool get hasNodes => wallet.type != WalletType.lightning;
|
||||
|
||||
@computed
|
||||
bool get hasPowNodes => wallet.type == WalletType.nano || wallet.type == WalletType.banano;
|
||||
|
||||
String get serviceMessage {
|
||||
if (wallet.type == WalletType.lightning) {
|
||||
final serviceStatus = lightningViewModel.serviceHealthCheck();
|
||||
if (serviceStatus == HealthCheckStatus.ServiceDisruption) {
|
||||
return S.current.breez_warning_disruption;
|
||||
} else if (serviceStatus == HealthCheckStatus.Maintenance) {
|
||||
return S.current.breez_warning_maintenance;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool get showRepWarning {
|
||||
if (wallet.type != WalletType.nano) {
|
||||
return false;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -16,14 +17,28 @@ abstract class ReceiveOptionViewModelBase with Store {
|
|||
: ReceivePageOption.mainnet),
|
||||
_options = [] {
|
||||
final walletType = _wallet.type;
|
||||
_options = walletType == WalletType.haven
|
||||
? [ReceivePageOption.mainnet]
|
||||
: walletType == WalletType.bitcoin
|
||||
? [
|
||||
...bitcoin!.getBitcoinReceivePageOptions(),
|
||||
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
|
||||
]
|
||||
: ReceivePageOptions;
|
||||
|
||||
switch (walletType) {
|
||||
case WalletType.haven:
|
||||
_options = [ReceivePageOption.mainnet];
|
||||
break;
|
||||
case WalletType.lightning:
|
||||
_options = [...lightning!.getLightningReceivePageOptions()];
|
||||
break;
|
||||
case WalletType.bitcoin:
|
||||
_options = [
|
||||
...bitcoin!.getBitcoinReceivePageOptions(),
|
||||
...ReceivePageOptions.where((element) => element != ReceivePageOption.mainnet)
|
||||
];
|
||||
break;
|
||||
default:
|
||||
_options = [
|
||||
ReceivePageOption.mainnet,
|
||||
ReceivePageOption.anonPayDonationLink,
|
||||
ReceivePageOption.anonPayInvoice
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final WalletBase _wallet;
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/entities/balance_display_mode.dart';
|
|||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
import 'package:cake_wallet/polygon/polygon.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
|
@ -122,6 +123,11 @@ class TransactionListItem extends ActionListItem with Keyable {
|
|||
cryptoAmount: bitcoin!.formatterBitcoinAmountToDouble(amount: transaction.amount),
|
||||
price: price);
|
||||
break;
|
||||
case WalletType.lightning:
|
||||
amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: lightning!.formatterLightningAmountToDouble(amount: transaction.amount),
|
||||
price: price);
|
||||
break;
|
||||
case WalletType.haven:
|
||||
final asset = haven!.assetOfTransaction(transaction);
|
||||
final price = balanceViewModel.fiatConvertationStore.prices[asset];
|
||||
|
|
|
@ -174,6 +174,11 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
}
|
||||
|
||||
static bool _checkIfCanSend(TradesStore tradesStore, WalletBase wallet) {
|
||||
|
||||
if (wallet.currency == CryptoCurrency.btcln) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool _isEthToken() =>
|
||||
wallet.currency == CryptoCurrency.eth &&
|
||||
tradesStore.trade!.from.tag == CryptoCurrency.eth.title;
|
||||
|
|
|
@ -278,12 +278,16 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
|
||||
bool get hasAllAmount =>
|
||||
(wallet.type == WalletType.bitcoin ||
|
||||
wallet.type == WalletType.lightning ||
|
||||
wallet.type == WalletType.litecoin ||
|
||||
wallet.type == WalletType.bitcoinCash) &&
|
||||
depositCurrency == wallet.currency;
|
||||
|
||||
bool get isMoneroWallet => wallet.type == WalletType.monero;
|
||||
|
||||
// lightning doesn't have the same concept of "addresses" (since it uses invoices)
|
||||
bool get hasAddress => wallet.type != WalletType.lightning;
|
||||
|
||||
bool get isLowFee {
|
||||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
|
@ -539,6 +543,7 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
/// return after the first successful trade
|
||||
return;
|
||||
} catch (e) {
|
||||
print(e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -651,6 +656,10 @@ abstract class ExchangeViewModelBase extends WalletChangeListenerViewModel with
|
|||
depositCurrency = CryptoCurrency.btc;
|
||||
receiveCurrency = CryptoCurrency.xmr;
|
||||
break;
|
||||
case WalletType.lightning:
|
||||
depositCurrency = CryptoCurrency.btcln;
|
||||
receiveCurrency = CryptoCurrency.xmr;
|
||||
break;
|
||||
case WalletType.litecoin:
|
||||
depositCurrency = CryptoCurrency.ltc;
|
||||
receiveCurrency = CryptoCurrency.xmr;
|
||||
|
|
130
lib/view_model/lightning_invoice_page_view_model.dart
Normal file
130
lib/view_model/lightning_invoice_page_view_model.dart
Normal file
|
@ -0,0 +1,130 @@
|
|||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/view_model/lightning_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/currency.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
part 'lightning_invoice_page_view_model.g.dart';
|
||||
|
||||
class LightningInvoicePageViewModel = LightningInvoicePageViewModelBase
|
||||
with _$LightningInvoicePageViewModel;
|
||||
|
||||
abstract class LightningInvoicePageViewModelBase with Store {
|
||||
LightningInvoicePageViewModelBase(
|
||||
this.settingsStore,
|
||||
this._wallet,
|
||||
this.sharedPreferences,
|
||||
this.lightningViewModel,
|
||||
) : description = '',
|
||||
amount = '',
|
||||
state = InitialExecutionState(),
|
||||
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type),
|
||||
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type) {
|
||||
_fetchLimits();
|
||||
}
|
||||
|
||||
List<Currency> get currencies => [walletTypeToCryptoCurrency(_wallet.type), ...FiatCurrency.all];
|
||||
final SettingsStore settingsStore;
|
||||
final WalletBase _wallet;
|
||||
final SharedPreferences sharedPreferences;
|
||||
final LightningViewModel lightningViewModel;
|
||||
|
||||
@observable
|
||||
Currency selectedCurrency;
|
||||
|
||||
CryptoCurrency cryptoCurrency;
|
||||
|
||||
@observable
|
||||
String description;
|
||||
|
||||
@observable
|
||||
String amount;
|
||||
|
||||
@observable
|
||||
ExecutionState state;
|
||||
|
||||
@computed
|
||||
int get selectedCurrencyIndex => currencies.indexOf(selectedCurrency);
|
||||
|
||||
@observable
|
||||
double? minimum;
|
||||
|
||||
@observable
|
||||
double? maximum;
|
||||
|
||||
@action
|
||||
void selectCurrency(Currency currency) {
|
||||
selectedCurrency = currency;
|
||||
maximum = minimum = null;
|
||||
if (currency is CryptoCurrency) {
|
||||
cryptoCurrency = currency;
|
||||
} else {
|
||||
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||
}
|
||||
|
||||
_fetchLimits();
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> createInvoice() async {
|
||||
state = IsExecutingState();
|
||||
if (amount.isNotEmpty) {
|
||||
final amountInCrypto = double.tryParse(amount);
|
||||
if (amountInCrypto == null) {
|
||||
state = FailureState('Amount is invalid');
|
||||
return;
|
||||
}
|
||||
if (minimum != null && amountInCrypto < minimum!) {
|
||||
state = FailureState('Amount is too small');
|
||||
return;
|
||||
}
|
||||
if (amountInCrypto > 4000000) {
|
||||
state = FailureState('Amount is too big');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String bolt11 = await lightningViewModel.createInvoice(
|
||||
amountSats: amount,
|
||||
description: description,
|
||||
);
|
||||
state = ExecutedSuccessfullyState(payload: bolt11);
|
||||
} catch (e) {
|
||||
state = FailureState(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
void setRequestParams({
|
||||
required String inputAmount,
|
||||
required String inputDescription,
|
||||
}) {
|
||||
description = inputDescription;
|
||||
amount = inputAmount;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> _fetchLimits() async {
|
||||
final limits = await lightningViewModel.invoiceSoftLimitsSats();
|
||||
minimum = limits.minFee.toDouble();
|
||||
maximum = limits.inboundLiquidity.toDouble();
|
||||
}
|
||||
|
||||
@action
|
||||
void reset() {
|
||||
selectedCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||
cryptoCurrency = walletTypeToCryptoCurrency(_wallet.type);
|
||||
description = '';
|
||||
amount = '';
|
||||
try {
|
||||
_fetchLimits();
|
||||
} catch (_) {}
|
||||
}
|
||||
}
|
93
lib/view_model/lightning_send_view_model.dart
Normal file
93
lib/view_model/lightning_send_view_model.dart
Normal file
|
@ -0,0 +1,93 @@
|
|||
import 'dart:async';
|
||||
import 'package:breez_sdk/breez_sdk.dart';
|
||||
import 'package:breez_sdk/bridge_generated.dart' as BZG;
|
||||
import 'package:cake_wallet/entities/calculate_fiat_amount_raw.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'lightning_send_view_model.g.dart';
|
||||
|
||||
class LightningSendViewModel = LightningSendViewModelBase with _$LightningSendViewModel;
|
||||
|
||||
abstract class LightningSendViewModelBase with Store {
|
||||
LightningSendViewModelBase({
|
||||
required this.settingsStore,
|
||||
required this.fiatConversionStore,
|
||||
}) {}
|
||||
|
||||
final SettingsStore settingsStore;
|
||||
final FiatConversionStore fiatConversionStore;
|
||||
|
||||
@observable
|
||||
bool loading = false;
|
||||
|
||||
@action
|
||||
void setLoading(bool value) {
|
||||
loading = value;
|
||||
}
|
||||
|
||||
FiatCurrency get fiat => settingsStore.fiatCurrency;
|
||||
|
||||
String formattedFiatAmount(int sats) {
|
||||
String amount = calculateFiatAmountRaw(
|
||||
cryptoAmount: lightning!.formatterLightningAmountToDouble(amount: sats),
|
||||
price: fiatConversionStore.prices[CryptoCurrency.btcln],
|
||||
);
|
||||
return amount;
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> send(BZG.LNInvoice invoice, int satAmount) async {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
final sdk = await BreezSDK();
|
||||
late BZG.SendPaymentRequest req;
|
||||
|
||||
if (invoice.amountMsat == null) {
|
||||
req = BZG.SendPaymentRequest(
|
||||
bolt11: invoice.bolt11,
|
||||
amountMsat: satAmount * 1000,
|
||||
);
|
||||
} else {
|
||||
req = BZG.SendPaymentRequest(bolt11: invoice.bolt11);
|
||||
}
|
||||
|
||||
await sdk.sendPayment(req: req);
|
||||
|
||||
setLoading(false);
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> processInput(BuildContext context, String input) async {
|
||||
FocusScope.of(context).unfocus();
|
||||
|
||||
final sdk = await BreezSDK();
|
||||
|
||||
late BZG.InputType inputType;
|
||||
|
||||
try {
|
||||
inputType = await sdk.parseInput(input: input);
|
||||
} catch (_) {
|
||||
throw Exception("Unknown input type");
|
||||
}
|
||||
|
||||
if (inputType is BZG.InputType_Bolt11) {
|
||||
final bolt11 = await sdk.parseInvoice(input);
|
||||
Navigator.of(context).pushNamed(Routes.lightningSendConfirm, arguments: bolt11);
|
||||
} else if (inputType is BZG.InputType_LnUrlPay) {
|
||||
throw Exception("Unsupported input type");
|
||||
} else {
|
||||
throw Exception("Unknown input type");
|
||||
}
|
||||
}
|
||||
}
|
130
lib/view_model/lightning_view_model.dart
Normal file
130
lib/view_model/lightning_view_model.dart
Normal file
|
@ -0,0 +1,130 @@
|
|||
import 'dart:async';
|
||||
import 'package:breez_sdk/breez_sdk.dart';
|
||||
import 'package:breez_sdk/bridge_generated.dart' as BZG;
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_lightning/.secrets.g.dart' as secrets;
|
||||
|
||||
part 'lightning_view_model.g.dart';
|
||||
|
||||
class LightningViewModel = LightningViewModelBase with _$LightningViewModel;
|
||||
|
||||
abstract class LightningViewModelBase with Store {
|
||||
LightningViewModelBase() {}
|
||||
|
||||
Future<ReceiveOnchainResult> receiveOnchain() async {
|
||||
final sdk = await BreezSDK();
|
||||
|
||||
BZG.ReceiveOnchainRequest req = const BZG.ReceiveOnchainRequest();
|
||||
BZG.SwapInfo swapInfo = await sdk.receiveOnchain(req: req);
|
||||
print("Minimum amount allowed to deposit in sats: ${swapInfo.minAllowedDeposit}");
|
||||
print("Maximum amount allowed to deposit in sats: ${swapInfo.maxAllowedDeposit}");
|
||||
|
||||
int fee = 0;
|
||||
double feePercent = 0;
|
||||
|
||||
try {
|
||||
final nodeState = (await sdk.nodeInfo())!;
|
||||
int inboundLiquidity = nodeState.inboundLiquidityMsats ~/ 1000;
|
||||
final openingFees = await sdk.openChannelFee(
|
||||
req: BZG.OpenChannelFeeRequest(amountMsat: inboundLiquidity + 1));
|
||||
feePercent = (openingFees.feeParams.proportional * 100) / 1000000;
|
||||
fee = openingFees.feeParams.minMsat ~/ 1000;
|
||||
} catch (_) {}
|
||||
|
||||
return ReceiveOnchainResult(
|
||||
bitcoinAddress: swapInfo.bitcoinAddress,
|
||||
minAllowedDeposit: swapInfo.minAllowedDeposit,
|
||||
maxAllowedDeposit: swapInfo.maxAllowedDeposit,
|
||||
feePercent: feePercent,
|
||||
fee: fee,
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> createInvoice({required String amountSats, String? description}) async {
|
||||
final sdk = await BreezSDK();
|
||||
final req = BZG.ReceivePaymentRequest(
|
||||
amountMsat: (double.parse(amountSats) * 1000).round(),
|
||||
description: description ?? '',
|
||||
);
|
||||
final res = await sdk.receivePayment(req: req);
|
||||
return res.lnInvoice.bolt11;
|
||||
}
|
||||
|
||||
Future<InvoiceSoftLimitsResult> invoiceSoftLimitsSats() async {
|
||||
double feePercent = 0.4;
|
||||
int minFee = (2500 * 1000) ~/ 1000; // 2500 sats
|
||||
int inboundLiquidity = 1000000000 * 1000 * 10; // 10 BTC
|
||||
int balance = 0;
|
||||
|
||||
final sdk = await BreezSDK();
|
||||
|
||||
try {
|
||||
final nodeState = (await sdk.nodeInfo())!;
|
||||
inboundLiquidity = nodeState.inboundLiquidityMsats ~/ 1000;
|
||||
|
||||
final openingFees = await sdk.openChannelFee(
|
||||
req: BZG.OpenChannelFeeRequest(amountMsat: inboundLiquidity + 1));
|
||||
|
||||
feePercent = (openingFees.feeParams.proportional * 100) / 1000000;
|
||||
minFee = openingFees.feeParams.minMsat ~/ 1000;
|
||||
balance = nodeState.channelsBalanceMsat ~/ 1000;
|
||||
} catch (_) {}
|
||||
return InvoiceSoftLimitsResult(
|
||||
minFee: minFee,
|
||||
inboundLiquidity: inboundLiquidity,
|
||||
feePercent: feePercent,
|
||||
balance: balance,
|
||||
);
|
||||
}
|
||||
|
||||
Future<int> getBalanceSats() async {
|
||||
try {
|
||||
final sdk = await BreezSDK();
|
||||
final nodeState = (await sdk.nodeInfo())!;
|
||||
return nodeState.channelsBalanceMsat ~/ 1000;
|
||||
} catch (_) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Future<BZG.HealthCheckStatus> serviceHealthCheck() async {
|
||||
try {
|
||||
final sdk = await BreezSDK();
|
||||
BZG.ServiceHealthCheckResponse response =
|
||||
await sdk.serviceHealthCheck(apiKey: secrets.breezApiKey);
|
||||
return response.status;
|
||||
} catch (_) {
|
||||
return BZG.HealthCheckStatus.ServiceDisruption;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReceiveOnchainResult {
|
||||
final String bitcoinAddress;
|
||||
final int minAllowedDeposit;
|
||||
final int maxAllowedDeposit;
|
||||
final int fee;
|
||||
final double feePercent;
|
||||
|
||||
ReceiveOnchainResult({
|
||||
required this.bitcoinAddress,
|
||||
required this.minAllowedDeposit,
|
||||
required this.maxAllowedDeposit,
|
||||
required this.fee,
|
||||
required this.feePercent,
|
||||
});
|
||||
}
|
||||
|
||||
class InvoiceSoftLimitsResult {
|
||||
final double feePercent;
|
||||
final int minFee;
|
||||
final int inboundLiquidity;
|
||||
final int balance;
|
||||
|
||||
InvoiceSoftLimitsResult({
|
||||
required this.inboundLiquidity,
|
||||
required this.feePercent,
|
||||
required this.minFee,
|
||||
required this.balance,
|
||||
});
|
||||
}
|
|
@ -85,6 +85,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
|
|||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.lightning:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,9 @@ abstract class NodeListViewModelBase with Store {
|
|||
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
|
||||
}
|
||||
break;
|
||||
case WalletType.lightning:
|
||||
node = getBitcoinDefaultElectrumServer(nodes: _nodeSource)!;
|
||||
break;
|
||||
case WalletType.monero:
|
||||
node = getMoneroDefaultNode(nodes: _nodeSource);
|
||||
break;
|
||||
|
|
|
@ -85,6 +85,7 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
|||
spendKey: restoreWallet.spendKey ?? '',
|
||||
height: restoreWallet.height ?? 0);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.lightning:
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
||||
name: name, password: password, wif: wif);
|
||||
|
|
|
@ -22,6 +22,9 @@ class WalletRestoreFromQRCode {
|
|||
'bitcoin': WalletType.bitcoin,
|
||||
'bitcoin-wallet': WalletType.bitcoin,
|
||||
'bitcoin_wallet': WalletType.bitcoin,
|
||||
'lightning': WalletType.lightning,
|
||||
'lightning-wallet': WalletType.lightning,
|
||||
'lightning_wallet': WalletType.lightning,
|
||||
'litecoin': WalletType.litecoin,
|
||||
'litecoin-wallet': WalletType.litecoin,
|
||||
'litecoin_wallet': WalletType.litecoin,
|
||||
|
|
|
@ -58,6 +58,9 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
case WalletType.bitcoinCash:
|
||||
_addElectrumListItems(tx, dateFormat);
|
||||
break;
|
||||
case WalletType.lightning:
|
||||
_addLightningListItems(tx, dateFormat);
|
||||
break;
|
||||
case WalletType.haven:
|
||||
_addHavenListItems(tx, dateFormat);
|
||||
break;
|
||||
|
@ -100,14 +103,16 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
|
||||
final type = wallet.type;
|
||||
|
||||
items.add(BlockExplorerListItem(
|
||||
title: S.current.view_in_block_explorer,
|
||||
value: _explorerDescription(type),
|
||||
onTap: () {
|
||||
try {
|
||||
launch(_explorerUrl(type, tx.id));
|
||||
} catch (e) {}
|
||||
}));
|
||||
if (_explorerDescription(type) != '') {
|
||||
items.add(BlockExplorerListItem(
|
||||
title: S.current.view_in_block_explorer,
|
||||
value: _explorerDescription(type),
|
||||
onTap: () {
|
||||
try {
|
||||
launch(_explorerUrl(type, tx.id));
|
||||
} catch (e) {}
|
||||
}));
|
||||
}
|
||||
|
||||
final description = transactionDescriptionBox.values.firstWhere(
|
||||
(val) => val.id == transactionInfo.id,
|
||||
|
@ -262,6 +267,19 @@ abstract class TransactionDetailsViewModelBase with Store {
|
|||
items.addAll(_items);
|
||||
}
|
||||
|
||||
void _addLightningListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||
final _items = [
|
||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date, value: dateFormat.format(tx.date)),
|
||||
StandartListItem(title: S.current.transaction_details_amount, value: tx.amountFormatted()),
|
||||
if (tx.feeFormatted()?.isNotEmpty ?? false)
|
||||
StandartListItem(title: S.current.transaction_details_fee, value: tx.feeFormatted()!),
|
||||
];
|
||||
|
||||
items.addAll(_items);
|
||||
}
|
||||
|
||||
void _addHavenListItems(TransactionInfo tx, DateFormat dateFormat) {
|
||||
items.addAll([
|
||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
|
|
|
@ -83,6 +83,16 @@ class BitcoinURI extends PaymentURI {
|
|||
}
|
||||
}
|
||||
|
||||
class LightningURI extends PaymentURI {
|
||||
LightningURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
throw Exception('N/A for lightning wallets (need to make a bolt11 invoice).');
|
||||
}
|
||||
}
|
||||
|
||||
class LitecoinURI extends PaymentURI {
|
||||
LitecoinURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
|
@ -282,6 +292,10 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
|
|||
return BitcoinURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.lightning) {
|
||||
return LightningURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.litecoin) {
|
||||
return LitecoinURI(amount: amount, address: address.address);
|
||||
}
|
||||
|
|
|
@ -104,6 +104,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
derivationType: DerivationType.nano,
|
||||
);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.lightning:
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.getElectrumDerivations()[DerivationType.electrum]!.first;
|
||||
default:
|
||||
|
@ -118,6 +119,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
derivationType: DerivationType.nano,
|
||||
);
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.lightning:
|
||||
return DerivationInfo(
|
||||
derivationType: DerivationType.bip39,
|
||||
derivationPath: "m/84'/0'/0'/0",
|
||||
|
|
|
@ -21,6 +21,7 @@ class WalletKeysViewModel = WalletKeysViewModelBase with _$WalletKeysViewModel;
|
|||
abstract class WalletKeysViewModelBase with Store {
|
||||
WalletKeysViewModelBase(this._appStore)
|
||||
: title = _appStore.wallet!.type == WalletType.bitcoin ||
|
||||
_appStore.wallet!.type == WalletType.lightning ||
|
||||
_appStore.wallet!.type == WalletType.litecoin ||
|
||||
_appStore.wallet!.type == WalletType.bitcoinCash
|
||||
? S.current.wallet_seed
|
||||
|
@ -163,6 +164,7 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
}
|
||||
|
||||
if (_appStore.wallet!.type == WalletType.bitcoin ||
|
||||
_appStore.wallet!.type == WalletType.lightning ||
|
||||
_appStore.wallet!.type == WalletType.litecoin ||
|
||||
_appStore.wallet!.type == WalletType.bitcoinCash) {
|
||||
// final keys = bitcoin!.getWalletKeys(_appStore.wallet!);
|
||||
|
@ -247,6 +249,8 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
return 'banano-wallet';
|
||||
case WalletType.polygon:
|
||||
return 'polygon-wallet';
|
||||
case WalletType.lightning:
|
||||
return 'lightning-wallet';
|
||||
case WalletType.solana:
|
||||
return 'solana-wallet';
|
||||
case WalletType.tron:
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
|
||||
import 'package:cake_wallet/lightning/lightning.dart';
|
||||
import 'package:cake_wallet/solana/solana.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/wownero/wownero.dart';
|
||||
|
@ -69,6 +70,8 @@ abstract class WalletNewVMBase extends WalletCreationVM with Store {
|
|||
name: name, language: options!.first as String, isPolyseed: options.last as bool);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
||||
case WalletType.lightning:
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinNewWalletCredentials(name: name);
|
||||
case WalletType.haven:
|
||||
|
|
|
@ -108,6 +108,14 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
derivationType: derivationInfo!.derivationType!,
|
||||
derivationPath: derivationInfo.derivationPath!,
|
||||
);
|
||||
case WalletType.lightning:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
mnemonic: seed,
|
||||
password: password,
|
||||
derivationType: derivationInfo!.derivationType!,
|
||||
derivationPath: derivationInfo.derivationPath!,
|
||||
);
|
||||
case WalletType.haven:
|
||||
return haven!.createHavenRestoreWalletFromSeedCredentials(
|
||||
name: name, height: height, mnemonic: seed, password: password);
|
||||
|
|
|
@ -2,6 +2,7 @@ cd cw_core; flutter pub get; flutter packages pub run build_runner build --delet
|
|||
cd cw_evm; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||
cd cw_monero; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||
cd cw_bitcoin; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||
cd cw_lightning && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
|
||||
cd cw_haven; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||
cd cw_nano; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||
cd cw_bitcoin_cash; flutter pub get; flutter packages pub run build_runner build --delete-conflicting-outputs; cd ..
|
||||
|
|
|
@ -12,7 +12,7 @@ dependencies:
|
|||
version: 4.0.2
|
||||
shared_preferences: ^2.0.15
|
||||
# provider: ^6.0.3
|
||||
rxdart: ^0.27.4
|
||||
rxdart: ^0.28.0
|
||||
yaml: ^3.1.1
|
||||
#barcode_scan: any
|
||||
barcode_scan2: ^4.2.1
|
||||
|
@ -107,14 +107,20 @@ dependencies:
|
|||
ref: cake-update-v3
|
||||
ledger_flutter: ^1.0.1
|
||||
|
||||
breez_sdk:
|
||||
git:
|
||||
url: https://github.com/breez/breez-sdk-flutter.git
|
||||
ref: v0.4.3-rc1
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
build_runner: ^2.3.3
|
||||
build_runner: ^2.4.7
|
||||
logging: ^1.2.0
|
||||
mobx_codegen: ^2.1.1
|
||||
build_resolvers: ^2.0.9
|
||||
hive_generator: ^1.1.3
|
||||
hive_generator: ^2.0.1
|
||||
# flutter_launcher_icons: ^0.11.0
|
||||
# check flutter_launcher_icons for usage
|
||||
pedantic: ^1.8.0
|
||||
|
@ -128,6 +134,8 @@ dependency_overrides:
|
|||
bech32:
|
||||
git:
|
||||
url: https://github.com/cake-tech/bech32.git
|
||||
flutter_rust_bridge: ^1.82.6
|
||||
uuid: ^4.1.0
|
||||
ledger_flutter:
|
||||
git:
|
||||
url: https://github.com/cake-tech/ledger-flutter.git
|
||||
|
|
|
@ -81,6 +81,8 @@
|
|||
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.",
|
||||
"block_remaining": "1 كتلة متبقية",
|
||||
"Blocks_remaining": "بلوك متبقي ${status}",
|
||||
"breez_warning_disruption": "خدمة Breez تواجه حاليًا قضايا. الرجاء معاودة المحاولة في وقت لاحق.",
|
||||
"breez_warning_maintenance": "تمر خدمة Breez حاليًا بالصيانة. الرجاء معاودة المحاولة في وقت لاحق.",
|
||||
"bluetooth": "بلوتوث",
|
||||
"bright_theme": "مشرق",
|
||||
"bump_fee": "رسوم عثرة",
|
||||
|
@ -337,6 +339,8 @@
|
|||
"inputs": "المدخلات",
|
||||
"introducing_cake_pay": "نقدم لكم Cake Pay!",
|
||||
"invalid_input": "مدخل غير صالح",
|
||||
"invoice": "فاتورة",
|
||||
"invoice_created": "الفاتورة التي تم إنشاؤها",
|
||||
"invoice_details": "تفاصيل الفاتورة",
|
||||
"is_percentage": "يكون",
|
||||
"last_30_days": "آخر 30 يومًا",
|
||||
|
@ -347,6 +351,10 @@
|
|||
"ledger_error_wrong_app": "يرجى التأكد",
|
||||
"ledger_please_enable_bluetooth": "يرجى تمكين البلوتوث للكشف عن دفتر الأستاذ الخاص بك",
|
||||
"light_theme": "فاتح",
|
||||
"lightning_invoice_min": "<سيتم تطبيق رسوم الإعداد ${feePercent} ٪ مع ما لا يقل عن ${min} SATs عند تلقي هذه الفاتورة",
|
||||
"lightning_invoice_min_max": "سيتم تطبيق رسوم إعداد ${feePercent} ٪ مع ما لا يقل عن ${min} SATs لتلقي أكثر من ${max} SATs",
|
||||
"lightning_invoice_warning": "يجب أن تبقي التطبيق مفتوحًا حتى يتم الانتهاء من الدفع أو تفشل المعاملة",
|
||||
"lightning_receive_limits": "أرسل أكثر من ${min} SATs وحتى ${max} SATs إلى هذا العنوان. سيتم تطبيق رسوم إعداد ${feePercent} ٪ مع ما لا يقل عن ${fee} SATs عند تلقي هذه الفاتورة. سيؤدي ذلك إلى تحويل أي Bitcoin المستلم إلى Lightning. سيتم تطبيق رسوم على السلسلة. لا يمكن استخدام هذا العنوان إلا مرة واحدة.",
|
||||
"load_more": "تحميل المزيد",
|
||||
"loading_your_wallet": "يتم تحميل محفظتك",
|
||||
"login": "تسجيل الدخول",
|
||||
|
@ -360,6 +368,7 @@
|
|||
"market_place": "منصة التجارة",
|
||||
"matrix_green_dark_theme": "موضوع ماتريكس الأخضر الداكن",
|
||||
"max_amount": "الحد الأقصى: ${value}",
|
||||
"max_receivable": "ماكس القبض",
|
||||
"max_value": "الحد الأقصى: ${value} ${currency}",
|
||||
"memo": "مذكرة:",
|
||||
"message": "ﺔﻟﺎﺳﺭ",
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue