mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-05 10:29:23 +00:00
Merge branch 'mweb-bg-sync-2' of https://github.com/cake-tech/cake_wallet into mweb-bg-sync-3
This commit is contained in:
commit
2e13a93f78
69 changed files with 1508 additions and 1410 deletions
|
@ -171,8 +171,8 @@ jobs:
|
|||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
|
@ -185,6 +185,7 @@ jobs:
|
|||
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 ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||
echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_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
|
||||
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
|
||||
|
|
3
.github/workflows/pr_test_build_android.yml
vendored
3
.github/workflows/pr_test_build_android.yml
vendored
|
@ -182,8 +182,8 @@ jobs:
|
|||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
|
@ -197,6 +197,7 @@ jobs:
|
|||
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 ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||
echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_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
|
||||
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
|
||||
|
|
3
.github/workflows/pr_test_build_linux.yml
vendored
3
.github/workflows/pr_test_build_linux.yml
vendored
|
@ -154,8 +154,8 @@ jobs:
|
|||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
|
@ -167,6 +167,7 @@ jobs:
|
|||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
|
||||
echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_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
|
||||
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
-
|
||||
uri: ethereum.publicnode.com
|
||||
uri: ethereum-rpc.publicnode.com
|
||||
useSSL: true
|
||||
isDefault: true
|
||||
-
|
||||
uri: eth.llamarpc.com
|
||||
-
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
-
|
||||
uri: polygon-rpc.com
|
||||
-
|
||||
uri: polygon-bor.publicnode.com
|
||||
uri: polygon-bor-rpc.publicnode.com
|
||||
useSSL: true
|
||||
isDefault: true
|
||||
-
|
||||
uri: polygon.llamarpc.com
|
||||
-
|
||||
|
|
|
@ -7,4 +7,7 @@
|
|||
-
|
||||
uri: solana-rpc.publicnode.com:443
|
||||
useSSL: true
|
||||
-
|
||||
uri: solana-mainnet.core.chainstack.com
|
||||
useSSL: true
|
||||
is_default: true
|
|
@ -39,7 +39,7 @@ class ElectrumBalance extends Balance {
|
|||
int secondUnconfirmed = 0;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
|
||||
String get formattedAvailableBalance => bitcoinAmountToString(amount: ((confirmed + unconfirmed) - frozen) );
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
|
||||
|
@ -58,7 +58,7 @@ class ElectrumBalance extends Balance {
|
|||
|
||||
@override
|
||||
String get formattedFullAvailableBalance =>
|
||||
bitcoinAmountToString(amount: confirmed + secondConfirmed - frozen);
|
||||
bitcoinAmountToString(amount: (confirmed + unconfirmed) + secondConfirmed - frozen);
|
||||
|
||||
String toJSON() => json.encode({
|
||||
'confirmed': confirmed,
|
||||
|
|
|
@ -4,7 +4,6 @@ import 'dart:io';
|
|||
import 'dart:isolate';
|
||||
|
||||
import 'package:bitcoin_base/bitcoin_base.dart';
|
||||
import 'package:cw_bitcoin/litecoin_wallet_addresses.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cw_bitcoin/litecoin_wallet.dart';
|
||||
|
@ -1014,6 +1013,9 @@ abstract class ElectrumWalletBase
|
|||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
try {
|
||||
// start by updating unspent coins
|
||||
await updateAllUnspents();
|
||||
|
||||
final outputs = <BitcoinOutput>[];
|
||||
final transactionCredentials = credentials as BitcoinTransactionCredentials;
|
||||
final hasMultiDestination = transactionCredentials.outputs.length > 1;
|
||||
|
@ -2236,18 +2238,6 @@ abstract class ElectrumWalletBase
|
|||
var totalConfirmed = 0;
|
||||
var totalUnconfirmed = 0;
|
||||
|
||||
unspentCoinsInfo.values.forEach((info) {
|
||||
unspentCoins.forEach((element) {
|
||||
if (element.hash == info.hash &&
|
||||
element.vout == info.vout &&
|
||||
info.isFrozen &&
|
||||
element.bitcoinAddressRecord.address == info.address &&
|
||||
element.value == info.value) {
|
||||
totalFrozen += element.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (hasSilentPaymentsScanning) {
|
||||
// Add values from unspent coins that are not fetched by the address list
|
||||
// i.e. scanned silent payments
|
||||
|
@ -2263,6 +2253,20 @@ abstract class ElectrumWalletBase
|
|||
});
|
||||
}
|
||||
|
||||
unspentCoinsInfo.values.forEach((info) {
|
||||
unspentCoins.forEach((element) {
|
||||
if (element.bitcoinAddressRecord is BitcoinSilentPaymentAddressRecord) return;
|
||||
|
||||
if (element.hash == info.hash &&
|
||||
element.vout == info.vout &&
|
||||
info.isFrozen &&
|
||||
element.bitcoinAddressRecord.address == info.address &&
|
||||
element.value == info.value) {
|
||||
totalFrozen += element.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
final balances = await Future.wait(balanceFutures);
|
||||
|
||||
if (balances.isNotEmpty && balances.first['confirmed'] == null) {
|
||||
|
|
|
@ -47,7 +47,11 @@ class TransactionInputNotSupported implements Exception {}
|
|||
|
||||
class SignNativeTokenTransactionRentException implements Exception {}
|
||||
|
||||
class CreateAssociatedTokenAccountException implements Exception {}
|
||||
class CreateAssociatedTokenAccountException implements Exception {
|
||||
final String errorMessage;
|
||||
|
||||
CreateAssociatedTokenAccountException(this.errorMessage);
|
||||
}
|
||||
|
||||
class SignSPLTokenTransactionRentException implements Exception {}
|
||||
|
||||
|
|
|
@ -3,36 +3,25 @@ import 'package:cw_core/monero_amount_format.dart';
|
|||
|
||||
class MoneroBalance extends Balance {
|
||||
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||
: formattedFullBalance = moneroAmountToString(amount: frozenBalance + fullBalance),
|
||||
: formattedUnconfirmedBalance = moneroAmountToString(amount: fullBalance - unlockedBalance),
|
||||
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
|
||||
formattedLockedBalance =
|
||||
moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
|
||||
formattedFrozenBalance = moneroAmountToString(amount: frozenBalance),
|
||||
super(unlockedBalance, fullBalance);
|
||||
|
||||
MoneroBalance.fromString(
|
||||
{required this.formattedFullBalance,
|
||||
required this.formattedUnlockedBalance,
|
||||
this.formattedLockedBalance = '0.0'})
|
||||
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
|
||||
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
|
||||
frozenBalance = moneroParseAmount(amount: formattedLockedBalance),
|
||||
super(moneroParseAmount(amount: formattedUnlockedBalance),
|
||||
moneroParseAmount(amount: formattedFullBalance));
|
||||
|
||||
final int fullBalance;
|
||||
final int unlockedBalance;
|
||||
final int frozenBalance;
|
||||
final String formattedFullBalance;
|
||||
final String formattedUnconfirmedBalance;
|
||||
final String formattedUnlockedBalance;
|
||||
final String formattedLockedBalance;
|
||||
final String formattedFrozenBalance;
|
||||
|
||||
@override
|
||||
String get formattedUnAvailableBalance =>
|
||||
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
|
||||
formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance => formattedFullBalance;
|
||||
String get formattedAdditionalBalance => formattedUnconfirmedBalance;
|
||||
}
|
||||
|
|
|
@ -99,8 +99,8 @@ class Node extends HiveObject with Keyable {
|
|||
case WalletType.polygon:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
return Uri.parse(
|
||||
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") ? path : "/$path"}");
|
||||
return Uri.parse(
|
||||
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") ? path : "/$path"}");
|
||||
case WalletType.none:
|
||||
throw Exception('Unexpected type ${type.toString()} for Node uri');
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ class Node extends HiveObject with Keyable {
|
|||
return requestMoneroNode();
|
||||
case WalletType.nano:
|
||||
case WalletType.banano:
|
||||
return requestNanoNode();
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
|
@ -198,14 +199,16 @@ class Node extends HiveObject with Keyable {
|
|||
);
|
||||
client.close();
|
||||
|
||||
if ((
|
||||
response.body.contains("400 Bad Request") // Some other generic error
|
||||
|| response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|
||||
|| response.headers["location"] != null // Generic reverse proxy
|
||||
|| response.body.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
|
||||
) && !(useSSL??false)
|
||||
) {
|
||||
|
||||
if ((response.body.contains("400 Bad Request") // Some other generic error
|
||||
||
|
||||
response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|
||||
||
|
||||
response.headers["location"] != null // Generic reverse proxy
|
||||
||
|
||||
response.body
|
||||
.contains("301 Moved Permanently") // Poorly configured generic reverse proxy
|
||||
) &&
|
||||
!(useSSL ?? false)) {
|
||||
final oldUseSSL = useSSL;
|
||||
useSSL = true;
|
||||
try {
|
||||
|
@ -271,6 +274,35 @@ class Node extends HiveObject with Keyable {
|
|||
}
|
||||
}
|
||||
|
||||
Future<bool> requestNanoNode() async {
|
||||
try {
|
||||
final response = await http.post(
|
||||
uri,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"nano-app": "cake-wallet"
|
||||
},
|
||||
body: jsonEncode(
|
||||
{
|
||||
"action": "account_balance",
|
||||
"account": "nano_38713x95zyjsqzx6nm1dsom1jmm668owkeb9913ax6nfgj15az3nu8xkx579",
|
||||
},
|
||||
),
|
||||
);
|
||||
final data = await jsonDecode(response.body);
|
||||
if (response.statusCode != 200 ||
|
||||
data["error"] != null ||
|
||||
data["balance"] == null ||
|
||||
data["receivable"] == null) {
|
||||
throw Exception(
|
||||
"Error while trying to get balance! ${data["error"] != null ? data["error"] : ""}");
|
||||
}
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> requestEthereumServer() async {
|
||||
try {
|
||||
final response = await http.get(
|
||||
|
|
|
@ -3,36 +3,26 @@ import 'package:cw_core/wownero_amount_format.dart';
|
|||
|
||||
class WowneroBalance extends Balance {
|
||||
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||
: formattedFullBalance = wowneroAmountToString(amount: fullBalance),
|
||||
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
|
||||
formattedLockedBalance =
|
||||
wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
|
||||
: formattedUnconfirmedBalance = wowneroAmountToString(amount: fullBalance - unlockedBalance),
|
||||
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance),
|
||||
formattedFrozenBalance =
|
||||
wowneroAmountToString(amount: frozenBalance),
|
||||
super(unlockedBalance, fullBalance);
|
||||
|
||||
WowneroBalance.fromString(
|
||||
{required this.formattedFullBalance,
|
||||
required this.formattedUnlockedBalance,
|
||||
this.formattedLockedBalance = '0.0'})
|
||||
: fullBalance = wowneroParseAmount(amount: formattedFullBalance),
|
||||
unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
|
||||
frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
|
||||
super(wowneroParseAmount(amount: formattedUnlockedBalance),
|
||||
wowneroParseAmount(amount: formattedFullBalance));
|
||||
|
||||
final int fullBalance;
|
||||
final int unlockedBalance;
|
||||
final int frozenBalance;
|
||||
final String formattedFullBalance;
|
||||
final String formattedUnconfirmedBalance;
|
||||
final String formattedUnlockedBalance;
|
||||
final String formattedLockedBalance;
|
||||
final String formattedFrozenBalance;
|
||||
|
||||
@override
|
||||
String get formattedUnAvailableBalance =>
|
||||
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
|
||||
formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance => formattedFullBalance;
|
||||
String get formattedAdditionalBalance => formattedUnconfirmedBalance;
|
||||
}
|
|
@ -11,13 +11,12 @@ class EVMChainERC20Balance extends Balance {
|
|||
final int exponent;
|
||||
|
||||
@override
|
||||
String get formattedAdditionalBalance {
|
||||
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
|
||||
return formattedBalance.substring(0, min(12, formattedBalance.length));
|
||||
}
|
||||
String get formattedAdditionalBalance => _balance();
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance {
|
||||
String get formattedAvailableBalance => _balance();
|
||||
|
||||
String _balance() {
|
||||
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
|
||||
return formattedBalance.substring(0, min(12, formattedBalance.length));
|
||||
}
|
||||
|
|
|
@ -742,10 +742,19 @@ abstract class MoneroWalletBase
|
|||
int _getFrozenBalance() {
|
||||
var frozenBalance = 0;
|
||||
|
||||
for (var coin in unspentCoinsInfo.values.where((element) =>
|
||||
element.walletId == id && element.accountIndex == walletAddresses.account!.id)) {
|
||||
if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value;
|
||||
}
|
||||
unspentCoinsInfo.values.forEach((info) {
|
||||
unspentCoins.forEach((element) {
|
||||
if (element.hash == info.hash &&
|
||||
element.vout == info.vout &&
|
||||
info.isFrozen &&
|
||||
element.value == info.value &&
|
||||
info.walletId == id &&
|
||||
info.accountIndex == walletAddresses.account!.id) {
|
||||
if (element.isFrozen && !element.isSending) frozenBalance += element.value;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return frozenBalance;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,12 +54,12 @@ class NanoClient {
|
|||
}
|
||||
}
|
||||
|
||||
Map<String, String> getHeaders() {
|
||||
Map<String, String> getHeaders(String host) {
|
||||
final headers = Map<String, String>.from(CAKE_HEADERS);
|
||||
if (_node!.uri.host == "rpc.nano.to") {
|
||||
if (host == "rpc.nano.to") {
|
||||
headers["key"] = nano_secrets.nano2ApiKey;
|
||||
}
|
||||
if (_node!.uri.host == "nano.nownodes.io") {
|
||||
if (host == "nano.nownodes.io") {
|
||||
headers["api-key"] = nano_secrets.nanoNowNodesApiKey;
|
||||
}
|
||||
return headers;
|
||||
|
@ -68,7 +68,7 @@ class NanoClient {
|
|||
Future<NanoBalance> getBalance(String address) async {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode(
|
||||
{
|
||||
"action": "account_balance",
|
||||
|
@ -95,7 +95,7 @@ class NanoClient {
|
|||
try {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode(
|
||||
{
|
||||
"action": "account_info",
|
||||
|
@ -116,7 +116,7 @@ class NanoClient {
|
|||
try {
|
||||
final response = await http.post(
|
||||
_node!.uri,
|
||||
headers: CAKE_HEADERS,
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode(
|
||||
{
|
||||
"action": "block_info",
|
||||
|
@ -183,7 +183,7 @@ class NanoClient {
|
|||
Future<String> requestWork(String hash) async {
|
||||
final response = await http.post(
|
||||
_powNode!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_powNode!.uri.host),
|
||||
body: json.encode(
|
||||
{
|
||||
"action": "work_generate",
|
||||
|
@ -226,7 +226,7 @@ class NanoClient {
|
|||
|
||||
final processResponse = await http.post(
|
||||
_node!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: processBody,
|
||||
);
|
||||
|
||||
|
@ -425,7 +425,7 @@ class NanoClient {
|
|||
});
|
||||
final processResponse = await http.post(
|
||||
_node!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: processBody,
|
||||
);
|
||||
|
||||
|
@ -441,7 +441,7 @@ class NanoClient {
|
|||
required String privateKey,
|
||||
}) async {
|
||||
final receivableResponse = await http.post(_node!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "receivable",
|
||||
"account": destinationAddress,
|
||||
|
@ -493,7 +493,7 @@ class NanoClient {
|
|||
Future<List<NanoTransactionModel>> fetchTransactions(String address) async {
|
||||
try {
|
||||
final response = await http.post(_node!.uri,
|
||||
headers: getHeaders(),
|
||||
headers: getHeaders(_node!.uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "account_history",
|
||||
"account": address,
|
||||
|
@ -509,15 +509,16 @@ class NanoClient {
|
|||
.map<NanoTransactionModel>((transaction) => NanoTransactionModel.fromJson(transaction))
|
||||
.toList();
|
||||
} catch (e) {
|
||||
printV(e);
|
||||
return [];
|
||||
printV("error fetching transactions: $e");
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<N2Node>> getN2Reps() async {
|
||||
final uri = Uri.parse(N2_REPS_ENDPOINT);
|
||||
final response = await http.post(
|
||||
Uri.parse(N2_REPS_ENDPOINT),
|
||||
headers: CAKE_HEADERS,
|
||||
uri,
|
||||
headers: getHeaders(uri.host),
|
||||
body: jsonEncode({"action": "reps"}),
|
||||
);
|
||||
try {
|
||||
|
@ -531,9 +532,10 @@ class NanoClient {
|
|||
}
|
||||
|
||||
Future<int> getRepScore(String rep) async {
|
||||
final uri = Uri.parse(N2_REPS_ENDPOINT);
|
||||
final response = await http.post(
|
||||
Uri.parse(N2_REPS_ENDPOINT),
|
||||
headers: CAKE_HEADERS,
|
||||
uri,
|
||||
headers: getHeaders(uri.host),
|
||||
body: jsonEncode({
|
||||
"action": "rep_info",
|
||||
"account": rep,
|
||||
|
|
|
@ -21,22 +21,23 @@ class SolanaWalletClient {
|
|||
|
||||
bool connect(Node node) {
|
||||
try {
|
||||
Uri? rpcUri;
|
||||
String webSocketUrl;
|
||||
bool isModifiedNodeUri = false;
|
||||
Uri rpcUri = node.uri;
|
||||
String webSocketUrl = 'wss://${node.uriRaw}';
|
||||
|
||||
if (node.uriRaw == 'rpc.ankr.com') {
|
||||
isModifiedNodeUri = true;
|
||||
String ankrApiKey = secrets.ankrApiKey;
|
||||
|
||||
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
|
||||
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
|
||||
} else {
|
||||
webSocketUrl = 'wss://${node.uriRaw}';
|
||||
} else if (node.uriRaw == 'solana-mainnet.core.chainstack.com') {
|
||||
String chainStackApiKey = secrets.chainStackApiKey;
|
||||
|
||||
rpcUri = Uri.https(node.uriRaw, '/$chainStackApiKey');
|
||||
webSocketUrl = 'wss://${node.uriRaw}/$chainStackApiKey';
|
||||
}
|
||||
|
||||
_client = SolanaClient(
|
||||
rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri,
|
||||
rpcUrl: rpcUri,
|
||||
websocketUrl: Uri.parse(webSocketUrl),
|
||||
timeout: const Duration(minutes: 2),
|
||||
);
|
||||
|
@ -115,10 +116,14 @@ class SolanaWalletClient {
|
|||
final message =
|
||||
_getMessageForNativeTransaction(ownerKeypair, ownerKeypair.address, lamportsPerSol);
|
||||
|
||||
final recentBlockhash = await _getRecentBlockhash(commitment);
|
||||
final latestBlockhash = await _getLatestBlockhash(commitment);
|
||||
|
||||
final estimatedFee =
|
||||
_getFeeFromCompiledMessage(message, ownerKeypair.publicKey, recentBlockhash, commitment);
|
||||
final estimatedFee = _getFeeFromCompiledMessage(
|
||||
message,
|
||||
ownerKeypair.publicKey,
|
||||
latestBlockhash,
|
||||
commitment,
|
||||
);
|
||||
return estimatedFee;
|
||||
}
|
||||
|
||||
|
@ -131,13 +136,25 @@ class SolanaWalletClient {
|
|||
List<SolanaTransactionModel> transactions = [];
|
||||
|
||||
try {
|
||||
final response = await _client!.rpcClient.getTransactionsList(
|
||||
publicKey,
|
||||
final signatures = await _client!.rpcClient.getSignaturesForAddress(
|
||||
publicKey.toBase58(),
|
||||
commitment: Commitment.confirmed,
|
||||
limit: 1000,
|
||||
);
|
||||
|
||||
for (final tx in response) {
|
||||
final List<TransactionDetails> transactionDetails = [];
|
||||
for (int i = 0; i < signatures.length; i += 20) {
|
||||
final response = await _client!.rpcClient.getMultipleTransactions(
|
||||
signatures.sublist(i, math.min(i + 20, signatures.length)),
|
||||
commitment: Commitment.confirmed,
|
||||
encoding: Encoding.jsonParsed,
|
||||
);
|
||||
transactionDetails.addAll(response);
|
||||
|
||||
// to avoid reaching the node RPS limit
|
||||
await Future.delayed(Duration(milliseconds: 500));
|
||||
}
|
||||
|
||||
for (final tx in transactionDetails) {
|
||||
if (tx.transaction is ParsedTransaction) {
|
||||
final parsedTx = (tx.transaction as ParsedTransaction);
|
||||
final message = parsedTx.message;
|
||||
|
@ -310,16 +327,16 @@ class SolanaWalletClient {
|
|||
}
|
||||
}
|
||||
|
||||
Future<RecentBlockhash> _getRecentBlockhash(Commitment commitment) async {
|
||||
final latestBlockhash =
|
||||
Future<LatestBlockhash> _getLatestBlockhash(Commitment commitment) async {
|
||||
final latestBlockHashResult =
|
||||
await _client!.rpcClient.getLatestBlockhash(commitment: commitment).value;
|
||||
|
||||
final recentBlockhash = RecentBlockhash(
|
||||
blockhash: latestBlockhash.blockhash,
|
||||
feeCalculator: const FeeCalculator(lamportsPerSignature: 500),
|
||||
final latestBlockhash = LatestBlockhash(
|
||||
blockhash: latestBlockHashResult.blockhash,
|
||||
lastValidBlockHeight: latestBlockHashResult.lastValidBlockHeight,
|
||||
);
|
||||
|
||||
return recentBlockhash;
|
||||
return latestBlockhash;
|
||||
}
|
||||
|
||||
Message _getMessageForNativeTransaction(
|
||||
|
@ -342,11 +359,11 @@ class SolanaWalletClient {
|
|||
Future<double> _getFeeFromCompiledMessage(
|
||||
Message message,
|
||||
Ed25519HDPublicKey feePayer,
|
||||
RecentBlockhash recentBlockhash,
|
||||
LatestBlockhash latestBlockhash,
|
||||
Commitment commitment,
|
||||
) async {
|
||||
final compile = message.compile(
|
||||
recentBlockhash: recentBlockhash.blockhash,
|
||||
recentBlockhash: latestBlockhash.blockhash,
|
||||
feePayer: feePayer,
|
||||
);
|
||||
|
||||
|
@ -362,16 +379,18 @@ class SolanaWalletClient {
|
|||
required double solBalance,
|
||||
required double fee,
|
||||
}) async {
|
||||
final rent =
|
||||
await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed);
|
||||
|
||||
final rentInSol = (rent / lamportsPerSol).toDouble();
|
||||
|
||||
final remnant = solBalance - (inputAmount + fee);
|
||||
|
||||
if (remnant > rentInSol) return true;
|
||||
|
||||
return false;
|
||||
return true;
|
||||
// TODO: this is not doing what the name inclines
|
||||
// final rent =
|
||||
// await _client!.getMinimumBalanceForMintRentExemption(commitment: Commitment.confirmed);
|
||||
//
|
||||
// final rentInSol = (rent / lamportsPerSol).toDouble();
|
||||
//
|
||||
// final remnant = solBalance - (inputAmount + fee);
|
||||
//
|
||||
// if (remnant > rentInSol) return true;
|
||||
//
|
||||
// return false;
|
||||
}
|
||||
|
||||
Future<PendingSolanaTransaction> _signNativeTokenTransaction({
|
||||
|
@ -391,12 +410,12 @@ class SolanaWalletClient {
|
|||
|
||||
final signers = [ownerKeypair];
|
||||
|
||||
RecentBlockhash recentBlockhash = await _getRecentBlockhash(commitment);
|
||||
LatestBlockhash latestBlockhash = await _getLatestBlockhash(commitment);
|
||||
|
||||
final fee = await _getFeeFromCompiledMessage(
|
||||
message,
|
||||
signers.first.publicKey,
|
||||
recentBlockhash,
|
||||
latestBlockhash,
|
||||
commitment,
|
||||
);
|
||||
|
||||
|
@ -422,14 +441,14 @@ class SolanaWalletClient {
|
|||
message: updatedMessage,
|
||||
signers: signers,
|
||||
commitment: commitment,
|
||||
recentBlockhash: recentBlockhash,
|
||||
latestBlockhash: latestBlockhash,
|
||||
);
|
||||
} else {
|
||||
signedTx = await _signTransactionInternal(
|
||||
message: message,
|
||||
signers: signers,
|
||||
commitment: commitment,
|
||||
recentBlockhash: recentBlockhash,
|
||||
latestBlockhash: latestBlockhash,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -507,12 +526,12 @@ class SolanaWalletClient {
|
|||
|
||||
final signers = [ownerKeypair];
|
||||
|
||||
RecentBlockhash recentBlockhash = await _getRecentBlockhash(commitment);
|
||||
LatestBlockhash latestBlockhash = await _getLatestBlockhash(commitment);
|
||||
|
||||
final fee = await _getFeeFromCompiledMessage(
|
||||
message,
|
||||
signers.first.publicKey,
|
||||
recentBlockhash,
|
||||
latestBlockhash,
|
||||
commitment,
|
||||
);
|
||||
|
||||
|
@ -530,7 +549,7 @@ class SolanaWalletClient {
|
|||
message: message,
|
||||
signers: signers,
|
||||
commitment: commitment,
|
||||
recentBlockhash: recentBlockhash,
|
||||
latestBlockhash: latestBlockhash,
|
||||
);
|
||||
|
||||
sendTx() async => await sendTransaction(
|
||||
|
@ -552,9 +571,9 @@ class SolanaWalletClient {
|
|||
required Message message,
|
||||
required List<Ed25519HDKeyPair> signers,
|
||||
required Commitment commitment,
|
||||
required RecentBlockhash recentBlockhash,
|
||||
required LatestBlockhash latestBlockhash,
|
||||
}) async {
|
||||
final signedTx = await signTransaction(recentBlockhash, message, signers);
|
||||
final signedTx = await signTransaction(latestBlockhash, message, signers);
|
||||
|
||||
return signedTx;
|
||||
}
|
||||
|
|
|
@ -25,9 +25,7 @@ class SolanaSignNativeTokenTransactionRentException
|
|||
extends SignNativeTokenTransactionRentException {}
|
||||
|
||||
class SolanaCreateAssociatedTokenAccountException extends CreateAssociatedTokenAccountException {
|
||||
SolanaCreateAssociatedTokenAccountException(this.exceptionMessage);
|
||||
|
||||
final String exceptionMessage;
|
||||
SolanaCreateAssociatedTokenAccountException(super.errorMessage);
|
||||
}
|
||||
|
||||
class SolanaSignSPLTokenTransactionRentException extends SignSPLTokenTransactionRentException {}
|
||||
|
|
|
@ -11,7 +11,7 @@ environment:
|
|||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
solana: ^0.30.4
|
||||
solana: ^0.31.0+1
|
||||
cw_core:
|
||||
path: ../cw_core
|
||||
http: ^1.1.0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance/crypto_balance_widget.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
||||
class PayfuraBuyProvider {
|
||||
PayfuraBuyProvider({required SettingsStore settingsStore, required WalletBase wallet})
|
||||
: this._settingsStore = settingsStore,
|
||||
this._wallet = wallet;
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
final WalletBase _wallet;
|
||||
|
||||
static const _baseUrl = 'exchange.payfura.com';
|
||||
|
||||
Uri requestUrl() {
|
||||
return Uri.https(_baseUrl, '', <String, dynamic>{
|
||||
'apiKey': secrets.payfuraApiKey,
|
||||
'to': _wallet.currency.title,
|
||||
'from': _settingsStore.fiatCurrency.title,
|
||||
'walletAddress': '${_wallet.currency.title}:${_wallet.walletAddresses.address}',
|
||||
'mode': 'buy'
|
||||
});
|
||||
}
|
||||
}
|
|
@ -204,8 +204,8 @@ class CakePayApi {
|
|||
/// Get Vendors
|
||||
Future<List<CakePayVendor>> getVendors({
|
||||
required String apiKey,
|
||||
required String country,
|
||||
int? page,
|
||||
String? country,
|
||||
String? countryCode,
|
||||
String? search,
|
||||
List<String>? vendorIds,
|
||||
|
@ -230,6 +230,7 @@ class CakePayApi {
|
|||
|
||||
var headers = {
|
||||
'accept': 'application/json; charset=UTF-8',
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Authorization': 'Api-Key $apiKey',
|
||||
};
|
||||
|
||||
|
@ -240,14 +241,14 @@ class CakePayApi {
|
|||
'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}');
|
||||
}
|
||||
|
||||
final bodyJson = json.decode(response.body);
|
||||
final bodyJson = json.decode(utf8.decode(response.bodyBytes));
|
||||
|
||||
if (bodyJson is List<dynamic> && bodyJson.isEmpty) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return (bodyJson['results'] as List)
|
||||
.map((e) => CakePayVendor.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => CakePayVendor.fromJson(e as Map<String, dynamic>, country))
|
||||
.toList();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/entities/fiat_currency.dart';
|
||||
|
||||
class CakePayCard {
|
||||
|
@ -38,17 +36,11 @@ class CakePayCard {
|
|||
});
|
||||
|
||||
factory CakePayCard.fromJson(Map<String, dynamic> json) {
|
||||
|
||||
final name = stripHtmlIfNeeded(json['name'] as String? ?? '');
|
||||
final decodedName = fixEncoding(name);
|
||||
|
||||
final description = stripHtmlIfNeeded(json['description'] as String? ?? '');
|
||||
final decodedDescription = fixEncoding(description);
|
||||
|
||||
final termsAndConditions = stripHtmlIfNeeded(json['terms_and_conditions'] as String? ?? '');
|
||||
final decodedTermsAndConditions = fixEncoding(termsAndConditions);
|
||||
|
||||
final howToUse = stripHtmlIfNeeded(json['how_to_use'] as String? ?? '');
|
||||
final decodedHowToUse = fixEncoding(howToUse);
|
||||
|
||||
final fiatCurrency = FiatCurrency.deserialize(raw: json['currency_code'] as String? ?? '');
|
||||
|
||||
|
@ -59,10 +51,10 @@ class CakePayCard {
|
|||
|
||||
return CakePayCard(
|
||||
id: json['id'] as int? ?? 0,
|
||||
name: decodedName,
|
||||
description: decodedDescription,
|
||||
termsAndConditions: decodedTermsAndConditions,
|
||||
howToUse: decodedHowToUse,
|
||||
name: name,
|
||||
description: description,
|
||||
termsAndConditions: termsAndConditions,
|
||||
howToUse: howToUse,
|
||||
expiryAndValidity: json['expiry_and_validity'] as String?,
|
||||
cardImageUrl: json['card_image_url'] as String?,
|
||||
country: json['country'] as String?,
|
||||
|
@ -79,9 +71,4 @@ class CakePayCard {
|
|||
static String stripHtmlIfNeeded(String text) {
|
||||
return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ');
|
||||
}
|
||||
|
||||
static String fixEncoding(String text) {
|
||||
final bytes = latin1.encode(text);
|
||||
return utf8.decode(bytes, allowMalformed: true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ class CakePayService {
|
|||
|
||||
/// Get Vendors
|
||||
Future<List<CakePayVendor>> getVendors({
|
||||
required String country,
|
||||
int? page,
|
||||
String? country,
|
||||
String? countryCode,
|
||||
String? search,
|
||||
List<String>? vendorIds,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'cake_pay_card.dart';
|
||||
|
||||
class CakePayVendor {
|
||||
|
@ -7,7 +5,7 @@ class CakePayVendor {
|
|||
final String name;
|
||||
final bool unavailable;
|
||||
final String? cakeWarnings;
|
||||
final List<String> countries;
|
||||
final String country;
|
||||
final CakePayCard? card;
|
||||
|
||||
CakePayVendor({
|
||||
|
@ -15,37 +13,35 @@ class CakePayVendor {
|
|||
required this.name,
|
||||
required this.unavailable,
|
||||
this.cakeWarnings,
|
||||
required this.countries,
|
||||
required this.country,
|
||||
this.card,
|
||||
});
|
||||
|
||||
factory CakePayVendor.fromJson(Map<String, dynamic> json) {
|
||||
factory CakePayVendor.fromJson(Map<String, dynamic> json, String country) {
|
||||
final name = stripHtmlIfNeeded(json['name'] as String);
|
||||
final decodedName = fixEncoding(name);
|
||||
|
||||
var cardsJson = json['cards'] as List?;
|
||||
CakePayCard? firstCard;
|
||||
CakePayCard? cardForVendor;
|
||||
|
||||
if (cardsJson != null && cardsJson.isNotEmpty) {
|
||||
firstCard = CakePayCard.fromJson(cardsJson.first as Map<String, dynamic>);
|
||||
try {
|
||||
cardForVendor = CakePayCard.fromJson(cardsJson
|
||||
.where((element) => element['country'] == country)
|
||||
.first as Map<String, dynamic>);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
return CakePayVendor(
|
||||
id: json['id'] as int,
|
||||
name: decodedName,
|
||||
name: name,
|
||||
unavailable: json['unavailable'] as bool? ?? false,
|
||||
cakeWarnings: json['cake_warnings'] as String?,
|
||||
countries: List<String>.from(json['countries'] as List? ?? []),
|
||||
card: firstCard,
|
||||
country: country,
|
||||
card: cardForVendor,
|
||||
);
|
||||
}
|
||||
|
||||
static String stripHtmlIfNeeded(String text) {
|
||||
return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ');
|
||||
}
|
||||
|
||||
static String fixEncoding(String text) {
|
||||
final bytes = latin1.encode(text);
|
||||
return utf8.decode(bytes, allowMalformed: true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,25 +140,24 @@ abstract class Web3WalletServiceBase with Store {
|
|||
for (final cId in SolanaChainId.values) {
|
||||
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
|
||||
|
||||
Uri? rpcUri;
|
||||
String webSocketUrl;
|
||||
bool isModifiedNodeUri = false;
|
||||
Uri rpcUri = node.uri;
|
||||
String webSocketUrl = 'wss://${node.uriRaw}';
|
||||
|
||||
if (node.uriRaw == 'rpc.ankr.com') {
|
||||
isModifiedNodeUri = true;
|
||||
|
||||
//A better way to handle this instead of adding this to the general secrets?
|
||||
String ankrApiKey = secrets.ankrApiKey;
|
||||
|
||||
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
|
||||
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
|
||||
} else {
|
||||
webSocketUrl = 'wss://${node.uriRaw}';
|
||||
} else if (node.uriRaw == 'solana-mainnet.core.chainstack.com') {
|
||||
String chainStackApiKey = secrets.chainStackApiKey;
|
||||
|
||||
rpcUri = Uri.https(node.uriRaw, '/$chainStackApiKey');
|
||||
webSocketUrl = 'wss://${node.uriRaw}/$chainStackApiKey';
|
||||
}
|
||||
|
||||
SolanaChainServiceImpl(
|
||||
reference: cId,
|
||||
rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri,
|
||||
rpcUrl: rpcUri,
|
||||
webSocketUrl: webSocketUrl,
|
||||
wcKeyService: walletKeyService,
|
||||
bottomSheetService: _bottomSheetHandler,
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
|
|||
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
|
||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
|
||||
import 'package:cake_wallet/core/new_wallet_arguments.dart';
|
||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
|
@ -81,7 +80,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_wallet
|
|||
import 'package:cake_wallet/src/screens/dashboard/edit_token_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/home_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/address_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
|
||||
|
@ -1021,11 +1020,6 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactoryParam<WebViewPage, String, Uri>((title, uri) => WebViewPage(title, uri));
|
||||
|
||||
getIt.registerFactory<PayfuraBuyProvider>(() => PayfuraBuyProvider(
|
||||
settingsStore: getIt.get<AppStore>().settingsStore,
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
));
|
||||
|
||||
getIt.registerFactory(() => ExchangeViewModel(
|
||||
getIt.get<AppStore>(),
|
||||
_tradesSource,
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
|||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||
import 'package:cw_bitcoin/electrum_wallet.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/utils/print_verbose.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -236,26 +237,26 @@ Future<void> onStart(ServiceInstance service) async {
|
|||
// get all bitcoin wallets and add them:
|
||||
final List<WalletListItem> bitcoinWallets =
|
||||
walletListViewModel.wallets.where((element) => element.type == WalletType.bitcoin).toList();
|
||||
bool spSupported = true;
|
||||
for (int i = 0; i < bitcoinWallets.length; i++) {
|
||||
try {
|
||||
if (!spSupported) continue;
|
||||
final wallet =
|
||||
await walletLoadingService.load(bitcoinWallets[i].type, bitcoinWallets[i].name);
|
||||
final node = settingsStore.getCurrentNode(WalletType.bitcoin);
|
||||
var node = settingsStore.getCurrentNode(WalletType.bitcoin);
|
||||
await wallet.connectToNode(node: node);
|
||||
|
||||
bool nodeSupportsSP = await (wallet as ElectrumWallet).getNodeSupportsSilentPayments();
|
||||
if (!nodeSupportsSP) {
|
||||
printV("Configured node does not support silent payments, skipping wallet");
|
||||
setWalletNotification(
|
||||
flutterLocalNotificationsPlugin,
|
||||
title: initialNotificationTitle,
|
||||
content: spNodeNotificationMessage,
|
||||
walletNum: syncingWallets.length + 1,
|
||||
);
|
||||
spSupported = false;
|
||||
continue;
|
||||
// printV("Configured node does not support silent payments, skipping wallet");
|
||||
// setWalletNotification(
|
||||
// flutterLocalNotificationsPlugin,
|
||||
// title: initialNotificationTitle,
|
||||
// content: spNodeNotificationMessage,
|
||||
// walletNum: syncingWallets.length + 1,
|
||||
// );
|
||||
// spSupported = false;
|
||||
// continue;
|
||||
node = Node(uri: "electrs.cakewallet.com:50001");
|
||||
await wallet.connectToNode(node: node);
|
||||
}
|
||||
|
||||
await wallet.stopSync();
|
||||
|
|
|
@ -35,12 +35,12 @@ const publicBitcoinTestnetElectrumUri =
|
|||
'$publicBitcoinTestnetElectrumAddress:$publicBitcoinTestnetElectrumPort';
|
||||
const cakeWalletLitecoinElectrumUri = 'ltc-electrum.cakewallet.com:50002';
|
||||
const havenDefaultNodeUri = 'nodes.havenprotocol.org:443';
|
||||
const ethereumDefaultNodeUri = 'ethereum.publicnode.com';
|
||||
const polygonDefaultNodeUri = 'polygon-bor.publicnode.com';
|
||||
const ethereumDefaultNodeUri = 'ethereum-rpc.publicnode.com';
|
||||
const polygonDefaultNodeUri = 'polygon-bor-rpc.publicnode.com';
|
||||
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
|
||||
const nanoDefaultNodeUri = 'nano.nownodes.io';
|
||||
const nanoDefaultPowNodeUri = 'rpc.nano.to';
|
||||
const solanaDefaultNodeUri = 'solana-rpc.publicnode.com:443';
|
||||
const solanaDefaultNodeUri = 'solana-mainnet.core.chainstack.com';
|
||||
const tronDefaultNodeUri = 'api.trongrid.io';
|
||||
const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
|
||||
const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
||||
|
@ -347,6 +347,31 @@ Future<void> defaultSettingsMigration(
|
|||
type: WalletType.litecoin,
|
||||
useSSL: true,
|
||||
);
|
||||
_changeDefaultNode(
|
||||
nodes: nodes,
|
||||
sharedPreferences: sharedPreferences,
|
||||
type: WalletType.solana,
|
||||
newDefaultUri: solanaDefaultNodeUri,
|
||||
currentNodePreferenceKey: PreferencesKey.currentSolanaNodeIdKey,
|
||||
useSSL: true,
|
||||
oldUri: [
|
||||
'rpc.ankr.com',
|
||||
'api.mainnet-beta.solana.com:443',
|
||||
'solana-rpc.publicnode.com:443',
|
||||
],
|
||||
);
|
||||
_updateNode(
|
||||
nodes: nodes,
|
||||
currentUri: "ethereum.publicnode.com",
|
||||
newUri: "ethereum-rpc.publicnode.com",
|
||||
useSSL: true,
|
||||
);
|
||||
_updateNode(
|
||||
nodes: nodes,
|
||||
currentUri: "polygon-bor.publicnode.com",
|
||||
newUri: "polygon-bor-rpc.publicnode.com",
|
||||
useSSL: true,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -362,6 +387,24 @@ Future<void> defaultSettingsMigration(
|
|||
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
|
||||
}
|
||||
|
||||
void _updateNode({
|
||||
required Box<Node> nodes,
|
||||
required String currentUri,
|
||||
String? newUri,
|
||||
bool? useSSL,
|
||||
}) {
|
||||
for (Node node in nodes.values) {
|
||||
if (node.uriRaw == currentUri) {
|
||||
if (newUri != null) {
|
||||
node.uriRaw = newUri;
|
||||
}
|
||||
if (useSSL != null) {
|
||||
node.useSSL = useSSL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _backupHavenSeeds(Box<HavenSeedStore> havenSeedStore) async {
|
||||
final future = haven?.backupHavenSeeds(havenSeedStore);
|
||||
if (future != null) {
|
||||
|
@ -462,7 +505,7 @@ Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
|
|||
];
|
||||
// add new nodes:
|
||||
for (final node in nodeList) {
|
||||
if (listOfNewEndpoints.contains(node.uriRaw)) {
|
||||
if (listOfNewEndpoints.contains(node.uriRaw) && !nodes.values.contains(node)) {
|
||||
await nodes.add(node);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
|||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/menu_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/action_button.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
|
|
|
@ -8,7 +8,7 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
|
|||
import 'package:cake_wallet/utils/version_comparator.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance_page.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_page.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/router.dart' as Router;
|
||||
|
|
88
lib/src/screens/dashboard/pages/balance/balance_page.dart
Normal file
88
lib/src/screens/dashboard/pages/balance/balance_page.dart
Normal file
|
@ -0,0 +1,88 @@
|
|||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance/crypto_balance_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/nft_listing_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class BalancePage extends StatelessWidget {
|
||||
BalancePage({
|
||||
required this.dashboardViewModel,
|
||||
required this.settingsStore,
|
||||
required this.nftViewModel,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
final NFTViewModel nftViewModel;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) {
|
||||
final isEVMCompatible = isEVMCompatibleChain(dashboardViewModel.type);
|
||||
return DefaultTabController(
|
||||
length: isEVMCompatible ? 2 : 1,
|
||||
child: Column(
|
||||
children: [
|
||||
if (isEVMCompatible)
|
||||
Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 8),
|
||||
child: TabBar(
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
isScrollable: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
labelStyle: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
unselectedLabelStyle: TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
labelColor:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
dividerColor: Colors.transparent,
|
||||
indicatorColor:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
unselectedLabelColor: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.pageTitleTextColor
|
||||
.withOpacity(0.5),
|
||||
tabAlignment: TabAlignment.start,
|
||||
tabs: [
|
||||
Tab(text: 'My Crypto'),
|
||||
Tab(text: 'My NFTs'),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
children: [
|
||||
CryptoBalanceWidget(dashboardViewModel: dashboardViewModel),
|
||||
if (isEVMCompatible) NFTListingPage(nftViewModel: nftViewModel)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
654
lib/src/screens/dashboard/pages/balance/balance_row_widget.dart
Normal file
654
lib/src/screens/dashboard/pages/balance/balance_row_widget.dart
Normal file
|
@ -0,0 +1,654 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.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/crypto_currency.dart';
|
||||
import 'package:cw_core/unspent_coin_type.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class BalanceRowWidget extends StatelessWidget {
|
||||
BalanceRowWidget({
|
||||
required this.availableBalanceLabel,
|
||||
required this.availableBalance,
|
||||
required this.availableFiatBalance,
|
||||
required this.additionalBalanceLabel,
|
||||
required this.additionalBalance,
|
||||
required this.additionalFiatBalance,
|
||||
required this.secondAvailableBalanceLabel,
|
||||
required this.secondAvailableBalance,
|
||||
required this.secondAvailableFiatBalance,
|
||||
required this.secondAdditionalBalanceLabel,
|
||||
required this.secondAdditionalBalance,
|
||||
required this.secondAdditionalFiatBalance,
|
||||
required this.frozenBalance,
|
||||
required this.frozenFiatBalance,
|
||||
required this.currency,
|
||||
required this.hasAdditionalBalance,
|
||||
required this.hasSecondAvailableBalance,
|
||||
required this.hasSecondAdditionalBalance,
|
||||
required this.isTestnet,
|
||||
required this.dashboardViewModel,
|
||||
super.key,
|
||||
});
|
||||
|
||||
final String availableBalanceLabel;
|
||||
final String availableBalance;
|
||||
final String availableFiatBalance;
|
||||
final String additionalBalanceLabel;
|
||||
final String additionalBalance;
|
||||
final String additionalFiatBalance;
|
||||
final String secondAvailableBalanceLabel;
|
||||
final String secondAvailableBalance;
|
||||
final String secondAvailableFiatBalance;
|
||||
final String secondAdditionalBalanceLabel;
|
||||
final String secondAdditionalBalance;
|
||||
final String secondAdditionalFiatBalance;
|
||||
final String frozenBalance;
|
||||
final String frozenFiatBalance;
|
||||
final CryptoCurrency currency;
|
||||
final bool hasAdditionalBalance;
|
||||
final bool hasSecondAvailableBalance;
|
||||
final bool hasSecondAdditionalBalance;
|
||||
final bool isTestnet;
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 16, right: 16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
||||
),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: hasAdditionalBalance
|
||||
? () => _showBalanceDescription(
|
||||
context, S.of(context).available_balance_description)
|
||||
: null,
|
||||
child: Row(
|
||||
children: [
|
||||
Semantics(
|
||||
hint: 'Double tap to see more information',
|
||||
container: true,
|
||||
child: Text('${availableBalanceLabel}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1)),
|
||||
),
|
||||
if (hasAdditionalBalance)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 6),
|
||||
AutoSizeText(availableBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.balanceAmountColor,
|
||||
height: 1),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.start),
|
||||
SizedBox(height: 6),
|
||||
if (isTestnet)
|
||||
Text(S.of(context).testnet_coins_no_value,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1)),
|
||||
if (!isTestnet)
|
||||
Text('${availableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1)),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: min(MediaQuery.of(context).size.width * 0.2, 100),
|
||||
child: Center(
|
||||
child: Column(
|
||||
children: [
|
||||
CakeImageWidget(
|
||||
imageUrl: currency.iconPath,
|
||||
height: 40,
|
||||
width: 40,
|
||||
displayOnError: Container(
|
||||
height: 30.0,
|
||||
width: 30.0,
|
||||
child: Center(
|
||||
child: Text(
|
||||
currency.title.substring(0, min(currency.title.length, 2)),
|
||||
style: TextStyle(fontSize: 11),
|
||||
),
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Colors.grey.shade400,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
currency.title,
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (frozenBalance.isNotEmpty)
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: hasAdditionalBalance
|
||||
? () => _showBalanceDescription(
|
||||
context, S.of(context).unavailable_balance_description)
|
||||
: null,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 26),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).unavailable_balance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
frozenBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.balanceAmountColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
frozenFiatBalance,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (hasAdditionalBalance)
|
||||
GestureDetector(
|
||||
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24),
|
||||
Text(
|
||||
'${additionalBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
additionalBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${additionalFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
if (hasSecondAdditionalBalance || hasSecondAvailableBalance) ...[
|
||||
SizedBox(height: 10),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 16, right: 16),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
||||
),
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 16, left: 24, right: 8, bottom: 16),
|
||||
child: Stack(
|
||||
children: [
|
||||
if (currency == CryptoCurrency.ltc)
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.only(right: 16, top: 0),
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
child: ImageIcon(
|
||||
AssetImage('assets/images/mweb_logo.png'),
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
'MWEB',
|
||||
style: TextStyle(
|
||||
fontSize: 15,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w800,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (hasSecondAvailableBalance)
|
||||
GestureDetector(
|
||||
onTap: () => dashboardViewModel.balanceViewModel.switchBalanceValue(),
|
||||
child: Row(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => launchUrl(
|
||||
Uri.parse(
|
||||
"https://docs.cakewallet.com/cryptos/litecoin.html#mweb"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
'${secondAvailableBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
secondAvailableBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 6),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${secondAvailableFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(top: 0, left: 24, right: 8, bottom: 16),
|
||||
child: Stack(
|
||||
children: [
|
||||
if (hasSecondAdditionalBalance)
|
||||
Row(
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(height: 24),
|
||||
Text(
|
||||
'${secondAdditionalBalanceLabel}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
AutoSizeText(
|
||||
secondAdditionalBalance,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
if (!isTestnet)
|
||||
Text(
|
||||
'${secondAdditionalFiatBalance}',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
IntrinsicHeight(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Semantics(
|
||||
label: S.of(context).litecoin_mweb_pegin,
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
final mwebAddress =
|
||||
bitcoin!.getUnusedMwebAddress(dashboardViewModel.wallet);
|
||||
PaymentRequest? paymentRequest = null;
|
||||
if ((mwebAddress?.isNotEmpty ?? false)) {
|
||||
paymentRequest = PaymentRequest.fromUri(
|
||||
Uri.parse("litecoin:${mwebAddress}"));
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.send,
|
||||
arguments: {
|
||||
'paymentRequest': paymentRequest,
|
||||
'coinTypeToSpendFrom': UnspentCoinType.nonMweb,
|
||||
},
|
||||
);
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: Colors.grey.shade400.withAlpha(50),
|
||||
side: BorderSide(
|
||||
color: Colors.grey.shade400.withAlpha(50), width: 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
height: 30,
|
||||
width: 30,
|
||||
'assets/images/received.png',
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.balanceAmountColor,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
S.of(context).litecoin_mweb_pegin,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.textColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 24),
|
||||
Expanded(
|
||||
child: Semantics(
|
||||
label: S.of(context).litecoin_mweb_pegout,
|
||||
child: OutlinedButton(
|
||||
onPressed: () {
|
||||
final litecoinAddress =
|
||||
bitcoin!.getUnusedSegwitAddress(dashboardViewModel.wallet);
|
||||
PaymentRequest? paymentRequest = null;
|
||||
if ((litecoinAddress?.isNotEmpty ?? false)) {
|
||||
paymentRequest = PaymentRequest.fromUri(
|
||||
Uri.parse("litecoin:${litecoinAddress}"));
|
||||
}
|
||||
Navigator.pushNamed(
|
||||
context,
|
||||
Routes.send,
|
||||
arguments: {
|
||||
'paymentRequest': paymentRequest,
|
||||
'coinTypeToSpendFrom': UnspentCoinType.mweb,
|
||||
},
|
||||
);
|
||||
},
|
||||
style: OutlinedButton.styleFrom(
|
||||
backgroundColor: Colors.grey.shade400.withAlpha(50),
|
||||
side: BorderSide(
|
||||
color: Colors.grey.shade400.withAlpha(50), width: 0),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(vertical: 12),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Image.asset(
|
||||
height: 30,
|
||||
width: 30,
|
||||
'assets/images/upload.png',
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.balanceAmountColor,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
S.of(context).litecoin_mweb_pegout,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.textColor,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 16),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _showBalanceDescription(BuildContext context, String content) {
|
||||
showPopUp<void>(context: context, builder: (_) => InformationPage(information: content));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,424 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/pages/balance/balance_row_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/home_screen_account_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_switch.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class CryptoBalanceWidget extends StatelessWidget {
|
||||
const CryptoBalanceWidget({
|
||||
super.key,
|
||||
required this.dashboardViewModel,
|
||||
});
|
||||
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (dashboardViewModel.getMoneroError != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: "Invalid monero bindings",
|
||||
subTitle: dashboardViewModel.getMoneroError.toString(),
|
||||
onTap: () {},
|
||||
),
|
||||
);
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (dashboardViewModel.getWowneroError != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: "Invalid wownero bindings",
|
||||
subTitle: dashboardViewModel.getWowneroError.toString(),
|
||||
onTap: () {},
|
||||
));
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => dashboardViewModel.balanceViewModel.hasAccounts
|
||||
? HomeScreenAccountWidget(
|
||||
walletName: dashboardViewModel.name, accountName: dashboardViewModel.subname)
|
||||
: Column(
|
||||
children: [
|
||||
SizedBox(height: 16),
|
||||
Container(
|
||||
margin: const EdgeInsets.only(left: 24, bottom: 16),
|
||||
child: Observer(
|
||||
builder: (_) {
|
||||
return Row(
|
||||
children: [
|
||||
Text(
|
||||
dashboardViewModel.balanceViewModel.asset,
|
||||
style: TextStyle(
|
||||
fontSize: 24,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.pageTitleTextColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (dashboardViewModel.wallet.isHardwareWallet)
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Image.asset(
|
||||
'assets/images/hardware_wallet/ledger_nano_x.png',
|
||||
width: 24,
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.pageTitleTextColor,
|
||||
),
|
||||
),
|
||||
if (dashboardViewModel
|
||||
.balanceViewModel.isHomeScreenSettingsEnabled)
|
||||
InkWell(
|
||||
onTap: () => Navigator.pushNamed(context, Routes.homeSettings,
|
||||
arguments: dashboardViewModel.balanceViewModel),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Image.asset(
|
||||
'assets/images/home_screen_settings_icon.png',
|
||||
color: Theme.of(context)
|
||||
.extension<DashboardPageTheme>()!
|
||||
.pageTitleTextColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
if (dashboardViewModel.balanceViewModel.isShowCard && FeatureFlag.isCakePayEnabled) {
|
||||
return IntroducingCard(
|
||||
title: S.of(context).introducing_cake_pay,
|
||||
subTitle: S.of(context).cake_pay_learn_more,
|
||||
borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
closeCard: dashboardViewModel.balanceViewModel.disableIntroCakePayCard);
|
||||
}
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
Observer(builder: (_) {
|
||||
if (!dashboardViewModel.showRepWarning) {
|
||||
return const SizedBox();
|
||||
}
|
||||
return Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
title: S.of(context).rep_warning,
|
||||
subTitle: S.of(context).rep_warning_sub,
|
||||
onTap: () => Navigator.of(context).pushNamed(Routes.changeRep),
|
||||
onClose: () {
|
||||
dashboardViewModel.settingsStore.shouldShowRepWarning = false;
|
||||
},
|
||||
),
|
||||
);
|
||||
}),
|
||||
Observer(
|
||||
builder: (_) {
|
||||
return ListView.separated(
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
separatorBuilder: (_, __) => Container(padding: EdgeInsets.only(bottom: 8)),
|
||||
itemCount: dashboardViewModel.balanceViewModel.formattedBalances.length,
|
||||
itemBuilder: (__, index) {
|
||||
final balance =
|
||||
dashboardViewModel.balanceViewModel.formattedBalances.elementAt(index);
|
||||
return Observer(builder: (_) {
|
||||
return BalanceRowWidget(
|
||||
dashboardViewModel: dashboardViewModel,
|
||||
availableBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.availableBalanceLabel}',
|
||||
availableBalance: balance.availableBalance,
|
||||
availableFiatBalance: balance.fiatAvailableBalance,
|
||||
additionalBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.additionalBalanceLabel}',
|
||||
additionalBalance: balance.additionalBalance,
|
||||
additionalFiatBalance: balance.fiatAdditionalBalance,
|
||||
frozenBalance: balance.frozenBalance,
|
||||
frozenFiatBalance: balance.fiatFrozenBalance,
|
||||
currency: balance.asset,
|
||||
hasAdditionalBalance:
|
||||
dashboardViewModel.balanceViewModel.hasAdditionalBalance,
|
||||
hasSecondAdditionalBalance:
|
||||
dashboardViewModel.balanceViewModel.hasSecondAdditionalBalance,
|
||||
hasSecondAvailableBalance:
|
||||
dashboardViewModel.balanceViewModel.hasSecondAvailableBalance,
|
||||
secondAdditionalBalance: balance.secondAdditionalBalance,
|
||||
secondAdditionalFiatBalance: balance.fiatSecondAdditionalBalance,
|
||||
secondAvailableBalance: balance.secondAvailableBalance,
|
||||
secondAvailableFiatBalance: balance.fiatSecondAvailableBalance,
|
||||
secondAdditionalBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.secondAdditionalBalanceLabel}',
|
||||
secondAvailableBalanceLabel:
|
||||
'${dashboardViewModel.balanceViewModel.secondAvailableBalanceLabel}',
|
||||
isTestnet: dashboardViewModel.isTestnet,
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
Observer(builder: (context) {
|
||||
return Column(
|
||||
children: [
|
||||
if (dashboardViewModel.isMoneroWalletBrokenReasons.isNotEmpty) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: "This wallet has encountered an issue",
|
||||
subTitle: "Here are the things that you should note:\n - " +
|
||||
dashboardViewModel.isMoneroWalletBrokenReasons.join("\n - ") +
|
||||
"\n\nPlease restart your wallet and if it doesn't help contact our support.",
|
||||
onTap: () {},
|
||||
))
|
||||
],
|
||||
if (dashboardViewModel.showSilentPaymentsCard) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: S.of(context).silent_payments,
|
||||
subTitle: S.of(context).enable_silent_payments_scanning,
|
||||
hint: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => launchUrl(
|
||||
Uri.parse(
|
||||
"https://docs.cakewallet.com/cryptos/bitcoin#silent-payments"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).what_is_silent_payments,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
softWrap: true,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: Icon(Icons.help_outline,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<BalancePageTheme>()!
|
||||
.labelTextColor),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => StandardSwitch(
|
||||
value: dashboardViewModel.silentPaymentsScanningActive,
|
||||
onTaped: () => _toggleSilentPaymentsScanning(context),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => _toggleSilentPaymentsScanning(context),
|
||||
icon: Icon(
|
||||
Icons.lock,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.pageTitleTextColor,
|
||||
size: 50,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
if (dashboardViewModel.showMwebCard) ...[
|
||||
SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: DashBoardRoundedCardWidget(
|
||||
customBorder: 30,
|
||||
title: S.of(context).litecoin_mweb,
|
||||
subTitle: S.of(context).litecoin_mweb_description,
|
||||
hint: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => launchUrl(
|
||||
Uri.parse("https://docs.cakewallet.com/cryptos/litecoin/#mweb"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
child: Text(
|
||||
S.of(context).learn_more,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
|
||||
height: 1,
|
||||
),
|
||||
softWrap: true,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => _dismissMweb(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Theme.of(context).primaryColor,
|
||||
),
|
||||
child: Text(
|
||||
S.of(context).litecoin_mweb_dismiss,
|
||||
style: TextStyle(color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => _enableMweb(context),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.white,
|
||||
foregroundColor: Colors.black,
|
||||
),
|
||||
child: Text(
|
||||
S.of(context).enable,
|
||||
maxLines: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => {},
|
||||
icon: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: ImageIcon(
|
||||
AssetImage('assets/images/mweb_logo.png'),
|
||||
color: Color.fromARGB(255, 11, 70, 129),
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _toggleSilentPaymentsScanning(BuildContext context) async {
|
||||
final isSilentPaymentsScanningActive = dashboardViewModel.silentPaymentsScanningActive;
|
||||
final newValue = !isSilentPaymentsScanningActive;
|
||||
|
||||
dashboardViewModel.silentPaymentsScanningActive = newValue;
|
||||
|
||||
final needsToSwitch = !isSilentPaymentsScanningActive &&
|
||||
await bitcoin!.getNodeIsElectrsSPEnabled(dashboardViewModel.wallet) == false;
|
||||
|
||||
if (needsToSwitch) {
|
||||
return showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_current_node_title,
|
||||
alertContent: S.of(context).confirm_silent_payments_switch_node,
|
||||
rightButtonText: S.of(context).confirm,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
actionRightButton: () {
|
||||
dashboardViewModel.setSilentPaymentsScanning(newValue);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
actionLeftButton: () {
|
||||
dashboardViewModel.silentPaymentsScanningActive = isSilentPaymentsScanningActive;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
return dashboardViewModel.setSilentPaymentsScanning(newValue);
|
||||
}
|
||||
|
||||
Future<void> _enableMweb(BuildContext context) async {
|
||||
if (!dashboardViewModel.hasEnabledMwebBefore) {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertWithOneAction(
|
||||
alertTitle: S.of(context).alert_notice,
|
||||
alertContent: S.of(context).litecoin_mweb_warning,
|
||||
buttonText: S.of(context).understand,
|
||||
buttonAction: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
));
|
||||
}
|
||||
dashboardViewModel.setMwebEnabled();
|
||||
}
|
||||
|
||||
Future<void> _dismissMweb(BuildContext context) async {
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) => AlertWithOneAction(
|
||||
alertTitle: S.of(context).alert_notice,
|
||||
alertContent: S.of(context).litecoin_mweb_enable_later,
|
||||
buttonText: S.of(context).understand,
|
||||
buttonAction: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
));
|
||||
dashboardViewModel.dismissMweb();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -20,7 +20,8 @@ class SeedVerificationPage extends BasePage {
|
|||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: walletSeedViewModel.isVerificationComplete
|
||||
child: walletSeedViewModel.isVerificationComplete ||
|
||||
walletSeedViewModel.verificationIndices.isEmpty
|
||||
? SeedVerificationSuccessView(
|
||||
imageColor: titleColor(context),
|
||||
)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
|
||||
class FeatureFlag {
|
||||
static const bool isCakePayEnabled = false;
|
||||
static const bool isExolixEnabled = true;
|
||||
static const bool isInAppTorEnabled = false;
|
||||
static const bool isBackgroundSyncEnabled = true;
|
||||
static const int verificationWordsCount = 2;
|
||||
static const int verificationWordsCount = kDebugMode ? 0 : 2;
|
||||
}
|
|
@ -158,17 +158,17 @@ abstract class BalanceViewModelBase with Store {
|
|||
case WalletType.banano:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.none:
|
||||
return S.current.xmr_available_balance;
|
||||
default:
|
||||
return S.current.confirmed;
|
||||
}
|
||||
}
|
||||
|
||||
@computed
|
||||
String get additionalBalanceLabel {
|
||||
switch (wallet.type) {
|
||||
case WalletType.monero:
|
||||
case WalletType.wownero:
|
||||
case WalletType.haven:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.polygon:
|
||||
|
@ -357,7 +357,12 @@ abstract class BalanceViewModelBase with Store {
|
|||
bool mwebEnabled = false;
|
||||
|
||||
@computed
|
||||
bool get hasAdditionalBalance => _hasAdditionalBalanceForWalletType(wallet.type);
|
||||
bool get hasAdditionalBalance {
|
||||
bool isWalletTypeActivated = _hasAdditionalBalanceForWalletType(wallet.type);
|
||||
bool isNotZeroAmount = additionalBalance != "0.0";
|
||||
|
||||
return isWalletTypeActivated && isNotZeroAmount;
|
||||
}
|
||||
|
||||
@computed
|
||||
bool get hasSecondAdditionalBalance =>
|
||||
|
@ -373,6 +378,9 @@ abstract class BalanceViewModelBase with Store {
|
|||
case WalletType.polygon:
|
||||
case WalletType.solana:
|
||||
case WalletType.tron:
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.bitcoinCash:
|
||||
case WalletType.litecoin:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
|
|
|
@ -680,7 +680,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
|||
}
|
||||
|
||||
if (error is CreateAssociatedTokenAccountException) {
|
||||
return S.current.solana_create_associated_token_account_exception;
|
||||
return "${S.current.solana_create_associated_token_account_exception}\n\n${error.errorMessage}";
|
||||
}
|
||||
|
||||
if (error is SignSPLTokenTransactionRentException) {
|
||||
|
|
|
@ -29,6 +29,7 @@ abstract class WalletSeedViewModelBase with Store {
|
|||
List<String> get seedSplit => seed.split(RegExp(r'\s+'));
|
||||
|
||||
int get columnCount => seedSplit.length <= 16 ? 2 : 3;
|
||||
|
||||
double get columnAspectRatio => seedSplit.length <= 16 ? 1.8 : 2.8;
|
||||
|
||||
/// The indices of the seed to be verified.
|
||||
|
@ -60,8 +61,10 @@ abstract class WalletSeedViewModelBase with Store {
|
|||
bool isVerificationComplete = false;
|
||||
|
||||
void setupSeedVerification() {
|
||||
generateRandomIndices();
|
||||
generateOptions();
|
||||
if (verificationWordCount != 0) {
|
||||
generateRandomIndices();
|
||||
generateOptions();
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the indices of the seeds to be verified.
|
||||
|
|
|
@ -109,7 +109,7 @@ dependencies:
|
|||
flutter_svg: ^2.0.9
|
||||
polyseed: ^0.0.6
|
||||
nostr_tools: ^1.0.9
|
||||
solana: ^0.30.1
|
||||
solana: ^0.31.0+1
|
||||
ledger_flutter_plus: ^1.4.1
|
||||
hashlib: ^1.19.2
|
||||
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "تجميد",
|
||||
"frequently_asked_questions": "الأسئلة الشائعة",
|
||||
"frozen": "مجمدة",
|
||||
"frozen_balance": "التوازن المجمد",
|
||||
"full_balance": "الرصيد الكامل",
|
||||
"gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
|
||||
"generate_name": "توليد الاسم",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Замразяване",
|
||||
"frequently_asked_questions": "Често задавани въпроси",
|
||||
"frozen": "Замразени",
|
||||
"frozen_balance": "Замразен баланс",
|
||||
"full_balance": "Пълен баланс",
|
||||
"gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
|
||||
"generate_name": "Генериране на име",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Zmrazit",
|
||||
"frequently_asked_questions": "Často kladené otázky",
|
||||
"frozen": "Zmraženo",
|
||||
"frozen_balance": "Zmrazená rovnováha",
|
||||
"full_balance": "Celkový zůstatek",
|
||||
"gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
|
||||
"generate_name": "Generovat jméno",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Einfrieren",
|
||||
"frequently_asked_questions": "Häufig gestellte Fragen",
|
||||
"frozen": "Gefroren",
|
||||
"frozen_balance": "Gefrorenes Gleichgewicht",
|
||||
"full_balance": "Gesamtguthaben",
|
||||
"gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
|
||||
"generate_name": "Namen generieren",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Freeze",
|
||||
"frequently_asked_questions": "Frequently asked questions",
|
||||
"frozen": "Frozen",
|
||||
"frozen_balance": "Frozen Balance",
|
||||
"full_balance": "Full Balance",
|
||||
"gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
|
||||
"generate_name": "Generate Name",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Congelar",
|
||||
"frequently_asked_questions": "Preguntas frecuentes",
|
||||
"frozen": "Congelada",
|
||||
"frozen_balance": "Equilibrio congelado",
|
||||
"full_balance": "Balance completo",
|
||||
"gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
|
||||
"generate_name": "Generar nombre",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Geler",
|
||||
"frequently_asked_questions": "Foire aux questions",
|
||||
"frozen": "Gelées",
|
||||
"frozen_balance": "Équilibre gelé",
|
||||
"full_balance": "Solde Complet",
|
||||
"gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
|
||||
"generate_name": "Générer un nom",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Daskare",
|
||||
"frequently_asked_questions": "Tambayoyin da ake yawan yi",
|
||||
"frozen": "Daskararre",
|
||||
"frozen_balance": "Daidaituwa mai sanyi",
|
||||
"full_balance": "DUKAN KUDI",
|
||||
"gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
|
||||
"generate_name": "Ƙirƙirar Suna",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "फ्रीज",
|
||||
"frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न",
|
||||
"frozen": "जमा हुआ",
|
||||
"frozen_balance": "जमे हुए संतुलन",
|
||||
"full_balance": "पूर्ण संतुलन",
|
||||
"gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
|
||||
"generate_name": "नाम जनरेट करें",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Zamrznuti",
|
||||
"frequently_asked_questions": "Često postavljana pitanja",
|
||||
"frozen": "Smrznuto",
|
||||
"frozen_balance": "Smrznuta ravnoteža",
|
||||
"full_balance": "Pun iznos",
|
||||
"gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
|
||||
"generate_name": "Generiraj ime",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Կասեցնել",
|
||||
"frequently_asked_questions": "Հաճախ տրվող հարցեր",
|
||||
"frozen": "Կասեցված",
|
||||
"frozen_balance": "Սառեցված հավասարակշռություն",
|
||||
"full_balance": "Լրիվ մնացորդ",
|
||||
"gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
|
||||
"generate_name": "Գեներացնել անուն",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Freeze",
|
||||
"frequently_asked_questions": "Pertanyaan yang sering diajukan",
|
||||
"frozen": "Dibekukan",
|
||||
"frozen_balance": "Keseimbangan beku",
|
||||
"full_balance": "Saldo Penuh",
|
||||
"gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
|
||||
"generate_name": "Hasilkan Nama",
|
||||
|
|
|
@ -334,6 +334,7 @@
|
|||
"freeze": "Congelare",
|
||||
"frequently_asked_questions": "Domande frequenti",
|
||||
"frozen": "Congelato",
|
||||
"frozen_balance": "Equilibrio congelato",
|
||||
"full_balance": "Saldo Completo",
|
||||
"gas_exceeds_allowance": "Il gas richiesto dalla transazione supera l'indennità.",
|
||||
"generate_name": "Genera nome",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "氷結",
|
||||
"frequently_asked_questions": "よくある質問",
|
||||
"frozen": "凍った",
|
||||
"frozen_balance": "凍結バランス",
|
||||
"full_balance": "フルバランス",
|
||||
"gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。",
|
||||
"generate_name": "名前の生成",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "얼다",
|
||||
"frequently_asked_questions": "자주 묻는 질문",
|
||||
"frozen": "겨울 왕국",
|
||||
"frozen_balance": "냉동 균형",
|
||||
"full_balance": "풀 밸런스",
|
||||
"gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
|
||||
"generate_name": "이름 생성",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "အေးခဲ",
|
||||
"frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ",
|
||||
"frozen": "ဖြူဖြူ",
|
||||
"frozen_balance": "လက်ကျန်ငွေ",
|
||||
"full_balance": "Balance အပြည့်",
|
||||
"gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
|
||||
"generate_name": "အမည်ဖန်တီးပါ။",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Bevriezen",
|
||||
"frequently_asked_questions": "Veelgestelde vragen",
|
||||
"frozen": "Bevroren",
|
||||
"frozen_balance": "Bevroren balans",
|
||||
"full_balance": "Volledig saldo",
|
||||
"gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
|
||||
"generate_name": "Naam genereren",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Zamróź",
|
||||
"frequently_asked_questions": "Często zadawane pytania",
|
||||
"frozen": "Zamrożone",
|
||||
"frozen_balance": "Mrożona równowaga",
|
||||
"full_balance": "Pełne saldo",
|
||||
"gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
|
||||
"generate_name": "Wygeneruj nazwę",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Congelar",
|
||||
"frequently_asked_questions": "Perguntas frequentes",
|
||||
"frozen": "Congeladas",
|
||||
"frozen_balance": "Equilíbrio congelado",
|
||||
"full_balance": "Saldo total",
|
||||
"gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
|
||||
"generate_name": "Gerar nome",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Заморозить",
|
||||
"frequently_asked_questions": "Часто задаваемые вопросы",
|
||||
"frozen": "Заморожено",
|
||||
"frozen_balance": "Замороженный баланс",
|
||||
"full_balance": "Весь баланс",
|
||||
"gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
|
||||
"generate_name": "Создать имя",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "ดักจับ",
|
||||
"frequently_asked_questions": "คำถามที่พบบ่อย",
|
||||
"frozen": "ถูกดักจับ",
|
||||
"frozen_balance": "สมดุลแช่แข็ง",
|
||||
"full_balance": "ยอดคงเหลือทั้งหมด",
|
||||
"gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ",
|
||||
"generate_name": "สร้างชื่อ",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "I-freeze",
|
||||
"frequently_asked_questions": "Mga madalas itanong",
|
||||
"frozen": "Frozen",
|
||||
"frozen_balance": "Frozen na balanse",
|
||||
"full_balance": "Buong Balanse",
|
||||
"gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.",
|
||||
"generate_name": "Bumuo ng pangalan",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Dondur",
|
||||
"frequently_asked_questions": "Sıkça sorulan sorular",
|
||||
"frozen": "Dondurulmuş",
|
||||
"frozen_balance": "Dondurulmuş denge",
|
||||
"full_balance": "Tüm bakiye",
|
||||
"gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.",
|
||||
"generate_name": "İsim Oluştur",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "Заморозити",
|
||||
"frequently_asked_questions": "Часті запитання",
|
||||
"frozen": "Заморожено",
|
||||
"frozen_balance": "Заморожений баланс",
|
||||
"full_balance": "Весь баланс",
|
||||
"gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.",
|
||||
"generate_name": "Згенерувати назву",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "منجمد",
|
||||
"frequently_asked_questions": "اکثر پوچھے گئے سوالات",
|
||||
"frozen": "منجمد",
|
||||
"frozen_balance": "منجمد توازن",
|
||||
"full_balance": "مکمل بیلنس",
|
||||
"gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔",
|
||||
"generate_name": "نام پیدا کریں۔",
|
||||
|
|
|
@ -332,6 +332,7 @@
|
|||
"freeze": "Đóng băng",
|
||||
"frequently_asked_questions": "Các câu hỏi thường gặp",
|
||||
"frozen": "Đã đóng băng",
|
||||
"frozen_balance": "Cân bằng đông lạnh",
|
||||
"full_balance": "Số dư đầy đủ",
|
||||
"gas_exceeds_allowance": "Gas theo yêu cầu của giao dịch vượt quá trợ cấp.",
|
||||
"generate_name": "Tạo tên",
|
||||
|
|
|
@ -334,6 +334,7 @@
|
|||
"freeze": "Tì pa",
|
||||
"frequently_asked_questions": "Àwọn ìbéèrè la máa ń béèrè",
|
||||
"frozen": "Ó l'a tì pa",
|
||||
"frozen_balance": "Iwontunwonsi ti o tutu",
|
||||
"full_balance": "Ìyókù owó kíkún",
|
||||
"gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.",
|
||||
"generate_name": "Ṣẹda Orukọ",
|
||||
|
|
|
@ -333,6 +333,7 @@
|
|||
"freeze": "凍結",
|
||||
"frequently_asked_questions": "常见问题",
|
||||
"frozen": "凍結的",
|
||||
"frozen_balance": "冷冻平衡",
|
||||
"full_balance": "全部余额",
|
||||
"gas_exceeds_allowance": "交易要求的气体超出了津贴。",
|
||||
"generate_name": "生成名称",
|
||||
|
|
|
@ -30,7 +30,6 @@ class SecretKey {
|
|||
SecretKey('twitterBearerToken', () => ''),
|
||||
SecretKey('anonPayReferralCode', () => ''),
|
||||
SecretKey('fiatApiKey', () => ''),
|
||||
SecretKey('payfuraApiKey', () => ''),
|
||||
SecretKey('chatwootWebsiteToken', () => ''),
|
||||
SecretKey('exolixApiKey', () => ''),
|
||||
SecretKey('robinhoodApplicationId', () => ''),
|
||||
|
@ -38,6 +37,7 @@ class SecretKey {
|
|||
SecretKey('walletConnectProjectId', () => ''),
|
||||
SecretKey('moralisApiKey', () => ''),
|
||||
SecretKey('ankrApiKey', () => ''),
|
||||
SecretKey('chainStackApiKey', () => ''),
|
||||
SecretKey('quantexExchangeMarkup', () => ''),
|
||||
SecretKey('seeds', () => ''),
|
||||
SecretKey('testCakePayApiKey', () => ''),
|
||||
|
@ -86,6 +86,7 @@ class SecretKey {
|
|||
|
||||
static final solanaSecrets = [
|
||||
SecretKey('ankrApiKey', () => ''),
|
||||
SecretKey('chainStackApiKey', () => ''),
|
||||
];
|
||||
|
||||
static final nanoSecrets = [
|
||||
|
|
Loading…
Reference in a new issue