mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-01-07 03:19:31 +00:00
Merge branch 'main' into ui-enhancements
This commit is contained in:
commit
f52b8faa72
62 changed files with 307 additions and 232 deletions
|
@ -171,8 +171,8 @@ jobs:
|
||||||
echo "const trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
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 anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
|
||||||
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> 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 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 etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_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
|
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 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 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 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 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 cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> 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 trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> 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 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 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 etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const polygonScanApiKey = '${{ secrets.POLYGON_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
|
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 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 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 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 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 cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> 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 trocadorExchangeMarkup = '${{ secrets.TROCADOR_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
|
||||||
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> 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 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 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 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 moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
|
||||||
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> 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 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 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 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 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 cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
|
||||||
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
|
echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
|
||||||
|
|
|
@ -7,4 +7,7 @@
|
||||||
-
|
-
|
||||||
uri: solana-rpc.publicnode.com:443
|
uri: solana-rpc.publicnode.com:443
|
||||||
useSSL: true
|
useSSL: true
|
||||||
|
-
|
||||||
|
uri: solana-mainnet.core.chainstack.com
|
||||||
|
useSSL: true
|
||||||
is_default: true
|
is_default: true
|
|
@ -235,7 +235,7 @@ class ElectrumClient {
|
||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
Future<List<Map<String, dynamic>>> getListUnspent(String scriptHash) async {
|
Future<List<Map<String, dynamic>>?> getListUnspent(String scriptHash) async {
|
||||||
final result = await call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]);
|
final result = await call(method: 'blockchain.scripthash.listunspent', params: [scriptHash]);
|
||||||
|
|
||||||
if (result is List) {
|
if (result is List) {
|
||||||
|
@ -248,7 +248,7 @@ class ElectrumClient {
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<List<Map<String, dynamic>>> getMempool(String scriptHash) =>
|
Future<List<Map<String, dynamic>>> getMempool(String scriptHash) =>
|
||||||
|
|
|
@ -39,7 +39,7 @@ class ElectrumBalance extends Balance {
|
||||||
int secondUnconfirmed = 0;
|
int secondUnconfirmed = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
|
String get formattedAvailableBalance => bitcoinAmountToString(amount: ((confirmed + unconfirmed) - frozen) );
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
|
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
|
||||||
|
@ -58,7 +58,7 @@ class ElectrumBalance extends Balance {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedFullAvailableBalance =>
|
String get formattedFullAvailableBalance =>
|
||||||
bitcoinAmountToString(amount: confirmed + secondConfirmed - frozen);
|
bitcoinAmountToString(amount: (confirmed + unconfirmed) + secondConfirmed - frozen);
|
||||||
|
|
||||||
String toJSON() => json.encode({
|
String toJSON() => json.encode({
|
||||||
'confirmed': confirmed,
|
'confirmed': confirmed,
|
||||||
|
|
|
@ -478,6 +478,7 @@ abstract class ElectrumWalletBase
|
||||||
if (alwaysScan == true) {
|
if (alwaysScan == true) {
|
||||||
_setListeners(walletInfo.restoreHeight);
|
_setListeners(walletInfo.restoreHeight);
|
||||||
} else {
|
} else {
|
||||||
|
if (syncStatus is LostConnectionSyncStatus) return;
|
||||||
syncStatus = SyncedSyncStatus();
|
syncStatus = SyncedSyncStatus();
|
||||||
}
|
}
|
||||||
} catch (e, stacktrace) {
|
} catch (e, stacktrace) {
|
||||||
|
@ -1361,6 +1362,10 @@ abstract class ElectrumWalletBase
|
||||||
Future<void> updateAllUnspents() async {
|
Future<void> updateAllUnspents() async {
|
||||||
List<BitcoinUnspent> updatedUnspentCoins = [];
|
List<BitcoinUnspent> updatedUnspentCoins = [];
|
||||||
|
|
||||||
|
final previousUnspentCoins = List<BitcoinUnspent>.from(unspentCoins.where((utxo) =>
|
||||||
|
utxo.bitcoinAddressRecord.type != SegwitAddresType.mweb &&
|
||||||
|
utxo.bitcoinAddressRecord is! BitcoinSilentPaymentAddressRecord));
|
||||||
|
|
||||||
if (hasSilentPaymentsScanning) {
|
if (hasSilentPaymentsScanning) {
|
||||||
// Update unspents stored from scanned silent payment transactions
|
// Update unspents stored from scanned silent payment transactions
|
||||||
transactionHistory.transactions.values.forEach((tx) {
|
transactionHistory.transactions.values.forEach((tx) {
|
||||||
|
@ -1377,13 +1382,27 @@ abstract class ElectrumWalletBase
|
||||||
if (addr is! BitcoinSilentPaymentAddressRecord) addr.balance = 0;
|
if (addr is! BitcoinSilentPaymentAddressRecord) addr.balance = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
await Future.wait(walletAddresses.allAddresses
|
final addressFutures = walletAddresses.allAddresses
|
||||||
.where((element) => element.type != SegwitAddresType.mweb)
|
.where((element) => element.type != SegwitAddresType.mweb)
|
||||||
.map((address) async {
|
.map((address) => fetchUnspent(address))
|
||||||
updatedUnspentCoins.addAll(await fetchUnspent(address));
|
.toList();
|
||||||
}));
|
|
||||||
|
|
||||||
unspentCoins = updatedUnspentCoins;
|
final results = await Future.wait(addressFutures);
|
||||||
|
final failedCount = results.where((result) => result == null).length;
|
||||||
|
|
||||||
|
if (failedCount == 0) {
|
||||||
|
for (final result in results) {
|
||||||
|
updatedUnspentCoins.addAll(result!);
|
||||||
|
}
|
||||||
|
unspentCoins = updatedUnspentCoins;
|
||||||
|
} else {
|
||||||
|
unspentCoins = handleFailedUtxoFetch(
|
||||||
|
failedCount: failedCount,
|
||||||
|
previousUnspentCoins: previousUnspentCoins,
|
||||||
|
updatedUnspentCoins: updatedUnspentCoins,
|
||||||
|
results: results,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final currentWalletUnspentCoins =
|
final currentWalletUnspentCoins =
|
||||||
unspentCoinsInfo.values.where((element) => element.walletId == id);
|
unspentCoinsInfo.values.where((element) => element.walletId == id);
|
||||||
|
@ -1396,6 +1415,38 @@ abstract class ElectrumWalletBase
|
||||||
await _refreshUnspentCoinsInfo();
|
await _refreshUnspentCoinsInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<BitcoinUnspent> handleFailedUtxoFetch({
|
||||||
|
required int failedCount,
|
||||||
|
required List<BitcoinUnspent> previousUnspentCoins,
|
||||||
|
required List<BitcoinUnspent> updatedUnspentCoins,
|
||||||
|
required List<List<BitcoinUnspent>?> results,
|
||||||
|
}) {
|
||||||
|
|
||||||
|
if (failedCount == results.length) {
|
||||||
|
printV("All UTXOs failed to fetch, falling back to previous UTXOs");
|
||||||
|
return previousUnspentCoins;
|
||||||
|
}
|
||||||
|
|
||||||
|
final successfulUtxos = <BitcoinUnspent>[];
|
||||||
|
for (final result in results) {
|
||||||
|
if (result != null) {
|
||||||
|
successfulUtxos.addAll(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedCount > 0 && successfulUtxos.isEmpty) {
|
||||||
|
printV("Some UTXOs failed, but no successful UTXOs, falling back to previous UTXOs");
|
||||||
|
return previousUnspentCoins;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedCount > 0) {
|
||||||
|
printV("Some UTXOs failed, updating with successful UTXOs");
|
||||||
|
updatedUnspentCoins.addAll(successfulUtxos);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedUnspentCoins;
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateCoins(List<BitcoinUnspent> newUnspentCoins) async {
|
Future<void> updateCoins(List<BitcoinUnspent> newUnspentCoins) async {
|
||||||
if (newUnspentCoins.isEmpty) {
|
if (newUnspentCoins.isEmpty) {
|
||||||
return;
|
return;
|
||||||
|
@ -1427,15 +1478,17 @@ abstract class ElectrumWalletBase
|
||||||
@action
|
@action
|
||||||
Future<void> updateUnspentsForAddress(BitcoinAddressRecord address) async {
|
Future<void> updateUnspentsForAddress(BitcoinAddressRecord address) async {
|
||||||
final newUnspentCoins = await fetchUnspent(address);
|
final newUnspentCoins = await fetchUnspent(address);
|
||||||
await updateCoins(newUnspentCoins);
|
await updateCoins(newUnspentCoins ?? []);
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
Future<List<BitcoinUnspent>> fetchUnspent(BitcoinAddressRecord address) async {
|
Future<List<BitcoinUnspent>?> fetchUnspent(BitcoinAddressRecord address) async {
|
||||||
List<Map<String, dynamic>> unspents = [];
|
|
||||||
List<BitcoinUnspent> updatedUnspentCoins = [];
|
List<BitcoinUnspent> updatedUnspentCoins = [];
|
||||||
|
|
||||||
unspents = await electrumClient.getListUnspent(address.getScriptHash(network));
|
final unspents = await electrumClient.getListUnspent(address.getScriptHash(network));
|
||||||
|
|
||||||
|
// Failed to fetch unspents
|
||||||
|
if (unspents == null) return null;
|
||||||
|
|
||||||
await Future.wait(unspents.map((unspent) async {
|
await Future.wait(unspents.map((unspent) async {
|
||||||
try {
|
try {
|
||||||
|
@ -2160,18 +2213,6 @@ abstract class ElectrumWalletBase
|
||||||
var totalConfirmed = 0;
|
var totalConfirmed = 0;
|
||||||
var totalUnconfirmed = 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) {
|
if (hasSilentPaymentsScanning) {
|
||||||
// Add values from unspent coins that are not fetched by the address list
|
// Add values from unspent coins that are not fetched by the address list
|
||||||
// i.e. scanned silent payments
|
// i.e. scanned silent payments
|
||||||
|
@ -2187,6 +2228,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);
|
final balances = await Future.wait(balanceFutures);
|
||||||
|
|
||||||
if (balances.isNotEmpty && balances.first['confirmed'] == null) {
|
if (balances.isNotEmpty && balances.first['confirmed'] == null) {
|
||||||
|
|
|
@ -47,7 +47,11 @@ class TransactionInputNotSupported implements Exception {}
|
||||||
|
|
||||||
class SignNativeTokenTransactionRentException implements Exception {}
|
class SignNativeTokenTransactionRentException implements Exception {}
|
||||||
|
|
||||||
class CreateAssociatedTokenAccountException implements Exception {}
|
class CreateAssociatedTokenAccountException implements Exception {
|
||||||
|
final String errorMessage;
|
||||||
|
|
||||||
|
CreateAssociatedTokenAccountException(this.errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
class SignSPLTokenTransactionRentException implements Exception {}
|
class SignSPLTokenTransactionRentException implements Exception {}
|
||||||
|
|
||||||
|
|
|
@ -3,36 +3,25 @@ import 'package:cw_core/monero_amount_format.dart';
|
||||||
|
|
||||||
class MoneroBalance extends Balance {
|
class MoneroBalance extends Balance {
|
||||||
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||||
: formattedFullBalance = moneroAmountToString(amount: frozenBalance + fullBalance),
|
: formattedUnconfirmedBalance = moneroAmountToString(amount: fullBalance - unlockedBalance),
|
||||||
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
|
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance - frozenBalance),
|
||||||
formattedLockedBalance =
|
formattedFrozenBalance = moneroAmountToString(amount: frozenBalance),
|
||||||
moneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
|
|
||||||
super(unlockedBalance, fullBalance);
|
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 fullBalance;
|
||||||
final int unlockedBalance;
|
final int unlockedBalance;
|
||||||
final int frozenBalance;
|
final int frozenBalance;
|
||||||
final String formattedFullBalance;
|
final String formattedUnconfirmedBalance;
|
||||||
final String formattedUnlockedBalance;
|
final String formattedUnlockedBalance;
|
||||||
final String formattedLockedBalance;
|
final String formattedFrozenBalance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedUnAvailableBalance =>
|
String get formattedUnAvailableBalance =>
|
||||||
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
|
formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAdditionalBalance => formattedFullBalance;
|
String get formattedAdditionalBalance => formattedUnconfirmedBalance;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,8 @@ class Node extends HiveObject with Keyable {
|
||||||
this.useSSL,
|
this.useSSL,
|
||||||
this.trusted = false,
|
this.trusted = false,
|
||||||
this.socksProxyAddress,
|
this.socksProxyAddress,
|
||||||
|
this.path = '',
|
||||||
String? uri,
|
String? uri,
|
||||||
String? path,
|
|
||||||
WalletType? type,
|
WalletType? type,
|
||||||
}) {
|
}) {
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
|
@ -32,9 +32,6 @@ class Node extends HiveObject with Keyable {
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
if (path != null) {
|
|
||||||
this.path = path;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Node.fromMap(Map<String, Object?> map)
|
Node.fromMap(Map<String, Object?> map)
|
||||||
|
@ -95,19 +92,15 @@ class Node extends HiveObject with Keyable {
|
||||||
case WalletType.bitcoin:
|
case WalletType.bitcoin:
|
||||||
case WalletType.litecoin:
|
case WalletType.litecoin:
|
||||||
case WalletType.bitcoinCash:
|
case WalletType.bitcoinCash:
|
||||||
return createUriFromElectrumAddress(uriRaw, path ?? '');
|
return createUriFromElectrumAddress(uriRaw, path!);
|
||||||
case WalletType.nano:
|
case WalletType.nano:
|
||||||
case WalletType.banano:
|
case WalletType.banano:
|
||||||
if (isSSL) {
|
|
||||||
return Uri.https(uriRaw, path ?? '');
|
|
||||||
} else {
|
|
||||||
return Uri.http(uriRaw, path ?? '');
|
|
||||||
}
|
|
||||||
case WalletType.ethereum:
|
case WalletType.ethereum:
|
||||||
case WalletType.polygon:
|
case WalletType.polygon:
|
||||||
case WalletType.solana:
|
case WalletType.solana:
|
||||||
case WalletType.tron:
|
case WalletType.tron:
|
||||||
return Uri.https(uriRaw, path ?? '');
|
return Uri.parse(
|
||||||
|
"http${isSSL ? "s" : ""}://$uriRaw${path!.startsWith("/") ? path : "/$path"}");
|
||||||
case WalletType.none:
|
case WalletType.none:
|
||||||
throw Exception('Unexpected type ${type.toString()} for Node uri');
|
throw Exception('Unexpected type ${type.toString()} for Node uri');
|
||||||
}
|
}
|
||||||
|
@ -247,7 +240,7 @@ class Node extends HiveObject with Keyable {
|
||||||
if (proxy == null) {
|
if (proxy == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
final proxyAddress = proxy!.split(':')[0];
|
final proxyAddress = proxy.split(':')[0];
|
||||||
final proxyPort = int.parse(proxy.split(':')[1]);
|
final proxyPort = int.parse(proxy.split(':')[1]);
|
||||||
try {
|
try {
|
||||||
final socket = await Socket.connect(proxyAddress, proxyPort, timeout: Duration(seconds: 5));
|
final socket = await Socket.connect(proxyAddress, proxyPort, timeout: Duration(seconds: 5));
|
||||||
|
|
|
@ -3,36 +3,26 @@ import 'package:cw_core/wownero_amount_format.dart';
|
||||||
|
|
||||||
class WowneroBalance extends Balance {
|
class WowneroBalance extends Balance {
|
||||||
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||||
: formattedFullBalance = wowneroAmountToString(amount: fullBalance),
|
: formattedUnconfirmedBalance = wowneroAmountToString(amount: fullBalance - unlockedBalance),
|
||||||
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
|
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
|
||||||
formattedLockedBalance =
|
formattedFrozenBalance =
|
||||||
wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
|
wowneroAmountToString(amount: frozenBalance),
|
||||||
super(unlockedBalance, fullBalance);
|
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 fullBalance;
|
||||||
final int unlockedBalance;
|
final int unlockedBalance;
|
||||||
final int frozenBalance;
|
final int frozenBalance;
|
||||||
final String formattedFullBalance;
|
final String formattedUnconfirmedBalance;
|
||||||
final String formattedUnlockedBalance;
|
final String formattedUnlockedBalance;
|
||||||
final String formattedLockedBalance;
|
final String formattedFrozenBalance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedUnAvailableBalance =>
|
String get formattedUnAvailableBalance =>
|
||||||
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
|
formattedFrozenBalance == '0.0' ? '' : formattedFrozenBalance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAdditionalBalance => formattedFullBalance;
|
String get formattedAdditionalBalance => formattedUnconfirmedBalance;
|
||||||
}
|
}
|
|
@ -11,13 +11,12 @@ class EVMChainERC20Balance extends Balance {
|
||||||
final int exponent;
|
final int exponent;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAdditionalBalance {
|
String get formattedAdditionalBalance => _balance();
|
||||||
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
|
|
||||||
return formattedBalance.substring(0, min(12, formattedBalance.length));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get formattedAvailableBalance {
|
String get formattedAvailableBalance => _balance();
|
||||||
|
|
||||||
|
String _balance() {
|
||||||
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
|
final String formattedBalance = (balance / BigInt.from(10).pow(exponent)).toString();
|
||||||
return formattedBalance.substring(0, min(12, formattedBalance.length));
|
return formattedBalance.substring(0, min(12, formattedBalance.length));
|
||||||
}
|
}
|
||||||
|
|
|
@ -751,11 +751,18 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
||||||
int _getFrozenBalance() {
|
int _getFrozenBalance() {
|
||||||
var frozenBalance = 0;
|
var frozenBalance = 0;
|
||||||
|
|
||||||
for (var coin in unspentCoinsInfo.values.where((element) =>
|
unspentCoinsInfo.values.forEach((info) {
|
||||||
element.walletId == id &&
|
unspentCoins.forEach((element) {
|
||||||
element.accountIndex == walletAddresses.account!.id)) {
|
if (element.hash == info.hash &&
|
||||||
if (coin.isFrozen && !coin.isSending) frozenBalance += coin.value;
|
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;
|
return frozenBalance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,22 +21,23 @@ class SolanaWalletClient {
|
||||||
|
|
||||||
bool connect(Node node) {
|
bool connect(Node node) {
|
||||||
try {
|
try {
|
||||||
Uri? rpcUri;
|
Uri rpcUri = node.uri;
|
||||||
String webSocketUrl;
|
String webSocketUrl = 'wss://${node.uriRaw}';
|
||||||
bool isModifiedNodeUri = false;
|
|
||||||
|
|
||||||
if (node.uriRaw == 'rpc.ankr.com') {
|
if (node.uriRaw == 'rpc.ankr.com') {
|
||||||
isModifiedNodeUri = true;
|
|
||||||
String ankrApiKey = secrets.ankrApiKey;
|
String ankrApiKey = secrets.ankrApiKey;
|
||||||
|
|
||||||
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
|
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
|
||||||
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
|
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
|
||||||
} else {
|
} else if (node.uriRaw == 'solana-mainnet.core.chainstack.com') {
|
||||||
webSocketUrl = 'wss://${node.uriRaw}';
|
String chainStackApiKey = secrets.chainStackApiKey;
|
||||||
|
|
||||||
|
rpcUri = Uri.https(node.uriRaw, '/$chainStackApiKey');
|
||||||
|
webSocketUrl = 'wss://${node.uriRaw}/$chainStackApiKey';
|
||||||
}
|
}
|
||||||
|
|
||||||
_client = SolanaClient(
|
_client = SolanaClient(
|
||||||
rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri,
|
rpcUrl: rpcUri,
|
||||||
websocketUrl: Uri.parse(webSocketUrl),
|
websocketUrl: Uri.parse(webSocketUrl),
|
||||||
timeout: const Duration(minutes: 2),
|
timeout: const Duration(minutes: 2),
|
||||||
);
|
);
|
||||||
|
@ -115,10 +116,14 @@ class SolanaWalletClient {
|
||||||
final message =
|
final message =
|
||||||
_getMessageForNativeTransaction(ownerKeypair, ownerKeypair.address, lamportsPerSol);
|
_getMessageForNativeTransaction(ownerKeypair, ownerKeypair.address, lamportsPerSol);
|
||||||
|
|
||||||
final recentBlockhash = await _getRecentBlockhash(commitment);
|
final latestBlockhash = await _getLatestBlockhash(commitment);
|
||||||
|
|
||||||
final estimatedFee =
|
final estimatedFee = _getFeeFromCompiledMessage(
|
||||||
_getFeeFromCompiledMessage(message, ownerKeypair.publicKey, recentBlockhash, commitment);
|
message,
|
||||||
|
ownerKeypair.publicKey,
|
||||||
|
latestBlockhash,
|
||||||
|
commitment,
|
||||||
|
);
|
||||||
return estimatedFee;
|
return estimatedFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,13 +136,25 @@ class SolanaWalletClient {
|
||||||
List<SolanaTransactionModel> transactions = [];
|
List<SolanaTransactionModel> transactions = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final response = await _client!.rpcClient.getTransactionsList(
|
final signatures = await _client!.rpcClient.getSignaturesForAddress(
|
||||||
publicKey,
|
publicKey.toBase58(),
|
||||||
commitment: Commitment.confirmed,
|
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) {
|
if (tx.transaction is ParsedTransaction) {
|
||||||
final parsedTx = (tx.transaction as ParsedTransaction);
|
final parsedTx = (tx.transaction as ParsedTransaction);
|
||||||
final message = parsedTx.message;
|
final message = parsedTx.message;
|
||||||
|
@ -310,16 +327,16 @@ class SolanaWalletClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<RecentBlockhash> _getRecentBlockhash(Commitment commitment) async {
|
Future<LatestBlockhash> _getLatestBlockhash(Commitment commitment) async {
|
||||||
final latestBlockhash =
|
final latestBlockHashResult =
|
||||||
await _client!.rpcClient.getLatestBlockhash(commitment: commitment).value;
|
await _client!.rpcClient.getLatestBlockhash(commitment: commitment).value;
|
||||||
|
|
||||||
final recentBlockhash = RecentBlockhash(
|
final latestBlockhash = LatestBlockhash(
|
||||||
blockhash: latestBlockhash.blockhash,
|
blockhash: latestBlockHashResult.blockhash,
|
||||||
feeCalculator: const FeeCalculator(lamportsPerSignature: 500),
|
lastValidBlockHeight: latestBlockHashResult.lastValidBlockHeight,
|
||||||
);
|
);
|
||||||
|
|
||||||
return recentBlockhash;
|
return latestBlockhash;
|
||||||
}
|
}
|
||||||
|
|
||||||
Message _getMessageForNativeTransaction(
|
Message _getMessageForNativeTransaction(
|
||||||
|
@ -342,11 +359,11 @@ class SolanaWalletClient {
|
||||||
Future<double> _getFeeFromCompiledMessage(
|
Future<double> _getFeeFromCompiledMessage(
|
||||||
Message message,
|
Message message,
|
||||||
Ed25519HDPublicKey feePayer,
|
Ed25519HDPublicKey feePayer,
|
||||||
RecentBlockhash recentBlockhash,
|
LatestBlockhash latestBlockhash,
|
||||||
Commitment commitment,
|
Commitment commitment,
|
||||||
) async {
|
) async {
|
||||||
final compile = message.compile(
|
final compile = message.compile(
|
||||||
recentBlockhash: recentBlockhash.blockhash,
|
recentBlockhash: latestBlockhash.blockhash,
|
||||||
feePayer: feePayer,
|
feePayer: feePayer,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -391,12 +408,12 @@ class SolanaWalletClient {
|
||||||
|
|
||||||
final signers = [ownerKeypair];
|
final signers = [ownerKeypair];
|
||||||
|
|
||||||
RecentBlockhash recentBlockhash = await _getRecentBlockhash(commitment);
|
LatestBlockhash latestBlockhash = await _getLatestBlockhash(commitment);
|
||||||
|
|
||||||
final fee = await _getFeeFromCompiledMessage(
|
final fee = await _getFeeFromCompiledMessage(
|
||||||
message,
|
message,
|
||||||
signers.first.publicKey,
|
signers.first.publicKey,
|
||||||
recentBlockhash,
|
latestBlockhash,
|
||||||
commitment,
|
commitment,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -422,14 +439,14 @@ class SolanaWalletClient {
|
||||||
message: updatedMessage,
|
message: updatedMessage,
|
||||||
signers: signers,
|
signers: signers,
|
||||||
commitment: commitment,
|
commitment: commitment,
|
||||||
recentBlockhash: recentBlockhash,
|
latestBlockhash: latestBlockhash,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
signedTx = await _signTransactionInternal(
|
signedTx = await _signTransactionInternal(
|
||||||
message: message,
|
message: message,
|
||||||
signers: signers,
|
signers: signers,
|
||||||
commitment: commitment,
|
commitment: commitment,
|
||||||
recentBlockhash: recentBlockhash,
|
latestBlockhash: latestBlockhash,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,12 +524,12 @@ class SolanaWalletClient {
|
||||||
|
|
||||||
final signers = [ownerKeypair];
|
final signers = [ownerKeypair];
|
||||||
|
|
||||||
RecentBlockhash recentBlockhash = await _getRecentBlockhash(commitment);
|
LatestBlockhash latestBlockhash = await _getLatestBlockhash(commitment);
|
||||||
|
|
||||||
final fee = await _getFeeFromCompiledMessage(
|
final fee = await _getFeeFromCompiledMessage(
|
||||||
message,
|
message,
|
||||||
signers.first.publicKey,
|
signers.first.publicKey,
|
||||||
recentBlockhash,
|
latestBlockhash,
|
||||||
commitment,
|
commitment,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -530,7 +547,7 @@ class SolanaWalletClient {
|
||||||
message: message,
|
message: message,
|
||||||
signers: signers,
|
signers: signers,
|
||||||
commitment: commitment,
|
commitment: commitment,
|
||||||
recentBlockhash: recentBlockhash,
|
latestBlockhash: latestBlockhash,
|
||||||
);
|
);
|
||||||
|
|
||||||
sendTx() async => await sendTransaction(
|
sendTx() async => await sendTransaction(
|
||||||
|
@ -552,9 +569,9 @@ class SolanaWalletClient {
|
||||||
required Message message,
|
required Message message,
|
||||||
required List<Ed25519HDKeyPair> signers,
|
required List<Ed25519HDKeyPair> signers,
|
||||||
required Commitment commitment,
|
required Commitment commitment,
|
||||||
required RecentBlockhash recentBlockhash,
|
required LatestBlockhash latestBlockhash,
|
||||||
}) async {
|
}) async {
|
||||||
final signedTx = await signTransaction(recentBlockhash, message, signers);
|
final signedTx = await signTransaction(latestBlockhash, message, signers);
|
||||||
|
|
||||||
return signedTx;
|
return signedTx;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,9 +25,7 @@ class SolanaSignNativeTokenTransactionRentException
|
||||||
extends SignNativeTokenTransactionRentException {}
|
extends SignNativeTokenTransactionRentException {}
|
||||||
|
|
||||||
class SolanaCreateAssociatedTokenAccountException extends CreateAssociatedTokenAccountException {
|
class SolanaCreateAssociatedTokenAccountException extends CreateAssociatedTokenAccountException {
|
||||||
SolanaCreateAssociatedTokenAccountException(this.exceptionMessage);
|
SolanaCreateAssociatedTokenAccountException(super.errorMessage);
|
||||||
|
|
||||||
final String exceptionMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SolanaSignSPLTokenTransactionRentException extends SignSPLTokenTransactionRentException {}
|
class SolanaSignSPLTokenTransactionRentException extends SignSPLTokenTransactionRentException {}
|
||||||
|
|
|
@ -11,7 +11,7 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
solana: ^0.30.4
|
solana: ^0.31.0+1
|
||||||
cw_core:
|
cw_core:
|
||||||
path: ../cw_core
|
path: ../cw_core
|
||||||
http: ^1.1.0
|
http: ^1.1.0
|
||||||
|
|
|
@ -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
|
/// Get Vendors
|
||||||
Future<List<CakePayVendor>> getVendors({
|
Future<List<CakePayVendor>> getVendors({
|
||||||
required String apiKey,
|
required String apiKey,
|
||||||
|
required String country,
|
||||||
int? page,
|
int? page,
|
||||||
String? country,
|
|
||||||
String? countryCode,
|
String? countryCode,
|
||||||
String? search,
|
String? search,
|
||||||
List<String>? vendorIds,
|
List<String>? vendorIds,
|
||||||
|
@ -247,7 +247,7 @@ class CakePayApi {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (bodyJson['results'] as List)
|
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();
|
.toList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,11 @@ class CakePayCard {
|
||||||
}
|
}
|
||||||
|
|
||||||
static String fixEncoding(String text) {
|
static String fixEncoding(String text) {
|
||||||
final bytes = latin1.encode(text);
|
try {
|
||||||
return utf8.decode(bytes, allowMalformed: true);
|
final bytes = latin1.encode(text);
|
||||||
|
return utf8.decode(bytes, allowMalformed: true);
|
||||||
|
} catch (_) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,8 @@ class CakePayService {
|
||||||
|
|
||||||
/// Get Vendors
|
/// Get Vendors
|
||||||
Future<List<CakePayVendor>> getVendors({
|
Future<List<CakePayVendor>> getVendors({
|
||||||
|
required String country,
|
||||||
int? page,
|
int? page,
|
||||||
String? country,
|
|
||||||
String? countryCode,
|
String? countryCode,
|
||||||
String? search,
|
String? search,
|
||||||
List<String>? vendorIds,
|
List<String>? vendorIds,
|
||||||
|
|
|
@ -7,7 +7,7 @@ class CakePayVendor {
|
||||||
final String name;
|
final String name;
|
||||||
final bool unavailable;
|
final bool unavailable;
|
||||||
final String? cakeWarnings;
|
final String? cakeWarnings;
|
||||||
final List<String> countries;
|
final String country;
|
||||||
final CakePayCard? card;
|
final CakePayCard? card;
|
||||||
|
|
||||||
CakePayVendor({
|
CakePayVendor({
|
||||||
|
@ -15,19 +15,23 @@ class CakePayVendor {
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.unavailable,
|
required this.unavailable,
|
||||||
this.cakeWarnings,
|
this.cakeWarnings,
|
||||||
required this.countries,
|
required this.country,
|
||||||
this.card,
|
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 name = stripHtmlIfNeeded(json['name'] as String);
|
||||||
final decodedName = fixEncoding(name);
|
final decodedName = fixEncoding(name);
|
||||||
|
|
||||||
var cardsJson = json['cards'] as List?;
|
var cardsJson = json['cards'] as List?;
|
||||||
CakePayCard? firstCard;
|
CakePayCard? cardForVendor;
|
||||||
|
|
||||||
if (cardsJson != null && cardsJson.isNotEmpty) {
|
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(
|
return CakePayVendor(
|
||||||
|
@ -35,8 +39,8 @@ class CakePayVendor {
|
||||||
name: decodedName,
|
name: decodedName,
|
||||||
unavailable: json['unavailable'] as bool? ?? false,
|
unavailable: json['unavailable'] as bool? ?? false,
|
||||||
cakeWarnings: json['cake_warnings'] as String?,
|
cakeWarnings: json['cake_warnings'] as String?,
|
||||||
countries: List<String>.from(json['countries'] as List? ?? []),
|
country: country,
|
||||||
card: firstCard,
|
card: cardForVendor,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,25 +140,24 @@ abstract class Web3WalletServiceBase with Store {
|
||||||
for (final cId in SolanaChainId.values) {
|
for (final cId in SolanaChainId.values) {
|
||||||
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
|
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
|
||||||
|
|
||||||
Uri? rpcUri;
|
Uri rpcUri = node.uri;
|
||||||
String webSocketUrl;
|
String webSocketUrl = 'wss://${node.uriRaw}';
|
||||||
bool isModifiedNodeUri = false;
|
|
||||||
|
|
||||||
if (node.uriRaw == 'rpc.ankr.com') {
|
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;
|
String ankrApiKey = secrets.ankrApiKey;
|
||||||
|
|
||||||
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
|
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
|
||||||
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
|
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
|
||||||
} else {
|
} else if (node.uriRaw == 'solana-mainnet.core.chainstack.com') {
|
||||||
webSocketUrl = 'wss://${node.uriRaw}';
|
String chainStackApiKey = secrets.chainStackApiKey;
|
||||||
|
|
||||||
|
rpcUri = Uri.https(node.uriRaw, '/$chainStackApiKey');
|
||||||
|
webSocketUrl = 'wss://${node.uriRaw}/$chainStackApiKey';
|
||||||
}
|
}
|
||||||
|
|
||||||
SolanaChainServiceImpl(
|
SolanaChainServiceImpl(
|
||||||
reference: cId,
|
reference: cId,
|
||||||
rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri,
|
rpcUrl: rpcUri,
|
||||||
webSocketUrl: webSocketUrl,
|
webSocketUrl: webSocketUrl,
|
||||||
wcKeyService: walletKeyService,
|
wcKeyService: walletKeyService,
|
||||||
bottomSheetService: _bottomSheetHandler,
|
bottomSheetService: _bottomSheetHandler,
|
||||||
|
|
|
@ -2,12 +2,10 @@ import 'dart:async';
|
||||||
|
|
||||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||||
import 'package:cake_wallet/core/key_service.dart';
|
import 'package:cake_wallet/core/key_service.dart';
|
||||||
import 'package:cake_wallet/core/secure_storage.dart';
|
|
||||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/main.dart';
|
import 'package:cake_wallet/main.dart';
|
||||||
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
import 'package:cake_wallet/reactions/on_authentication_state_change.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
|
||||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||||
|
|
|
@ -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/moonpay/moonpay_provider.dart';
|
||||||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||||
import 'package:cake_wallet/buy/order.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/core/new_wallet_arguments.dart';
|
||||||
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
|
||||||
import 'package:cake_wallet/core/auth_service.dart';
|
import 'package:cake_wallet/core/auth_service.dart';
|
||||||
|
@ -1022,11 +1021,6 @@ Future<void> setup({
|
||||||
|
|
||||||
getIt.registerFactoryParam<WebViewPage, String, Uri>((title, uri) => WebViewPage(title, uri));
|
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.registerFactory(() => ExchangeViewModel(
|
||||||
getIt.get<AppStore>(),
|
getIt.get<AppStore>(),
|
||||||
_tradesSource,
|
_tradesSource,
|
||||||
|
|
|
@ -40,7 +40,7 @@ const polygonDefaultNodeUri = 'polygon-bor.publicnode.com';
|
||||||
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
|
const cakeWalletBitcoinCashDefaultNodeUri = 'bitcoincash.stackwallet.com:50002';
|
||||||
const nanoDefaultNodeUri = 'nano.nownodes.io';
|
const nanoDefaultNodeUri = 'nano.nownodes.io';
|
||||||
const nanoDefaultPowNodeUri = 'rpc.nano.to';
|
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 tronDefaultNodeUri = 'api.trongrid.io';
|
||||||
const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
|
const newCakeWalletBitcoinUri = 'btc-electrum.cakewallet.com:50002';
|
||||||
const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
const wowneroDefaultNodeUri = 'node3.monerodevs.org:34568';
|
||||||
|
@ -167,7 +167,11 @@ Future<void> defaultSettingsMigration(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 18:
|
case 18:
|
||||||
await addOnionNode(nodes);
|
await updateWalletTypeNodesWithNewNode(
|
||||||
|
nodes: nodes,
|
||||||
|
newNodeUri: "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081",
|
||||||
|
type: WalletType.monero,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 19:
|
case 19:
|
||||||
|
@ -261,15 +265,15 @@ Future<void> defaultSettingsMigration(
|
||||||
await updateTronNodesWithNowNodes(sharedPreferences: sharedPreferences, nodes: nodes);
|
await updateTronNodesWithNowNodes(sharedPreferences: sharedPreferences, nodes: nodes);
|
||||||
break;
|
break;
|
||||||
case 42:
|
case 42:
|
||||||
updateBtcElectrumNodeToUseSSL(nodes, sharedPreferences);
|
_fixNodesUseSSLFlag(nodes);
|
||||||
break;
|
break;
|
||||||
case 43:
|
case 43:
|
||||||
await _updateCakeXmrNode(nodes);
|
_fixNodesUseSSLFlag(nodes);
|
||||||
_deselectExchangeProvider(sharedPreferences, "THORChain");
|
_deselectExchangeProvider(sharedPreferences, "THORChain");
|
||||||
_deselectExchangeProvider(sharedPreferences, "SimpleSwap");
|
_deselectExchangeProvider(sharedPreferences, "SimpleSwap");
|
||||||
break;
|
break;
|
||||||
case 44:
|
case 44:
|
||||||
await _updateCakeXmrNode(nodes);
|
_fixNodesUseSSLFlag(nodes);
|
||||||
await _changeDefaultNode(
|
await _changeDefaultNode(
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
sharedPreferences: sharedPreferences,
|
sharedPreferences: sharedPreferences,
|
||||||
|
@ -297,14 +301,12 @@ Future<void> defaultSettingsMigration(
|
||||||
|
|
||||||
updateWalletTypeNodesWithNewNode(
|
updateWalletTypeNodesWithNewNode(
|
||||||
newNodeUri: 'matic.nownodes.io',
|
newNodeUri: 'matic.nownodes.io',
|
||||||
sharedPreferences: sharedPreferences,
|
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
type: WalletType.polygon,
|
type: WalletType.polygon,
|
||||||
useSSL: true,
|
useSSL: true,
|
||||||
);
|
);
|
||||||
updateWalletTypeNodesWithNewNode(
|
updateWalletTypeNodesWithNewNode(
|
||||||
newNodeUri: 'eth.nownodes.io',
|
newNodeUri: 'eth.nownodes.io',
|
||||||
sharedPreferences: sharedPreferences,
|
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
type: WalletType.ethereum,
|
type: WalletType.ethereum,
|
||||||
useSSL: true,
|
useSSL: true,
|
||||||
|
@ -330,6 +332,35 @@ Future<void> defaultSettingsMigration(
|
||||||
useSSL: true,
|
useSSL: true,
|
||||||
oldUri: ['rpc.ankr.com'],
|
oldUri: ['rpc.ankr.com'],
|
||||||
);
|
);
|
||||||
|
break;
|
||||||
|
case 46:
|
||||||
|
_fixNodesUseSSLFlag(nodes);
|
||||||
|
updateWalletTypeNodesWithNewNode(
|
||||||
|
newNodeUri: 'litecoin.stackwallet.com:20063',
|
||||||
|
nodes: nodes,
|
||||||
|
type: WalletType.litecoin,
|
||||||
|
useSSL: true,
|
||||||
|
);
|
||||||
|
updateWalletTypeNodesWithNewNode(
|
||||||
|
newNodeUri: 'electrum-ltc.bysh.me:50002',
|
||||||
|
nodes: nodes,
|
||||||
|
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',
|
||||||
|
],
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +392,8 @@ Future<void> _changeDefaultNode({
|
||||||
required String newDefaultUri,
|
required String newDefaultUri,
|
||||||
required String currentNodePreferenceKey,
|
required String currentNodePreferenceKey,
|
||||||
required bool useSSL,
|
required bool useSSL,
|
||||||
required List<String> oldUri, // leave empty if you want to force replace the node regardless of the user's current node
|
required List<String>
|
||||||
|
oldUri, // leave empty if you want to force replace the node regardless of the user's current node
|
||||||
}) async {
|
}) async {
|
||||||
final currentNodeId = sharedPreferences.getInt(currentNodePreferenceKey);
|
final currentNodeId = sharedPreferences.getInt(currentNodePreferenceKey);
|
||||||
final currentNode = nodes.values.firstWhere((node) => node.key == currentNodeId);
|
final currentNode = nodes.values.firstWhere((node) => node.key == currentNodeId);
|
||||||
|
@ -389,11 +421,10 @@ Future<void> _changeDefaultNode({
|
||||||
|
|
||||||
/// Generic function for adding a new Node for a Wallet Type.
|
/// Generic function for adding a new Node for a Wallet Type.
|
||||||
Future<void> updateWalletTypeNodesWithNewNode({
|
Future<void> updateWalletTypeNodesWithNewNode({
|
||||||
required SharedPreferences sharedPreferences,
|
|
||||||
required Box<Node> nodes,
|
required Box<Node> nodes,
|
||||||
required WalletType type,
|
required WalletType type,
|
||||||
required String newNodeUri,
|
required String newNodeUri,
|
||||||
required bool useSSL,
|
bool? useSSL,
|
||||||
}) async {
|
}) async {
|
||||||
// If it already exists in the box of nodes, no need to add it annymore.
|
// If it already exists in the box of nodes, no need to add it annymore.
|
||||||
if (nodes.values.any((node) => node.uriRaw == newNodeUri)) return;
|
if (nodes.values.any((node) => node.uriRaw == newNodeUri)) return;
|
||||||
|
@ -407,26 +438,6 @@ Future<void> updateWalletTypeNodesWithNewNode({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _updateCakeXmrNode(Box<Node> nodes) async {
|
|
||||||
final node = nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletMoneroUri);
|
|
||||||
|
|
||||||
if (node != null) {
|
|
||||||
node.trusted = true;
|
|
||||||
node.useSSL = true;
|
|
||||||
await node.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateBtcElectrumNodeToUseSSL(Box<Node> nodes, SharedPreferences sharedPreferences) {
|
|
||||||
final btcElectrumNode =
|
|
||||||
nodes.values.firstWhereOrNull((element) => element.uriRaw == newCakeWalletBitcoinUri);
|
|
||||||
|
|
||||||
if (btcElectrumNode != null) {
|
|
||||||
btcElectrumNode.useSSL = true;
|
|
||||||
btcElectrumNode.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _deselectExchangeProvider(SharedPreferences sharedPreferences, String providerName) {
|
void _deselectExchangeProvider(SharedPreferences sharedPreferences, String providerName) {
|
||||||
final Map<String, dynamic> exchangeProvidersSelection =
|
final Map<String, dynamic> exchangeProvidersSelection =
|
||||||
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
|
json.decode(sharedPreferences.getString(PreferencesKey.exchangeProvidersSelection) ?? "{}")
|
||||||
|
@ -445,8 +456,10 @@ void _fixNodesUseSSLFlag(Box<Node> nodes) {
|
||||||
switch (node.uriRaw) {
|
switch (node.uriRaw) {
|
||||||
case cakeWalletLitecoinElectrumUri:
|
case cakeWalletLitecoinElectrumUri:
|
||||||
case cakeWalletBitcoinElectrumUri:
|
case cakeWalletBitcoinElectrumUri:
|
||||||
|
case newCakeWalletBitcoinUri:
|
||||||
|
case newCakeWalletMoneroUri:
|
||||||
node.useSSL = true;
|
node.useSSL = true;
|
||||||
break;
|
node.trusted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -580,15 +593,6 @@ Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPre
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addOnionNode(Box<Node> nodes) async {
|
|
||||||
final onionNodeUri = "cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081";
|
|
||||||
|
|
||||||
// check if the user has this node before (added it manually)
|
|
||||||
if (nodes.values.firstWhereOrNull((element) => element.uriRaw == onionNodeUri) == null) {
|
|
||||||
await nodes.add(Node(uri: onionNodeUri, type: WalletType.monero));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
|
Future<void> replaceNodesMigration({required Box<Node> nodes}) async {
|
||||||
final replaceNodes = <String, Node>{
|
final replaceNodes = <String, Node>{
|
||||||
'eu-node.cakewallet.io:18081':
|
'eu-node.cakewallet.io:18081':
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'package:cake_wallet/src/screens/wallet_connect/utils/string_parsing.dart';
|
||||||
|
|
||||||
class EVMTransactionErrorFeesHandler {
|
class EVMTransactionErrorFeesHandler {
|
||||||
EVMTransactionErrorFeesHandler({
|
EVMTransactionErrorFeesHandler({
|
||||||
this.balanceWei,
|
this.balanceWei,
|
||||||
|
@ -64,14 +66,14 @@ class EVMTransactionErrorFeesHandler {
|
||||||
|
|
||||||
return EVMTransactionErrorFeesHandler(
|
return EVMTransactionErrorFeesHandler(
|
||||||
balanceWei: balanceWei.toString(),
|
balanceWei: balanceWei.toString(),
|
||||||
balanceEth: balanceEth.toString().substring(0, 12),
|
balanceEth: balanceEth.toString().safeSubString(0, 12),
|
||||||
balanceUsd: balanceUsd.toString().substring(0, 4),
|
balanceUsd: balanceUsd.toString().safeSubString(0, 4),
|
||||||
txCostWei: txCostWei.toString(),
|
txCostWei: txCostWei.toString(),
|
||||||
txCostEth: txCostEth.toString().substring(0, 12),
|
txCostEth: txCostEth.toString().safeSubString(0, 12),
|
||||||
txCostUsd: txCostUsd.toString().substring(0, 4),
|
txCostUsd: txCostUsd.toString().safeSubString(0, 4),
|
||||||
overshotWei: overshotWei.toString(),
|
overshotWei: overshotWei.toString(),
|
||||||
overshotEth: overshotEth.toString().substring(0, 12),
|
overshotEth: overshotEth.toString().safeSubString(0, 12),
|
||||||
overshotUsd: overshotUsd.toString().substring(0, 4),
|
overshotUsd: overshotUsd.toString().safeSubString(0, 4),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// If any value is missing, return an error message
|
// If any value is missing, return an error message
|
||||||
|
|
|
@ -215,7 +215,7 @@ Future<void> initializeAppConfigs() async {
|
||||||
secureStorage: secureStorage,
|
secureStorage: secureStorage,
|
||||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||||
havenSeedStore: havenSeedStore,
|
havenSeedStore: havenSeedStore,
|
||||||
initialMigrationVersion: 45,
|
initialMigrationVersion: 46,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,8 @@ class SeedVerificationStepView extends StatelessWidget {
|
||||||
(option) {
|
(option) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
|
if (walletSeedViewModel.wrongEntries > 2) return;
|
||||||
|
|
||||||
final isCorrectWord = walletSeedViewModel.isChosenWordCorrect(option);
|
final isCorrectWord = walletSeedViewModel.isChosenWordCorrect(option);
|
||||||
final isSecondWrongEntry = walletSeedViewModel.wrongEntries >= 2;
|
final isSecondWrongEntry = walletSeedViewModel.wrongEntries >= 2;
|
||||||
if (!isCorrectWord) {
|
if (!isCorrectWord) {
|
||||||
|
@ -81,7 +83,9 @@ class SeedVerificationStepView extends StatelessWidget {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isSecondWrongEntry) {
|
if (isSecondWrongEntry) {
|
||||||
Navigator.pop(context);
|
if (context.mounted) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:convert/convert.dart';
|
import 'package:convert/convert.dart';
|
||||||
|
|
||||||
|
@ -13,4 +14,8 @@ extension StringParsing on String {
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String safeSubString(int start, int end) {
|
||||||
|
return this.substring(0, min(this.toString().length, 12));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,9 +219,9 @@ class ExceptionHandler {
|
||||||
// probably when the device was locked and then opened on Cake
|
// probably when the device was locked and then opened on Cake
|
||||||
// this is solved by a restart of the app
|
// this is solved by a restart of the app
|
||||||
// just ignoring until we find a solution to this issue or migrate from flutter secure storage
|
// just ignoring until we find a solution to this issue or migrate from flutter secure storage
|
||||||
"core/auth_service.dart:63",
|
"core/auth_service.dart:64",
|
||||||
"core/key_service.dart:14",
|
"core/key_service.dart:14",
|
||||||
"core/wallet_loading_service.dart:133",
|
"core/wallet_loading_service.dart:131",
|
||||||
];
|
];
|
||||||
|
|
||||||
static Future<void> _addDeviceInfo(File file) async {
|
static Future<void> _addDeviceInfo(File file) async {
|
||||||
|
|
|
@ -4,13 +4,11 @@ import 'dart:io' show Platform;
|
||||||
|
|
||||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||||
import 'package:cake_wallet/buy/buy_provider.dart';
|
|
||||||
import 'package:cake_wallet/core/key_service.dart';
|
import 'package:cake_wallet/core/key_service.dart';
|
||||||
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
|
||||||
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
import 'package:cake_wallet/entities/balance_display_mode.dart';
|
||||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||||
import 'package:cake_wallet/entities/provider_types.dart';
|
|
||||||
import 'package:cake_wallet/entities/service_status.dart';
|
import 'package:cake_wallet/entities/service_status.dart';
|
||||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
@ -643,7 +641,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
|
|
||||||
transactions.clear();
|
transactions.clear();
|
||||||
|
|
||||||
transactions.addAll(
|
transactions = ObservableList.of(
|
||||||
wallet.transactionHistory.transactions.values.map(
|
wallet.transactionHistory.transactions.values.map(
|
||||||
(transaction) => TransactionListItem(
|
(transaction) => TransactionListItem(
|
||||||
transaction: transaction,
|
transaction: transaction,
|
||||||
|
@ -705,7 +703,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
|
monero!.getTransactionInfoAccountId(tx) == monero!.getCurrentAccount(wallet).id)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
transactions.addAll(
|
transactions = ObservableList.of(
|
||||||
_accountTransactions.map(
|
_accountTransactions.map(
|
||||||
(transaction) => TransactionListItem(
|
(transaction) => TransactionListItem(
|
||||||
transaction: transaction,
|
transaction: transaction,
|
||||||
|
@ -725,7 +723,7 @@ abstract class DashboardViewModelBase with Store {
|
||||||
wow.wownero!.getCurrentAccount(wallet).id)
|
wow.wownero!.getCurrentAccount(wallet).id)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
transactions.addAll(
|
transactions = ObservableList.of(
|
||||||
_accountTransactions.map(
|
_accountTransactions.map(
|
||||||
(transaction) => TransactionListItem(
|
(transaction) => TransactionListItem(
|
||||||
transaction: transaction,
|
transaction: transaction,
|
||||||
|
|
|
@ -680,7 +680,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
|
||||||
}
|
}
|
||||||
|
|
||||||
if (error is CreateAssociatedTokenAccountException) {
|
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) {
|
if (error is SignSPLTokenTransactionRentException) {
|
||||||
|
|
|
@ -106,7 +106,7 @@ dependencies:
|
||||||
flutter_svg: ^2.0.9
|
flutter_svg: ^2.0.9
|
||||||
polyseed: ^0.0.6
|
polyseed: ^0.0.6
|
||||||
nostr_tools: ^1.0.9
|
nostr_tools: ^1.0.9
|
||||||
solana: ^0.30.1
|
solana: ^0.31.0+1
|
||||||
ledger_flutter_plus: ^1.4.1
|
ledger_flutter_plus: ^1.4.1
|
||||||
hashlib: ^1.19.2
|
hashlib: ^1.19.2
|
||||||
|
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "تجميد",
|
"freeze": "تجميد",
|
||||||
"frequently_asked_questions": "الأسئلة الشائعة",
|
"frequently_asked_questions": "الأسئلة الشائعة",
|
||||||
"frozen": "مجمدة",
|
"frozen": "مجمدة",
|
||||||
|
"frozen_balance": "التوازن المجمد",
|
||||||
"full_balance": "الرصيد الكامل",
|
"full_balance": "الرصيد الكامل",
|
||||||
"gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
|
"gas_exceeds_allowance": "الغاز المطلوب بالمعاملة يتجاوز البدل.",
|
||||||
"generate_name": "توليد الاسم",
|
"generate_name": "توليد الاسم",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Замразяване",
|
"freeze": "Замразяване",
|
||||||
"frequently_asked_questions": "Често задавани въпроси",
|
"frequently_asked_questions": "Често задавани въпроси",
|
||||||
"frozen": "Замразени",
|
"frozen": "Замразени",
|
||||||
|
"frozen_balance": "Замразен баланс",
|
||||||
"full_balance": "Пълен баланс",
|
"full_balance": "Пълен баланс",
|
||||||
"gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
|
"gas_exceeds_allowance": "Газът, изискван от транзакцията, надвишава надбавката.",
|
||||||
"generate_name": "Генериране на име",
|
"generate_name": "Генериране на име",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Zmrazit",
|
"freeze": "Zmrazit",
|
||||||
"frequently_asked_questions": "Často kladené otázky",
|
"frequently_asked_questions": "Často kladené otázky",
|
||||||
"frozen": "Zmraženo",
|
"frozen": "Zmraženo",
|
||||||
|
"frozen_balance": "Zmrazená rovnováha",
|
||||||
"full_balance": "Celkový zůstatek",
|
"full_balance": "Celkový zůstatek",
|
||||||
"gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
|
"gas_exceeds_allowance": "Plyn vyžadovaný transakcí přesahuje příspěvek.",
|
||||||
"generate_name": "Generovat jméno",
|
"generate_name": "Generovat jméno",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Einfrieren",
|
"freeze": "Einfrieren",
|
||||||
"frequently_asked_questions": "Häufig gestellte Fragen",
|
"frequently_asked_questions": "Häufig gestellte Fragen",
|
||||||
"frozen": "Gefroren",
|
"frozen": "Gefroren",
|
||||||
|
"frozen_balance": "Gefrorenes Gleichgewicht",
|
||||||
"full_balance": "Gesamtguthaben",
|
"full_balance": "Gesamtguthaben",
|
||||||
"gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
|
"gas_exceeds_allowance": "Die durch Transaktion erforderliche Gas übertrifft die Zulage.",
|
||||||
"generate_name": "Namen generieren",
|
"generate_name": "Namen generieren",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Freeze",
|
"freeze": "Freeze",
|
||||||
"frequently_asked_questions": "Frequently asked questions",
|
"frequently_asked_questions": "Frequently asked questions",
|
||||||
"frozen": "Frozen",
|
"frozen": "Frozen",
|
||||||
|
"frozen_balance": "Frozen Balance",
|
||||||
"full_balance": "Full Balance",
|
"full_balance": "Full Balance",
|
||||||
"gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
|
"gas_exceeds_allowance": "Gas required by transaction exceeds allowance.",
|
||||||
"generate_name": "Generate Name",
|
"generate_name": "Generate Name",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Congelar",
|
"freeze": "Congelar",
|
||||||
"frequently_asked_questions": "Preguntas frecuentes",
|
"frequently_asked_questions": "Preguntas frecuentes",
|
||||||
"frozen": "Congelada",
|
"frozen": "Congelada",
|
||||||
|
"frozen_balance": "Equilibrio congelado",
|
||||||
"full_balance": "Balance completo",
|
"full_balance": "Balance completo",
|
||||||
"gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
|
"gas_exceeds_allowance": "El gas requerido por la transacción excede la asignación.",
|
||||||
"generate_name": "Generar nombre",
|
"generate_name": "Generar nombre",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Geler",
|
"freeze": "Geler",
|
||||||
"frequently_asked_questions": "Foire aux questions",
|
"frequently_asked_questions": "Foire aux questions",
|
||||||
"frozen": "Gelées",
|
"frozen": "Gelées",
|
||||||
|
"frozen_balance": "Équilibre gelé",
|
||||||
"full_balance": "Solde Complet",
|
"full_balance": "Solde Complet",
|
||||||
"gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
|
"gas_exceeds_allowance": "Le gaz requis par la transaction dépasse l'allocation.",
|
||||||
"generate_name": "Générer un nom",
|
"generate_name": "Générer un nom",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Daskare",
|
"freeze": "Daskare",
|
||||||
"frequently_asked_questions": "Tambayoyin da ake yawan yi",
|
"frequently_asked_questions": "Tambayoyin da ake yawan yi",
|
||||||
"frozen": "Daskararre",
|
"frozen": "Daskararre",
|
||||||
|
"frozen_balance": "Daidaituwa mai sanyi",
|
||||||
"full_balance": "DUKAN KUDI",
|
"full_balance": "DUKAN KUDI",
|
||||||
"gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
|
"gas_exceeds_allowance": "Gas da ake buƙata ta hanyar ma'amala ya wuce izini.",
|
||||||
"generate_name": "Ƙirƙirar Suna",
|
"generate_name": "Ƙirƙirar Suna",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "फ्रीज",
|
"freeze": "फ्रीज",
|
||||||
"frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न",
|
"frequently_asked_questions": "अक्सर पूछे जाने वाले प्रश्न",
|
||||||
"frozen": "जमा हुआ",
|
"frozen": "जमा हुआ",
|
||||||
|
"frozen_balance": "जमे हुए संतुलन",
|
||||||
"full_balance": "पूर्ण संतुलन",
|
"full_balance": "पूर्ण संतुलन",
|
||||||
"gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
|
"gas_exceeds_allowance": "लेनदेन द्वारा आवश्यक गैस भत्ता से अधिक है।",
|
||||||
"generate_name": "नाम जनरेट करें",
|
"generate_name": "नाम जनरेट करें",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Zamrznuti",
|
"freeze": "Zamrznuti",
|
||||||
"frequently_asked_questions": "Često postavljana pitanja",
|
"frequently_asked_questions": "Često postavljana pitanja",
|
||||||
"frozen": "Smrznuto",
|
"frozen": "Smrznuto",
|
||||||
|
"frozen_balance": "Smrznuta ravnoteža",
|
||||||
"full_balance": "Pun iznos",
|
"full_balance": "Pun iznos",
|
||||||
"gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
|
"gas_exceeds_allowance": "Plin potreban transakcijom premašuje dodatak.",
|
||||||
"generate_name": "Generiraj ime",
|
"generate_name": "Generiraj ime",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Կասեցնել",
|
"freeze": "Կասեցնել",
|
||||||
"frequently_asked_questions": "Հաճախ տրվող հարցեր",
|
"frequently_asked_questions": "Հաճախ տրվող հարցեր",
|
||||||
"frozen": "Կասեցված",
|
"frozen": "Կասեցված",
|
||||||
|
"frozen_balance": "Սառեցված հավասարակշռություն",
|
||||||
"full_balance": "Լրիվ մնացորդ",
|
"full_balance": "Լրիվ մնացորդ",
|
||||||
"gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
|
"gas_exceeds_allowance": "Գործարքով պահանջվող գազը գերազանցում է նպաստը:",
|
||||||
"generate_name": "Գեներացնել անուն",
|
"generate_name": "Գեներացնել անուն",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Freeze",
|
"freeze": "Freeze",
|
||||||
"frequently_asked_questions": "Pertanyaan yang sering diajukan",
|
"frequently_asked_questions": "Pertanyaan yang sering diajukan",
|
||||||
"frozen": "Dibekukan",
|
"frozen": "Dibekukan",
|
||||||
|
"frozen_balance": "Keseimbangan beku",
|
||||||
"full_balance": "Saldo Penuh",
|
"full_balance": "Saldo Penuh",
|
||||||
"gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
|
"gas_exceeds_allowance": "Gas yang dibutuhkan oleh transaksi melebihi tunjangan.",
|
||||||
"generate_name": "Hasilkan Nama",
|
"generate_name": "Hasilkan Nama",
|
||||||
|
|
|
@ -331,6 +331,7 @@
|
||||||
"freeze": "Congelare",
|
"freeze": "Congelare",
|
||||||
"frequently_asked_questions": "Domande frequenti",
|
"frequently_asked_questions": "Domande frequenti",
|
||||||
"frozen": "Congelato",
|
"frozen": "Congelato",
|
||||||
|
"frozen_balance": "Equilibrio congelato",
|
||||||
"full_balance": "Saldo Completo",
|
"full_balance": "Saldo Completo",
|
||||||
"gas_exceeds_allowance": "Il gas richiesto dalla transazione supera l'indennità.",
|
"gas_exceeds_allowance": "Il gas richiesto dalla transazione supera l'indennità.",
|
||||||
"generate_name": "Genera nome",
|
"generate_name": "Genera nome",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "氷結",
|
"freeze": "氷結",
|
||||||
"frequently_asked_questions": "よくある質問",
|
"frequently_asked_questions": "よくある質問",
|
||||||
"frozen": "凍った",
|
"frozen": "凍った",
|
||||||
|
"frozen_balance": "凍結バランス",
|
||||||
"full_balance": "フルバランス",
|
"full_balance": "フルバランス",
|
||||||
"gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。",
|
"gas_exceeds_allowance": "取引に必要なガスは、手当を超えています。",
|
||||||
"generate_name": "名前の生成",
|
"generate_name": "名前の生成",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "얼다",
|
"freeze": "얼다",
|
||||||
"frequently_asked_questions": "자주 묻는 질문",
|
"frequently_asked_questions": "자주 묻는 질문",
|
||||||
"frozen": "겨울 왕국",
|
"frozen": "겨울 왕국",
|
||||||
|
"frozen_balance": "냉동 균형",
|
||||||
"full_balance": "풀 밸런스",
|
"full_balance": "풀 밸런스",
|
||||||
"gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
|
"gas_exceeds_allowance": "거래에 필요한 가스는 수당을 초과합니다.",
|
||||||
"generate_name": "이름 생성",
|
"generate_name": "이름 생성",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "အေးခဲ",
|
"freeze": "အေးခဲ",
|
||||||
"frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ",
|
"frequently_asked_questions": "မေးလေ့ရှိသောမေးခွန်းများ",
|
||||||
"frozen": "ဖြူဖြူ",
|
"frozen": "ဖြူဖြူ",
|
||||||
|
"frozen_balance": "လက်ကျန်ငွေ",
|
||||||
"full_balance": "Balance အပြည့်",
|
"full_balance": "Balance အပြည့်",
|
||||||
"gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
|
"gas_exceeds_allowance": "ငွေပေးငွေယူမှလိုအပ်သောဓာတ်ငွေ့ထောက်ပံ့ကြေးကျော်လွန်။",
|
||||||
"generate_name": "အမည်ဖန်တီးပါ။",
|
"generate_name": "အမည်ဖန်တီးပါ။",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Bevriezen",
|
"freeze": "Bevriezen",
|
||||||
"frequently_asked_questions": "Veelgestelde vragen",
|
"frequently_asked_questions": "Veelgestelde vragen",
|
||||||
"frozen": "Bevroren",
|
"frozen": "Bevroren",
|
||||||
|
"frozen_balance": "Bevroren balans",
|
||||||
"full_balance": "Volledig saldo",
|
"full_balance": "Volledig saldo",
|
||||||
"gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
|
"gas_exceeds_allowance": "Gas vereist door transactie overschrijdt de vergoeding.",
|
||||||
"generate_name": "Naam genereren",
|
"generate_name": "Naam genereren",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Zamróź",
|
"freeze": "Zamróź",
|
||||||
"frequently_asked_questions": "Często zadawane pytania",
|
"frequently_asked_questions": "Często zadawane pytania",
|
||||||
"frozen": "Zamrożone",
|
"frozen": "Zamrożone",
|
||||||
|
"frozen_balance": "Mrożona równowaga",
|
||||||
"full_balance": "Pełne saldo",
|
"full_balance": "Pełne saldo",
|
||||||
"gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
|
"gas_exceeds_allowance": "Gaz wymagany przez transakcję przekracza dodatek.",
|
||||||
"generate_name": "Wygeneruj nazwę",
|
"generate_name": "Wygeneruj nazwę",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Congelar",
|
"freeze": "Congelar",
|
||||||
"frequently_asked_questions": "Perguntas frequentes",
|
"frequently_asked_questions": "Perguntas frequentes",
|
||||||
"frozen": "Congeladas",
|
"frozen": "Congeladas",
|
||||||
|
"frozen_balance": "Equilíbrio congelado",
|
||||||
"full_balance": "Saldo total",
|
"full_balance": "Saldo total",
|
||||||
"gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
|
"gas_exceeds_allowance": "O gás exigido pela transação excede o subsídio.",
|
||||||
"generate_name": "Gerar nome",
|
"generate_name": "Gerar nome",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Заморозить",
|
"freeze": "Заморозить",
|
||||||
"frequently_asked_questions": "Часто задаваемые вопросы",
|
"frequently_asked_questions": "Часто задаваемые вопросы",
|
||||||
"frozen": "Заморожено",
|
"frozen": "Заморожено",
|
||||||
|
"frozen_balance": "Замороженный баланс",
|
||||||
"full_balance": "Весь баланс",
|
"full_balance": "Весь баланс",
|
||||||
"gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
|
"gas_exceeds_allowance": "Газ, требуемый в результате транзакции, превышает пособие.",
|
||||||
"generate_name": "Создать имя",
|
"generate_name": "Создать имя",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "ดักจับ",
|
"freeze": "ดักจับ",
|
||||||
"frequently_asked_questions": "คำถามที่พบบ่อย",
|
"frequently_asked_questions": "คำถามที่พบบ่อย",
|
||||||
"frozen": "ถูกดักจับ",
|
"frozen": "ถูกดักจับ",
|
||||||
|
"frozen_balance": "สมดุลแช่แข็ง",
|
||||||
"full_balance": "ยอดคงเหลือทั้งหมด",
|
"full_balance": "ยอดคงเหลือทั้งหมด",
|
||||||
"gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ",
|
"gas_exceeds_allowance": "ก๊าซที่ต้องการโดยการทำธุรกรรมเกินค่าเผื่อ",
|
||||||
"generate_name": "สร้างชื่อ",
|
"generate_name": "สร้างชื่อ",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "I-freeze",
|
"freeze": "I-freeze",
|
||||||
"frequently_asked_questions": "Mga madalas itanong",
|
"frequently_asked_questions": "Mga madalas itanong",
|
||||||
"frozen": "Frozen",
|
"frozen": "Frozen",
|
||||||
|
"frozen_balance": "Frozen na balanse",
|
||||||
"full_balance": "Buong Balanse",
|
"full_balance": "Buong Balanse",
|
||||||
"gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.",
|
"gas_exceeds_allowance": "Ang gas na kinakailangan ng transaksyon ay lumampas sa allowance.",
|
||||||
"generate_name": "Bumuo ng pangalan",
|
"generate_name": "Bumuo ng pangalan",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Dondur",
|
"freeze": "Dondur",
|
||||||
"frequently_asked_questions": "Sıkça sorulan sorular",
|
"frequently_asked_questions": "Sıkça sorulan sorular",
|
||||||
"frozen": "Dondurulmuş",
|
"frozen": "Dondurulmuş",
|
||||||
|
"frozen_balance": "Dondurulmuş denge",
|
||||||
"full_balance": "Tüm bakiye",
|
"full_balance": "Tüm bakiye",
|
||||||
"gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.",
|
"gas_exceeds_allowance": "İşlemin gerektirdiği gaz ödeneği aşar.",
|
||||||
"generate_name": "İsim Oluştur",
|
"generate_name": "İsim Oluştur",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "Заморозити",
|
"freeze": "Заморозити",
|
||||||
"frequently_asked_questions": "Часті запитання",
|
"frequently_asked_questions": "Часті запитання",
|
||||||
"frozen": "Заморожено",
|
"frozen": "Заморожено",
|
||||||
|
"frozen_balance": "Заморожений баланс",
|
||||||
"full_balance": "Весь баланс",
|
"full_balance": "Весь баланс",
|
||||||
"gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.",
|
"gas_exceeds_allowance": "Газ, необхідний транзакціям, перевищує надбавку.",
|
||||||
"generate_name": "Згенерувати назву",
|
"generate_name": "Згенерувати назву",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "منجمد",
|
"freeze": "منجمد",
|
||||||
"frequently_asked_questions": "اکثر پوچھے گئے سوالات",
|
"frequently_asked_questions": "اکثر پوچھے گئے سوالات",
|
||||||
"frozen": "منجمد",
|
"frozen": "منجمد",
|
||||||
|
"frozen_balance": "منجمد توازن",
|
||||||
"full_balance": "مکمل بیلنس",
|
"full_balance": "مکمل بیلنس",
|
||||||
"gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔",
|
"gas_exceeds_allowance": "لین دین کے ذریعہ درکار گیس الاؤنس سے زیادہ ہے۔",
|
||||||
"generate_name": "نام پیدا کریں۔",
|
"generate_name": "نام پیدا کریں۔",
|
||||||
|
|
|
@ -329,6 +329,7 @@
|
||||||
"freeze": "Đóng băng",
|
"freeze": "Đóng băng",
|
||||||
"frequently_asked_questions": "Các câu hỏi thường gặp",
|
"frequently_asked_questions": "Các câu hỏi thường gặp",
|
||||||
"frozen": "Đã đóng băng",
|
"frozen": "Đã đóng băng",
|
||||||
|
"frozen_balance": "Cân bằng đông lạnh",
|
||||||
"full_balance": "Số dư đầy đủ",
|
"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.",
|
"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",
|
"generate_name": "Tạo tên",
|
||||||
|
|
|
@ -331,6 +331,7 @@
|
||||||
"freeze": "Tì pa",
|
"freeze": "Tì pa",
|
||||||
"frequently_asked_questions": "Àwọn ìbéèrè la máa ń béèrè",
|
"frequently_asked_questions": "Àwọn ìbéèrè la máa ń béèrè",
|
||||||
"frozen": "Ó l'a tì pa",
|
"frozen": "Ó l'a tì pa",
|
||||||
|
"frozen_balance": "Iwontunwonsi ti o tutu",
|
||||||
"full_balance": "Ìyókù owó kíkún",
|
"full_balance": "Ìyókù owó kíkún",
|
||||||
"gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.",
|
"gas_exceeds_allowance": "Gaasi ti a beere nipasẹ idunadura ju lọ.",
|
||||||
"generate_name": "Ṣẹda Orukọ",
|
"generate_name": "Ṣẹda Orukọ",
|
||||||
|
|
|
@ -330,6 +330,7 @@
|
||||||
"freeze": "凍結",
|
"freeze": "凍結",
|
||||||
"frequently_asked_questions": "常见问题",
|
"frequently_asked_questions": "常见问题",
|
||||||
"frozen": "凍結的",
|
"frozen": "凍結的",
|
||||||
|
"frozen_balance": "冷冻平衡",
|
||||||
"full_balance": "全部余额",
|
"full_balance": "全部余额",
|
||||||
"gas_exceeds_allowance": "交易要求的气体超出了津贴。",
|
"gas_exceeds_allowance": "交易要求的气体超出了津贴。",
|
||||||
"generate_name": "生成名称",
|
"generate_name": "生成名称",
|
||||||
|
|
|
@ -30,7 +30,6 @@ class SecretKey {
|
||||||
SecretKey('twitterBearerToken', () => ''),
|
SecretKey('twitterBearerToken', () => ''),
|
||||||
SecretKey('anonPayReferralCode', () => ''),
|
SecretKey('anonPayReferralCode', () => ''),
|
||||||
SecretKey('fiatApiKey', () => ''),
|
SecretKey('fiatApiKey', () => ''),
|
||||||
SecretKey('payfuraApiKey', () => ''),
|
|
||||||
SecretKey('chatwootWebsiteToken', () => ''),
|
SecretKey('chatwootWebsiteToken', () => ''),
|
||||||
SecretKey('exolixApiKey', () => ''),
|
SecretKey('exolixApiKey', () => ''),
|
||||||
SecretKey('robinhoodApplicationId', () => ''),
|
SecretKey('robinhoodApplicationId', () => ''),
|
||||||
|
@ -38,6 +37,7 @@ class SecretKey {
|
||||||
SecretKey('walletConnectProjectId', () => ''),
|
SecretKey('walletConnectProjectId', () => ''),
|
||||||
SecretKey('moralisApiKey', () => ''),
|
SecretKey('moralisApiKey', () => ''),
|
||||||
SecretKey('ankrApiKey', () => ''),
|
SecretKey('ankrApiKey', () => ''),
|
||||||
|
SecretKey('chainStackApiKey', () => ''),
|
||||||
SecretKey('quantexExchangeMarkup', () => ''),
|
SecretKey('quantexExchangeMarkup', () => ''),
|
||||||
SecretKey('seeds', () => ''),
|
SecretKey('seeds', () => ''),
|
||||||
SecretKey('testCakePayApiKey', () => ''),
|
SecretKey('testCakePayApiKey', () => ''),
|
||||||
|
@ -86,6 +86,7 @@ class SecretKey {
|
||||||
|
|
||||||
static final solanaSecrets = [
|
static final solanaSecrets = [
|
||||||
SecretKey('ankrApiKey', () => ''),
|
SecretKey('ankrApiKey', () => ''),
|
||||||
|
SecretKey('chainStackApiKey', () => ''),
|
||||||
];
|
];
|
||||||
|
|
||||||
static final nanoSecrets = [
|
static final nanoSecrets = [
|
||||||
|
|
Loading…
Reference in a new issue