mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-27 06:18:50 +01:00
Merge branch 'cake-tech:dev' into dev
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
-
|
||||
uri: api.trongrid.io
|
||||
isDefault: true
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
label: "TronGrid"
|
||||
@@ -10,6 +9,7 @@
|
||||
label: "PublicNode"
|
||||
-
|
||||
uri: trx.nownodes.io
|
||||
isDefault: true
|
||||
useSSL: true
|
||||
isEnabledForAutoSwitching: true
|
||||
label: "NOWNodes"
|
||||
@@ -124,7 +124,7 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
|
||||
|
||||
Future<PaymentURI> getPaymentRequestUri(String amount) async {
|
||||
if (addressPageType is LightningAddressType && lightningWallet != null) {
|
||||
final amountSats = amount.isNotEmpty ? parseFixed(amount, 8) : null;
|
||||
final amountSats = amount.isNotEmpty ? tryParseFixed(amount, 8) : null;
|
||||
final lnUrl = getLnurlOfLightningAddress(address);
|
||||
if (amountSats == null) {
|
||||
return LightningPaymentRequest(address: address, lnURL: lnUrl, amount: amount);
|
||||
|
||||
@@ -1536,7 +1536,7 @@ abstract class ElectrumWalletBase
|
||||
network: network,
|
||||
memo: estimatedTx.memo,
|
||||
inputOrdering: BitcoinOrdering.shuffle,
|
||||
outputOrdering: BitcoinOrdering.none,
|
||||
outputOrdering: BitcoinOrdering.shuffle,
|
||||
enableRBF: !estimatedTx.spendsUnconfirmedTX,
|
||||
);
|
||||
}
|
||||
@@ -1594,6 +1594,7 @@ abstract class ElectrumWalletBase
|
||||
isSendAll: estimatedTx.isSendAll,
|
||||
hasTaprootInputs: hasTaprootInputs,
|
||||
utxos: estimatedTx.utxos,
|
||||
derivedOutputs: updatedOutputs,
|
||||
publicKeys: estimatedTx.publicKeys,
|
||||
isViewOnly: keys.privateKey.isEmpty,
|
||||
)..addListener((transaction) async {
|
||||
@@ -2297,7 +2298,7 @@ abstract class ElectrumWalletBase
|
||||
network: network,
|
||||
memo: memo,
|
||||
inputOrdering: BitcoinOrdering.shuffle,
|
||||
outputOrdering: BitcoinOrdering.none,
|
||||
outputOrdering: BitcoinOrdering.shuffle,
|
||||
enableRBF: true,
|
||||
);
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
this.hasTaprootInputs = false,
|
||||
this.isMweb = false,
|
||||
this.utxos = const [],
|
||||
this.derivedOutputs = const [],
|
||||
this.publicKeys,
|
||||
this.commitOverride,
|
||||
this.unsignedPsbt,
|
||||
@@ -47,6 +48,9 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
final bool hasTaprootInputs;
|
||||
final bool isViewOnly;
|
||||
List<UtxoWithAddress> utxos;
|
||||
|
||||
final List<BitcoinOutput> derivedOutputs;
|
||||
|
||||
bool isMweb;
|
||||
String? changeAddressOverride;
|
||||
String? idOverride;
|
||||
@@ -79,6 +83,13 @@ class PendingBitcoinTransaction with PendingTransaction {
|
||||
|
||||
bool get hasSilentPayment => _tx.hasSilentPayment;
|
||||
|
||||
List<String?> get stealthAddresses => derivedOutputs
|
||||
.where((out) => !out.isChange)
|
||||
.map((out) => out.isSilentPayment
|
||||
? out.address.toAddress(network ?? BitcoinNetwork.mainnet)
|
||||
: null)
|
||||
.toList();
|
||||
|
||||
PendingChange? get change {
|
||||
try {
|
||||
final change = _tx.outputs.firstWhere((out) => out.isChange);
|
||||
|
||||
+119
-181
@@ -1,4 +1,4 @@
|
||||
import 'package:cw_core/format_fixed.dart';
|
||||
import "package:cw_core/format_fixed.dart";
|
||||
|
||||
abstract class PaymentURI {
|
||||
PaymentURI({required this.amount, required this.address});
|
||||
@@ -19,7 +19,7 @@ class MoneroURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'monero:$address';
|
||||
var base = "monero:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?tx_amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -34,7 +34,7 @@ class HavenURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'haven:$address';
|
||||
var base = "haven:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?tx_amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -45,7 +45,7 @@ class HavenURI extends PaymentURI {
|
||||
}
|
||||
|
||||
class BitcoinURI extends PaymentURI {
|
||||
BitcoinURI({required super.amount, required super.address, this.pjUri = ''});
|
||||
BitcoinURI({required super.amount, required super.address, this.pjUri = ""});
|
||||
|
||||
final String pjUri;
|
||||
|
||||
@@ -53,13 +53,16 @@ class BitcoinURI extends PaymentURI {
|
||||
String toString() {
|
||||
final qp = <String, String>{};
|
||||
|
||||
if (amount.isNotEmpty) qp['amount'] = amount.replaceAll(',', '.');
|
||||
if (pjUri.isNotEmpty && !address.startsWith("sp")) {
|
||||
qp['pjos'] = '0';
|
||||
qp['pj'] = pjUri;
|
||||
if (amount.isNotEmpty) {
|
||||
qp["amount"] = amount.replaceAll(",", ".");
|
||||
}
|
||||
|
||||
return Uri(scheme: 'bitcoin', path: address, queryParameters: qp).toString();
|
||||
if (pjUri.isNotEmpty && !address.startsWith("sp")) {
|
||||
qp["pjos"] = "0";
|
||||
qp["pj"] = pjUri;
|
||||
}
|
||||
|
||||
return Uri(scheme: "bitcoin", path: address, queryParameters: qp).toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +71,7 @@ class LitecoinURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'litecoin:$address';
|
||||
var base = "litecoin:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -83,52 +86,7 @@ class EthereumURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'ethereum:$address';
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
class BaseURI extends PaymentURI {
|
||||
BaseURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'base:$address';
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
class ArbitrumURI extends PaymentURI {
|
||||
ArbitrumURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'arbitrum:$address';
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
class BSCURI extends PaymentURI {
|
||||
BSCURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'bsc:$address';
|
||||
var base = "ethereum:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -158,22 +116,7 @@ class NanoURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'nano:$address';
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
class PolygonURI extends PaymentURI {
|
||||
PolygonURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'polygon:$address';
|
||||
|
||||
var base = "nano:$address";
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
}
|
||||
@@ -189,14 +132,14 @@ class SolanaURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'solana:$address';
|
||||
var base = "solana:$address";
|
||||
final params = <String>[];
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
params.add('amount=${amount.replaceAll(',', '.')}');
|
||||
}
|
||||
if (contractAddress != null && contractAddress!.isNotEmpty) {
|
||||
params.add('spl-token=$contractAddress');
|
||||
params.add("spl-token=$contractAddress");
|
||||
}
|
||||
if (params.isNotEmpty) {
|
||||
base += '?${params.join('&')}';
|
||||
@@ -213,14 +156,14 @@ class TronURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'tron:$address';
|
||||
var base = "tron:$address";
|
||||
final params = <String>[];
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
params.add('amount=${amount.replaceAll(',', '.')}');
|
||||
}
|
||||
if (contractAddress != null && contractAddress!.isNotEmpty) {
|
||||
params.add('token=$contractAddress');
|
||||
params.add("token=$contractAddress");
|
||||
}
|
||||
if (params.isNotEmpty) {
|
||||
base += '?${params.join('&')}';
|
||||
@@ -235,7 +178,7 @@ class WowneroURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'wownero:$address';
|
||||
var base = "wownero:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?tx_amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -246,12 +189,11 @@ class WowneroURI extends PaymentURI {
|
||||
}
|
||||
|
||||
class ZanoURI extends PaymentURI {
|
||||
ZanoURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
ZanoURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'zano:' + address;
|
||||
var base = "zano:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -262,12 +204,11 @@ class ZanoURI extends PaymentURI {
|
||||
}
|
||||
|
||||
class DecredURI extends PaymentURI {
|
||||
DecredURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
DecredURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'decred:' + address;
|
||||
var base = "decred:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -278,12 +219,11 @@ class DecredURI extends PaymentURI {
|
||||
}
|
||||
|
||||
class DogeURI extends PaymentURI {
|
||||
DogeURI({required String amount, required String address})
|
||||
: super(amount: amount, address: address);
|
||||
DogeURI({required super.amount, required super.address});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'doge:' + address;
|
||||
var base = "doge:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -298,7 +238,7 @@ class ZcashURI extends PaymentURI {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var base = 'zcash:$address';
|
||||
var base = "zcash:$address";
|
||||
|
||||
if (amount.isNotEmpty) {
|
||||
base += '?amount=${amount.replaceAll(',', '.')}';
|
||||
@@ -309,9 +249,6 @@ class ZcashURI extends PaymentURI {
|
||||
}
|
||||
|
||||
class ERC681URI extends PaymentURI {
|
||||
final int chainId;
|
||||
final String? contractAddress;
|
||||
|
||||
ERC681URI({
|
||||
required this.chainId,
|
||||
required super.address,
|
||||
@@ -319,74 +256,11 @@ class ERC681URI extends PaymentURI {
|
||||
required this.contractAddress,
|
||||
});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var uri = 'ethereum:';
|
||||
|
||||
final targetAddress = contractAddress ?? address;
|
||||
uri += targetAddress;
|
||||
|
||||
if (chainId != 1) {
|
||||
uri += '@$chainId';
|
||||
}
|
||||
|
||||
if (contractAddress != null) {
|
||||
uri += '/transfer';
|
||||
}
|
||||
|
||||
final params = <String, String>{};
|
||||
|
||||
if (contractAddress != null) {
|
||||
params['address'] = address;
|
||||
if (amount.isNotEmpty) {
|
||||
params['uint256'] = _formatAmountForERC20(amount);
|
||||
}
|
||||
} else {
|
||||
if (amount.isNotEmpty) {
|
||||
params['value'] = _formatAmountForNative(amount);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.isNotEmpty) {
|
||||
uri += '?';
|
||||
uri += params.entries.map((e) => '${e.key}=${e.value}').join('&');
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
/// Formats amount for ERC-20 token transfers (in atomic units)
|
||||
String _formatAmountForERC20(String amount) {
|
||||
try {
|
||||
// Convert decimal amount to BigInt (assuming 18 decimals)
|
||||
final amountDouble = double.parse(amount.replaceAll(',', '.'));
|
||||
final amountBigInt = BigInt.from(amountDouble * 1e18);
|
||||
return amountBigInt.toString();
|
||||
} catch (e) {
|
||||
// Fallback to original amount if parsing fails
|
||||
return amount.replaceAll(',', '.');
|
||||
}
|
||||
}
|
||||
|
||||
/// Formats amount for native ETH payments (in wei using scientific notation)
|
||||
String _formatAmountForNative(String amount) {
|
||||
try {
|
||||
// Convert decimal amount to double for scientific notation
|
||||
final amountDouble = double.parse(amount.replaceAll(',', '.'));
|
||||
|
||||
// Use scientific notation as recommended by ERC-681
|
||||
return '${amountDouble}e18';
|
||||
} catch (e) {
|
||||
// Fallback to original amount if parsing fails
|
||||
return amount.replaceAll(',', '.');
|
||||
}
|
||||
}
|
||||
|
||||
factory ERC681URI.fromUri(Uri uri) {
|
||||
final (isContract, targetAddress) = _getTargetAddress(uri.path);
|
||||
final chainId = _getChainID(uri.path);
|
||||
|
||||
final address = isContract ? uri.queryParameters["address"] ?? '' : targetAddress;
|
||||
final address = isContract ? uri.queryParameters["address"] ?? "" : targetAddress;
|
||||
final amountParam = isContract ? uri.queryParameters["uint256"] : uri.queryParameters["value"];
|
||||
|
||||
var formatedAmount = "";
|
||||
@@ -406,16 +280,78 @@ class ERC681URI extends PaymentURI {
|
||||
);
|
||||
}
|
||||
|
||||
static int _getChainID(String path) {
|
||||
return int.parse(RegExp(
|
||||
r'@\d*',
|
||||
).firstMatch(path)?.group(0)?.replaceAll("@", "") ??
|
||||
"1");
|
||||
final int chainId;
|
||||
final String? contractAddress;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var uri = "ethereum:";
|
||||
|
||||
final targetAddress = contractAddress ?? address;
|
||||
uri += targetAddress;
|
||||
|
||||
if (chainId != 1) {
|
||||
uri += "@$chainId";
|
||||
}
|
||||
|
||||
if (contractAddress != null) {
|
||||
uri += "/transfer";
|
||||
}
|
||||
|
||||
final params = <String, String>{};
|
||||
|
||||
if (contractAddress != null) {
|
||||
params["address"] = address;
|
||||
if (amount.isNotEmpty) {
|
||||
params["uint256"] = _formatAmountForERC20(amount);
|
||||
}
|
||||
} else {
|
||||
if (amount.isNotEmpty) {
|
||||
params["value"] = _formatAmountForNative(amount);
|
||||
}
|
||||
}
|
||||
|
||||
if (params.isNotEmpty) {
|
||||
uri += "?${params.entries.map((e) => "${e.key}=${e.value}").join("&")}";
|
||||
}
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
/// Formats amount for ERC-20 token transfers (in atomic units)
|
||||
String _formatAmountForERC20(String amount) {
|
||||
try {
|
||||
// Convert decimal amount to BigInt (assuming 18 decimals)
|
||||
final amountDouble = double.parse(amount.replaceAll(",", "."));
|
||||
final amountBigInt = BigInt.from(amountDouble * 1e18);
|
||||
return amountBigInt.toString();
|
||||
} catch (e) {
|
||||
// Fallback to original amount if parsing fails
|
||||
return amount.replaceAll(",", ".");
|
||||
}
|
||||
}
|
||||
|
||||
/// Formats amount for native ETH payments (in wei using scientific notation)
|
||||
String _formatAmountForNative(String amount) {
|
||||
try {
|
||||
// Convert decimal amount to double for scientific notation
|
||||
final amountDouble = double.parse(amount.replaceAll(",", "."));
|
||||
|
||||
// Use scientific notation as recommended by ERC-681
|
||||
return "${amountDouble}e18";
|
||||
} catch (e) {
|
||||
// Fallback to original amount if parsing fails
|
||||
return amount.replaceAll(",", ".");
|
||||
}
|
||||
}
|
||||
|
||||
static int _getChainID(String path) => int.parse(
|
||||
RegExp(r"@\d*").firstMatch(path)?.group(0)?.replaceAll("@", "") ?? "1",
|
||||
);
|
||||
|
||||
static (bool, String) _getTargetAddress(String path) {
|
||||
final targetAddress =
|
||||
RegExp(r'^(0x)?[0-9a-f]{40}', caseSensitive: false).firstMatch(path)!.group(0)!;
|
||||
RegExp(r"^(0x)?[0-9a-f]{40}", caseSensitive: false).firstMatch(path)!.group(0)!;
|
||||
return (path.contains("/"), targetAddress);
|
||||
}
|
||||
|
||||
@@ -426,25 +362,27 @@ class ERC681URI extends PaymentURI {
|
||||
/// - Scientific notation: "0.123e18", "1e6" → expanded to integer
|
||||
/// - Decimal ETH: "0.123456" → shifted by 18 decimals
|
||||
static String _normalizeToIntegerWei(String input) {
|
||||
final raw = input.replaceAll(',', '.').trim();
|
||||
final raw = input.replaceAll(",", ".").trim();
|
||||
|
||||
// First we check if it's already a plain integer (basically just a number with no dot, no exponent)
|
||||
try {
|
||||
final isPlainInteger = RegExp(r'^[+-]?\d+$').hasMatch(raw) &&
|
||||
!raw.contains('.') &&
|
||||
!raw.toLowerCase().contains('e');
|
||||
if (isPlainInteger) return raw.replaceFirst(RegExp(r'^\+'), '');
|
||||
final isPlainInteger = RegExp(r"^[+-]?\d+$").hasMatch(raw) &&
|
||||
!raw.contains(".") &&
|
||||
!raw.toLowerCase().contains("e");
|
||||
if (isPlainInteger) {
|
||||
return raw.replaceFirst(RegExp(r"^\+"), "");
|
||||
}
|
||||
|
||||
// Then we check if it's a scientific notation
|
||||
final sci = RegExp(r'^[+-]?(\d+\.?\d*|\d*\.?\d+)[eE][+-]?\d+$');
|
||||
final sci = RegExp(r"^[+-]?(\d+\.?\d*|\d*\.?\d+)[eE][+-]?\d+$");
|
||||
if (sci.hasMatch(raw)) {
|
||||
final mantissaStr = raw.toLowerCase().split('e')[0];
|
||||
final exp = int.parse(raw.toLowerCase().split('e')[1]);
|
||||
final mantissaStr = raw.toLowerCase().split("e")[0];
|
||||
final exp = int.parse(raw.toLowerCase().split("e")[1]);
|
||||
return _expandDecimal(mantissaStr, exp);
|
||||
}
|
||||
|
||||
// Lastly, we check if it's a fixed decimal ETH amount, here we shift by 18 to get wei for the amount
|
||||
if (raw.contains('.')) {
|
||||
if (raw.contains(".")) {
|
||||
return _expandDecimal(raw, 18);
|
||||
}
|
||||
return raw;
|
||||
@@ -462,34 +400,34 @@ class ERC681URI extends PaymentURI {
|
||||
/// _expandDecimal('1.2', 3) -> '1200'
|
||||
static String _expandDecimal(String decimalStr, int expShift) {
|
||||
var s = decimalStr.trim();
|
||||
var sign = '';
|
||||
if (s.startsWith('-') || s.startsWith('+')) {
|
||||
sign = s[0] == '-' ? '-' : '';
|
||||
var sign = "";
|
||||
if (s.startsWith("-") || s.startsWith("+")) {
|
||||
sign = s[0] == "-" ? "-" : "";
|
||||
s = s.substring(1);
|
||||
}
|
||||
|
||||
// First we split the integer and fractional parts
|
||||
final parts = s.split('.');
|
||||
final intPart = parts[0].isEmpty ? '0' : parts[0];
|
||||
final fracPart = parts.length > 1 ? parts[1] : '';
|
||||
final digits = (intPart + fracPart).replaceFirst(RegExp(r'^0+'), '');
|
||||
final parts = s.split(".");
|
||||
final intPart = parts[0].isEmpty ? "0" : parts[0];
|
||||
final fracPart = parts.length > 1 ? parts[1] : "";
|
||||
final digits = (intPart + fracPart).replaceFirst(RegExp(r"^0+"), "");
|
||||
final fracLen = fracPart.length;
|
||||
|
||||
// Then we calculate the effective shift = desired shift minus existing fractional digits
|
||||
final shift = expShift - fracLen;
|
||||
if (shift >= 0) {
|
||||
final head = digits.isEmpty ? '0' : digits;
|
||||
final zeros = List.filled(shift, '0').join();
|
||||
final head = digits.isEmpty ? "0" : digits;
|
||||
final zeros = List.filled(shift, "0").join();
|
||||
final res = head + zeros;
|
||||
return sign + (res.isEmpty ? '0' : res);
|
||||
return sign + (res.isEmpty ? "0" : res);
|
||||
} else {
|
||||
// Need to insert a decimal point within digits; return integer by truncating
|
||||
final cut = digits.length + shift;
|
||||
if (cut <= 0) {
|
||||
return '0';
|
||||
return "0";
|
||||
}
|
||||
final res = digits.substring(0, cut);
|
||||
return sign + (res.isEmpty ? '0' : res);
|
||||
return sign + (res.isEmpty ? "0" : res);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
import 'dart:developer';
|
||||
import "dart:developer";
|
||||
|
||||
import 'package:cw_core/payment_uris.dart';
|
||||
import 'package:cw_core/wallet_addresses.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import "package:cw_core/payment_uris.dart";
|
||||
import "package:cw_core/wallet_addresses.dart";
|
||||
import "package:mobx/mobx.dart";
|
||||
|
||||
part 'evm_chain_wallet_addresses.g.dart';
|
||||
part "evm_chain_wallet_addresses.g.dart";
|
||||
|
||||
class EVMChainWalletAddresses = EVMChainWalletAddressesBase with _$EVMChainWalletAddresses;
|
||||
|
||||
abstract class EVMChainWalletAddressesBase extends WalletAddresses with Store {
|
||||
EVMChainWalletAddressesBase(WalletInfo walletInfo, this._selectedChainId)
|
||||
: address = '',
|
||||
super(walletInfo);
|
||||
EVMChainWalletAddressesBase(super.walletInfo, this._selectedChainId) : address = "";
|
||||
|
||||
@override
|
||||
@observable
|
||||
@@ -33,7 +30,7 @@ abstract class EVMChainWalletAddressesBase extends WalletAddresses with Store {
|
||||
Future<void> updateAddressesInBox() async {
|
||||
try {
|
||||
addressesMap.clear();
|
||||
addressesMap[address] = '';
|
||||
addressesMap[address] = "";
|
||||
await saveAddressesInBox();
|
||||
} catch (e) {
|
||||
log(e.toString());
|
||||
@@ -41,20 +38,10 @@ abstract class EVMChainWalletAddressesBase extends WalletAddresses with Store {
|
||||
}
|
||||
|
||||
@override
|
||||
PaymentURI getPaymentUri(String amount) {
|
||||
switch (_selectedChainId) {
|
||||
case 1:
|
||||
return EthereumURI(amount: amount, address: address);
|
||||
case 137:
|
||||
return PolygonURI(amount: amount, address: address);
|
||||
case 8453:
|
||||
return BaseURI(amount: amount, address: address);
|
||||
case 42161:
|
||||
return ArbitrumURI(amount: amount, address: address);
|
||||
case 56:
|
||||
return BSCURI(amount: amount, address: address);
|
||||
default:
|
||||
return EthereumURI(amount: amount, address: address);
|
||||
}
|
||||
}
|
||||
PaymentURI getPaymentUri(String amount) => ERC681URI(
|
||||
address: address,
|
||||
amount: amount,
|
||||
chainId: _selectedChainId,
|
||||
contractAddress: null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
|
||||
addressesMap.clear();
|
||||
addressInfos.clear();
|
||||
|
||||
accountList.accounts.forEach((account) async {
|
||||
for (final account in accountList.accounts) {
|
||||
await _subaddressList.update(accountIndex: account.id);
|
||||
_subaddressList.subaddresses.forEach((subaddress) {
|
||||
addressesMap[subaddress.address] = subaddress.label;
|
||||
@@ -102,7 +102,7 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
|
||||
address: subaddress.address,
|
||||
label: subaddress.label));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
await saveAddressesInBox();
|
||||
} catch (e) {
|
||||
|
||||
+95
-6
@@ -1,12 +1,101 @@
|
||||
# Security Policy
|
||||
|
||||
## Reporting a Vulnerability
|
||||
Cake Wallet is developed by **Cake Labs LLC**. We take the security and privacy of
|
||||
our users seriously and welcome reports from security researchers.
|
||||
|
||||
If you need to report a vulnerability, please either:
|
||||
> **Cake Wallet is not affiliated with CAKE.com, Clockify, or security.cake.com.**
|
||||
> Those services belong to unrelated companies. The only official vulnerability
|
||||
> disclosure channels for Cake Wallet are the ones listed on this page and at
|
||||
> https://cakewallet.com/security.
|
||||
|
||||
* Open a security advisory: https://github.com/cake-tech/cake_wallet/security/advisories/new
|
||||
* Send an email to `dev@cakewallet.com` with details on the vulnerability
|
||||
## Reporting a vulnerability
|
||||
|
||||
## Supported Versions
|
||||
**Please do not open a public issue, pull request, or social-media post for a
|
||||
security vulnerability.** Public disclosure before a fix is available puts users'
|
||||
funds and privacy at risk. Use one of the private channels below and we will
|
||||
coordinate a fix and disclosure with you.
|
||||
|
||||
As we don't maintain previous versions of the app, only the latest release for each platform is supported and any updates will bump the version number.
|
||||
1. **GitHub private security advisory (preferred).**
|
||||
[Report a vulnerability](https://github.com/cake-tech/cake_wallet/security/advisories/new).
|
||||
This gives you a private, structured thread with the maintainers and is the
|
||||
fastest way to reach us.
|
||||
2. **Encrypted email.** Send details to **security@cakewallet.com**. For sensitive
|
||||
reports, please encrypt with our PGP key:
|
||||
- Key: https://cakewallet.com/.well-known/cakewallet-security.asc
|
||||
- Fingerprint: `DC91 6520 0271 AC6A 0533 3D3C BFE7 D9A5 0E4D 3A0A`
|
||||
|
||||
Both channels are monitored and automatically raise an alert in our internal
|
||||
security channel, so reports will not be missed.
|
||||
|
||||
### What to include
|
||||
|
||||
- A clear description of the issue and its security impact.
|
||||
- Step-by-step reproduction, ideally with a proof of concept.
|
||||
- Affected platforms (iOS, Android, macOS, Linux, Windows) and app version.
|
||||
- Affected wallet types / chains, if applicable.
|
||||
- Any relevant logs, addresses, or transaction IDs (for on-chain issues).
|
||||
|
||||
If you used AI tooling to find or write up the report, please say so.
|
||||
|
||||
## Our commitment (safe harbor)
|
||||
|
||||
We consider security research conducted in good faith under this policy to be
|
||||
authorized. We will not pursue or support legal action against researchers who:
|
||||
|
||||
- make a good-faith effort to avoid privacy violations, data destruction, and
|
||||
interruption or degradation of our services;
|
||||
- only interact with accounts they own or have explicit permission to access; and
|
||||
- give us a reasonable opportunity to fix an issue before disclosing it publicly.
|
||||
|
||||
If in doubt about whether an action is authorized, ask us first at
|
||||
security@cakewallet.com.
|
||||
|
||||
## What to expect
|
||||
|
||||
- **Acknowledgement:** within **2 business days**.
|
||||
- **Triage and initial assessment:** within **7 business days**.
|
||||
- **Coordinated disclosure:** we aim to ship a fix and coordinate public
|
||||
disclosure within **90 days** of the report. We will keep you updated on
|
||||
progress and agree on a disclosure date with you.
|
||||
- **Credit:** with your permission, we are happy to publicly credit you for the
|
||||
report once a fix is released.
|
||||
|
||||
## Scope
|
||||
|
||||
**In scope:** the Cake Wallet and Monero.com applications and the code in this
|
||||
repository and its sibling `cake-tech` repositories — anything that could lead to
|
||||
loss of funds, exposure of keys or seeds, a privacy leak, or a
|
||||
failed/incorrect transaction.
|
||||
|
||||
**Out of scope:** issues in third-party services, exchange/swap providers, or
|
||||
nodes we do not operate; reports generated solely by automated scanners without a
|
||||
demonstrated impact; low-severity or informational issues on our marketing and
|
||||
landing websites (for example reflected or self-XSS, missing security headers,
|
||||
clickjacking on pages with no sensitive actions, or SPF/DMARC and cookie-flag
|
||||
nitpicks) that do not affect the app or user funds; and social-engineering or
|
||||
physical attacks.
|
||||
|
||||
## Rewards
|
||||
|
||||
At our **sole discretion**, we may offer a reward for a valid report. To be
|
||||
eligible, a report must:
|
||||
|
||||
- be submitted **privately** through one of the channels above (a GitHub private
|
||||
security advisory or `security@cakewallet.com`) — anything disclosed publicly or
|
||||
sent through other channels is not eligible; and
|
||||
- identify a genuine vulnerability with real impact on users — typically loss of
|
||||
funds, exposure of keys or seeds, a privacy leak, or a failed or incorrect
|
||||
transaction.
|
||||
|
||||
Trivial or low-impact findings are **not** eligible — for example, reflected XSS
|
||||
or other low-severity issues on our marketing websites, missing security headers,
|
||||
hardening or best-practice suggestions, automated-scanner output without a working
|
||||
proof of concept, or already-known issues. There is no fixed bounty and no
|
||||
guaranteed payout; whether a report qualifies, and any amount, are determined
|
||||
solely by Cake Labs LLC.
|
||||
|
||||
## Supported versions
|
||||
|
||||
We do not maintain previous releases. Only the **latest release for each platform**
|
||||
is supported; security fixes are delivered in new versions. Please keep Cake Wallet
|
||||
up to date.
|
||||
|
||||
+18
-23
@@ -188,8 +188,6 @@ PODS:
|
||||
- Flutter
|
||||
- wakelock_plus (0.0.1):
|
||||
- Flutter
|
||||
- warp_api (0.0.1):
|
||||
- Flutter
|
||||
- YttriumWrapper (0.8.35)
|
||||
|
||||
DEPENDENCIES:
|
||||
@@ -236,7 +234,6 @@ DEPENDENCIES:
|
||||
- universal_ble (from `.symlinks/plugins/universal_ble/darwin`)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
|
||||
- warp_api (from `.symlinks/plugins/warp_api/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
@@ -341,8 +338,6 @@ EXTERNAL SOURCES:
|
||||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock_plus:
|
||||
:path: ".symlinks/plugins/wakelock_plus/ios"
|
||||
warp_api:
|
||||
:path: ".symlinks/plugins/warp_api/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
|
||||
@@ -351,17 +346,17 @@ SPEC CHECKSUMS:
|
||||
breez_sdk_spark_flutter: ed3b6709b8ce9b40309d8728640eade5b19e8a0d
|
||||
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
|
||||
CryptoSwift: e64e11850ede528a02a0f3e768cec8e9d92ecb90
|
||||
cw_decred: 9c0e1df74745b51a1289ec5e91fb9e24b68fa14a
|
||||
cw_mweb: 22cd01dfb8ad2d39b15332006f22046aaa8352a3
|
||||
device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7
|
||||
device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6
|
||||
devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926
|
||||
cw_decred: a02cf30175a46971c1e2fa22c48407534541edc6
|
||||
cw_mweb: 3aea2fb35b2bd04d8b2d21b83216f3b8fb768d85
|
||||
device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f
|
||||
device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89
|
||||
devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8
|
||||
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
|
||||
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
|
||||
dnssec_proof: d461cac7bd3301eb7447f87936745a0c1ae0a67e
|
||||
fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3
|
||||
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
|
||||
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
|
||||
flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f
|
||||
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb
|
||||
@@ -374,32 +369,32 @@ SPEC CHECKSUMS:
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
GTMAppAuth: f69bd07d68cd3b766125f7e072c45d7340dea0de
|
||||
GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6
|
||||
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
|
||||
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
|
||||
in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
|
||||
integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e
|
||||
local_auth_darwin: d2e8c53ef0c4f43c646462e3415432c4dab3ae19
|
||||
local_auth_darwin: c3ee6cce0a8d56be34c8ccb66ba31f7f180aaebb
|
||||
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
|
||||
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
|
||||
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
|
||||
payjoin_flutter: d9d4c8aa16bd5dfedb9b21d0edc8199e0187d96e
|
||||
permission_handler_apple: 92d754bbaa7361d436db2d6c3c1c2a0fdcec462e
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
quick_actions_ios: 4b07fb49d8d8f3518d7565fbb7a91014067a7d82
|
||||
quick_actions_ios: 500fcc11711d9f646739093395c4ae8eec25f779
|
||||
reown_yttrium: cee334ade64725b1d83f7b34c706a6aae2696d58
|
||||
rive_common: dd421daaf9ae69f0125aa761dd96abd278399952
|
||||
rlz: 3f4022361f540a5c26d9d2474fea1d2455b69d8d
|
||||
SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a
|
||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
|
||||
shared_preferences_foundation: 5086985c1d43c5ba4d5e69a4e8083a389e2909e6
|
||||
sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12
|
||||
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
|
||||
sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b
|
||||
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
|
||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||
sp_scanner: b1bc9321690980bdb44bba7ec85d5543e716d1b5
|
||||
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
|
||||
sqlite3: 73513155ec6979715d3904ef53a8d68892d4032b
|
||||
sqlite3_flutter_libs: 86f82662868ee26ff3451f73cac9c5fc2a1f57fa
|
||||
sqlite3_flutter_libs: 83f8e9f5b6554077f1d93119fe20ebaa5f3a9ef1
|
||||
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
|
||||
torch_dart: f4620705d10f05492fab047f2fa1c3a600e7d17d
|
||||
uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152
|
||||
universal_ble: 45519b2aeafe62761e2c6309f8927edb5288b914
|
||||
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
|
||||
universal_ble: a322ebabee64f0ec27a313e89a5dd6967f37a60f
|
||||
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
|
||||
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
|
||||
YttriumWrapper: 31e937fe9fbe0f1314d2ca6be9ce9b379a059966
|
||||
|
||||
|
||||
+10
-18
@@ -687,28 +687,20 @@ class CWBitcoin extends Bitcoin {
|
||||
}
|
||||
|
||||
List<Output> updateOutputs(PendingTransaction pendingTransaction, List<Output> outputs) {
|
||||
if (pendingTransaction is PendingLightningTransaction) return outputs;
|
||||
|
||||
final pendingTx = pendingTransaction as PendingBitcoinTransaction;
|
||||
|
||||
if (!pendingTx.hasSilentPayment) {
|
||||
if (pendingTransaction is! PendingBitcoinTransaction || !pendingTransaction.hasSilentPayment) {
|
||||
return outputs;
|
||||
}
|
||||
|
||||
final updatedOutputs = outputs.map((output) {
|
||||
try {
|
||||
final pendingOut = pendingTx.outputs[outputs.indexOf(output)];
|
||||
final updatedOutput = output;
|
||||
final stealthAddresses = pendingTransaction.stealthAddresses;
|
||||
if (stealthAddresses.length != outputs.length) {
|
||||
printV("well, that shouldn't happen");
|
||||
return outputs;
|
||||
}
|
||||
|
||||
updatedOutput.stealthAddress = P2trAddress.fromScriptPubkey(script: pendingOut.scriptPubKey)
|
||||
.toAddress(BitcoinNetwork.mainnet);
|
||||
return updatedOutput;
|
||||
} catch (_) {}
|
||||
|
||||
return output;
|
||||
}).toList();
|
||||
|
||||
return updatedOutputs;
|
||||
for (var i = 0; i < outputs.length; i++) {
|
||||
outputs[i].stealthAddress = stealthAddresses[i];
|
||||
}
|
||||
return outputs;
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -10,7 +10,6 @@ import 'package:cake_wallet/entities/fiat_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
import 'package:cake_wallet/entities/fs_migration.dart';
|
||||
import 'package:cake_wallet/entities/haven_seed_store.dart';
|
||||
import 'package:cake_wallet/entities/node_list.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/secret_store_key.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
@@ -46,7 +45,7 @@ const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
|
||||
const nanoDefaultNodeUri = 'rpc.nano.to';
|
||||
const nanoDefaultPowNodeUri = 'rpc.nano.to';
|
||||
const solanaDefaultNodeUri = 'solana-mainnet.core.chainstack.com';
|
||||
const tronDefaultNodeUri = 'api.trongrid.io';
|
||||
const tronDefaultNodeUri = 'trx.nownodes.io';
|
||||
const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
|
||||
const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
||||
const zanoDefaultNodeUri = '37.27.100.59:10500';
|
||||
@@ -607,6 +606,28 @@ Future<void> defaultSettingsMigration(
|
||||
enabled: true,
|
||||
);
|
||||
break;
|
||||
case 68:
|
||||
await _changeDefaultNode(
|
||||
sharedPreferences: sharedPreferences,
|
||||
type: WalletType.tron,
|
||||
newDefaultUri: tronDefaultNodeUri,
|
||||
currentNodePreferenceKey: PreferencesKey.currentTronNodeIdKey,
|
||||
useSSL: true,
|
||||
oldUri: [
|
||||
'tron-rpc.publicnode.com:443',
|
||||
'api.trongrid.io',
|
||||
],
|
||||
);
|
||||
await _changeDefaultNode(
|
||||
sharedPreferences: sharedPreferences,
|
||||
type: WalletType.monero,
|
||||
newDefaultUri: newCakeWalletMoneroUri,
|
||||
currentNodePreferenceKey: PreferencesKey.currentNodeIdKey,
|
||||
useSSL: true,
|
||||
trusted: true,
|
||||
oldUri: ['nodes.hashvault.pro:18081'],
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -663,7 +684,7 @@ Future<void> _changeDefaultNode({
|
||||
} else {
|
||||
final currentNode = nodes.firstWhereOrNull((node) => node.id == currentNodeId);
|
||||
shouldReplace =
|
||||
currentNode == null || (oldUri?.any((e) => currentNode!.uriRaw.contains(e)) ?? true);
|
||||
currentNode == null || (oldUri?.any((e) => currentNode.uriRaw.contains(e)) ?? true);
|
||||
}
|
||||
|
||||
if (shouldReplace) {
|
||||
|
||||
@@ -539,7 +539,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
}
|
||||
|
||||
Future<Uri> _getUri(String path, Map<String, String> queryParams) async {
|
||||
final uri = Uri.http(onionApiAuthority, path, queryParams);
|
||||
final uri = Uri.https(onionApiAuthority, path, queryParams);
|
||||
|
||||
if (useTorOnly) return uri;
|
||||
|
||||
|
||||
+1
-1
@@ -315,7 +315,7 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
||||
payjoinSessionSource: payjoinSessionSource,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
havenSeedStore: havenSeedStore,
|
||||
initialMigrationVersion: 67,
|
||||
initialMigrationVersion: 68,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+759
-680
File diff suppressed because it is too large
Load Diff
@@ -1,22 +1,10 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/modern_button.dart';
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/copy_wrapper.dart';
|
||||
import "package:cake_wallet/generated/i18n.dart";
|
||||
import "package:cake_wallet/new-ui/widgets/copy_wrapper.dart";
|
||||
import "package:cake_wallet/new-ui/widgets/modern_button.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
|
||||
class ReceiveBottomButtons extends StatefulWidget {
|
||||
final bool largeQrMode;
|
||||
final ClipboardData? copyData;
|
||||
final VoidCallback onCopyButtonPressed;
|
||||
final VoidCallback onAmountButtonPressed;
|
||||
final VoidCallback onLabelButtonPressed;
|
||||
final VoidCallback onAccountsButtonPressed;
|
||||
final bool showLabelButton;
|
||||
final bool showAccountsButton;
|
||||
|
||||
const ReceiveBottomButtons({
|
||||
required this.largeQrMode,
|
||||
required this.onCopyButtonPressed,
|
||||
@@ -29,6 +17,15 @@ class ReceiveBottomButtons extends StatefulWidget {
|
||||
super.key,
|
||||
});
|
||||
|
||||
final bool largeQrMode;
|
||||
final ClipboardData? copyData;
|
||||
final VoidCallback onCopyButtonPressed;
|
||||
final VoidCallback onAmountButtonPressed;
|
||||
final VoidCallback onLabelButtonPressed;
|
||||
final VoidCallback onAccountsButtonPressed;
|
||||
final bool showLabelButton;
|
||||
final bool showAccountsButton;
|
||||
|
||||
@override
|
||||
State<ReceiveBottomButtons> createState() => _ReceiveBottomButtonsState();
|
||||
}
|
||||
@@ -49,7 +46,7 @@ class _ReceiveBottomButtonsState extends State<ReceiveBottomButtons> {
|
||||
opacity: targetOpacity,
|
||||
curve: Curves.easeOut,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32.0),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
@@ -57,12 +54,13 @@ class _ReceiveBottomButtonsState extends State<ReceiveBottomButtons> {
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: widget.copyData == null ? widget.onCopyButtonPressed : null,
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: IgnorePointer(
|
||||
ignoring: widget.copyData == null,
|
||||
child: CopyWrapper(
|
||||
data: widget.copyData,
|
||||
builder: (context, copied) => AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 200),
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: IgnorePointer(
|
||||
child: ModernButton.svg(
|
||||
key: ValueKey(copied),
|
||||
@@ -84,25 +82,28 @@ class _ReceiveBottomButtonsState extends State<ReceiveBottomButtons> {
|
||||
),
|
||||
),
|
||||
ModernButton.svg(
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
svgPath: "assets/new-ui/set-amount.svg",
|
||||
onPressed: widget.onAmountButtonPressed,
|
||||
label: S.of(context).set_amount),
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
svgPath: "assets/new-ui/set-amount.svg",
|
||||
onPressed: widget.onAmountButtonPressed,
|
||||
label: S.of(context).set_amount,
|
||||
),
|
||||
if (widget.showLabelButton)
|
||||
ModernButton.svg(
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
svgPath: "assets/new-ui/add-label.svg",
|
||||
onPressed: widget.onLabelButtonPressed,
|
||||
label: S.of(context).label),
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
svgPath: "assets/new-ui/add-label.svg",
|
||||
onPressed: widget.onLabelButtonPressed,
|
||||
label: S.of(context).label,
|
||||
),
|
||||
if (widget.showAccountsButton)
|
||||
ModernButton.svg(
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
svgPath: "assets/new-ui/addr-book.svg",
|
||||
onPressed: widget.onAccountsButtonPressed,
|
||||
label: S.of(context).addresses),
|
||||
size: 60,
|
||||
iconSize: 32,
|
||||
svgPath: "assets/new-ui/addr-book.svg",
|
||||
onPressed: widget.onAccountsButtonPressed,
|
||||
label: S.of(context).addresses,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/modern_button.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import "package:cake_wallet/generated/i18n.dart";
|
||||
import "package:cake_wallet/new-ui/widgets/modern_button.dart";
|
||||
import "package:cw_core/crypto_amount_format.dart";
|
||||
import "package:flutter/material.dart";
|
||||
|
||||
class FiatAmountBar extends StatelessWidget {
|
||||
const FiatAmountBar(
|
||||
{super.key,
|
||||
required this.fiatInputMode,
|
||||
required this.onSwitchButtonPressed,
|
||||
this.onAllButtonPressed,
|
||||
required this.cryptoAmount,
|
||||
required this.fiatAmount,
|
||||
required this.cryptoCurrencySymbol,
|
||||
required this.fiatCurrencySymbol,
|
||||
this.allAmount,
|
||||
this.foregroundElementColor,
|
||||
this.textColor,
|
||||
this.allAmountColor,
|
||||
this.allAmountTextColor});
|
||||
const FiatAmountBar({
|
||||
required this.fiatInputMode,
|
||||
required this.onSwitchButtonPressed,
|
||||
required this.cryptoAmount,
|
||||
required this.fiatAmount,
|
||||
required this.cryptoCurrencySymbol,
|
||||
required this.fiatCurrencySymbol,
|
||||
super.key,
|
||||
this.onAllButtonPressed,
|
||||
this.allAmount,
|
||||
this.foregroundElementColor,
|
||||
this.textColor,
|
||||
this.allAmountColor,
|
||||
this.allAmountTextColor,
|
||||
});
|
||||
|
||||
final bool fiatInputMode;
|
||||
final VoidCallback onSwitchButtonPressed;
|
||||
@@ -34,42 +35,41 @@ class FiatAmountBar extends StatelessWidget {
|
||||
final Color? allAmountTextColor;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
ModernButton.svg(
|
||||
backgroundColor: foregroundElementColor,
|
||||
size: 28,
|
||||
svgPath: "assets/new-ui/switch.svg",
|
||||
iconSize: 18,
|
||||
onPressed: onSwitchButtonPressed,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: onSwitchButtonPressed,
|
||||
child: Text(
|
||||
fiatInputMode
|
||||
? "${cryptoAmount.isEmpty ? "0" : cryptoAmount.withMaxDecimals(8)} $cryptoCurrencySymbol"
|
||||
: "${fiatAmount.isEmpty ? "0" : fiatAmount} $fiatCurrencySymbol",
|
||||
style: TextStyle(color: textColor ?? Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (allAmount != null && allAmount!.isNotEmpty)
|
||||
Widget build(BuildContext context) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text(
|
||||
"${S.of(context).max}.",
|
||||
style: TextStyle(color: textColor ?? Theme.of(context).colorScheme.onSurface),
|
||||
ModernButton.svg(
|
||||
backgroundColor: foregroundElementColor,
|
||||
size: 28,
|
||||
svgPath: "assets/new-ui/switch.svg",
|
||||
iconSize: 18,
|
||||
onPressed: onSwitchButtonPressed,
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(999999)),
|
||||
child: Material(
|
||||
GestureDetector(
|
||||
onTap: onSwitchButtonPressed,
|
||||
child: Text(
|
||||
fiatInputMode
|
||||
? "${cryptoAmount.isEmpty ? "0" : cryptoAmount.withMaxDecimals(8)} $cryptoCurrencySymbol"
|
||||
: "${fiatAmount.isEmpty ? "0" : fiatAmount} $fiatCurrencySymbol",
|
||||
style: TextStyle(color: textColor ?? Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (allAmount != null && allAmount!.isNotEmpty)
|
||||
Row(
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text(
|
||||
"${S.of(context).max}.",
|
||||
style: TextStyle(color: textColor ?? Theme.of(context).colorScheme.onSurface),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(borderRadius: BorderRadius.circular(999999)),
|
||||
child: Material(
|
||||
color: allAmountColor ??
|
||||
foregroundElementColor ??
|
||||
Theme.of(context).colorScheme.surfaceContainer,
|
||||
@@ -78,22 +78,23 @@ class FiatAmountBar extends StatelessWidget {
|
||||
borderRadius: BorderRadius.circular(99999),
|
||||
onTap: onAllButtonPressed,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
child: Text(
|
||||
formatAmount(allAmount!),
|
||||
_formatAmount(allAmount!),
|
||||
style: TextStyle(
|
||||
color: allAmountTextColor ?? Theme.of(context).colorScheme.primary),
|
||||
color: allAmountTextColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
String formatAmount(String amount) {
|
||||
String _formatAmount(String amount) {
|
||||
try {
|
||||
return double.parse(amount).toStringAsPrecision(8).replaceFirst(RegExp(r"\.?0+$"), "");
|
||||
} catch (e) {
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import 'package:cake_wallet/new-ui/widgets/coins_page/token_image_widget.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/send_page/floating_icon_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/utils/decimal_input_formatter.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import "package:cake_wallet/new-ui/widgets/coins_page/token_image_widget.dart";
|
||||
import "package:cake_wallet/new-ui/widgets/send_page/floating_icon_button.dart";
|
||||
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
|
||||
import "package:cake_wallet/utils/decimal_input_formatter.dart";
|
||||
import "package:flutter/material.dart";
|
||||
import "package:flutter/services.dart";
|
||||
import "package:flutter_mobx/flutter_mobx.dart";
|
||||
|
||||
class NewSendAmountInput extends StatefulWidget {
|
||||
const NewSendAmountInput({
|
||||
super.key,
|
||||
required this.currency,
|
||||
required this.maxDecimals,
|
||||
required this.hasPicker,
|
||||
required this.onPickerClicked,
|
||||
required this.currencyIconPath,
|
||||
required this.amountController,
|
||||
super.key,
|
||||
this.validator,
|
||||
});
|
||||
|
||||
@@ -41,27 +41,28 @@ class _NewSendAmountInputState extends State<NewSendAmountInput> {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FormField<String>(
|
||||
key: formFieldKey,
|
||||
initialValue: widget.amountController.text,
|
||||
validator: widget.validator,
|
||||
builder: (state) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
Widget build(BuildContext context) => FormField<String>(
|
||||
key: formFieldKey,
|
||||
initialValue: widget.amountController.text,
|
||||
validator: widget.validator,
|
||||
builder: (state) => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: widget.hasPicker
|
||||
? Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(18)),
|
||||
color: widget.hasPicker
|
||||
? Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(18),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.horizontal(left: Radius.circular(18))),
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: const BorderRadius.horizontal(left: Radius.circular(18)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
spacing: 8,
|
||||
@@ -79,82 +80,87 @@ class _NewSendAmountInputState extends State<NewSendAmountInput> {
|
||||
],
|
||||
controller: widget.amountController,
|
||||
decoration: InputDecoration(
|
||||
hintText: widget.maxDecimals > 0 ? "0" : "0.00",
|
||||
hintText: widget.maxDecimals == 0 ? "0" : "0.00",
|
||||
errorMaxLines: 3,
|
||||
),
|
||||
onChanged: state.didChange,
|
||||
),
|
||||
),
|
||||
FloatingIconButton(
|
||||
iconPath: "assets/new-ui/paste.svg",
|
||||
onPressed: () async {
|
||||
final data = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
if (data != null && data.text != null) {
|
||||
final text = data.text!;
|
||||
widget.amountController.value = TextEditingValue(
|
||||
text: text,
|
||||
selection: TextSelection.collapsed(offset: text.length),
|
||||
);
|
||||
}
|
||||
}),
|
||||
iconPath: "assets/new-ui/paste.svg",
|
||||
onPressed: () async {
|
||||
final data = await Clipboard.getData(Clipboard.kTextPlain);
|
||||
if (data != null && data.text != null) {
|
||||
final text = data.text!;
|
||||
widget.amountController.value = TextEditingValue(
|
||||
text: text,
|
||||
selection: TextSelection.collapsed(offset: text.length),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
IntrinsicWidth(
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
return GestureDetector(
|
||||
onTap: widget.onPickerClicked,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(18),
|
||||
bottomRight: Radius.circular(18)),
|
||||
color: widget.hasPicker
|
||||
? Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
: Theme.of(context).colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
spacing: 8,
|
||||
children: [
|
||||
if (widget.hasPicker && widget.currencyIconPath.isNotEmpty)
|
||||
TokenImageWidget(
|
||||
imageUrl: widget.currencyIconPath, size: 24),
|
||||
Text(widget.currency),
|
||||
if (widget.hasPicker)
|
||||
CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/chooser.svg",
|
||||
width: 12,
|
||||
height: 12,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn),
|
||||
)
|
||||
],
|
||||
))),
|
||||
);
|
||||
},
|
||||
builder: (_) => GestureDetector(
|
||||
onTap: widget.onPickerClicked,
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.only(
|
||||
topRight: Radius.circular(18),
|
||||
bottomRight: Radius.circular(18),
|
||||
),
|
||||
color: widget.hasPicker
|
||||
? Theme.of(context).colorScheme.surfaceContainerHigh
|
||||
: Theme.of(context).colorScheme.surfaceContainer,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
spacing: 8,
|
||||
children: [
|
||||
if (widget.hasPicker && widget.currencyIconPath.isNotEmpty)
|
||||
TokenImageWidget(
|
||||
imageUrl: widget.currencyIconPath,
|
||||
size: 24,
|
||||
),
|
||||
Text(widget.currency),
|
||||
if (widget.hasPicker)
|
||||
CakeImageWidget(
|
||||
imageUrl: "assets/new-ui/chooser.svg",
|
||||
width: 12,
|
||||
height: 12,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Theme.of(context).colorScheme.primary,
|
||||
BlendMode.srcIn,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
if (state.hasError)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 6, left: 8),
|
||||
child: Text(
|
||||
state.errorText!,
|
||||
style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.error),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
),
|
||||
if (state.hasError)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 6, left: 8),
|
||||
child: Text(
|
||||
state.errorText!,
|
||||
style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.error),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/copy_wrapper.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
|
||||
import 'package:cake_wallet/new-ui/widgets/swap_page/swap_modal_header.dart';
|
||||
@@ -9,6 +10,7 @@ import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/payment_uris.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class SwapSendExternalModal extends StatefulWidget {
|
||||
const SwapSendExternalModal(
|
||||
@@ -166,10 +168,59 @@ class _SwapSendExternalModalState extends State<SwapSendExternalModal> {
|
||||
),
|
||||
)),
|
||||
if (widget.exchangeTradeViewModel.trade.extraId != null)
|
||||
Text(
|
||||
"${S.of(context).destination_tag} ${widget.exchangeTradeViewModel.trade.extraId}",
|
||||
style: TextStyle(
|
||||
fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
CopyWrapper(
|
||||
data: ClipboardData(
|
||||
text: widget.exchangeTradeViewModel.trade.extraId!),
|
||||
builder: (context, copied) => Container(
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 8,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).destination_tag,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
spacing: 8,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Text(
|
||||
widget.exchangeTradeViewModel.trade.extraId!,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.primary),
|
||||
),
|
||||
),
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: Icon(
|
||||
copied ? Icons.check : Icons.copy,
|
||||
key: ValueKey(copied),
|
||||
size: 18,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
spacing: 8,
|
||||
|
||||
@@ -34,6 +34,8 @@ class MoneroHardwareWalletPassphraseInputModal extends StatelessWidget {
|
||||
BaseTextFormField(
|
||||
controller: controller,
|
||||
hintText: S.of(context).passphrase_raw,
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
),
|
||||
const SizedBox(),
|
||||
NewPrimaryButton(
|
||||
|
||||
@@ -442,16 +442,11 @@ abstract class ExchangeTradeViewModelBase with Store {
|
||||
case WalletType.dogecoin:
|
||||
return DogeURI(address: inputAddress, amount: amount);
|
||||
case WalletType.ethereum:
|
||||
return _createERC681URI(fromCurrency, inputAddress, amount);
|
||||
// TODO: Expand ERC681URI support to Polygon(modify decoding flow for QRs, pay anything, and deep link handling)
|
||||
case WalletType.polygon:
|
||||
return PolygonURI(amount: amount, address: inputAddress);
|
||||
case WalletType.base:
|
||||
return BaseURI(amount: amount, address: inputAddress);
|
||||
case WalletType.arbitrum:
|
||||
return ArbitrumURI(amount: amount, address: inputAddress);
|
||||
case WalletType.bsc:
|
||||
return BSCURI(amount: amount, address: inputAddress);
|
||||
return _createERC681URI(fromCurrency, inputAddress, amount);
|
||||
case WalletType.solana:
|
||||
return SolanaURI(amount: amount, address: inputAddress);
|
||||
case WalletType.tron:
|
||||
|
||||
@@ -14,15 +14,15 @@ TYPES=($MONERO_COM $CAKEWALLET)
|
||||
APP_ANDROID_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="6.2.1"
|
||||
MONERO_COM_BUILD_NUMBER=4161
|
||||
MONERO_COM_VERSION="6.3.0"
|
||||
MONERO_COM_BUILD_NUMBER=4162
|
||||
MONERO_COM_BUNDLE_ID="com.monero.app"
|
||||
MONERO_COM_PACKAGE="com.monero.app"
|
||||
MONERO_COM_SCHEME="monero.com"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="6.2.1"
|
||||
CAKEWALLET_BUILD_NUMBER=4413
|
||||
CAKEWALLET_VERSION="6.3.0"
|
||||
CAKEWALLET_BUILD_NUMBER=4414
|
||||
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
||||
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
||||
CAKEWALLET_SCHEME="cakewallet"
|
||||
|
||||
@@ -12,13 +12,13 @@ TYPES=($MONERO_COM $CAKEWALLET)
|
||||
APP_IOS_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="6.2.1"
|
||||
MONERO_COM_BUILD_NUMBER=167
|
||||
MONERO_COM_VERSION="6.3.0"
|
||||
MONERO_COM_BUILD_NUMBER=168
|
||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="6.2.1"
|
||||
CAKEWALLET_BUILD_NUMBER=423
|
||||
CAKEWALLET_VERSION="6.3.0"
|
||||
CAKEWALLET_BUILD_NUMBER=424
|
||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user