Merge branch 'main' into CW-1094-WalletConnect-Issues

This commit is contained in:
Omar Hatem 2025-06-24 05:48:17 +03:00 committed by GitHub
commit 8c9bd74f41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
175 changed files with 5208 additions and 1035 deletions

21
.github/workflows/no_http_imports.yaml vendored Normal file
View file

@ -0,0 +1,21 @@
name: No http imports
on: [pull_request]
jobs:
PR_test_build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Check for http package usage
if: github.event_name == 'pull_request'
run: |
GIT_GREP_OUT="$(git grep package:http | (grep .dart: || test $? = 1) | (grep -v proxy_wrapper.dart || test $? = 1) | (grep -v very_insecure_http_do_not_use || test $? = 1) || true)"
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
echo "$GIT_GREP_OUT"
echo "There are .dart files which use http imports"
echo "Using http package breaks proxy integration"
echo "Please use ProxyWrapper.getHttpClient() from package:cw_core/utils/proxy_wrapper.dart"
exit 1

View file

@ -15,5 +15,5 @@ jobs:
[[ "x$GIT_GREP_OUT" == "x" ]] && exit 0 [[ "x$GIT_GREP_OUT" == "x" ]] && exit 0
echo "$GIT_GREP_OUT" echo "$GIT_GREP_OUT"
echo "There are .dart files which use print() statements" echo "There are .dart files which use print() statements"
echo "Please use printV from package: cw_core/utils/print_verbose.dart" echo "Please use printV from package:cw_core/utils/print_verbose.dart"
exit 1 exit 1

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 150.5 91.1" enable-background="new 0 0 150.5 91.1" xml:space="preserve">
<g>
<g>
<g id="layer3_22_" transform="translate(-92,-63.999774)">
<g id="layer5_22_">
<g id="path2554_38_">
<path fill="#68B044" d="M176.9,70.8l-2.4,9.6c3.4-6.8,8.9-11.9,15.2-16.4c-4.6,5.3-8.8,10.6-11.3,16
c4.3-6.1,10.1-9.4,16.6-11.7c-8.7,7.7-15.6,16.1-20.8,24.4l-4.2-1.8C170.7,84.2,173.2,77.4,176.9,70.8L176.9,70.8z"/>
</g>
<g id="path2534_13_">
<path fill="#F5F8DE" d="M165.8,89.1l7.9,3.3c0,2-0.2,8.2,1.1,10c13.2,17,11,51.2-2.7,52c-20.8,0-28.8-14.1-28.8-27.1
c0-11.9,14.2-19.7,22.7-26.7C168.3,98.7,167.9,94.5,165.8,89.1L165.8,89.1z"/>
</g>
<g id="path2536_23_">
<path fill="#7E4798" d="M173.7,92.3l2.9,1.5c-0.3,1.9,0.1,6.1,2,7.1c8.4,5.2,16.2,10.8,19.3,16.5c11,19.9-7.7,38.4-24,36.6
c8.8-6.5,11.4-19.9,8.1-34.6c-1.3-5.7-3.4-10.9-7.1-16.8C173.3,99.9,173.9,96.3,173.7,92.3L173.7,92.3z"/>
</g>
</g>
<g id="layer4_22_">
<g id="path2540_23_">
<path fill="#010101" d="M170.5,101.8c-0.6,3.1-1.3,8.7-4,10.8c-1.1,0.8-2.3,1.6-3.5,2.4c-4.9,3.3-9.7,6.4-11.9,14.3
c-0.5,1.7-0.1,3.5,0.3,5.2c1.2,4.9,4.6,10.1,7.3,13.2c0,0.1,0.5,0.5,0.5,0.6c2.2,2.6,2.9,3.4,11.3,5.3l-0.2,0.9
c-5.1-1.3-9.2-2.6-11.9-5.6c0-0.1-0.5-0.5-0.5-0.5c-2.8-3.2-6.3-8.6-7.5-13.7c-0.5-2-0.9-3.6-0.3-5.7
c2.3-8.2,7.3-11.5,12.3-14.9c1.1-0.7,2.5-1.4,3.6-2.3C168.3,110.3,169.4,105.6,170.5,101.8L170.5,101.8z"/>
</g>
<g id="path2542_23_">
<path fill="#010101" d="M172.7,114.8c0.1,3.5-0.3,5.3,0.6,7.8c0.5,1.5,2.4,3.5,2.9,5.5c0.7,2.6,1.5,5.5,1.5,7.3
c0,2-0.1,5.8-1,9.8c-0.7,3.3-2.2,6.2-4.8,7.8c-2.7-0.5-5.8-1.5-7.6-3.1c-3.6-3.1-6.7-8.3-7.1-12.8c-0.3-3.7,3.1-9.2,7.9-11.9
c4-2.4,5-5,5.9-9.4c-1.2,3.8-2.4,6.9-6.3,9c-5.7,3-8.6,7.9-8.3,12.7c0.4,6.1,2.8,10.2,7.6,13.5c2,1.4,5.8,2.9,8.2,3.3v-0.3
c1.8-0.3,4.1-3.3,5.3-7.2c1-3.6,1.4-8.1,1.3-11c-0.1-1.7-0.8-5.3-2.2-8.6c-0.7-1.8-1.9-3.6-2.6-4.9
C173.1,120.8,173.1,118,172.7,114.8z"/>
</g>
<g id="path2544_23_">
<path fill="#010101" d="M172.1,128.5c0.1,2.4,1,5.4,1.4,8.5c0.3,2.3,0.2,4.6,0.1,6.6c-0.1,2.3-0.8,6.5-1.9,8.6
c-1-0.5-1.4-1-2.1-1.8c-0.8-1.1-1.4-2.3-1.9-3.6c-0.4-1-0.9-2.2-1.1-3.5c-0.3-2-0.2-5.2,2.1-8.4c1.8-2.6,2.2-2.8,2.8-5.7
c-0.8,2.6-1.4,2.9-3.3,5.1c-2.1,2.4-2.4,6-2.4,8.9c0,1.2,0.5,2.6,1,3.8c0.5,1.3,1,2.7,1.7,3.7c1.1,1.6,2.5,2.6,3.2,2.7
c0,0,0,0,0,0c0,0,0,0,0,0v-0.1c1.3-1.5,2.1-2.9,2.4-4.4c0.3-1.8,0.4-3.5,0.6-5.6c0.2-1.8,0.1-4.1-0.4-6.5
C173.7,133.8,172.6,130.7,172.1,128.5L172.1,128.5z"/>
</g>
<g id="path2550_23_">
<path fill="#010101" d="M172.5,99c0.1,3.5,0.3,10,1.3,12.6c0.3,0.9,2.8,4.7,4.5,9.4c1.2,3.2,1.5,6.2,1.7,7.1
c0.8,3.8-0.2,10.3-1.5,16.4c-0.7,3.3-3,7.4-5.6,9l-0.5,0.9c1.5-0.1,5.1-3.6,6.4-8.1c2.2-7.5,3-11,2-19.4
c-0.1-0.8-0.5-3.6-1.8-6.5c-1.9-4.5-4.6-8.8-4.9-9.7C173.4,109.3,172.6,103.1,172.5,99L172.5,99z"/>
</g>
<g id="path2552_23_">
<path fill="#010101" d="M173.7,92.6c-0.2,3.6-0.2,6.4,0.4,9.1c0.7,2.9,4.5,7.1,6.1,11.9c3,9.2,2.2,21.2,0.1,30.5
c-0.8,3.3-4.6,8.1-8.5,9.6l2.8,0.7c1.5-0.1,5.5-3.8,7.1-8c2.5-6.7,3-14.6,2-23c-0.1-0.8-1.4-8-2.7-11
c-1.8-4.5-4.7-7.7-5.7-10.5c-0.8-2.1-1.1-7.7-0.6-8.8L173.7,92.6z"/>
</g>
</g>
</g>
<g id="path2528_18_">
<path fill="#7E4798" d="M3.8,8.8h54.1c2,0,3.8,1.7,3.8,3.8v16c0,2.1-1.8,3.8-3.8,3.8H46.8c-2.5,0-3.6,1.4-3.6,3v52.3
c0,1.8-1.4,3.1-3.1,3.1H21.7c-1.7,0-3-1.3-3-3.1V34.9c0-1.6-1.5-2.6-2.6-2.6H3.8c-2.1,0-3.8-1.7-3.8-3.8v-16
C0,10.5,1.7,8.8,3.8,8.8z"/>
</g>
<g id="path2532_18_">
<path fill="#7E4798" d="M142.6,30h4.8c1.8,0,3.2,1.4,3.2,3.1v17.1c0,2.2,0.1,3.1-2.6,3.1c-5.3,0-7.7,2.8-7.7,5.9v28.9
c0,1.3-1.3,2.5-2.8,2.5h-17.2c-1.5,0-2.8-1.1-2.8-2.5V55.2c0-0.6,0-1.4,0.1-1.9c0.9-12.2,10.5-21.9,22.6-23.2
C140.5,30.1,141.9,30,142.6,30L142.6,30z"/>
</g>
</g>
<g>
<path fill="#010101" d="M101.7,46.3c-2.9-2.6-6.5-4.8-10.3-6.9c-1.7-0.9-6.9-5-5.1-10.8l-13.1-5.4l-0.9,0.7
c4.4,7.9,2.1,12.1-0.1,13.5c-4.4,3-10.8,6.8-13.9,10.1c-6.1,6.3-7.9,12.3-7.3,20.1c0.6,10.1,7.9,18.5,17.8,21.8
c4.3,1.4,8.3,1.6,12.7,1.6c7.1,0,14.5-1.9,19.8-6.3c5.7-4.7,9-11.8,9-19.1C110.3,58.3,107.2,51.3,101.7,46.3z M99.8,83.2
c-4.9,4-13.7,6.8-18.4,6.6c-5.2-0.3-10.3-1.1-14.8-3.3c-7.9-3.8-13.1-12.1-13.5-18.8C52.4,54,59,50.1,65.1,45.1
c3.4-2.8,8.2-4.2,10.9-9.2c0.5-1.1,0.8-3.5,0.2-6c-0.3-0.9-1.5-3.9-2-4.6l9.8,4.3c-1.2,4.5,2.5,9.2,5.5,10.9
c3,1.7,7.7,4.9,10.6,7.5c5.1,4.5,7.7,10.9,7.7,17.6C107.8,72.3,105,78.9,99.8,83.2z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -266,6 +266,12 @@ abstract class BitcoinWalletBase extends ElectrumWallet with Store {
derivationPath: walletInfo.derivationInfo!.derivationPath!); derivationPath: walletInfo.derivationInfo!.derivationPath!);
} }
@override
Future<void> close({bool shouldCleanup = false}) async {
payjoinManager.cleanupSessions();
super.close(shouldCleanup: shouldCleanup);
}
late final PayjoinManager payjoinManager; late final PayjoinManager payjoinManager;
bool get isPayjoinAvailable => unspentCoinsInfo.values bool get isPayjoinAvailable => unspentCoinsInfo.values

View file

@ -59,19 +59,26 @@ abstract class BitcoinWalletAddressesBase extends ElectrumWalletAddresses with S
@action @action
Future<void> initPayjoin() async { Future<void> initPayjoin() async {
await payjoinManager.initPayjoin(); try {
currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress); await payjoinManager.initPayjoin();
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint(); currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
payjoinManager.resumeSessions(); payjoinManager.resumeSessions();
} catch (e) {
printV(e);
}
} }
@action @action
Future<void> newPayjoinReceiver() async { Future<void> newPayjoinReceiver() async {
currentPayjoinReceiver = await payjoinManager.initReceiver(primaryAddress); try {
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint(); currentPayjoinReceiver = await payjoinManager.getUnusedReceiver(primaryAddress);
payjoinEndpoint = (await currentPayjoinReceiver?.pjUri())?.pjEndpoint();
printV("Initializing new Payjoin Receiver"); payjoinManager.spawnReceiver(receiver: currentPayjoinReceiver!);
payjoinManager.spawnNewReceiver(receiver: currentPayjoinReceiver!); } catch (e) {
printV(e);
}
} }
} }

View file

@ -5,6 +5,8 @@ import 'dart:typed_data';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_socket/abstract.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart'; import 'package:rxdart/rxdart.dart';
@ -42,7 +44,7 @@ class ElectrumClient {
static const aliveTimerDuration = Duration(seconds: 4); static const aliveTimerDuration = Duration(seconds: 4);
bool get isConnected => _isConnected; bool get isConnected => _isConnected;
Socket? socket; ProxySocket? socket;
void Function(ConnectionStatus)? onConnectionStatusChange; void Function(ConnectionStatus)? onConnectionStatusChange;
int _id; int _id;
final Map<String, SocketTask> _tasks; final Map<String, SocketTask> _tasks;
@ -72,18 +74,11 @@ class ElectrumClient {
} catch (_) {} } catch (_) {}
socket = null; socket = null;
final ssl = !(useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum")));
try { try {
if (useSSL == false || (useSSL == null && uri.toString().contains("btc-electrum"))) { socket = await ProxyWrapper().getSocksSocket(ssl, host, port, connectionTimeout: connectionTimeout);
socket = await Socket.connect(host, port, timeout: connectionTimeout);
} else {
socket = await SecureSocket.connect(
host,
port,
timeout: connectionTimeout,
onBadCertificate: (_) => true,
);
}
} catch (e) { } catch (e) {
printV("connect: $e");
if (e is HandshakeException) { if (e is HandshakeException) {
useSSL = !(useSSL ?? false); useSSL = !(useSSL ?? false);
} }
@ -105,7 +100,6 @@ class ElectrumClient {
// use ping to determine actual connection status since we could've just not timed out yet: // use ping to determine actual connection status since we could've just not timed out yet:
// _setConnectionStatus(ConnectionStatus.connected); // _setConnectionStatus(ConnectionStatus.connected);
socket!.listen( socket!.listen(
(Uint8List event) { (Uint8List event) {
try { try {

View file

@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:isolate'; import 'dart:isolate';
import 'package:bitcoin_base/bitcoin_base.dart'; import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/format_amount.dart'; import 'package:cw_core/format_amount.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
@ -49,7 +50,6 @@ import 'package:mobx/mobx.dart';
import 'package:rxdart/subjects.dart'; import 'package:rxdart/subjects.dart';
import 'package:sp_scanner/sp_scanner.dart'; import 'package:sp_scanner/sp_scanner.dart';
import 'package:hex/hex.dart'; import 'package:hex/hex.dart';
import 'package:http/http.dart' as http;
part 'electrum_wallet.g.dart'; part 'electrum_wallet.g.dart';
@ -493,10 +493,9 @@ abstract class ElectrumWalletBase
Future<void> updateFeeRates() async { Future<void> updateFeeRates() async {
if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) { if (await checkIfMempoolAPIIsEnabled() && type == WalletType.bitcoin) {
try { try {
final response = await http final response = await ProxyWrapper()
.get(Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended")) .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/fees/recommended"))
.timeout(Duration(seconds: 5)); .timeout(Duration(seconds: 15));
final result = json.decode(response.body) as Map<String, dynamic>; final result = json.decode(response.body) as Map<String, dynamic>;
final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0; final slowFee = (result['economyFee'] as num?)?.toInt() ?? 0;
int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0; int mediumFee = (result['hourFee'] as num?)?.toInt() ?? 0;
@ -1176,20 +1175,18 @@ abstract class ElectrumWalletBase
} }
}); });
return PendingBitcoinTransaction( return PendingBitcoinTransaction(transaction, type,
transaction, electrumClient: electrumClient,
type, amount: estimatedTx.amount,
electrumClient: electrumClient, fee: estimatedTx.fee,
amount: estimatedTx.amount, feeRate: feeRateInt.toString(),
fee: estimatedTx.fee, network: network,
feeRate: feeRateInt.toString(), hasChange: estimatedTx.hasChange,
network: network, isSendAll: estimatedTx.isSendAll,
hasChange: estimatedTx.hasChange, hasTaprootInputs: hasTaprootInputs,
isSendAll: estimatedTx.isSendAll, utxos: estimatedTx.utxos,
hasTaprootInputs: hasTaprootInputs, publicKeys: estimatedTx.publicKeys)
utxos: estimatedTx.utxos, ..addListener((transaction) async {
publicKeys: estimatedTx.publicKeys
)..addListener((transaction) async {
transactionHistory.addOne(transaction); transactionHistory.addOne(transaction);
if (estimatedTx.spendsSilentPayment) { if (estimatedTx.spendsSilentPayment) {
transactionHistory.transactions.values.forEach((tx) { transactionHistory.transactions.values.forEach((tx) {
@ -1880,20 +1877,17 @@ abstract class ElectrumWalletBase
if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) { if (height != null && height > 0 && await checkIfMempoolAPIIsEnabled()) {
try { try {
final blockHash = await http.get( final blockHash = await ProxyWrapper()
Uri.parse( .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block-height/$height"))
"https://mempool.cakewallet.com/api/v1/block-height/$height", .timeout(Duration(seconds: 15));
),
);
if (blockHash.statusCode == 200 && if (blockHash.statusCode == 200 &&
blockHash.body.isNotEmpty && blockHash.body.isNotEmpty &&
jsonDecode(blockHash.body) != null) { jsonDecode(blockHash.body) != null) {
final blockResponse = await http.get( final blockResponse = await ProxyWrapper()
Uri.parse( .get(clearnetUri: Uri.parse("https://mempool.cakewallet.com/api/v1/block/${blockHash}"))
"https://mempool.cakewallet.com/api/v1/block/${blockHash.body}", .timeout(Duration(seconds: 15));
),
);
if (blockResponse.statusCode == 200 && if (blockResponse.statusCode == 200 &&
blockResponse.body.isNotEmpty && blockResponse.body.isNotEmpty &&
jsonDecode(blockResponse.body)['timestamp'] != null) { jsonDecode(blockResponse.body)['timestamp'] != null) {

View file

@ -53,7 +53,7 @@ class PayjoinManager {
} }
final receiver = Receiver.fromJson(json: session.receiver!); final receiver = Receiver.fromJson(json: session.receiver!);
printV("Resuming Payjoin Receiver Session ${receiver.id()}"); printV("Resuming Payjoin Receiver Session ${receiver.id()}");
return _spawnReceiver(receiver: receiver); return spawnReceiver(receiver: receiver);
}); });
printV("Resumed ${spawnedSessions.length} Payjoin Sessions"); printV("Resumed ${spawnedSessions.length} Payjoin Sessions");
@ -121,15 +121,13 @@ class PayjoinManager {
} }
} catch (e) { } catch (e) {
_cleanupSession(pjUri); _cleanupSession(pjUri);
printV(e); await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, e.toString());
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri); completer.complete();
completer.completeError(e);
} }
} else if (message is PayjoinSessionError) { } else if (message is PayjoinSessionError) {
_cleanupSession(pjUri); _cleanupSession(pjUri);
if (message is UnrecoverableError) { if (message is UnrecoverableError) {
printV(message.message); await _payjoinStorage.markSenderSessionUnrecoverable(pjUri, message.message);
await _payjoinStorage.markSenderSessionUnrecoverable(pjUri);
completer.complete(); completer.complete();
} else if (message is RecoverableError) { } else if (message is RecoverableError) {
completer.complete(); completer.complete();
@ -149,42 +147,41 @@ class PayjoinManager {
return completer.future; return completer.future;
} }
Future<Receiver> initReceiver(String address, Future<Receiver> getUnusedReceiver(String address,
[bool isTestnet = false]) async { [bool isTestnet = false]) async {
try { final session = _payjoinStorage.getUnusedActiveReceiverSession(_wallet.id);
final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
ohttpRelay: await randomOhttpRelayUrl(),
payjoinDirectory: payjoinDirectoryUrl,
);
final newReceiver = await NewReceiver.create( if (session != null) {
address: address, await PayjoinUri.Url.fromStr(payjoinDirectoryUrl);
network: isTestnet ? Network.testnet : Network.bitcoin,
directory: payjoinDirectoryUrl,
ohttpKeys: ohttpKeys,
);
final persister = PayjoinReceiverPersister.impl();
final receiverToken = await newReceiver.persist(persister: persister);
final receiver =
await Receiver.load(persister: persister, token: receiverToken);
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id); return Receiver.fromJson(json: session.receiver!);
return receiver;
} catch (e) {
throw Exception('Error initializing Payjoin Receiver: $e');
} }
return initReceiver(address);
} }
Future<void> spawnNewReceiver({ Future<Receiver> initReceiver(String address, [bool isTestnet = false]) async {
required Receiver receiver, final ohttpKeys = await PayjoinUri.fetchOhttpKeys(
bool isTestnet = false, ohttpRelay: await randomOhttpRelayUrl(),
}) async { payjoinDirectory: payjoinDirectoryUrl,
);
final newReceiver = await NewReceiver.create(
address: address,
network: isTestnet ? Network.testnet : Network.bitcoin,
directory: payjoinDirectoryUrl,
ohttpKeys: ohttpKeys,
);
final persister = PayjoinReceiverPersister.impl();
final receiverToken = await newReceiver.persist(persister: persister);
final receiver = await Receiver.load(persister: persister, token: receiverToken);
await _payjoinStorage.insertReceiverSession(receiver, _wallet.id); await _payjoinStorage.insertReceiverSession(receiver, _wallet.id);
return _spawnReceiver(isTestnet: isTestnet, receiver: receiver);
return receiver;
} }
Future<void> _spawnReceiver({ Future<void> spawnReceiver({
required Receiver receiver, required Receiver receiver,
bool isTestnet = false, bool isTestnet = false,
}) async { }) async {
@ -229,6 +226,10 @@ class PayjoinManager {
case PayjoinReceiverRequestTypes.getCandidateInputs: case PayjoinReceiverRequestTypes.getCandidateInputs:
utxos = _wallet.getUtxoWithPrivateKeys(); utxos = _wallet.getUtxoWithPrivateKeys();
if (utxos.isEmpty) {
await _wallet.updateAllUnspents();
utxos = _wallet.getUtxoWithPrivateKeys();
}
mainToIsolateSendPort?.send({ mainToIsolateSendPort?.send({
'requestId': message['requestId'], 'requestId': message['requestId'],
'result': utxos, 'result': utxos,

View file

@ -8,11 +8,12 @@ import 'package:cw_bitcoin/payjoin/manager.dart';
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart'; import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
import 'package:cw_bitcoin/psbt/signer.dart'; import 'package:cw_bitcoin/psbt/signer.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:payjoin_flutter/bitcoin_ffi.dart'; import 'package:payjoin_flutter/bitcoin_ffi.dart';
import 'package:payjoin_flutter/common.dart'; import 'package:payjoin_flutter/common.dart';
import 'package:payjoin_flutter/receive.dart'; import 'package:payjoin_flutter/receive.dart';
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj; import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
import 'package:http/http.dart' as very_insecure_http_do_not_use; // for errors
enum PayjoinReceiverRequestTypes { enum PayjoinReceiverRequestTypes {
processOriginalTx, processOriginalTx,
@ -28,7 +29,7 @@ class PayjoinReceiverWorker {
final pendingRequests = <String, Completer<dynamic>>{}; final pendingRequests = <String, Completer<dynamic>>{};
PayjoinReceiverWorker._(this.sendPort); PayjoinReceiverWorker._(this.sendPort);
static final client = ProxyWrapper().getHttpIOClient();
static Future<void> run(List<Object> args) async { static Future<void> run(List<Object> args) async {
await pj.core.init(); await pj.core.init();
@ -42,11 +43,10 @@ class PayjoinReceiverWorker {
receivePort.listen(worker.handleMessage); receivePort.listen(worker.handleMessage);
try { try {
final httpClient = http.Client();
final receiver = Receiver.fromJson(json: receiverJson); final receiver = Receiver.fromJson(json: receiverJson);
final uncheckedProposal = final uncheckedProposal =
await worker.receiveUncheckedProposal(httpClient, receiver); await worker.receiveUncheckedProposal(receiver);
final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast(); final originalTx = await uncheckedProposal.extractTxToScheduleBroadcast();
sendPort.send({ sendPort.send({
@ -57,14 +57,14 @@ class PayjoinReceiverWorker {
final payjoinProposal = await worker.processPayjoinProposal( final payjoinProposal = await worker.processPayjoinProposal(
uncheckedProposal, uncheckedProposal,
); );
final psbt = await worker.sendFinalProposal(httpClient, payjoinProposal); final psbt = await worker.sendFinalProposal(payjoinProposal);
sendPort.send({ sendPort.send({
'type': PayjoinReceiverRequestTypes.proposalSent, 'type': PayjoinReceiverRequestTypes.proposalSent,
'psbt': psbt, 'psbt': psbt,
}); });
} catch (e) { } catch (e) {
if (e is HttpException || if (e is HttpException ||
(e is http.ClientException && (e is very_insecure_http_do_not_use.ClientException &&
e.message.contains("Software caused connection abort"))) { e.message.contains("Software caused connection abort"))) {
sendPort.send(PayjoinSessionError.recoverable(e.toString())); sendPort.send(PayjoinSessionError.recoverable(e.toString()));
} else { } else {
@ -98,16 +98,16 @@ class PayjoinReceiverWorker {
return completer.future; return completer.future;
} }
Future<UncheckedProposal> receiveUncheckedProposal( Future<UncheckedProposal> receiveUncheckedProposal(Receiver session) async {
http.Client httpClient, Receiver session) async {
while (true) { while (true) {
printV("Polling for Proposal (${session.id()})"); printV("Polling for Proposal (${session.id()})");
final extractReq = await session.extractReq( final extractReq = await session.extractReq(
ohttpRelay: PayjoinManager.randomOhttpRelayUrl()); ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
);
final request = extractReq.$1; final request = extractReq.$1;
final url = Uri.parse(request.url.asString()); final url = Uri.parse(request.url.asString());
final httpRequest = await httpClient.post(url, final httpRequest = await client.post(url,
headers: {'Content-Type': request.contentType}, body: request.body); headers: {'Content-Type': request.contentType}, body: request.body);
final proposal = await session.processRes( final proposal = await session.processRes(
@ -116,14 +116,14 @@ class PayjoinReceiverWorker {
} }
} }
Future<String> sendFinalProposal( Future<String> sendFinalProposal(PayjoinProposal finalProposal) async {
http.Client httpClient, PayjoinProposal finalProposal) async {
final req = await finalProposal.extractReq( final req = await finalProposal.extractReq(
ohttpRelay: PayjoinManager.randomOhttpRelayUrl()); ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
);
final proposalReq = req.$1; final proposalReq = req.$1;
final proposalCtx = req.$2; final proposalCtx = req.$2;
final request = await httpClient.post( final request = await client.post(
Uri.parse(proposalReq.url.asString()), Uri.parse(proposalReq.url.asString()),
headers: {"Content-Type": proposalReq.contentType}, headers: {"Content-Type": proposalReq.contentType},
body: proposalReq.body, body: proposalReq.body,
@ -174,7 +174,7 @@ class PayjoinReceiverWorker {
final listUnspent = final listUnspent =
await _sendRequest(PayjoinReceiverRequestTypes.getCandidateInputs); await _sendRequest(PayjoinReceiverRequestTypes.getCandidateInputs);
final unspent = listUnspent as List<UtxoWithPrivateKey>; final unspent = listUnspent as List<UtxoWithPrivateKey>;
if (unspent.isEmpty) throw Exception('No unspent outputs available'); if (unspent.isEmpty) throw RecoverableError('No unspent outputs available');
final selectedUtxo = await _inputPairFromUtxo(unspent[0]); final selectedUtxo = await _inputPairFromUtxo(unspent[0]);
final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]); final pj6 = await pj5.contributeInputs(replacementInputs: [selectedUtxo]);

View file

@ -5,7 +5,7 @@ import 'dart:isolate';
import 'package:cw_bitcoin/payjoin/manager.dart'; import 'package:cw_bitcoin/payjoin/manager.dart';
import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart'; import 'package:cw_bitcoin/payjoin/payjoin_session_errors.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:payjoin_flutter/common.dart'; import 'package:payjoin_flutter/common.dart';
import 'package:payjoin_flutter/send.dart'; import 'package:payjoin_flutter/send.dart';
import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj; import 'package:payjoin_flutter/src/generated/frb_generated.dart' as pj;
@ -44,17 +44,17 @@ class PayjoinSenderWorker {
sendPort.send(e); sendPort.send(e);
} }
} }
final client = ProxyWrapper().getHttpIOClient();
/// Run a payjoin sender (V2 protocol first, fallback to V1). /// Run a payjoin sender (V2 protocol first, fallback to V1).
Future<String> runSender(Sender sender) async { Future<String> runSender(Sender sender) async {
final httpClient = http.Client();
try { try {
return await _runSenderV2(sender, httpClient); return await _runSenderV2(sender);
} catch (e) { } catch (e) {
printV(e); printV(e);
if (e is pj_error.FfiCreateRequestError) { if (e is pj_error.FfiCreateRequestError) {
return await _runSenderV1(sender, httpClient); return await _runSenderV1(sender);
} else if (e is HttpException) { } else if (e is HttpException) {
printV(e); printV(e);
throw Exception(PayjoinSessionError.recoverable(e.toString())); throw Exception(PayjoinSessionError.recoverable(e.toString()));
@ -65,14 +65,14 @@ class PayjoinSenderWorker {
} }
/// Attempt to send payjoin using the V2 of the protocol. /// Attempt to send payjoin using the V2 of the protocol.
Future<String> _runSenderV2(Sender sender, http.Client httpClient) async { Future<String> _runSenderV2(Sender sender) async {
try { try {
final postRequest = await sender.extractV2( final postRequest = await sender.extractV2(
ohttpProxyUrl: ohttpProxyUrl:
await pj_uri.Url.fromStr(PayjoinManager.randomOhttpRelayUrl()), await pj_uri.Url.fromStr(PayjoinManager.randomOhttpRelayUrl()),
); );
final postResult = await _postRequest(httpClient, postRequest.$1); final postResult = await _postRequest(postRequest.$1);
final getContext = final getContext =
await postRequest.$2.processResponse(response: postResult); await postRequest.$2.processResponse(response: postResult);
@ -84,7 +84,7 @@ class PayjoinSenderWorker {
final getRequest = await getContext.extractReq( final getRequest = await getContext.extractReq(
ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(), ohttpRelay: await PayjoinManager.randomOhttpRelayUrl(),
); );
final getRes = await _postRequest(httpClient, getRequest.$1); final getRes = await _postRequest(getRequest.$1);
final proposalPsbt = await getContext.processResponse( final proposalPsbt = await getContext.processResponse(
response: getRes, response: getRes,
ohttpCtx: getRequest.$2, ohttpCtx: getRequest.$2,
@ -98,10 +98,10 @@ class PayjoinSenderWorker {
} }
/// Attempt to send payjoin using the V1 of the protocol. /// Attempt to send payjoin using the V1 of the protocol.
Future<String> _runSenderV1(Sender sender, http.Client httpClient) async { Future<String> _runSenderV1(Sender sender) async {
try { try {
final postRequest = await sender.extractV1(); final postRequest = await sender.extractV1();
final response = await _postRequest(httpClient, postRequest.$1); final response = await _postRequest(postRequest.$1);
sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted}); sendPort.send({'type': PayjoinSenderRequestTypes.requestPosted});
@ -111,7 +111,7 @@ class PayjoinSenderWorker {
} }
} }
Future<List<int>> _postRequest(http.Client client, Request req) async { Future<List<int>> _postRequest(Request req) async {
final httpRequest = await client.post(Uri.parse(req.url.asString()), final httpRequest = await client.post(Uri.parse(req.url.asString()),
headers: {'Content-Type': req.contentType}, body: req.body); headers: {'Content-Type': req.contentType}, body: req.body);

View file

@ -23,6 +23,14 @@ class PayjoinStorage {
), ),
); );
PayjoinSession? getUnusedActiveReceiverSession(String walletId) =>
_payjoinSessionSources.values
.where((session) =>
session.walletId == walletId &&
session.status == PayjoinSessionStatus.created.name &&
!session.isSenderSession)
.firstOrNull;
Future<void> markReceiverSessionComplete( Future<void> markReceiverSessionComplete(
String sessionId, String txId, String amount) async { String sessionId, String txId, String amount) async {
final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!; final session = _payjoinSessionSources.get("$_receiverPrefix${sessionId}")!;
@ -76,10 +84,11 @@ class PayjoinStorage {
await session.save(); await session.save();
} }
Future<void> markSenderSessionUnrecoverable(String pjUrl) async { Future<void> markSenderSessionUnrecoverable(String pjUrl, String reason) async {
final session = _payjoinSessionSources.get("$_senderPrefix$pjUrl")!; final session = _payjoinSessionSources.get("$_senderPrefix$pjUrl")!;
session.status = PayjoinSessionStatus.unrecoverable.name; session.status = PayjoinSessionStatus.unrecoverable.name;
session.error = reason;
await session.save(); await session.save();
} }

View file

@ -948,11 +948,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: "direct main"
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -1038,10 +1048,19 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.1"
tor_binary:
dependency: transitive
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -54,6 +54,10 @@ dependencies:
git: git:
url: https://github.com/cake-tech/ledger-flutter-plus-plugins url: https://github.com/cake-tech/ledger-flutter-plus-plugins
path: packages/ledger-litecoin path: packages/ledger-litecoin
socks_socket:
git:
url: https://github.com/sneurlax/socks_socket
ref: e6232c53c1595469931ababa878759a067c02e94
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -1,7 +1,7 @@
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http;
// FIXME: Hardcoded values; Works only for monero // FIXME: Hardcoded values; Works only for monero
@ -234,10 +234,14 @@ int getHavenHeightByDate({required DateTime date}) {
} }
Future<int> getHavenCurrentHeight() async { Future<int> getHavenCurrentHeight() async {
final response = await http.get(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo')); final req = await ProxyWrapper().getHttpClient()
.getUrl(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'))
.timeout(Duration(seconds: 15));
final response = await req.close();
final stringResponse = await response.transform(utf8.decoder).join();
if (response.statusCode == 200) { if (response.statusCode == 200) {
final info = jsonDecode(response.body); final info = jsonDecode(stringResponse);
return info['data']['height'] as int; return info['data']['height'] as int;
} else { } else {
throw Exception('Failed to load current blockchain height'); throw Exception('Failed to load current blockchain height');
@ -269,13 +273,13 @@ const bitcoinDates = {
}; };
Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async { Future<int> getBitcoinHeightByDateAPI({required DateTime date}) async {
final response = await http.get( final req = await ProxyWrapper().getHttpClient()
Uri.parse( .getUrl(Uri.parse("https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}"))
"https://mempool.cakewallet.com/api/v1/mining/blocks/timestamp/${(date.millisecondsSinceEpoch / 1000).round()}", .timeout(Duration(seconds: 15));
), final response = await req.close();
); final stringResponse = await response.transform(utf8.decoder).join();
return jsonDecode(response.body)['height'] as int; return jsonDecode(stringResponse)['height'] as int;
} }
int getBitcoinHeightByDate({required DateTime date}) { int getBitcoinHeightByDate({required DateTime date}) {

View file

@ -1,12 +1,12 @@
import 'dart:io'; import 'dart:io';
import 'package:cw_core/keyable.dart'; import 'package:cw_core/keyable.dart';
import 'package:cw_core/utils/proxy_socket/abstract.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:cw_core/hive_type_ids.dart'; import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:http/io_client.dart' as ioc;
import 'dart:math' as math; import 'dart:math' as math;
import 'package:convert/convert.dart'; import 'package:convert/convert.dart';
@ -184,23 +184,17 @@ class Node extends HiveObject with Keyable {
final body = {'jsonrpc': '2.0', 'id': '0', 'method': "getinfo"}; final body = {'jsonrpc': '2.0', 'id': '0', 'method': "getinfo"};
try { try {
final authenticatingClient = HttpClient();
authenticatingClient.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
final http.Client client = ioc.IOClient(authenticatingClient);
final jsonBody = json.encode(body); final jsonBody = json.encode(body);
final response = await client.post( final response = await ProxyWrapper().post(
rpcUri, clearnetUri: rpcUri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: jsonBody, body: jsonBody,
); );
printV("node check response: ${response.body}");
final resBody = json.decode(response.body) as Map<String, dynamic>; final resBody = json.decode(response.body) as Map<String, dynamic>;
return resBody['result']['height'] != null; return resBody['result']['height'] != null;
} catch (e) { } catch (e) {
printV("error: $e"); printV("error: $e");
@ -218,11 +212,7 @@ class Node extends HiveObject with Keyable {
final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName}; final body = {'jsonrpc': '2.0', 'id': '0', 'method': methodName};
try { try {
final authenticatingClient = HttpClient(); final client = ProxyWrapper().getHttpIOClient();
authenticatingClient.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
final http.Client client = ioc.IOClient(authenticatingClient);
final jsonBody = json.encode(body); final jsonBody = json.encode(body);
@ -242,15 +232,15 @@ class Node extends HiveObject with Keyable {
return !(response['offline'] as bool); return !(response['offline'] as bool);
} }
printV("node check response: ${response.body}"); final responseString = await response.body;
if ((response.body.contains("400 Bad Request") // Some other generic error if ((responseString.contains("400 Bad Request") // Some other generic error
|| ||
response.body.contains("plain HTTP request was sent to HTTPS port") // Cloudflare responseString.contains("plain HTTP request was sent to HTTPS port") // Cloudflare
|| ||
response.headers["location"] != null // Generic reverse proxy response.headers["location"] != null // Generic reverse proxy
|| ||
response.body responseString
.contains("301 Moved Permanently") // Poorly configured generic reverse proxy .contains("301 Moved Permanently") // Poorly configured generic reverse proxy
) && ) &&
!(useSSL ?? false)) { !(useSSL ?? false)) {
@ -277,15 +267,16 @@ class Node extends HiveObject with Keyable {
} }
Future<bool> requestNodeWithProxy() async { Future<bool> requestNodeWithProxy() async {
if (!isValidProxyAddress /* && !Tor.instance.enabled*/) { if (!isValidProxyAddress && !CakeTor.instance.enabled) {
return false; return false;
} }
String? proxy = socksProxyAddress; String? proxy = socksProxyAddress;
// if ((proxy?.isEmpty ?? true) && Tor.instance.enabled) { if ((proxy?.isEmpty ?? true) && CakeTor.instance.enabled) {
// proxy = "${InternetAddress.loopbackIPv4.address}:${Tor.instance.port}"; proxy = "${InternetAddress.loopbackIPv4.address}:${CakeTor.instance.port}";
// } }
printV("proxy: $proxy");
if (proxy == null) { if (proxy == null) {
return false; return false;
} }
@ -305,13 +296,9 @@ class Node extends HiveObject with Keyable {
// you try to communicate with it // you try to communicate with it
Future<bool> requestElectrumServer() async { Future<bool> requestElectrumServer() async {
try { try {
final Socket socket; final ProxySocket socket;
if (useSSL == true) { socket = await ProxyWrapper().getSocksSocket(useSSL ?? false, uri.host, uri.port);
socket = await SecureSocket.connect(uri.host, uri.port,
timeout: Duration(seconds: 5), onBadCertificate: (_) => true);
} else {
socket = await Socket.connect(uri.host, uri.port, timeout: Duration(seconds: 5));
}
socket.destroy(); socket.destroy();
return true; return true;
@ -322,8 +309,8 @@ class Node extends HiveObject with Keyable {
Future<bool> requestNanoNode() async { Future<bool> requestNanoNode() async {
try { try {
final response = await http.post( final response = await ProxyWrapper().post(
uri, clearnetUri: uri,
headers: {"Content-Type": "application/json", "nano-app": "cake-wallet"}, headers: {"Content-Type": "application/json", "nano-app": "cake-wallet"},
body: jsonEncode( body: jsonEncode(
{ {
@ -332,7 +319,8 @@ class Node extends HiveObject with Keyable {
}, },
), ),
); );
final data = await jsonDecode(response.body);
final data = jsonDecode(response.body);
if (response.statusCode != 200 || if (response.statusCode != 200 ||
data["error"] != null || data["error"] != null ||
data["balance"] == null || data["balance"] == null ||
@ -348,13 +336,14 @@ class Node extends HiveObject with Keyable {
Future<bool> requestEthereumServer() async { Future<bool> requestEthereumServer() async {
try { try {
final response = await http.get( final req = await ProxyWrapper().getHttpClient()
uri, .getUrl(uri,)
headers: {'Content-Type': 'application/json'}, .timeout(Duration(seconds: 15));
); final response = await req.close();
return response.statusCode >= 200 && response.statusCode < 300; return response.statusCode >= 200 && response.statusCode < 300;
} catch (_) { } catch (err) {
printV("Failed to request ethereum server: $err");
return false; return false;
} }
} }
@ -462,7 +451,7 @@ class DaemonRpc {
/// Perform a JSON-RPC call with Digest Authentication. /// Perform a JSON-RPC call with Digest Authentication.
Future<Map<String, dynamic>> call(String method, Map<String, dynamic> params) async { Future<Map<String, dynamic>> call(String method, Map<String, dynamic> params) async {
final http.Client client = http.Client(); final client = ProxyWrapper().getHttpIOClient();
final DigestAuth digestAuth = DigestAuth(username, password); final DigestAuth digestAuth = DigestAuth(username, password);
// Initial request to get the `WWW-Authenticate` header. // Initial request to get the `WWW-Authenticate` header.

View file

@ -1,20 +1,19 @@
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart'; import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:on_chain/solana/solana.dart'; import 'package:on_chain/solana/solana.dart';
class SolanaRPCHTTPService implements SolanaJSONRPCService { class SolanaRPCHTTPService implements SolanaJSONRPCService {
SolanaRPCHTTPService( SolanaRPCHTTPService(
{required this.url, Client? client, this.defaultRequestTimeout = const Duration(seconds: 30)}) {required this.url,
: client = client ?? Client(); this.defaultRequestTimeout = const Duration(seconds: 30)});
@override @override
final String url; final String url;
final Client client;
final Duration defaultRequestTimeout; final Duration defaultRequestTimeout;
@override Future<Map<String, dynamic>> call(SolanaRequestDetails params,
Future<Map<String, dynamic>> call(SolanaRequestDetails params, [Duration? timeout]) async { [Duration? timeout]) async {
final response = await client.post( final response = await ProxyWrapper().post(
Uri.parse(url), clearnetUri: Uri.parse(url),
body: params.toRequestBody(), body: params.toRequestBody(),
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',

View file

@ -0,0 +1,29 @@
import 'dart:typed_data';
import 'package:http/http.dart' as very_insecure_http_do_not_use;
enum RequestNetwork {
clearnet,
tor,
}
enum RequestMethod {
get,
post,
put,
delete,
newHttpClient,
newHttpIOClient,
newProxySocket,
}
abstract class ProxyLogger {
void log({
required Uri? uri,
required RequestMethod method,
required Uint8List body,
required very_insecure_http_do_not_use.Response? response,
required RequestNetwork network,
required String? error,
});
}

View file

@ -0,0 +1,63 @@
import 'dart:typed_data';
import 'package:cw_core/utils/proxy_logger/abstract.dart';
import 'package:http/http.dart' as very_insecure_http_do_not_use;
class MemoryProxyLoggerEntry {
MemoryProxyLoggerEntry({
required this.trace,
required this.uri,
required this.body,
required this.network,
required this.method,
required this.response,
required this.error,
}) : time = DateTime.now();
final StackTrace trace;
final Uri? uri;
final Uint8List body;
final RequestNetwork network;
final very_insecure_http_do_not_use.Response? response;
final RequestMethod method;
final String? error;
final DateTime time;
@override
String toString() => """MemoryProxyLoggerEntry(
uri: $uri,
body: $body,
network: $network,
method: $method,
response:
code: ${response?.statusCode},
headers: ${response?.headers},
body: ${response?.body},
error: $error,
time: $time,
trace: ${trace}
);""";
}
class MemoryProxyLogger implements ProxyLogger {
static List<MemoryProxyLoggerEntry> logs = [];
@override
void log({
required Uri? uri,
required RequestMethod method,
required Uint8List body,
required very_insecure_http_do_not_use.Response? response,
required RequestNetwork network,
required String? error,
}) {
final trace = StackTrace.current;
logs.add(MemoryProxyLoggerEntry(
method: method,
trace: trace,
uri: uri,
body: body,
network: network,
response: response,
error: error,),
);
}
}

View file

@ -0,0 +1,17 @@
import 'dart:typed_data';
import 'package:cw_core/utils/proxy_logger/abstract.dart';
import 'package:http/http.dart' as very_insecure_http_do_not_use;
// we are not doing anything
class SilentProxyLogger implements ProxyLogger {
@override
void log({
required Uri? uri,
required RequestMethod method,
required Uint8List body,
required very_insecure_http_do_not_use.Response? response,
required RequestNetwork network,
required String? error,
}) {}
}

View file

@ -0,0 +1,47 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:cw_core/utils/proxy_socket/insecure.dart';
import 'package:cw_core/utils/proxy_socket/secure.dart';
import 'package:cw_core/utils/proxy_socket/socks.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:socks_socket/socks_socket.dart';
class ProxyAddress {
final String host;
final int port;
ProxyAddress({required this.host, required this.port});
}
abstract class ProxySocket {
static Future<ProxySocket> connect(bool sslEnabled, ProxyAddress address, {Duration? connectionTimeout}) async {
if (CakeTor.instance.started) {
var socksSocket = await SOCKSSocket.create(
proxyHost: InternetAddress.loopbackIPv4.address,
proxyPort: CakeTor.instance.port,
sslEnabled: sslEnabled,
);
await socksSocket.connect();
await socksSocket.connectTo(address.host, address.port);
return ProxySocketSocks(socksSocket);
}
if (sslEnabled == false) {
return ProxySocketInsecure(await Socket.connect(address.host, address.port, timeout: connectionTimeout));
} else {
return ProxySocketSecure(await SecureSocket.connect(
address.host,
address.port,
timeout: connectionTimeout,
onBadCertificate: (_) => true,
));
}
}
Future<void> close();
Future<void> destroy();
Future<void> write(String data);
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function (Object error)? onError, Function ()? onDone, bool cancelOnError = true});
ProxyAddress get address;
}

View file

@ -0,0 +1,34 @@
import 'package:cw_core/utils/proxy_socket/abstract.dart';
import 'dart:async';
import 'dart:typed_data';
import 'dart:io';
class ProxySocketInsecure implements ProxySocket {
final Socket socket;
ProxySocketInsecure(this.socket);
ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort);
@override
Future<void> close() => socket.close();
@override
Future<void> destroy() async => socket.destroy();
@override
Future<void> write(String data) async => socket.write(data);
@override
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
return socket.listen(
(data) {
onData(Uint8List.fromList(data));
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}
}

View file

@ -0,0 +1,34 @@
import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:cw_core/utils/proxy_socket/abstract.dart';
class ProxySocketSecure implements ProxySocket {
final SecureSocket socket;
ProxySocketSecure(this.socket);
ProxyAddress get address => ProxyAddress(host: socket.remoteAddress.host, port: socket.remotePort);
@override
Future<void> close() => socket.close();
@override
Future<void> destroy() async => socket.destroy();
@override
Future<void> write(String data) async => socket.write(data);
@override
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
return socket.listen(
(data) {
onData(Uint8List.fromList(data));
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}
}

View file

@ -0,0 +1,36 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:cw_core/utils/proxy_socket/abstract.dart';
import 'package:socks_socket/socks_socket.dart';
class ProxySocketSocks implements ProxySocket {
final SOCKSSocket socket;
ProxySocketSocks(this.socket);
@override
ProxyAddress get address => ProxyAddress(host: socket.proxyHost, port: socket.proxyPort);
@override
Future<void> close() => socket.close();
@override
Future<void> destroy() => close();
@override
Future<void> write(String data) async => socket.write(data);
@override
StreamSubscription<List<int>> listen(Function(Uint8List event) onData, {Function(Object error)? onError, Function()? onDone, bool cancelOnError = true}) {
return socket.listen(
(data) {
onData(Uint8List.fromList(data));
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
}
}

View file

@ -0,0 +1,447 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:cw_core/utils/proxy_logger/abstract.dart';
import 'package:cw_core/utils/proxy_socket/abstract.dart';
import 'package:cw_core/utils/tor/abstract.dart';
import 'package:cw_core/utils/tor/android.dart';
import 'package:cw_core/utils/tor/disabled.dart';
import 'package:http/http.dart';
import 'package:socks5_proxy/socks_client.dart';
import 'package:http/io_client.dart' as ioc;
class ProxyWrapper {
static final ProxyWrapper _proxyWrapper = ProxyWrapper._internal();
static ProxyLogger? logger;
factory ProxyWrapper() {
return _proxyWrapper;
}
ProxyWrapper._internal();
Future<ProxySocket> getSocksSocket(bool sslEnabled, String host, int port, {Duration? connectionTimeout}) async {
logger?.log(
uri: Uri(
scheme: sslEnabled ? "https" : "http",
host: host,
port: port,
),
method: RequestMethod.newProxySocket,
body: Uint8List(0),
response: null,
network: requestNetwork(),
error: null
);
return ProxySocket.connect(sslEnabled, ProxyAddress(host: host, port: port), connectionTimeout: connectionTimeout);
}
RequestNetwork requestNetwork() {
return CakeTor.instance.started ? RequestNetwork.tor : RequestNetwork.clearnet;
}
ioc.IOClient getHttpIOClient({int? portOverride, bool internal = false}) {
if (!internal) {
logger?.log(
uri: null,
method: RequestMethod.newHttpIOClient,
body: Uint8List(0),
response: null,
network: requestNetwork(),
error: null,
);
}
// ignore: deprecated_member_use_from_same_package
final httpClient = ProxyWrapper().getHttpClient(portOverride: portOverride, internal: true);
return ioc.IOClient(httpClient);
}
int getPort() => CakeTor.instance.port;
@Deprecated('Use ProxyWrapper().get/post/put methods instead, and provide proper clearnet and onion uri.')
HttpClient getHttpClient({int? portOverride, bool internal = false}) {
if (!internal) {
logger?.log(
uri: null,
method: RequestMethod.newProxySocket,
body: Uint8List(0),
response: null,
network: requestNetwork(),
error: null
);
}
if (CakeTor.instance.started) {
// Assign connection factory.
final client = HttpClient();
SocksTCPClient.assignToHttpClient(client, [
ProxySettings(
InternetAddress.loopbackIPv4,
CakeTor.instance.port,
password: null,
),
]);
return client;
} else {
return HttpClient();
}
}
Future<Response> _make({
required RequestMethod method,
required ioc.IOClient client,
required Uri uri,
required Map<String, String>? headers,
String? body,
}) async {
Object? error;
Response? resp;
try {
switch (method) {
case RequestMethod.get:
resp = await client. get(
uri,
headers: headers,
);
break;
case RequestMethod.delete:
resp = await client.delete(
uri,
headers: headers,
body: body,
);
break;
case RequestMethod.post:
resp = await client.post(
uri,
headers: headers,
body: body,
);
break;
case RequestMethod.put:
resp = await client.put(
uri,
headers: headers,
body: body,
);
break;
case RequestMethod.newHttpClient:
case RequestMethod.newHttpIOClient:
case RequestMethod.newProxySocket:
throw UnimplementedError();
}
return resp;
} catch (e) {
error = e;
rethrow;
} finally {
logger?.log(
uri: uri,
method: RequestMethod.get,
body: utf8.encode(body ?? ''),
response: resp,
network: requestNetwork(),
error: error?.toString(),
);
}
}
Future<Response> get({
Map<String, String>? headers,
int? portOverride,
Uri? clearnetUri,
Uri? onionUri,
}) async {
ioc.IOClient? torClient;
bool torEnabled = CakeTor.instance.started;
if (CakeTor.instance.started) {
torEnabled = true;
} else {
torEnabled = false;
}
// if tor is enabled, try to connect to the onion url first:
if (torEnabled) {
try {
// ignore: deprecated_member_use_from_same_package
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
} catch (_) {
rethrow;
}
if (onionUri != null) {
try {
return await _make(
method: RequestMethod.get,
client: torClient,
uri: onionUri,
headers: headers,
);
} catch (_) {
rethrow;
}
}
if (clearnetUri != null) {
try {
return await _make(
method: RequestMethod.get,
client: torClient,
uri: clearnetUri,
headers: headers,
);
} catch (_) {
rethrow;
}
}
}
if (clearnetUri != null) {
try {
return HttpOverrides.runZoned(
() async {
return await _make(
method: RequestMethod.get,
client: ioc.IOClient(),
uri: clearnetUri,
headers: headers,
);
},
);
} catch (_) {
// we weren't able to get a response:
rethrow;
}
}
throw Exception("Unable to connect to server");
}
Future<Response> post({
Map<String, String>? headers,
int? portOverride,
Uri? clearnetUri,
Uri? onionUri,
String? body,
bool allowMitmMoneroBypassSSLCheck = false,
}) async {
HttpClient? torHttpClient;
HttpClient cleatnetHttpClient = HttpClient();
if (allowMitmMoneroBypassSSLCheck) {
cleatnetHttpClient.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
}
ioc.IOClient clearnetClient = ioc.IOClient(cleatnetHttpClient);
bool torEnabled = CakeTor.instance.started;
if (torEnabled) {
try {
// ignore: deprecated_member_use_from_same_package
torHttpClient = await getHttpClient(portOverride: portOverride);
} catch (_) {
rethrow;
}
if (allowMitmMoneroBypassSSLCheck) {
torHttpClient.badCertificateCallback =
((X509Certificate cert, String host, int port) => true);
}
if (onionUri != null) {
try {
return await _make(
method: RequestMethod.post,
client: ioc.IOClient(torHttpClient),
uri: onionUri,
headers: headers,
body: body,
);
} catch (_) {
rethrow;
}
}
if (clearnetUri != null) {
try {
return await _make(
method: RequestMethod.post,
client: ioc.IOClient(torHttpClient),
uri: clearnetUri,
headers: headers,
body: body,
);
} catch (_) {
rethrow;
}
}
}
if (clearnetUri != null) {
try {
return HttpOverrides.runZoned(
() async {
return await _make(
method: RequestMethod.post,
client: clearnetClient,
uri: clearnetUri,
headers: headers,
body: body,
);
},
);
} catch (_) {
rethrow;
}
}
throw Exception("Unable to connect to server");
}
Future<Response> put({
Map<String, String>? headers,
int? portOverride,
Uri? clearnetUri,
Uri? onionUri,
String? body,
}) async {
ioc.IOClient? torClient;
bool torEnabled = CakeTor.instance.started;
if (torEnabled) {
try {
// ignore: deprecated_member_use_from_same_package
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
} catch (_) {}
if (onionUri != null) {
try {
return await _make(
method: RequestMethod.put,
client: torClient!,
uri: onionUri,
headers: headers,
body: body,
);
} catch (_) {
rethrow;
}
}
if (clearnetUri != null) {
try {
return await _make(
method: RequestMethod.put,
client: torClient!,
uri: clearnetUri,
headers: headers,
body: body,
);
} catch (_) {
rethrow;
}
}
}
if (clearnetUri != null) {
try {
return HttpOverrides.runZoned(
() async {
return await _make(
method: RequestMethod.put,
client: ioc.IOClient(),
uri: clearnetUri,
headers: headers,
body: body,
);
},
);
} catch (_) {
// we weren't able to get a response:
rethrow;
}
}
throw Exception("Unable to connect to server");
}
Future<Response> delete({
Map<String, String>? headers,
int? portOverride,
Uri? clearnetUri,
Uri? onionUri,
}) async {
ioc.IOClient? torClient;
bool torEnabled = CakeTor.instance.started;
if (CakeTor.instance.started) {
torEnabled = true;
} else {
torEnabled = false;
}
// if tor is enabled, try to connect to the onion url first:
if (torEnabled) {
try {
// ignore: deprecated_member_use_from_same_package
torClient = await getHttpIOClient(portOverride: portOverride, internal: true);
} catch (_) {
rethrow;
}
if (onionUri != null) {
try {
return await _make(
method: RequestMethod.delete,
client: torClient,
uri: onionUri,
headers: headers,
);
} catch (_) {
rethrow;
}
}
if (clearnetUri != null) {
try {
return await _make(
method: RequestMethod.delete,
client: torClient,
uri: clearnetUri,
headers: headers,
);
} catch (_) {
rethrow;
}
}
}
if (clearnetUri != null) {
try {
return HttpOverrides.runZoned(
() async {
return await _make(
method: RequestMethod.delete,
client: ioc.IOClient(),
uri: clearnetUri,
headers: headers,
);
},
);
} catch (_) {
// we weren't able to get a response:
rethrow;
}
}
throw Exception("Unable to connect to server");
}
}
class CakeTor {
static final CakeTorInstance instance = CakeTorInstance.getInstance();
}

View file

@ -0,0 +1,38 @@
import 'dart:io';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/tor/android.dart';
import 'package:cw_core/utils/tor/disabled.dart';
import 'package:cw_core/utils/tor/tails.dart';
abstract class CakeTorInstance {
bool get started;
int get port => -1;
bool get enabled => false;
bool get bootstrapped => false;
Future<void> start();
Future<void> stop();
static CakeTorInstance getInstance() {
if (Platform.isAndroid) {
return CakeTorAndroid();
}
if (Platform.isLinux) {
try {
final os = File("/etc/os-release").readAsLinesSync();
for (var line in os) {
if (!line.startsWith("ID=")) continue;
if (!line.contains("tails")) continue;
return CakeTorTails();
}
} catch (e) {
printV("Failed to identify linux version - /etc/os-release missing");
}
}
return CakeTorDisabled();
}
}

View file

@ -0,0 +1,73 @@
import 'dart:convert';
import 'dart:io';
import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/tor/abstract.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:tor_binary/tor_binary_platform_interface.dart';
class CakeTorAndroid implements CakeTorInstance {
@override
bool get bootstrapped => _proc != null;
@override
bool get enabled => _proc != null;
@override
int get port => 42142;
@override
Future<void> start() async {
await _runEmbeddedTor();
}
@override
bool get started => _proc != null;
@override
Future<void> stop() async {
_proc?.kill();
await _proc?.exitCode;
_proc = null;
}
static Process? _proc;
Future<void> _runEmbeddedTor() async {
final dir = await getApplicationCacheDirectory();
final torBinPath = p.join((await TorBinaryPlatform.instance.getBinaryPath())!, "libtor.so");
printV("torPath: $torBinPath");
if (started) {
printV("Proxy is running");
return;
}
printV("Starting embedded tor");
printV("app docs: $dir");
final torrc = """
SocksPort $port
Log notice file ${p.join(dir.path, "tor.log")}
RunAsDaemon 0
DataDirectory ${p.join(dir.path, "tor-data")}
""";
final torrcPath = p.join(dir.absolute.path, "torrc");
File(torrcPath).writeAsStringSync(torrc);
if (_proc != null) {
try {
_proc?.kill();
await _proc?.exitCode;
_proc = null;
} catch (e) {
printV(e);
}
}
printV("path: $torBinPath -f $torrcPath");
_proc = await Process.start(torBinPath, ["-f", torrcPath]);
_proc?.stdout.transform(utf8.decoder).forEach(printV);
_proc?.stderr.transform(utf8.decoder).forEach(printV);
}
}

View file

@ -0,0 +1,21 @@
import 'package:cw_core/utils/tor/abstract.dart';
class CakeTorDisabled implements CakeTorInstance {
@override
bool get bootstrapped => false;
@override
bool get enabled => false;
@override
int get port => -1;
@override
Future<void> start() => throw UnimplementedError();
@override
bool get started => false;
@override
Future<void> stop() => throw UnimplementedError();
}

View file

@ -0,0 +1,21 @@
import 'package:cw_core/utils/tor/abstract.dart';
class CakeTorTails implements CakeTorInstance {
@override
bool get bootstrapped => true;
@override
bool get enabled => true;
@override
int get port => 9150;
@override
Future<void> start() async {}
@override
bool get started => true;
@override
Future<void> stop() async {}
}

View file

@ -479,7 +479,7 @@ packages:
description: description:
path: "." path: "."
ref: cake-update-v2 ref: cake-update-v2
resolved-ref: "01cbbacbb05d2113aafa8b7c4a2bb766f749d8d8" resolved-ref: "096865a8c6b89c260beadfec04f7e184c40a3273"
url: "https://github.com/cake-tech/on_chain.git" url: "https://github.com/cake-tech/on_chain.git"
source: git source: git
version: "3.7.0" version: "3.7.0"
@ -635,11 +635,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: "direct main" dependency: "direct main"
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: "direct main"
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -716,10 +726,19 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.1"
tor_binary:
dependency: "direct main"
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -25,16 +25,23 @@ dependencies:
url: https://github.com/cake-tech/cake_backup.git url: https://github.com/cake-tech/cake_backup.git
ref: main ref: main
version: 1.0.0 version: 1.0.0
socks5_proxy: ^1.0.4 socks5_proxy:
git:
url: https://github.com/LacticWhale/socks_dart
ref: 27ad7c2efae8d7460325c74b90f660085cbd0685
unorm_dart: ^0.3.0 unorm_dart: ^0.3.0
on_chain: on_chain:
git: git:
url: https://github.com/cake-tech/on_chain.git url: https://github.com/cake-tech/on_chain.git
ref: cake-update-v2 ref: cake-update-v2
# tor: socks_socket:
# git: git:
# url: https://github.com/cake-tech/tor.git url: https://github.com/sneurlax/socks_socket
# ref: main ref: e6232c53c1595469931ababa878759a067c02e94
tor_binary:
git:
url: https://github.com/MrCyjaneK/flutter-tor_binary
ref: cb811c610871a9517d47134b87c2f590c15c96c5
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View file

@ -666,11 +666,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: transitive
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -751,6 +761,15 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.2"
tor_binary:
dependency: transitive
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -0,0 +1,121 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:crypto/crypto.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_ethereum/deuro/deuro_savings_contract.dart';
import 'package:cw_ethereum/ethereum_wallet.dart';
import 'package:cw_evm/contract/erc20.dart';
import 'package:cw_evm/evm_chain_transaction_priority.dart';
import 'package:cw_evm/pending_evm_chain_transaction.dart';
import 'package:web3dart/web3dart.dart';
const String savingsGatewayAddress =
"0x073493d73258C4BEb6542e8dd3e1b2891C972303";
const String dEuroAddress = "0xbA3f535bbCcCcA2A154b573Ca6c5A49BAAE0a3ea";
class DEuro {
final SavingsGateway _savingsGateway;
final ERC20 _dEuro;
final EthereumWallet _wallet;
DEuro(EthereumWallet wallet)
: _wallet = wallet,
_savingsGateway = _getSavingsGateway(wallet.getWeb3Client()!),
_dEuro = _getDEuroToken(wallet.getWeb3Client()!);
static SavingsGateway _getSavingsGateway(Web3Client client) => SavingsGateway(
address: EthereumAddress.fromHex(savingsGatewayAddress),
client: client,
);
static ERC20 _getDEuroToken(Web3Client client) => ERC20(
address: EthereumAddress.fromHex(dEuroAddress),
client: client,
);
final frontendCode =
Uint8List.fromList(sha256.convert(utf8.encode("wallet")).bytes);
EthereumAddress get _address =>
EthereumAddress.fromHex(_wallet.walletAddresses.primaryAddress);
Future<BigInt> get savingsBalance async =>
(await _savingsGateway.savings(accountOwner: _address)).saved;
Future<BigInt> get accruedInterest =>
_savingsGateway.accruedInterest(accountOwner: _address);
Future<BigInt> get interestRate => _savingsGateway.currentRatePPM();
Future<BigInt> get approvedBalance =>
_dEuro.allowance(_address, _savingsGateway.self.address);
Future<PendingEVMChainTransaction> depositSavings(
BigInt amount, EVMChainTransactionPriority priority) async {
final signedTransaction = await _savingsGateway.save(
(amount: amount, frontendCode: frontendCode),
credentials: _wallet.evmChainPrivateKey,
);
final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction(
amount: amount,
contractAddress: _savingsGateway.self.address.hexEip55,
receivingAddressHex: _savingsGateway.self.address.hexEip55,
priority: priority,
data: _savingsGateway.self.abi.functions[17]
.encodeCall([amount, frontendCode]),
);
final sendTransaction =
() => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction);
return PendingEVMChainTransaction(
sendTransaction: sendTransaction,
signedTransaction: signedTransaction,
fee: BigInt.from(fee.estimatedGasFee),
amount: amount.toString(),
exponent: 18);
}
Future<PendingEVMChainTransaction> withdrawSavings(
BigInt amount, EVMChainTransactionPriority priority) async {
final signedTransaction = await _savingsGateway.withdraw(
(target: _address, amount: amount, frontendCode: frontendCode),
credentials: _wallet.evmChainPrivateKey,
);
final fee = await _wallet.calculateActualEstimatedFeeForCreateTransaction(
amount: amount,
contractAddress: _savingsGateway.self.address.hexEip55,
receivingAddressHex: _savingsGateway.self.address.hexEip55,
priority: priority,
data: _savingsGateway.self.abi.functions[17]
.encodeCall([amount, frontendCode]),
);
final sendTransaction =
() => _wallet.getWeb3Client()!.sendRawTransaction(signedTransaction);
return PendingEVMChainTransaction(
sendTransaction: sendTransaction,
signedTransaction: signedTransaction,
fee: BigInt.from(fee.estimatedGasFee),
amount: amount.toString(),
exponent: 18);
}
// Set an infinite approval to save gas in the future
Future<PendingEVMChainTransaction> enableSavings(
EVMChainTransactionPriority priority) async =>
(await _wallet.createApprovalTransaction(
BigInt.parse(
'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
radix: 16,
),
_savingsGateway.self.address.hexEip55,
CryptoCurrency.deuro,
priority,
)) as PendingEVMChainTransaction;
}

File diff suppressed because one or more lines are too long

View file

@ -19,7 +19,7 @@ class EthereumClient extends EVMChainClient {
Future<List<EVMChainTransactionModel>> fetchTransactions(String address, Future<List<EVMChainTransactionModel>> fetchTransactions(String address,
{String? contractAddress}) async { {String? contractAddress}) async {
try { try {
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", { final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
"chainid": "$chainId", "chainid": "$chainId",
"module": "account", "module": "account",
"action": contractAddress != null ? "tokentx" : "txlist", "action": contractAddress != null ? "tokentx" : "txlist",
@ -51,7 +51,7 @@ class EthereumClient extends EVMChainClient {
@override @override
Future<List<EVMChainTransactionModel>> fetchInternalTransactions(String address) async { Future<List<EVMChainTransactionModel>> fetchInternalTransactions(String address) async {
try { try {
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", { final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
"chainid": "$chainId", "chainid": "$chainId",
"module": "account", "module": "account",
"action": "txlistinternal", "action": "txlistinternal",

View file

@ -6,7 +6,7 @@ author: Cake Wallet
homepage: https://cakewallet.com homepage: https://cakewallet.com
environment: environment:
sdk: '>=2.18.2 <3.0.0' sdk: ^3.5.0
flutter: ">=1.17.0" flutter: ">=1.17.0"
dependencies: dependencies:

View file

@ -5,6 +5,7 @@ import 'dart:developer';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/erc20_token.dart'; import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_evm/evm_chain_transaction_model.dart'; import 'package:cw_evm/evm_chain_transaction_model.dart';
import 'package:cw_evm/evm_chain_transaction_priority.dart'; import 'package:cw_evm/evm_chain_transaction_priority.dart';
import 'package:cw_evm/evm_erc20_balance.dart'; import 'package:cw_evm/evm_erc20_balance.dart';
@ -12,13 +13,12 @@ import 'package:cw_evm/pending_evm_chain_transaction.dart';
import 'package:cw_evm/.secrets.g.dart' as secrets; import 'package:cw_evm/.secrets.g.dart' as secrets;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:hex/hex.dart' as hex; import 'package:hex/hex.dart' as hex;
import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart'; import 'package:web3dart/web3dart.dart';
import 'contract/erc20.dart'; import 'contract/erc20.dart';
abstract class EVMChainClient { abstract class EVMChainClient {
final httpClient = Client(); late final client = ProxyWrapper().getHttpIOClient();
Web3Client? _client; Web3Client? _client;
//! To be overridden by all child classes //! To be overridden by all child classes
@ -47,7 +47,7 @@ abstract class EVMChainClient {
} }
_client = _client =
Web3Client(isModifiedNodeUri ? rpcUri!.toString() : node.uri.toString(), httpClient); Web3Client(isModifiedNodeUri ? rpcUri!.toString() : node.uri.toString(), client);
return true; return true;
} catch (e) { } catch (e) {
@ -76,7 +76,7 @@ abstract class EVMChainClient {
Future<int> getGasUnitPrice() async { Future<int> getGasUnitPrice() async {
try { try {
final gasPrice = await _client!.getGasPrice(); final gasPrice = await _client!.getGasPrice();
return gasPrice.getInWei.toInt(); return gasPrice.getInWei.toInt();
} catch (_) { } catch (_) {
return 0; return 0;
@ -101,6 +101,7 @@ abstract class EVMChainClient {
String? contractAddress, String? contractAddress,
EtherAmount? gasPrice, EtherAmount? gasPrice,
EtherAmount? maxFeePerGas, EtherAmount? maxFeePerGas,
Uint8List? data,
}) async { }) async {
try { try {
if (contractAddress == null) { if (contractAddress == null) {
@ -108,7 +109,6 @@ abstract class EVMChainClient {
sender: senderAddress, sender: senderAddress,
to: toAddress, to: toAddress,
value: value, value: value,
// maxFeePerGas: maxFeePerGas,
); );
return estimatedGas.toInt(); return estimatedGas.toInt();
@ -124,7 +124,7 @@ abstract class EVMChainClient {
final gasEstimate = await _client!.estimateGas( final gasEstimate = await _client!.estimateGas(
sender: senderAddress, sender: senderAddress,
to: EthereumAddress.fromHex(contractAddress), to: EthereumAddress.fromHex(contractAddress),
data: transfer.encodeCall([ data: data ?? transfer.encodeCall([
toAddress, toAddress,
value.getInWei, value.getInWei,
]), ]),
@ -137,6 +137,21 @@ abstract class EVMChainClient {
} }
} }
Uint8List getEncodedDataForApprovalTransaction({
required EthereumAddress toAddress,
required EtherAmount value,
required EthereumAddress contractAddress,
}) {
final contract = DeployedContract(ethereumContractAbi, contractAddress);
final approve = contract.function('approve');
return approve.encodeCall([
toAddress,
value.getInWei,
]);
}
Future<PendingEVMChainTransaction> signTransaction({ Future<PendingEVMChainTransaction> signTransaction({
required Credentials privateKey, required Credentials privateKey,
required String toAddress, required String toAddress,
@ -149,6 +164,7 @@ abstract class EVMChainClient {
required int exponent, required int exponent,
String? contractAddress, String? contractAddress,
String? data, String? data,
int? gasPrice,
}) async { }) async {
assert(currency == CryptoCurrency.eth || assert(currency == CryptoCurrency.eth ||
currency == CryptoCurrency.maticpoly || currency == CryptoCurrency.maticpoly ||
@ -164,6 +180,7 @@ abstract class EVMChainClient {
data: data != null ? hexToBytes(data) : null, data: data != null ? hexToBytes(data) : null,
maxGas: estimatedGasUnits, maxGas: estimatedGasUnits,
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas), maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
gasPrice: gasPrice != null ? EtherAmount.fromInt(EtherUnit.wei, gasPrice) : null,
); );
Uint8List signedTransaction; Uint8List signedTransaction;
@ -198,6 +215,52 @@ abstract class EVMChainClient {
); );
} }
Future<PendingEVMChainTransaction> signApprovalTransaction({
required Credentials privateKey,
required String spender,
required BigInt amount,
required BigInt gasFee,
required int estimatedGasUnits,
required int maxFeePerGas,
required EVMChainTransactionPriority priority,
required int exponent,
required String contractAddress,
int? gasPrice,
}) async {
final Transaction transaction = createTransaction(
from: privateKey.address,
to: EthereumAddress.fromHex(contractAddress),
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
amount: EtherAmount.zero(),
maxGas: estimatedGasUnits,
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
gasPrice: gasPrice != null ? EtherAmount.fromInt(EtherUnit.wei, gasPrice) : null,
);
final erc20 = ERC20(
client: _client!,
address: EthereumAddress.fromHex(contractAddress),
chainId: chainId,
);
final signedTransaction = await erc20.approve(
EthereumAddress.fromHex(spender),
amount,
credentials: privateKey,
transaction: transaction,
);
return PendingEVMChainTransaction(
signedTransaction: prepareSignedTransactionForSending(signedTransaction),
amount: amount.toString(),
fee: gasFee,
sendTransaction: () => sendTransaction(signedTransaction),
exponent: exponent,
isInfiniteApproval: amount.toRadixString(16) == 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff',
);
}
Transaction createTransaction({ Transaction createTransaction({
required EthereumAddress from, required EthereumAddress from,
required EthereumAddress to, required EthereumAddress to,
@ -293,7 +356,7 @@ abstract class EVMChainClient {
}, },
); );
final response = await httpClient.get( final response = await client.get(
uri, uri,
headers: { headers: {
"Accept": "application/json", "Accept": "application/json",

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'dart:typed_data';
import 'package:bip32/bip32.dart' as bip32; import 'package:bip32/bip32.dart' as bip32;
import 'package:bip39/bip39.dart' as bip39; import 'package:bip39/bip39.dart' as bip39;
@ -197,8 +198,8 @@ abstract class EVMChainWalletBase
for (var token in erc20Currencies) { for (var token in erc20Currencies) {
bool isPotentialScam = false; bool isPotentialScam = false;
bool isWhitelisted = bool isWhitelisted = getDefaultTokenContractAddresses
getDefaultTokenContractAddresses.any((element) => element == token.contractAddress); .any((element) => element.toLowerCase() == token.contractAddress.toLowerCase());
final tokenSymbol = token.title.toUpperCase(); final tokenSymbol = token.title.toUpperCase();
@ -213,6 +214,16 @@ abstract class EVMChainWalletBase
token.iconPath = null; token.iconPath = null;
await token.save(); await token.save();
} }
// For fixing wrongly classified tokens
if (!isPotentialScam && token.isPotentialScam) {
token.isPotentialScam = false;
final iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
token.iconPath = iconPath;
await token.save();
}
} }
} }
@ -255,36 +266,72 @@ abstract class EVMChainWalletBase
required String? contractAddress, required String? contractAddress,
required String receivingAddressHex, required String receivingAddressHex,
required TransactionPriority priority, required TransactionPriority priority,
Uint8List? data,
}) async { }) async {
try { try {
if (priority is EVMChainTransactionPriority) { if (priority is EVMChainTransactionPriority) {
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt(); final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
int maxFeePerGas; int maxFeePerGas;
int adjustedGasPrice;
bool isPolygon = _client.chainId == 137;
if (gasBaseFee != null) { if (gasBaseFee != null) {
// MaxFeePerGas with EIP1559; // MaxFeePerGas with EIP1559;
maxFeePerGas = gasBaseFee! + priorityFee; maxFeePerGas = gasBaseFee! + priorityFee;
} else { } else {
// MaxFeePerGas with gasPrice // MaxFeePerGas with gasPrice
maxFeePerGas = gasPrice; maxFeePerGas = gasPrice + priorityFee;
}
adjustedGasPrice = maxFeePerGas;
// Polygon has a minimum priority fee of 25 gwei
if (isPolygon) {
int minPriorityFee = 25;
int minPriorityFeeWei =
EtherAmount.fromInt(EtherUnit.gwei, minPriorityFee).getInWei.toInt();
// Calculate user selected priority-based additional fee on top of minimum
int additionalPriorityFee = 0;
switch (priority) {
case EVMChainTransactionPriority.slow:
// We use minimum priority fee only
additionalPriorityFee = 0;
break;
case EVMChainTransactionPriority.medium:
// We add 15 gwei on top of minimum
additionalPriorityFee = EtherAmount.fromInt(EtherUnit.gwei, 15).getInWei.toInt();
break;
case EVMChainTransactionPriority.fast:
// We add 35 gwei on top of minimum
additionalPriorityFee = EtherAmount.fromInt(EtherUnit.gwei, 35).getInWei.toInt();
break;
}
int totalPriorityFee = minPriorityFeeWei + additionalPriorityFee;
adjustedGasPrice = gasPrice + totalPriorityFee;
maxFeePerGas = gasPrice + totalPriorityFee;
} }
final estimatedGas = await _client.getEstimatedGasUnitsForTransaction( final estimatedGas = await _client.getEstimatedGasUnitsForTransaction(
contractAddress: contractAddress, contractAddress: contractAddress,
senderAddress: _evmChainPrivateKey.address, senderAddress: _evmChainPrivateKey.address,
value: EtherAmount.fromBigInt(EtherUnit.wei, amount!), value: EtherAmount.fromBigInt(EtherUnit.wei, amount!),
gasPrice: EtherAmount.fromInt(EtherUnit.wei, gasPrice), gasPrice: EtherAmount.fromInt(EtherUnit.wei, adjustedGasPrice),
toAddress: EthereumAddress.fromHex(receivingAddressHex), toAddress: EthereumAddress.fromHex(receivingAddressHex),
maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas), maxFeePerGas: EtherAmount.fromInt(EtherUnit.wei, maxFeePerGas),
data: data,
); );
final totalGasFee = estimatedGas * maxFeePerGas; final totalGasFee = estimatedGas * adjustedGasPrice;
return GasParamsHandler( return GasParamsHandler(
estimatedGasUnits: estimatedGas, estimatedGasUnits: estimatedGas,
estimatedGasFee: totalGasFee, estimatedGasFee: totalGasFee,
maxFeePerGas: maxFeePerGas, maxFeePerGas: maxFeePerGas,
gasPrice: gasPrice, gasPrice: adjustedGasPrice,
); );
} }
return GasParamsHandler.zero(); return GasParamsHandler.zero();
@ -473,11 +520,46 @@ abstract class EVMChainWalletBase
contractAddress: contractAddress:
transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null, transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null,
data: hexOpReturnMemo, data: hexOpReturnMemo,
gasPrice: maxFeePerGasForTransaction,
); );
return pendingEVMChainTransaction; return pendingEVMChainTransaction;
} }
Future<PendingTransaction> createApprovalTransaction(BigInt amount, String spender,
CryptoCurrency token, EVMChainTransactionPriority priority) async {
final CryptoCurrency transactionCurrency =
balance.keys.firstWhere((element) => element.title == token.title);
assert(transactionCurrency is Erc20Token);
final data = _client.getEncodedDataForApprovalTransaction(
contractAddress: EthereumAddress.fromHex((transactionCurrency as Erc20Token).contractAddress),
value: EtherAmount.fromBigInt(EtherUnit.wei, amount),
toAddress: EthereumAddress.fromHex(spender),
);
final gasFeesModel = await calculateActualEstimatedFeeForCreateTransaction(
amount: amount,
receivingAddressHex: spender,
priority: priority,
contractAddress: transactionCurrency.contractAddress,
data: data,
);
return _client.signApprovalTransaction(
privateKey: _evmChainPrivateKey,
spender: spender,
amount: amount,
priority: priority,
gasFee: BigInt.from(gasFeesModel.estimatedGasFee),
maxFeePerGas: gasFeesModel.maxFeePerGas,
estimatedGasUnits: gasFeesModel.estimatedGasUnits,
exponent: transactionCurrency.decimal,
contractAddress: transactionCurrency.contractAddress,
gasPrice: gasFeesModel.gasPrice,
);
}
Future<void> _updateTransactions() async { Future<void> _updateTransactions() async {
try { try {
if (_isTransactionUpdating) { if (_isTransactionUpdating) {

View file

@ -11,6 +11,7 @@ class PendingEVMChainTransaction with PendingTransaction {
final BigInt fee; final BigInt fee;
final String amount; final String amount;
final int exponent; final int exponent;
final bool isInfiniteApproval;
PendingEVMChainTransaction({ PendingEVMChainTransaction({
required this.sendTransaction, required this.sendTransaction,
@ -18,10 +19,12 @@ class PendingEVMChainTransaction with PendingTransaction {
required this.fee, required this.fee,
required this.amount, required this.amount,
required this.exponent, required this.exponent,
this.isInfiniteApproval = false,
}); });
@override @override
String get amountFormatted { String get amountFormatted {
if (isInfiniteApproval) return "";
final _amount = (BigInt.parse(amount) / BigInt.from(pow(10, exponent))).toString(); final _amount = (BigInt.parse(amount) / BigInt.from(pow(10, exponent))).toString();
return _amount.substring(0, min(10, _amount.length)); return _amount.substring(0, min(10, _amount.length));
} }

View file

@ -30,6 +30,7 @@ dependencies:
git: git:
url: https://github.com/cake-tech/ledger-flutter-plus-plugins url: https://github.com/cake-tech/ledger-flutter-plus-plugins
path: packages/ledger-ethereum path: packages/ledger-ethereum
ref: f4761cd5171d4c1e2e42fd3298261650539fb2db
dependency_overrides: dependency_overrides:
web3dart: web3dart:

View file

@ -146,7 +146,25 @@ int getUnlockedBalance({int accountIndex = 0}) =>
int getCurrentHeight() => currentWallet?.blockChainHeight() ?? 0; int getCurrentHeight() => currentWallet?.blockChainHeight() ?? 0;
int getNodeHeightSync() => currentWallet?.daemonBlockChainHeight() ?? 0;
int cachedNodeHeight = 0;
bool isHeightRefreshing = false;
int getNodeHeightSync() {
if (isHeightRefreshing == false) {
(() async {
try {
isHeightRefreshing = true;
final wptrAddress = currentWallet!.ffiAddress();
cachedNodeHeight = await Isolate.run(() async {
return monero.Wallet_daemonBlockChainHeight(Pointer.fromAddress(wptrAddress));
});
} finally {
isHeightRefreshing = false;
}
})();
}
return cachedNodeHeight;
}
bool isConnectedSync() => currentWallet?.connected() != 0; bool isConnectedSync() => currentWallet?.connected() != 0;
@ -202,7 +220,6 @@ Future<bool> setupNodeSync(
} }
void startRefreshSync() { void startRefreshSync() {
currentWallet!.refreshAsync();
currentWallet!.startRefresh(); currentWallet!.startRefresh();
} }
@ -228,7 +245,7 @@ void storeSync({bool force = false}) async {
return monero.Wallet_synchronized(Pointer.fromAddress(addr)); return monero.Wallet_synchronized(Pointer.fromAddress(addr));
}); });
if (lastStorePointer == addr && if (lastStorePointer == addr &&
lastStoreHeight + 5000 > currentWallet!.blockChainHeight() && lastStoreHeight + 75000 > currentWallet!.blockChainHeight() &&
!synchronized && !synchronized &&
!force) { !force) {
return; return;

View file

@ -17,6 +17,7 @@ import 'package:cw_core/pending_transaction.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
@ -207,6 +208,14 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
@override @override
Future<void> connectToNode({required Node node}) async { Future<void> connectToNode({required Node node}) async {
String socksProxy = node.socksProxyAddress ?? '';
printV("bootstrapped: ${CakeTor.instance.bootstrapped}");
printV(" enabled: ${CakeTor.instance.enabled}");
printV(" port: ${CakeTor.instance.port}");
printV(" started: ${CakeTor.instance.started}");
if (CakeTor.instance.enabled) {
socksProxy = "127.0.0.1:${CakeTor.instance.port}";
}
try { try {
syncStatus = ConnectingSyncStatus(); syncStatus = ConnectingSyncStatus();
await monero_wallet.setupNodeSync( await monero_wallet.setupNodeSync(
@ -216,7 +225,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
useSSL: node.isSSL, useSSL: node.isSSL,
isLightWallet: false, isLightWallet: false,
// FIXME: hardcoded value // FIXME: hardcoded value
socksProxyAddress: node.socksProxyAddress); socksProxyAddress: socksProxy);
await monero_wallet.setTrustedDaemon(node.trusted); await monero_wallet.setTrustedDaemon(node.trusted);
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();

View file

@ -66,11 +66,11 @@ packages:
dependency: transitive dependency: transitive
description: description:
path: "." path: "."
ref: cake-update-v2 ref: cake-update-v4
resolved-ref: "59fdf29d72068e0522a96a8953ed7272833a9f57" resolved-ref: "437dadd0bd9bf73ec6a551299577799341f6486a"
url: "https://github.com/cake-tech/blockchain_utils" url: "https://github.com/cake-tech/blockchain_utils"
source: git source: git
version: "3.3.0" version: "4.3.0"
bluez: bluez:
dependency: transitive dependency: transitive
description: description:
@ -599,10 +599,10 @@ packages:
description: description:
path: "." path: "."
ref: cake-update-v2 ref: cake-update-v2
resolved-ref: "93440dc5126369b873ca1fccc13c3c1240b1c5c2" resolved-ref: "084fb7bf13ec42d74f26ac08c883ce07c10fca7e"
url: "https://github.com/cake-tech/on_chain.git" url: "https://github.com/cake-tech/on_chain.git"
source: git source: git
version: "3.7.0" version: "6.2.0"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -779,11 +779,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: transitive
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -860,10 +870,19 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.1"
tor_binary:
dependency: transitive
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -3,11 +3,11 @@ import 'dart:convert';
import 'package:cw_core/nano_account_info_response.dart'; import 'package:cw_core/nano_account_info_response.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_nano/nano_block_info_response.dart'; import 'package:cw_nano/nano_block_info_response.dart';
import 'package:cw_core/n2_node.dart'; import 'package:cw_core/n2_node.dart';
import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_transaction_model.dart'; import 'package:cw_nano/nano_transaction_model.dart';
import 'package:http/http.dart' as http;
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:nanoutil/nanoutil.dart'; import 'package:nanoutil/nanoutil.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
@ -66,8 +66,8 @@ class NanoClient {
} }
Future<NanoBalance> getBalance(String address) async { Future<NanoBalance> getBalance(String address) async {
final response = await http.post( final response = await ProxyWrapper().post(
_node!.uri, clearnetUri: _node!.uri,
headers: getHeaders(_node!.uri.host), headers: getHeaders(_node!.uri.host),
body: jsonEncode( body: jsonEncode(
{ {
@ -76,7 +76,8 @@ class NanoClient {
}, },
), ),
); );
final data = await jsonDecode(response.body);
final data = jsonDecode(response.body) as Map<String, dynamic>;
if (response.statusCode != 200 || if (response.statusCode != 200 ||
data["error"] != null || data["error"] != null ||
data["balance"] == null || data["balance"] == null ||
@ -93,8 +94,8 @@ class NanoClient {
Future<AccountInfoResponse?> getAccountInfo(String address) async { Future<AccountInfoResponse?> getAccountInfo(String address) async {
try { try {
final response = await http.post( final response = await ProxyWrapper().post(
_node!.uri, clearnetUri: _node!.uri,
headers: getHeaders(_node!.uri.host), headers: getHeaders(_node!.uri.host),
body: jsonEncode( body: jsonEncode(
{ {
@ -104,8 +105,9 @@ class NanoClient {
}, },
), ),
); );
final data = await jsonDecode(response.body);
return AccountInfoResponse.fromJson(data as Map<String, dynamic>); final data = jsonDecode(response.body) as Map<String, dynamic>;
return AccountInfoResponse.fromJson(data);
} catch (e) { } catch (e) {
printV("error while getting account info $e"); printV("error while getting account info $e");
return null; return null;
@ -114,8 +116,8 @@ class NanoClient {
Future<BlockContentsResponse?> getBlockContents(String block) async { Future<BlockContentsResponse?> getBlockContents(String block) async {
try { try {
final response = await http.post( final response = await ProxyWrapper().post(
_node!.uri, clearnetUri: _node!.uri,
headers: getHeaders(_node!.uri.host), headers: getHeaders(_node!.uri.host),
body: jsonEncode( body: jsonEncode(
{ {
@ -125,7 +127,8 @@ class NanoClient {
}, },
), ),
); );
final data = await jsonDecode(response.body);
final data = jsonDecode(response.body) as Map<String, dynamic>;
return BlockContentsResponse.fromJson(data["contents"] as Map<String, dynamic>); return BlockContentsResponse.fromJson(data["contents"] as Map<String, dynamic>);
} catch (e) { } catch (e) {
printV("error while getting block info $e"); printV("error while getting block info $e");
@ -181,8 +184,8 @@ class NanoClient {
} }
Future<String> requestWork(String hash) async { Future<String> requestWork(String hash) async {
final response = await http.post( final response = await ProxyWrapper().post(
_powNode!.uri, clearnetUri: _powNode!.uri,
headers: getHeaders(_powNode!.uri.host), headers: getHeaders(_powNode!.uri.host),
body: json.encode( body: json.encode(
{ {
@ -191,8 +194,9 @@ class NanoClient {
}, },
), ),
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>; final decoded = jsonDecode(response.body) as Map<String, dynamic>;
if (decoded.containsKey("error")) { if (decoded.containsKey("error")) {
throw Exception("Received error ${decoded["error"]}"); throw Exception("Received error ${decoded["error"]}");
} }
@ -224,13 +228,13 @@ class NanoClient {
"block": block, "block": block,
}); });
final processResponse = await http.post( final processResponse = await ProxyWrapper().post(
_node!.uri, clearnetUri: _node!.uri,
headers: getHeaders(_node!.uri.host), headers: getHeaders(_node!.uri.host),
body: processBody, body: processBody,
); );
final Map<String, dynamic> decoded = json.decode(processResponse.body) as Map<String, dynamic>; final Map<String, dynamic> decoded = jsonDecode(processResponse.body) as Map<String, dynamic>;
if (decoded.containsKey("error")) { if (decoded.containsKey("error")) {
throw Exception("Received error ${decoded["error"]}"); throw Exception("Received error ${decoded["error"]}");
} }
@ -423,12 +427,11 @@ class NanoClient {
"subtype": "receive", "subtype": "receive",
"block": receiveBlock, "block": receiveBlock,
}); });
final processResponse = await http.post( final processResponse = await ProxyWrapper().post(
_node!.uri, clearnetUri: _node!.uri,
headers: getHeaders(_node!.uri.host), headers: getHeaders(_node!.uri.host),
body: processBody, body: processBody,
); );
final Map<String, dynamic> decoded = json.decode(processResponse.body) as Map<String, dynamic>; final Map<String, dynamic> decoded = json.decode(processResponse.body) as Map<String, dynamic>;
if (decoded.containsKey("error")) { if (decoded.containsKey("error")) {
throw Exception("Received error ${decoded["error"]}"); throw Exception("Received error ${decoded["error"]}");
@ -440,16 +443,17 @@ class NanoClient {
required String destinationAddress, required String destinationAddress,
required String privateKey, required String privateKey,
}) async { }) async {
final receivableResponse = await http.post(_node!.uri, final receivableResponse = await ProxyWrapper().post(
headers: getHeaders(_node!.uri.host), clearnetUri: _node!.uri,
body: jsonEncode({ headers: getHeaders(_node!.uri.host),
"action": "receivable", body: jsonEncode({
"account": destinationAddress, "action": "receivable",
"count": "-1", "account": destinationAddress,
"source": true, "count": "-1",
})); "source": true,
}),
final receivableData = await jsonDecode(receivableResponse.body); );
final receivableData = jsonDecode(receivableResponse.body) as Map<String, dynamic>;
if (receivableData["blocks"] == "" || receivableData["blocks"] == null) { if (receivableData["blocks"] == "" || receivableData["blocks"] == null) {
return 0; return 0;
} }
@ -492,15 +496,18 @@ class NanoClient {
Future<List<NanoTransactionModel>> fetchTransactions(String address) async { Future<List<NanoTransactionModel>> fetchTransactions(String address) async {
try { try {
final response = await http.post(_node!.uri, final response = await ProxyWrapper().post(
headers: getHeaders(_node!.uri.host), clearnetUri: _node!.uri,
body: jsonEncode({ headers: getHeaders(_node!.uri.host),
"action": "account_history", body: jsonEncode({
"account": address, "action": "account_history",
"count": "100", "account": address,
// "raw": true, "count": "100",
})); // "raw": true,
final data = await jsonDecode(response.body); }),
);
final data = jsonDecode(response.body) as Map<String, dynamic>;
final transactions = data["history"] is List ? data["history"] as List<dynamic> : []; final transactions = data["history"] is List ? data["history"] as List<dynamic> : [];
// Map the transactions list to NanoTransactionModel using the factory // Map the transactions list to NanoTransactionModel using the factory
@ -516,13 +523,14 @@ class NanoClient {
Future<List<N2Node>> getN2Reps() async { Future<List<N2Node>> getN2Reps() async {
final uri = Uri.parse(N2_REPS_ENDPOINT); final uri = Uri.parse(N2_REPS_ENDPOINT);
final response = await http.post( final response = await ProxyWrapper().post(
uri, clearnetUri: uri,
headers: getHeaders(uri.host), headers: getHeaders(uri.host),
body: jsonEncode({"action": "reps"}), body: jsonEncode({"action": "reps"}),
); );
try { try {
final List<N2Node> nodes = (json.decode(response.body) as List<dynamic>)
final List<N2Node> nodes = (jsonDecode(response.body) as List<dynamic>)
.map((dynamic e) => N2Node.fromJson(e as Map<String, dynamic>)) .map((dynamic e) => N2Node.fromJson(e as Map<String, dynamic>))
.toList(); .toList();
return nodes; return nodes;
@ -533,8 +541,8 @@ class NanoClient {
Future<int> getRepScore(String rep) async { Future<int> getRepScore(String rep) async {
final uri = Uri.parse(N2_REPS_ENDPOINT); final uri = Uri.parse(N2_REPS_ENDPOINT);
final response = await http.post( final response = await ProxyWrapper().post(
uri, clearnetUri: uri,
headers: getHeaders(uri.host), headers: getHeaders(uri.host),
body: jsonEncode({ body: jsonEncode({
"action": "rep_info", "action": "rep_info",
@ -542,7 +550,8 @@ class NanoClient {
}), }),
); );
try { try {
final N2Node node = N2Node.fromJson(json.decode(response.body) as Map<String, dynamic>);
final N2Node node = N2Node.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
return node.score ?? 100; return node.score ?? 100;
} catch (error) { } catch (error) {
return 100; return 100;

View file

@ -784,11 +784,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: transitive
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -865,10 +875,19 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.1"
tor_binary:
dependency: transitive
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -84,6 +84,6 @@ class DefaultPolygonErc20Tokens {
.iconPath; .iconPath;
} catch (_) {} } catch (_) {}
return Erc20Token.copyWith(token, iconPath, 'POLY'); return Erc20Token.copyWith(token, iconPath, 'POL');
}).toList(); }).toList();
} }

View file

@ -18,13 +18,20 @@ class PolygonClient extends EVMChainClient {
EtherAmount? gasPrice, EtherAmount? gasPrice,
EtherAmount? maxFeePerGas, EtherAmount? maxFeePerGas,
}) { }) {
EtherAmount? finalGasPrice = gasPrice;
if (gasPrice == null && maxFeePerGas != null) {
// If we have EIP-1559 parameters but no legacy gasPrice, then use maxFeePerGas as gasPrice
finalGasPrice = maxFeePerGas;
}
return Transaction( return Transaction(
from: from, from: from,
to: to, to: to,
value: amount, value: amount,
// data: data, data: data,
maxGas: maxGas, maxGas: maxGas,
// gasPrice: gasPrice, gasPrice: finalGasPrice,
// maxFeePerGas: maxFeePerGas, // maxFeePerGas: maxFeePerGas,
// maxPriorityFeePerGas: maxPriorityFeePerGas, // maxPriorityFeePerGas: maxPriorityFeePerGas,
); );
@ -40,7 +47,7 @@ class PolygonClient extends EVMChainClient {
Future<List<EVMChainTransactionModel>> fetchTransactions(String address, Future<List<EVMChainTransactionModel>> fetchTransactions(String address,
{String? contractAddress}) async { {String? contractAddress}) async {
try { try {
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", { final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
"chainid": "$chainId", "chainid": "$chainId",
"module": "account", "module": "account",
"action": contractAddress != null ? "tokentx" : "txlist", "action": contractAddress != null ? "tokentx" : "txlist",
@ -68,7 +75,7 @@ class PolygonClient extends EVMChainClient {
@override @override
Future<List<EVMChainTransactionModel>> fetchInternalTransactions(String address) async { Future<List<EVMChainTransactionModel>> fetchInternalTransactions(String address) async {
try { try {
final response = await httpClient.get(Uri.https("api.etherscan.io", "/v2/api", { final response = await client.get(Uri.https("api.etherscan.io", "/v2/api", {
"chainid": "$chainId", "chainid": "$chainId",
"module": "account", "module": "account",
"action": "txlistinternal", "action": "txlistinternal",

View file

@ -45,7 +45,12 @@ class PolygonWallet extends EVMChainWallet {
final initialErc20Tokens = DefaultPolygonErc20Tokens().initialPolygonErc20Tokens; final initialErc20Tokens = DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
for (final token in initialErc20Tokens) { for (final token in initialErc20Tokens) {
if (!evmChainErc20TokensBox.containsKey(token.contractAddress)) { if (evmChainErc20TokensBox.containsKey(token.contractAddress)) {
final existingToken = evmChainErc20TokensBox.get(token.contractAddress);
if (existingToken?.tag != token.tag) {
evmChainErc20TokensBox.put(token.contractAddress, token);
}
} else {
if (isMigration) token.enabled = false; if (isMigration) token.enabled = false;
evmChainErc20TokensBox.put(token.contractAddress, token); evmChainErc20TokensBox.put(token.contractAddress, token);
} }

View file

@ -2,8 +2,10 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/solana_rpc_http_service.dart'; import 'package:cw_core/solana_rpc_http_service.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_solana/pending_solana_transaction.dart'; import 'package:cw_solana/pending_solana_transaction.dart';
@ -11,7 +13,6 @@ import 'package:cw_solana/solana_balance.dart';
import 'package:cw_solana/solana_exceptions.dart'; import 'package:cw_solana/solana_exceptions.dart';
import 'package:cw_solana/solana_transaction_model.dart'; import 'package:cw_solana/solana_transaction_model.dart';
import 'package:cw_solana/spl_token.dart'; import 'package:cw_solana/spl_token.dart';
import 'package:http/http.dart' as http;
import 'package:on_chain/solana/solana.dart'; import 'package:on_chain/solana/solana.dart';
import 'package:on_chain/solana/src/instructions/associated_token_account/constant.dart'; import 'package:on_chain/solana/src/instructions/associated_token_account/constant.dart';
import 'package:on_chain/solana/src/models/pda/pda.dart'; import 'package:on_chain/solana/src/models/pda/pda.dart';
@ -20,10 +21,10 @@ import 'package:on_chain/solana/src/rpc/models/models/confirmed_transaction_meta
import '.secrets.g.dart' as secrets; import '.secrets.g.dart' as secrets;
class SolanaWalletClient { class SolanaWalletClient {
final httpClient = http.Client();
SolanaRPC? _provider;
// Minimum amount in SOL to consider a transaction valid (to filter spam) // Minimum amount in SOL to consider a transaction valid (to filter spam)
static const double minValidAmount = 0.00000003; static const double minValidAmount = 0.00000003;
final httpClient = ProxyWrapper().getHttpClient();
SolanaRPC? _provider;
bool connect(Node node) { bool connect(Node node) {
try { try {
@ -86,7 +87,8 @@ class SolanaWalletClient {
} }
} }
Future<SolanaBalance?> getSplTokenBalance(String mintAddress, String walletAddress) async { Future<SolanaBalance?> getSplTokenBalance(
String mintAddress, String walletAddress) async {
// Fetch the token accounts (a token can have multiple accounts for various uses) // Fetch the token accounts (a token can have multiple accounts for various uses)
final tokenAccounts = await getSPLTokenAccounts(mintAddress, walletAddress); final tokenAccounts = await getSPLTokenAccounts(mintAddress, walletAddress);
@ -122,14 +124,16 @@ class SolanaWalletClient {
), ),
); );
final fee = (feeForMessage?.toDouble() ?? 0.0) / SolanaUtils.lamportsPerSol; final fee =
(feeForMessage?.toDouble() ?? 0.0) / SolanaUtils.lamportsPerSol;
return fee; return fee;
} catch (_) { } catch (_) {
return 0.0; return 0.0;
} }
} }
Future<double> getEstimatedFee(SolanaPublicKey publicKey, Commitment commitment) async { Future<double> getEstimatedFee(
SolanaPublicKey publicKey, Commitment commitment) async {
final message = await _getMessageForNativeTransaction( final message = await _getMessageForNativeTransaction(
publicKey: publicKey, publicKey: publicKey,
destinationAddress: publicKey.toAddress().address, destinationAddress: publicKey.toAddress().address,
@ -429,17 +433,20 @@ class SolanaWalletClient {
} }
})); }));
final versionedBatchResponses = batchResponses.whereType<VersionedTransactionResponse>(); final versionedBatchResponses =
batchResponses.whereType<VersionedTransactionResponse>();
final parsedTransactionsFutures = versionedBatchResponses.map((tx) => parseTransaction( final parsedTransactionsFutures =
txResponse: tx, versionedBatchResponses.map((tx) => parseTransaction(
splTokenSymbol: splTokenSymbol, txResponse: tx,
walletAddress: walletAddress?.address ?? address.address, splTokenSymbol: splTokenSymbol,
)); walletAddress: walletAddress?.address ?? address.address,
));
final parsedTransactions = await Future.wait(parsedTransactionsFutures); final parsedTransactions = await Future.wait(parsedTransactionsFutures);
transactions.addAll(parsedTransactions.whereType<SolanaTransactionModel>().toList()); transactions.addAll(
parsedTransactions.whereType<SolanaTransactionModel>().toList());
// Only update UI if we have new valid transactions // Only update UI if we have new valid transactions
if (parsedTransactions.isNotEmpty) { if (parsedTransactions.isNotEmpty) {
@ -508,8 +515,8 @@ class SolanaWalletClient {
} }
Future<SPLToken?> fetchSPLTokenInfo(String mintAddress) async { Future<SPLToken?> fetchSPLTokenInfo(String mintAddress) async {
final programAddress = final programAddress = MetaplexTokenMetaDataProgramUtils.findMetadataPda(
MetaplexTokenMetaDataProgramUtils.findMetadataPda(mint: SolAddress(mintAddress)); mint: SolAddress(mintAddress));
final token = await _provider!.request( final token = await _provider!.request(
SolanaRPCGetMetadataAccount( SolanaRPCGetMetadataAccount(
@ -530,8 +537,9 @@ class SolanaWalletClient {
// iconPath = await _client.getIconImageFromTokenUri(metadata.uri); // iconPath = await _client.getIconImageFromTokenUri(metadata.uri);
// } catch (_) {} // } catch (_) {}
String filteredTokenSymbol = String filteredTokenSymbol = metadata.symbol
metadata.symbol.replaceFirst(RegExp('^\\\$'), '').replaceAll('\u0000', ''); .replaceFirst(RegExp('^\\\$'), '')
.replaceAll('\u0000', '');
return SPLToken.fromMetadata( return SPLToken.fromMetadata(
name: metadata.name, name: metadata.name,
@ -647,7 +655,8 @@ class SolanaWalletClient {
return message; return message;
} }
Future<double> _getFeeFromCompiledMessage(Message message, Commitment commitment) async { Future<double> _getFeeFromCompiledMessage(
Message message, Commitment commitment) async {
final base64Message = base64Encode(message.serialize()); final base64Message = base64Encode(message.serialize());
final fee = await getFeeForMessage(base64Message, commitment); final fee = await getFeeForMessage(base64Message, commitment);
@ -786,7 +795,8 @@ class SolanaWalletClient {
required SolAddress mintAddress, required SolAddress mintAddress,
required bool shouldCreateATA, required bool shouldCreateATA,
}) async { }) async {
final associatedTokenAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( final associatedTokenAccount =
AssociatedTokenAccountProgramUtils.associatedTokenAccount(
mint: mintAddress, mint: mintAddress,
owner: ownerAddress, owner: ownerAddress,
); );
@ -857,7 +867,8 @@ class SolanaWalletClient {
final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt(); final amount = (inputAmount * math.pow(10, tokenDecimals)).toInt();
ProgramDerivedAddress? associatedSenderAccount; ProgramDerivedAddress? associatedSenderAccount;
try { try {
associatedSenderAccount = AssociatedTokenAccountProgramUtils.associatedTokenAccount( associatedSenderAccount =
AssociatedTokenAccountProgramUtils.associatedTokenAccount(
mint: mintAddress, mint: mintAddress,
owner: ownerPrivateKey.publicKey().toAddress(), owner: ownerPrivateKey.publicKey().toAddress(),
); );
@ -992,7 +1003,8 @@ class SolanaWalletClient {
if (uri.isEmpty || uri == '') return null; if (uri.isEmpty || uri == '') return null;
try { try {
final response = await httpClient.get(Uri.parse(uri)); final client = ProxyWrapper().getHttpIOClient();
final response = await client.get(Uri.parse(uri));
final jsonResponse = json.decode(response.body) as Map<String, dynamic>; final jsonResponse = json.decode(response.body) as Map<String, dynamic>;

View file

@ -5,6 +5,7 @@ import 'dart:developer';
import 'package:blockchain_utils/blockchain_utils.dart'; import 'package:blockchain_utils/blockchain_utils.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_tron/pending_tron_transaction.dart'; import 'package:cw_tron/pending_tron_transaction.dart';
import 'package:cw_tron/tron_abi.dart'; import 'package:cw_tron/tron_abi.dart';
import 'package:cw_tron/tron_balance.dart'; import 'package:cw_tron/tron_balance.dart';
@ -13,12 +14,12 @@ import 'package:cw_tron/tron_token.dart';
import 'package:cw_tron/tron_transaction_model.dart'; import 'package:cw_tron/tron_transaction_model.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:http/http.dart';
import '.secrets.g.dart' as secrets; import '.secrets.g.dart' as secrets;
import 'package:on_chain/on_chain.dart'; import 'package:on_chain/on_chain.dart';
class TronClient { class TronClient {
final httpClient = Client(); late final client = ProxyWrapper().getHttpIOClient();
TronProvider? _provider; TronProvider? _provider;
// This is an internal tracker, so we don't have to "refetch". // This is an internal tracker, so we don't have to "refetch".
int _nativeTxEstimatedFee = 0; int _nativeTxEstimatedFee = 0;
@ -28,7 +29,7 @@ class TronClient {
Future<List<TronTransactionModel>> fetchTransactions(String address, Future<List<TronTransactionModel>> fetchTransactions(String address,
{String? contractAddress}) async { {String? contractAddress}) async {
try { try {
final response = await httpClient.get( final response = await client.get(
Uri.https( Uri.https(
"api.trongrid.io", "api.trongrid.io",
"/v1/accounts/$address/transactions", "/v1/accounts/$address/transactions",
@ -61,7 +62,7 @@ class TronClient {
Future<List<TronTRC20TransactionModel>> fetchTrc20ExcludedTransactions(String address) async { Future<List<TronTRC20TransactionModel>> fetchTrc20ExcludedTransactions(String address) async {
try { try {
final response = await httpClient.get( final response = await client.get(
Uri.https( Uri.https(
"api.trongrid.io", "api.trongrid.io",
"/v1/accounts/$address/transactions/trc20", "/v1/accounts/$address/transactions/trc20",

View file

@ -1,22 +1,22 @@
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:on_chain/tron/tron.dart'; import 'package:on_chain/tron/tron.dart';
import '.secrets.g.dart' as secrets; import '.secrets.g.dart' as secrets;
class TronHTTPProvider implements TronServiceProvider { class TronHTTPProvider implements TronServiceProvider {
TronHTTPProvider( TronHTTPProvider(
{required this.url, {required this.url,
http.Client? client, this.defaultRequestTimeout = const Duration(seconds: 30)});
this.defaultRequestTimeout = const Duration(seconds: 30)})
: client = client ?? http.Client();
@override @override
final String url; final String url;
final http.Client client; late final client = ProxyWrapper().getHttpIOClient();
final Duration defaultRequestTimeout; final Duration defaultRequestTimeout;
@override @override
Future<Map<String, dynamic>> get(TronRequestDetails params, [Duration? timeout]) async { Future<Map<String, dynamic>> get(TronRequestDetails params,
[Duration? timeout]) async {
final response = await client.get(Uri.parse(params.url(url)), headers: { final response = await client.get(Uri.parse(params.url(url)), headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey, if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
@ -27,13 +27,16 @@ class TronHTTPProvider implements TronServiceProvider {
} }
@override @override
Future<Map<String, dynamic>> post(TronRequestDetails params, [Duration? timeout]) async { Future<Map<String, dynamic>> post(TronRequestDetails params,
[Duration? timeout]) async {
final response = await client final response = await client
.post(Uri.parse(params.url(url)), .post(Uri.parse(params.url(url)),
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
if (url.contains("trongrid")) 'TRON-PRO-API-KEY': secrets.tronGridApiKey, if (url.contains("trongrid"))
if (url.contains("nownodes")) 'api-key': secrets.tronNowNodesApiKey, 'TRON-PRO-API-KEY': secrets.tronGridApiKey,
if (url.contains("nownodes"))
'api-key': secrets.tronNowNodesApiKey,
}, },
body: params.toRequestBody()) body: params.toRequestBody())
.timeout(timeout ?? defaultRequestTimeout); .timeout(timeout ?? defaultRequestTimeout);

View file

@ -110,7 +110,16 @@ int getUnlockedBalance({int accountIndex = 0}) =>
int getCurrentHeight() => wownero.Wallet_blockChainHeight(wptr!); int getCurrentHeight() => wownero.Wallet_blockChainHeight(wptr!);
int getNodeHeightSync() => wownero.Wallet_daemonBlockChainHeight(wptr!); int cachedNodeHeight = 0;
int getNodeHeightSync() {
(() async {
final wptrAddress = wptr!.address;
cachedNodeHeight = await Isolate.run(() async {
return wownero.Wallet_daemonBlockChainHeight(Pointer.fromAddress(wptrAddress));
});
})();
return cachedNodeHeight;
}
bool isConnectedSync() => wownero.Wallet_connected(wptr!) != 0; bool isConnectedSync() => wownero.Wallet_connected(wptr!) != 0;
@ -154,7 +163,7 @@ Future<bool> setupNodeSync(
} }
void startRefreshSync() { void startRefreshSync() {
wownero.Wallet_refreshAsync(wptr!); // wownero.Wallet_refreshAsync(wptr!);
wownero.Wallet_startRefresh(wptr!); wownero.Wallet_startRefresh(wptr!);
} }

View file

@ -16,6 +16,7 @@ import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wownero_amount_format.dart'; import 'package:cw_core/wownero_amount_format.dart';
@ -183,6 +184,14 @@ abstract class WowneroWalletBase
@override @override
Future<void> connectToNode({required Node node}) async { Future<void> connectToNode({required Node node}) async {
String socksProxy = node.socksProxyAddress ?? '';
printV("bootstrapped: ${CakeTor.instance.bootstrapped}");
printV(" enabled: ${CakeTor.instance.enabled}");
printV(" port: ${CakeTor.instance.port}");
printV(" started: ${CakeTor.instance.started}");
if (CakeTor.instance.enabled) {
socksProxy = "127.0.0.1:${CakeTor.instance.port}";
}
try { try {
syncStatus = ConnectingSyncStatus(); syncStatus = ConnectingSyncStatus();
await wownero_wallet.setupNode( await wownero_wallet.setupNode(
@ -192,7 +201,7 @@ abstract class WowneroWalletBase
useSSL: node.isSSL, useSSL: node.isSSL,
isLightWallet: false, isLightWallet: false,
// FIXME: hardcoded value // FIXME: hardcoded value
socksProxyAddress: node.socksProxyAddress); socksProxyAddress: socksProxy);
wownero_wallet.setTrustedDaemon(node.trusted); wownero_wallet.setTrustedDaemon(node.trusted);
syncStatus = ConnectedSyncStatus(); syncStatus = ConnectedSyncStatus();

View file

@ -683,11 +683,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: transitive
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -764,10 +774,19 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: timing name: timing
sha256: "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe" sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.1"
tor_binary:
dependency: transitive
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -680,11 +680,21 @@ packages:
socks5_proxy: socks5_proxy:
dependency: transitive dependency: transitive
description: description:
name: socks5_proxy path: "."
sha256: "616818a0ea1064a4823b53c9f7eaf8da64ed82dcd51ed71371c7e54751ed5053" ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
url: "https://pub.dev" resolved-ref: "27ad7c2efae8d7460325c74b90f660085cbd0685"
source: hosted url: "https://github.com/LacticWhale/socks_dart"
version: "1.0.6" source: git
version: "2.1.0"
socks_socket:
dependency: transitive
description:
path: "."
ref: e6232c53c1595469931ababa878759a067c02e94
resolved-ref: e6232c53c1595469931ababa878759a067c02e94
url: "https://github.com/sneurlax/socks_socket"
source: git
version: "1.1.1"
source_gen: source_gen:
dependency: transitive dependency: transitive
description: description:
@ -765,6 +775,15 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.0.2" version: "1.0.2"
tor_binary:
dependency: transitive
description:
path: "."
ref: cb811c610871a9517d47134b87c2f590c15c96c5
resolved-ref: cb811c610871a9517d47134b87c2f590c15c96c5
url: "https://github.com/MrCyjaneK/flutter-tor_binary"
source: git
version: "4.7.14"
tuple: tuple:
dependency: transitive dependency: transitive
description: description:

View file

@ -70,7 +70,10 @@ class WalletKeysAndSeedPageRobot {
if (walletType == WalletType.bitcoin || if (walletType == WalletType.bitcoin ||
walletType == WalletType.litecoin || walletType == WalletType.litecoin ||
walletType == WalletType.bitcoinCash) { walletType == WalletType.bitcoinCash) {
commonTestCases.hasText(appStore.wallet!.seed!); final seedWords = appStore.wallet!.seed!.split(" ");
for (var seedWord in seedWords) {
commonTestCases.hasTextAtLestOnce(seedWord);
}
tester.printToConsole('$walletName wallet has seeds properly displayed'); tester.printToConsole('$walletName wallet has seeds properly displayed');
} }
@ -78,10 +81,14 @@ class WalletKeysAndSeedPageRobot {
walletType == WalletType.solana || walletType == WalletType.solana ||
walletType == WalletType.tron) { walletType == WalletType.tron) {
if (hasSeed) { if (hasSeed) {
commonTestCases.hasText(appStore.wallet!.seed!); final seedWords = appStore.wallet!.seed!.split(" ");
for (var seedWord in seedWords) {
commonTestCases.hasTextAtLestOnce(seedWord);
}
tester.printToConsole('$walletName wallet has seeds properly displayed'); tester.printToConsole('$walletName wallet has seeds properly displayed');
} }
if (hasPrivateKey) { if (hasPrivateKey) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(appStore.wallet!.privateKey!); commonTestCases.hasText(appStore.wallet!.privateKey!);
tester.printToConsole('$walletName wallet has private key properly displayed'); tester.printToConsole('$walletName wallet has private key properly displayed');
} }
@ -89,14 +96,19 @@ class WalletKeysAndSeedPageRobot {
if (walletType == WalletType.nano || walletType == WalletType.banano) { if (walletType == WalletType.nano || walletType == WalletType.banano) {
if (hasSeed) { if (hasSeed) {
commonTestCases.hasText(appStore.wallet!.seed!); final seedWords = appStore.wallet!.seed!.split(" ");
for (var seedWord in seedWords) {
commonTestCases.hasTextAtLestOnce(seedWord);
}
tester.printToConsole('$walletName wallet has seeds properly displayed'); tester.printToConsole('$walletName wallet has seeds properly displayed');
} }
if (hasHexSeed) { if (hasHexSeed) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(appStore.wallet!.hexSeed!); commonTestCases.hasText(appStore.wallet!.hexSeed!);
tester.printToConsole('$walletName wallet has hexSeed properly displayed'); tester.printToConsole('$walletName wallet has hexSeed properly displayed');
} }
if (hasPrivateKey) { if (hasPrivateKey) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(appStore.wallet!.privateKey!); commonTestCases.hasText(appStore.wallet!.privateKey!);
tester.printToConsole('$walletName wallet has private key properly displayed'); tester.printToConsole('$walletName wallet has private key properly displayed');
} }
@ -129,35 +141,39 @@ class WalletKeysAndSeedPageRobot {
final hasSeedLegacy = Polyseed.isValidSeed(seed); final hasSeedLegacy = Polyseed.isValidSeed(seed);
if (hasPublicSpendKey) { if (hasPublicSpendKey) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(keys.publicSpendKey); commonTestCases.hasText(keys.publicSpendKey);
tester.printToConsole('$walletName wallet has public spend key properly displayed'); tester.printToConsole('$walletName wallet has public spend key properly displayed');
} }
if (hasPrivateSpendKey) { if (hasPrivateSpendKey) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(keys.privateSpendKey); commonTestCases.hasText(keys.privateSpendKey);
tester.printToConsole('$walletName wallet has private spend key properly displayed'); tester.printToConsole('$walletName wallet has private spend key properly displayed');
} }
if (hasPublicViewKey) { if (hasPublicViewKey) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(keys.publicViewKey); commonTestCases.hasText(keys.publicViewKey);
tester.printToConsole('$walletName wallet has public view key properly displayed'); tester.printToConsole('$walletName wallet has public view key properly displayed');
} }
if (hasPrivateViewKey) { if (hasPrivateViewKey) {
await commonTestCases.tapItemByKey('wallet_keys_page_keys');
commonTestCases.hasText(keys.privateViewKey); commonTestCases.hasText(keys.privateViewKey);
tester.printToConsole('$walletName wallet has private view key properly displayed'); tester.printToConsole('$walletName wallet has private view key properly displayed');
} }
if (hasSeeds) { if (hasSeeds) {
await commonTestCases.dragUntilVisible( await commonTestCases.tapItemByKey('wallet_keys_page_seed');
'${walletName}_wallet_seed_item_key', final seedWords = seed.split(" ");
'wallet_keys_page_credentials_list_view_key', for (var seedWord in seedWords) {
); commonTestCases.hasTextAtLestOnce(seedWord);
commonTestCases.hasText(seed); }
tester.printToConsole('$walletName wallet has seeds properly displayed'); tester.printToConsole('$walletName wallet has seeds properly displayed');
} }
if (hasSeedLegacy) { if (hasSeedLegacy) {
await commonTestCases.dragUntilVisible( await commonTestCases.tapItemByKey('wallet_keys_page_seed_legacy');
'${walletName}_wallet_seed_legacy_item_key', final seedWords = legacySeed.split(" ");
'wallet_keys_page_credentials_list_view_key', for (var seedWord in seedWords) {
); commonTestCases.hasTextAtLestOnce(seedWord);
commonTestCases.hasText(legacySeed); }
tester.printToConsole('$walletName wallet has legacy seeds properly displayed'); tester.printToConsole('$walletName wallet has legacy seeds properly displayed');
} }
} }

View file

@ -6,8 +6,8 @@ import 'package:cake_wallet/anonpay/anonpay_status_response.dart';
import 'package:cake_wallet/core/fiat_conversion_service.dart'; import 'package:cake_wallet/core/fiat_conversion_service.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/exchange/limits.dart'; import 'package:cake_wallet/exchange/limits.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:http/http.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
@ -20,8 +20,9 @@ class AnonPayApi {
final WalletBase wallet; final WalletBase wallet;
static const anonpayRef = secrets.anonPayReferralCode; static const anonpayRef = secrets.anonPayReferralCode;
static const onionApiAuthority = 'tqzngtf2hybjbexznel6dhgsvbynjzezoybvtv6iofomx7gchqfssgqd.onion';
static const clearNetAuthority = 'trocador.app'; static const clearNetAuthority = 'trocador.app';
// static const onionApiAuthority = 'tqzngtf2hybjbexznel6dhgsvbynjzezoybvtv6iofomx7gchqfssgqd.onion';
static const onionApiAuthority = clearNetAuthority;
static const markup = secrets.trocadorExchangeMarkup; static const markup = secrets.trocadorExchangeMarkup;
static const anonPayPath = '/anonpay'; static const anonPayPath = '/anonpay';
static const anonPayStatus = '/anonpay/status'; static const anonPayStatus = '/anonpay/status';
@ -29,8 +30,11 @@ class AnonPayApi {
static const apiKey = secrets.trocadorApiKey; static const apiKey = secrets.trocadorApiKey;
Future<AnonpayStatusResponse> paymentStatus(String id) async { Future<AnonpayStatusResponse> paymentStatus(String id) async {
final authority = await _getAuthority(); final response = await ProxyWrapper().get(
final response = await get(Uri.https(authority, "$anonPayStatus/$id")); clearnetUri: Uri.https(clearNetAuthority, "$anonPayStatus/$id"),
onionUri: Uri.https(onionApiAuthority, "$anonPayStatus/$id"),
);
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final status = responseJSON['Status'] as String; final status = responseJSON['Status'] as String;
final fiatAmount = responseJSON['Fiat_Amount'] as double?; final fiatAmount = responseJSON['Fiat_Amount'] as double?;
@ -69,10 +73,11 @@ class AnonPayApi {
if (request.fiatEquivalent != null) { if (request.fiatEquivalent != null) {
body['fiat_equiv'] = request.fiatEquivalent; body['fiat_equiv'] = request.fiatEquivalent;
} }
final authority = await _getAuthority(); final response = await ProxyWrapper().get(
clearnetUri: Uri.https(clearNetAuthority, anonPayPath, body),
final response = await get(Uri.https(authority, anonPayPath, body)); onionUri: Uri.https(onionApiAuthority, anonPayPath, body),
);
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final id = responseJSON['ID'] as String; final id = responseJSON['ID'] as String;
final url = responseJSON['url'] as String; final url = responseJSON['url'] as String;
@ -146,17 +151,16 @@ class AnonPayApi {
'name': cryptoCurrency.name, 'name': cryptoCurrency.name,
}; };
final String apiAuthority = await _getAuthority(); final response = await ProxyWrapper().get(
final uri = Uri.https(apiAuthority, coinPath, params); clearnetUri: Uri.https(clearNetAuthority, coinPath, params),
onionUri: Uri.https(onionApiAuthority, coinPath, params),
final response = await get(uri); );
final responseJSON = json.decode(response.body) as List<dynamic>;
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final responseJSON = json.decode(response.body) as List<dynamic>;
if (responseJSON.isEmpty) { if (responseJSON.isEmpty) {
throw Exception('No data'); throw Exception('No data');
} }
@ -197,17 +201,4 @@ class AnonPayApi {
return tag.toLowerCase(); return tag.toLowerCase();
} }
} }
Future<String> _getAuthority() async {
try {
if (useTorOnly) {
return onionApiAuthority;
}
final uri = Uri.https(onionApiAuthority, '/anonpay');
await get(uri);
return onionApiAuthority;
} catch (e) {
return clearNetAuthority;
}
}
} }

View file

@ -1,8 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/anypay/any_pay_payment.dart'; import 'package:cake_wallet/anypay/any_pay_payment.dart';
import 'package:cake_wallet/anypay/any_pay_trasnaction.dart'; import 'package:cake_wallet/anypay/any_pay_trasnaction.dart';
@ -53,8 +53,12 @@ class AnyPayApi {
final body = <String, dynamic>{ final body = <String, dynamic>{
'chain': chainByScheme(scheme), 'chain': chainByScheme(scheme),
'currency': currencyByScheme(scheme).title}; 'currency': currencyByScheme(scheme).title};
final response = await post(url, headers: headers, body: utf8.encode(json.encode(body))); final response = await ProxyWrapper().post(
clearnetUri: url,
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
await ExceptionHandler.onError(FlutterErrorDetails(exception: response)); await ExceptionHandler.onError(FlutterErrorDetails(exception: response));
throw Exception('Unexpected response http code: ${response.statusCode}'); throw Exception('Unexpected response http code: ${response.statusCode}');
@ -79,7 +83,12 @@ class AnyPayApi {
'chain': chain, 'chain': chain,
'currency': currency, 'currency': currency,
'transactions': transactions.map((tx) => {'tx': tx.tx, 'tx_hash': tx.id, 'tx_key': tx.key}).toList()}; 'transactions': transactions.map((tx) => {'tx': tx.tx, 'tx_hash': tx.id, 'tx_key': tx.key}).toList()};
final response = await post(Uri.parse(uri), headers: headers, body: utf8.encode(json.encode(body))); final response = await ProxyWrapper().post(
clearnetUri: Uri.parse(uri),
headers: headers,
body: json.encode(body),
);
if (response.statusCode == 400) { if (response.statusCode == 400) {
final decodedBody = json.decode(response.body) as Map<String, dynamic>; final decodedBody = json.decode(response.body) as Map<String, dynamic>;
throw Exception(decodedBody['message'] as String? ?? 'Unexpected response\nError code: 400'); throw Exception(decodedBody['message'] as String? ?? 'Unexpected response\nError code: 400');

View file

@ -10,6 +10,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart'; import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
@ -17,7 +18,6 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class DFXBuyProvider extends BuyProvider { class DFXBuyProvider extends BuyProvider {
@ -100,11 +100,12 @@ class DFXBuyProvider extends BuyProvider {
}); });
final uri = Uri.https(_baseUrl, _authPath); final uri = Uri.https(_baseUrl, _authPath);
var response = await http.post( final response = await ProxyWrapper().post(
uri, clearnetUri: uri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: requestBody, body: requestBody,
); );
if (response.statusCode == 201) { if (response.statusCode == 201) {
final responseBody = jsonDecode(response.body); final responseBody = jsonDecode(response.body);
@ -137,8 +138,10 @@ class DFXBuyProvider extends BuyProvider {
final url = Uri.https(_baseUrl, '/v1/fiat'); final url = Uri.https(_baseUrl, '/v1/fiat');
try { try {
final response = await http.get(url, headers: {'accept': 'application/json'}); final response = await ProxyWrapper().get(
clearnetUri: url,
headers: {'accept': 'application/json'});
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = jsonDecode(response.body) as List<dynamic>; final data = jsonDecode(response.body) as List<dynamic>;
for (final item in data) { for (final item in data) {
@ -160,8 +163,8 @@ class DFXBuyProvider extends BuyProvider {
final url = Uri.https(_baseUrl, '/v1/asset', {'blockchains': blockchain}); final url = Uri.https(_baseUrl, '/v1/asset', {'blockchains': blockchain});
try { try {
final response = await http.get(url, headers: {'accept': 'application/json'}); final response = await ProxyWrapper().get(clearnetUri: url, headers: {'accept': 'application/json'});
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
@ -271,7 +274,12 @@ class DFXBuyProvider extends BuyProvider {
}); });
try { try {
final response = await http.put(url, headers: headers, body: body); final response = await ProxyWrapper().put(
clearnetUri: url,
headers: headers,
body: body,
);
final responseData = jsonDecode(response.body); final responseData = jsonDecode(response.body);
if (response.statusCode == 200) { if (response.statusCode == 200) {

View file

@ -9,10 +9,10 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:developer'; import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class KryptonimBuyProvider extends BuyProvider { class KryptonimBuyProvider extends BuyProvider {
@ -74,9 +74,14 @@ class KryptonimBuyProvider extends BuyProvider {
}); });
try { try {
final response = await http.post(url, headers: headers, body: body); final response = await ProxyWrapper().post(
clearnetUri: url,
headers: headers,
body: body,
);
if (response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 401) { if (response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 401) {
return jsonDecode(response.body) as Map<String, dynamic>; return jsonDecode(response.body) as Map<String, dynamic>;
} else { } else {
return {}; return {};

View file

@ -8,13 +8,13 @@ import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:developer'; import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class MeldBuyProvider extends BuyProvider { class MeldBuyProvider extends BuyProvider {
@ -71,8 +71,8 @@ class MeldBuyProvider extends BuyProvider {
final url = Uri.https(_baseUrl, path, params); final url = Uri.https(_baseUrl, path, params);
try { try {
final response = await http.get( final response = await ProxyWrapper().get(
url, clearnetUri: url,
headers: { headers: {
'Authorization': _isProduction ? '' : _testApiKey, 'Authorization': _isProduction ? '' : _testApiKey,
'Meld-Version': '2023-12-19', 'Meld-Version': '2023-12-19',
@ -80,6 +80,7 @@ class MeldBuyProvider extends BuyProvider {
'content-type': 'application/json', 'content-type': 'application/json',
}, },
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = jsonDecode(response.body) as List<dynamic>; final data = jsonDecode(response.body) as List<dynamic>;
@ -130,7 +131,12 @@ class MeldBuyProvider extends BuyProvider {
}); });
try { try {
final response = await http.post(url, headers: headers, body: body); final response = await ProxyWrapper().post(
clearnetUri: url,
headers: headers,
body: body,
);
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = jsonDecode(response.body) as Map<String, dynamic>; final data = jsonDecode(response.body) as Map<String, dynamic>;

View file

@ -16,12 +16,12 @@ import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/themes/core/material_base_theme.dart'; import 'package:cake_wallet/themes/core/material_base_theme.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class MoonPayProvider extends BuyProvider { class MoonPayProvider extends BuyProvider {
@ -98,9 +98,12 @@ class MoonPayProvider extends BuyProvider {
Future<String> getMoonpaySignature(String query) async { Future<String> getMoonpaySignature(String query) async {
final uri = Uri.https(_cIdBaseUrl, "/api/moonpay"); final uri = Uri.https(_cIdBaseUrl, "/api/moonpay");
final response = await post(uri, final response = await ProxyWrapper().post(
headers: {'Content-Type': 'application/json', 'x-api-key': _exchangeHelperApiKey}, clearnetUri: uri,
body: json.encode({'query': query})); headers: {'Content-Type': 'application/json', 'x-api-key': _exchangeHelperApiKey},
body: json.encode({'query': query}),
);
if (response.statusCode == 200) { if (response.statusCode == 200) {
return (jsonDecode(response.body) as Map<String, dynamic>)['signature'] as String; return (jsonDecode(response.body) as Map<String, dynamic>)['signature'] as String;
@ -120,7 +123,11 @@ class MoonPayProvider extends BuyProvider {
final url = Uri.https(_baseUrl, path, params); final url = Uri.https(_baseUrl, path, params);
try { try {
final response = await get(url, headers: {'accept': 'application/json'}); final response = await ProxyWrapper().get(
clearnetUri: url,
headers: {'accept': 'application/json'},
);
if (response.statusCode == 200) { if (response.statusCode == 200) {
return jsonDecode(response.body) as Map<String, dynamic>; return jsonDecode(response.body) as Map<String, dynamic>;
} else { } else {
@ -191,8 +198,8 @@ class MoonPayProvider extends BuyProvider {
final path = '$_currenciesPath/$formattedCryptoCurrency$quotePath'; final path = '$_currenciesPath/$formattedCryptoCurrency$quotePath';
final url = Uri.https(_baseUrl, path, params); final url = Uri.https(_baseUrl, path, params);
try { try {
final response = await get(url); final response = await ProxyWrapper().get(clearnetUri: url);
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = jsonDecode(response.body) as Map<String, dynamic>; final data = jsonDecode(response.body) as Map<String, dynamic>;
@ -306,7 +313,8 @@ class MoonPayProvider extends BuyProvider {
Future<Order> findOrderById(String id) async { Future<Order> findOrderById(String id) async {
final url = _apiUrl + _transactionsSuffix + '/$id' + '?apiKey=' + _apiKey; final url = _apiUrl + _transactionsSuffix + '/$id' + '?apiKey=' + _apiKey;
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw BuyException(title: providerDescription, content: 'Transaction $id is not found!'); throw BuyException(title: providerDescription, content: 'Transaction $id is not found!');

View file

@ -9,11 +9,12 @@ import 'package:cake_wallet/buy/payment_method.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/themes/core/theme_store.dart'; import 'package:cake_wallet/themes/core/theme_store.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class OnRamperBuyProvider extends BuyProvider { class OnRamperBuyProvider extends BuyProvider {
@ -66,8 +67,10 @@ class OnRamperBuyProvider extends BuyProvider {
final url = Uri.https(_baseApiUrl, '$supported$defaultsAll', params); final url = Uri.https(_baseApiUrl, '$supported$defaultsAll', params);
try { try {
final response = final response = await ProxyWrapper().get(
await http.get(url, headers: {'Authorization': _apiKey, 'accept': 'application/json'}); clearnetUri: url,
headers: {'Authorization': _apiKey, 'accept': 'application/json'},
);
if (response.statusCode == 200) { if (response.statusCode == 200) {
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>; final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
@ -102,8 +105,8 @@ class OnRamperBuyProvider extends BuyProvider {
try { try {
final response = final response =
await http.get(url, headers: {'Authorization': _apiKey, 'accept': 'application/json'}); await ProxyWrapper().get(clearnetUri: url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
if (response.statusCode == 200) { if (response.statusCode == 200) {
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>; final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
final List<dynamic> message = data['message'] as List<dynamic>; final List<dynamic> message = data['message'] as List<dynamic>;
@ -132,7 +135,8 @@ class OnRamperBuyProvider extends BuyProvider {
try { try {
final response = final response =
await http.get(url, headers: {'Authorization': _apiKey, 'accept': 'application/json'}); await ProxyWrapper().get(clearnetUri: url, headers: {'Authorization': _apiKey, 'accept': 'application/json'});
if (response.statusCode == 200) { if (response.statusCode == 200) {
final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>; final Map<String, dynamic> data = jsonDecode(response.body) as Map<String, dynamic>;
@ -195,8 +199,8 @@ class OnRamperBuyProvider extends BuyProvider {
final headers = {'Authorization': _apiKey, 'accept': 'application/json'}; final headers = {'Authorization': _apiKey, 'accept': 'application/json'};
try { try {
final response = await http.get(url, headers: headers); final response = await ProxyWrapper().get(clearnetUri: url, headers: headers);
if (response.statusCode == 200) { if (response.statusCode == 200) {
final data = jsonDecode(response.body) as List<dynamic>; final data = jsonDecode(response.body) as List<dynamic>;
if (data.isEmpty) return null; if (data.isEmpty) return null;

View file

@ -11,6 +11,7 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart'; import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
@ -18,7 +19,6 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
class RobinhoodBuyProvider extends BuyProvider { class RobinhoodBuyProvider extends BuyProvider {
@ -69,7 +69,8 @@ class RobinhoodBuyProvider extends BuyProvider {
final uri = Uri.https(_apiBaseUrl, '$_assetsPath', {'applicationId': _applicationId}); final uri = Uri.https(_apiBaseUrl, '$_assetsPath', {'applicationId': _applicationId});
try { try {
final response = await http.get(uri, headers: {'accept': 'application/json'}); final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'accept': 'application/json'});
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseData = jsonDecode(response.body) as Map<String, dynamic>; final responseData = jsonDecode(response.body) as Map<String, dynamic>;
@ -122,12 +123,14 @@ class RobinhoodBuyProvider extends BuyProvider {
final uri = Uri.https(_cIdBaseUrl, "/api/robinhood"); final uri = Uri.https(_cIdBaseUrl, "/api/robinhood");
var response = await http.post(uri, var response = await ProxyWrapper().post(
headers: {'Content-Type': 'application/json'}, clearnetUri: uri,
body: json headers: {'Content-Type': 'application/json'},
.encode({'valid_until': valid_until, 'wallet': walletAddress, 'signature': signature})); body: json.encode({'valid_until': valid_until, 'wallet': walletAddress, 'signature': signature}),
);
if (response.statusCode == 200) { if (response.statusCode == 200) {
return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String; return (jsonDecode(response.body) as Map<String, dynamic>)['connectId'] as String;
} else { } else {
throw Exception('Provider currently unavailable. Status: ${response.statusCode}'); throw Exception('Provider currently unavailable. Status: ${response.statusCode}');
@ -219,7 +222,8 @@ class RobinhoodBuyProvider extends BuyProvider {
Uri.https('api.robinhood.com', '/catpay/v1/${cryptoCurrency.title}/quote/', queryParams); Uri.https('api.robinhood.com', '/catpay/v1/${cryptoCurrency.title}/quote/', queryParams);
try { try {
final response = await http.get(uri, headers: {'accept': 'application/json'}); final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'accept': 'application/json'});
final responseData = jsonDecode(response.body) as Map<String, dynamic>; final responseData = jsonDecode(response.body) as Map<String, dynamic>;
if (response.statusCode == 200) { if (response.statusCode == 200) {

View file

@ -3,7 +3,7 @@ import 'package:cake_wallet/buy/buy_exception.dart';
import 'package:cake_wallet/buy/pairs_utils.dart'; import 'package:cake_wallet/buy/pairs_utils.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:http/http.dart'; import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cake_wallet/buy/buy_amount.dart'; import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/buy_provider.dart'; import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_provider_description.dart'; import 'package:cake_wallet/buy/buy_provider_description.dart';
@ -73,18 +73,21 @@ class WyreBuyProvider extends BuyProvider {
'referrerAccountId': _accountId, 'referrerAccountId': _accountId,
'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest'] 'lockFields': ['amount', 'sourceCurrency', 'destCurrency', 'dest']
}; };
final response = await post(uri, final response = await ProxyWrapper().post(
headers: { clearnetUri: uri,
'Authorization': 'Bearer $_secretKey', headers: {
'Content-Type': 'application/json', 'Authorization': 'Bearer $_secretKey',
'cache-control': 'no-cache' 'Content-Type': 'application/json',
}, 'cache-control': 'no-cache'
body: json.encode(body)); },
body: json.encode(body),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw BuyException(title: providerDescription, content: 'Url $url is not found!'); throw BuyException(title: providerDescription, content: 'Url $url is not found!');
} }
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final urlFromResponse = responseJSON['url'] as String; final urlFromResponse = responseJSON['url'] as String;
return urlFromResponse; return urlFromResponse;
@ -101,18 +104,21 @@ class WyreBuyProvider extends BuyProvider {
'country': _countryCode 'country': _countryCode
}; };
final uri = Uri.parse(quoteUrl); final uri = Uri.parse(quoteUrl);
final response = await post(uri, final response = await ProxyWrapper().post(
headers: { clearnetUri: uri,
'Authorization': 'Bearer $_secretKey', headers: {
'Content-Type': 'application/json', 'Authorization': 'Bearer $_secretKey',
'cache-control': 'no-cache' 'Content-Type': 'application/json',
}, 'cache-control': 'no-cache'
body: json.encode(body)); },
body: json.encode(body),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw BuyException(title: providerDescription, content: 'Quote is not found!'); throw BuyException(title: providerDescription, content: 'Quote is not found!');
} }
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final sourceAmount = responseJSON['sourceAmount'] as double; final sourceAmount = responseJSON['sourceAmount'] as double;
final destAmount = responseJSON['destAmount'] as double; final destAmount = responseJSON['destAmount'] as double;
@ -125,8 +131,7 @@ class WyreBuyProvider extends BuyProvider {
Future<Order> findOrderById(String id) async { Future<Order> findOrderById(String id) async {
final orderUrl = baseApiUrl + _ordersSuffix + '/$id'; final orderUrl = baseApiUrl + _ordersSuffix + '/$id';
final orderUri = Uri.parse(orderUrl); final orderUri = Uri.parse(orderUrl);
final orderResponse = await get(orderUri); final orderResponse = await ProxyWrapper().get(clearnetUri: orderUri);
if (orderResponse.statusCode != 200) { if (orderResponse.statusCode != 200) {
throw BuyException(title: providerDescription, content: 'Order $id is not found!'); throw BuyException(title: providerDescription, content: 'Order $id is not found!');
} }
@ -142,8 +147,7 @@ class WyreBuyProvider extends BuyProvider {
final transferUrl = baseApiUrl + _transferSuffix + transferId + _trackSuffix; final transferUrl = baseApiUrl + _transferSuffix + transferId + _trackSuffix;
final transferUri = Uri.parse(transferUrl); final transferUri = Uri.parse(transferUrl);
final transferResponse = await get(transferUri); final transferResponse = await ProxyWrapper().get(clearnetUri: transferUri);
if (transferResponse.statusCode != 200) { if (transferResponse.statusCode != 200) {
throw BuyException(title: providerDescription, content: 'Transfer $transferId is not found!'); throw BuyException(title: providerDescription, content: 'Transfer $transferId is not found!');
} }

View file

@ -3,9 +3,9 @@ import 'dart:convert';
import 'package:cake_wallet/cake_pay/cake_pay_order.dart'; import 'package:cake_wallet/cake_pay/cake_pay_order.dart';
import 'package:cake_wallet/cake_pay/cake_pay_user_credentials.dart'; import 'package:cake_wallet/cake_pay/cake_pay_user_credentials.dart';
import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cake_wallet/entities/country.dart'; import 'package:cake_wallet/entities/country.dart';
import 'package:http/http.dart' as http;
class CakePayApi { class CakePayApi {
static const testBaseUri = false; static const testBaseUri = false;
@ -32,12 +32,17 @@ class CakePayApi {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Authorization': 'Api-Key $apiKey', 'Authorization': 'Api-Key $apiKey',
}; };
final response = await http.post(uri, headers: headers, body: json.encode({'email': email})); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode({'email': email}),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, dynamic>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
if (bodyJson.containsKey('user') && bodyJson['user']['email'] != null) { if (bodyJson.containsKey('user') && bodyJson['user']['email'] != null) {
@ -64,12 +69,17 @@ class CakePayApi {
}; };
final query = <String, String>{'email': email, 'otp': code}; final query = <String, String>{'email': email, 'otp': code};
final response = await http.post(uri, headers: headers, body: json.encode(query)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(query),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
final bodyJson = json.decode(response.body) as Map<String, dynamic>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
if (bodyJson.containsKey('error')) { if (bodyJson.containsKey('error')) {
@ -116,9 +126,14 @@ class CakePayApi {
}; };
try { try {
final response = await http.post(uri, headers: headers, body: json.encode(query)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(query),
);
if (response.statusCode != 201) { if (response.statusCode != 201) {
final responseBody = json.decode(response.body); final responseBody = json.decode(response.body);
if (responseBody is List) { if (responseBody is List) {
throw '${responseBody[0]}'; throw '${responseBody[0]}';
@ -127,6 +142,7 @@ class CakePayApi {
} }
} }
final bodyJson = json.decode(response.body) as Map<String, dynamic>; final bodyJson = json.decode(response.body) as Map<String, dynamic>;
return CakePayOrder.fromMap(bodyJson); return CakePayOrder.fromMap(bodyJson);
} catch (e) { } catch (e) {
@ -145,7 +161,8 @@ class CakePayApi {
'X-CSRFToken': CSRFToken, 'X-CSRFToken': CSRFToken,
}; };
final response = await http.get(uri, headers: headers); final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
printV('Response: ${response.statusCode}'); printV('Response: ${response.statusCode}');
@ -168,7 +185,11 @@ class CakePayApi {
}; };
try { try {
final response = await http.post(uri, headers: headers, body: json.encode({'email': email})); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode({'email': email}),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
@ -187,8 +208,8 @@ class CakePayApi {
'Authorization': 'Api-Key $apiKey', 'Authorization': 'Api-Key $apiKey',
}; };
final response = await http.get(uri, headers: headers); final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
} }
@ -234,14 +255,15 @@ class CakePayApi {
'Authorization': 'Api-Key $apiKey', 'Authorization': 'Api-Key $apiKey',
}; };
var response = await http.get(uri, headers: headers); var response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception( throw Exception(
'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}'); 'Failed to fetch vendors: statusCode - ${response.statusCode}, queryParams -$queryParams, response - ${response.body}');
} }
final bodyJson = json.decode(utf8.decode(response.bodyBytes)); final bodyJson = json.decode(response.body);
if (bodyJson is List<dynamic> && bodyJson.isEmpty) { if (bodyJson is List<dynamic> && bodyJson.isEmpty) {
return []; return [];

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/preferences_key.dart'; import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/feature_flag.dart'; import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/tor.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; 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:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
@ -15,6 +16,7 @@ import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/foundation.dart';
class BackgroundSync { class BackgroundSync {
final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin(); final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();
@ -90,6 +92,11 @@ class BackgroundSync {
} }
Future<void> sync() async { Future<void> sync() async {
final settingsStore = getIt.get<SettingsStore>();
if (settingsStore.currentBuiltinTor) {
printV("Starting Tor");
await ensureTorStarted(context: null);
}
printV("Background sync started"); printV("Background sync started");
await _syncWallets(); await _syncWallets();
printV("Background sync completed"); printV("Background sync completed");
@ -100,7 +107,6 @@ class BackgroundSync {
final walletListViewModel = getIt.get<WalletListViewModel>(); final walletListViewModel = getIt.get<WalletListViewModel>();
final settingsStore = getIt.get<SettingsStore>(); final settingsStore = getIt.get<SettingsStore>();
final List<WalletListItem> moneroWallets = walletListViewModel.wallets final List<WalletListItem> moneroWallets = walletListViewModel.wallets
.where((element) => !element.isHardware) .where((element) => !element.isHardware)
.where((element) => ![WalletType.haven, WalletType.decred].contains(element.type)) .where((element) => ![WalletType.haven, WalletType.decred].contains(element.type))

View file

@ -1,18 +1,15 @@
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart'; import 'package:cake_wallet/entities/fiat_currency.dart';
import 'dart:convert'; import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com'; const _fiatApiClearNetAuthority = 'fiat-api.cakewallet.com';
const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion'; // const _fiatApiOnionAuthority = 'n4z7bdcmwk2oyddxvzaap3x2peqcplh3pzdy7tpkk5ejz5n4mhfvoxqd.onion';
const _fiatApiOnionAuthority = _fiatApiClearNetAuthority;
const _fiatApiPath = '/v2/rates'; const _fiatApiPath = '/v2/rates';
Future<double> _fetchPrice(Map<String, dynamic> args) async { Future<double> _fetchPrice(String crypto, String fiat, bool torOnly) async {
final crypto = args['crypto'] as String;
final fiat = args['fiat'] as String;
final torOnly = args['torOnly'] as bool;
final Map<String, String> queryParams = { final Map<String, String> queryParams = {
'interval_count': '1', 'interval_count': '1',
@ -24,14 +21,14 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
num price = 0.0; num price = 0.0;
try { try {
late final Uri uri; final onionUri = Uri.http(_fiatApiOnionAuthority, _fiatApiPath, queryParams);
if (torOnly) { final clearnetUri = Uri.https(_fiatApiClearNetAuthority, _fiatApiPath, queryParams);
uri = Uri.http(_fiatApiOnionAuthority, _fiatApiPath, queryParams);
} else {
uri = Uri.https(_fiatApiClearNetAuthority, _fiatApiPath, queryParams);
}
final response = await get(uri); final response = await ProxyWrapper().get(
onionUri: onionUri,
clearnetUri: torOnly ? onionUri : clearnetUri,
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
return 0.0; return 0.0;
@ -50,18 +47,11 @@ Future<double> _fetchPrice(Map<String, dynamic> args) async {
} }
} }
Future<double> _fetchPriceAsync(CryptoCurrency crypto, FiatCurrency fiat, bool torOnly) async =>
compute(_fetchPrice, {
'fiat': fiat.toString(),
'crypto': crypto.toString(),
'torOnly': torOnly,
});
class FiatConversionService { class FiatConversionService {
static Future<double> fetchPrice({ static Future<double> fetchPrice({
required CryptoCurrency crypto, required CryptoCurrency crypto,
required FiatCurrency fiat, required FiatCurrency fiat,
required bool torOnly, required bool torOnly,
}) async => }) async =>
await _fetchPriceAsync(crypto, fiat, torOnly); await _fetchPrice(crypto.toString(), fiat.toString(), torOnly);
} }

View file

@ -5,15 +5,13 @@ import 'package:cake_wallet/core/open_crypto_pay/exceptions.dart';
import 'package:cake_wallet/core/open_crypto_pay/lnurl.dart'; import 'package:cake_wallet/core/open_crypto_pay/lnurl.dart';
import 'package:cake_wallet/core/open_crypto_pay/models.dart'; import 'package:cake_wallet/core/open_crypto_pay/models.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:http/http.dart'; import 'package:cw_core/utils/proxy_wrapper.dart';
class OpenCryptoPayService { class OpenCryptoPayService {
static bool isOpenCryptoPayQR(String value) => static bool isOpenCryptoPayQR(String value) =>
value.toLowerCase().contains("lightning=lnurl") || value.toLowerCase().contains("lightning=lnurl") ||
value.toLowerCase().startsWith("lnurl"); value.toLowerCase().startsWith("lnurl");
final Client _httpClient = Client();
Future<String> commitOpenCryptoPayRequest( Future<String> commitOpenCryptoPayRequest(
String txHex, { String txHex, {
required String txId, required String txId,
@ -31,7 +29,8 @@ class OpenCryptoPayService {
queryParams['tx'] = txId; queryParams['tx'] = txId;
final response = final response =
await _httpClient.get(Uri.https(uri.authority, uri.path, queryParams)); await ProxyWrapper().get(clearnetUri: Uri.https(uri.authority, uri.path, queryParams));
if (response.statusCode == 200) { if (response.statusCode == 200) {
final body = jsonDecode(response.body) as Map; final body = jsonDecode(response.body) as Map;
@ -40,13 +39,13 @@ class OpenCryptoPayService {
throw OpenCryptoPayException(body.toString()); throw OpenCryptoPayException(body.toString());
} }
throw OpenCryptoPayException( throw OpenCryptoPayException(
"Unexpected status code ${response.statusCode} ${response.body}"); "Unexpected status code ${response.statusCode} ${response}");
} }
Future<void> cancelOpenCryptoPayRequest(OpenCryptoPayRequest request) async { Future<void> cancelOpenCryptoPayRequest(OpenCryptoPayRequest request) async {
final uri = Uri.parse(request.callbackUrl.replaceAll("/cb/", "/cancel/")); final uri = Uri.parse(request.callbackUrl.replaceAll("/cb/", "/cancel/"));
await _httpClient.delete(uri); await ProxyWrapper().delete(clearnetUri: uri);
} }
Future<OpenCryptoPayRequest> getOpenCryptoPayInvoice(String lnUrl) async { Future<OpenCryptoPayRequest> getOpenCryptoPayInvoice(String lnUrl) async {
@ -73,7 +72,8 @@ class OpenCryptoPayService {
Future<(_OpenCryptoPayQuote, Map<String, List<OpenCryptoPayQuoteAsset>>)> Future<(_OpenCryptoPayQuote, Map<String, List<OpenCryptoPayQuoteAsset>>)>
_getOpenCryptoPayParams(Uri uri) async { _getOpenCryptoPayParams(Uri uri) async {
final response = await _httpClient.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseBody = jsonDecode(response.body) as Map; final responseBody = jsonDecode(response.body) as Map;
@ -119,8 +119,8 @@ class OpenCryptoPayService {
queryParams['asset'] = asset.title; queryParams['asset'] = asset.title;
queryParams['method'] = _getMethod(asset); queryParams['method'] = _getMethod(asset);
final response = final response = await ProxyWrapper().get(clearnetUri: Uri.https(uri.authority, uri.path, queryParams));
await _httpClient.get(Uri.https(uri.authority, uri.path, queryParams));
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseBody = jsonDecode(response.body) as Map; final responseBody = jsonDecode(response.body) as Map;

View file

@ -73,8 +73,11 @@ class WalletLoadingService {
return wallet; return wallet;
} catch (error, stack) { } catch (error, stack) {
await ExceptionHandler.resetLastPopupDate(); await ExceptionHandler.resetLastPopupDate();
final isLedgerError = await ExceptionHandler.isLedgerError(error);
if (isLedgerError) rethrow;
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack)); await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
// try fetching the seeds of the corrupted wallet to show it to the user // try fetching the seeds of the corrupted wallet to show it to the user
String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):"; String corruptedWalletsSeeds = "Corrupted wallets seeds (if retrievable, empty otherwise):";
try { try {

View file

@ -1,7 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cake_wallet/entities/yat_record.dart'; import 'package:cake_wallet/entities/yat_record.dart';
import 'package:http/http.dart'; import 'package:cw_core/utils/proxy_wrapper.dart';
class YatService { class YatService {
static bool isDevMode = false; static bool isDevMode = false;
@ -33,7 +33,8 @@ class YatService {
final yatRecords = <YatRecord>[]; final yatRecords = <YatRecord>[];
try { try {
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
final resBody = json.decode(response.body) as Map<String, dynamic>; final resBody = json.decode(response.body) as Map<String, dynamic>;
final results = resBody["result"] as Map<dynamic, dynamic>; final results = resBody["result"] as Map<dynamic, dynamic>;
// Favour a subaddress over a standard address. // Favour a subaddress over a standard address.
@ -42,7 +43,7 @@ class YatService {
results[MONERO_STD_ADDRESS] ?? results[MONERO_STD_ADDRESS] ??
results[tag]) as Map<String, dynamic>; results[tag]) as Map<String, dynamic>;
if (yatRecord != null) { if (yatRecord.isNotEmpty) {
yatRecords.add(YatRecord.fromJson(yatRecord)); yatRecords.add(YatRecord.fromJson(yatRecord));
} }

View file

@ -33,9 +33,12 @@ import 'package:cake_wallet/exchange/provider/trocador_exchange_provider.dart';
import 'package:cake_wallet/haven/cw_haven.dart'; import 'package:cake_wallet/haven/cw_haven.dart';
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart'; import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart'; import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart';
import 'package:cake_wallet/src/screens/dev/network_requests.dart';
import 'package:cake_wallet/src/screens/dev/secure_preferences_page.dart'; import 'package:cake_wallet/src/screens/dev/secure_preferences_page.dart';
import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart'; import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart';
import 'package:cake_wallet/src/screens/integrations/deuro/savings_page.dart';
import 'package:cake_wallet/src/screens/settings/background_sync_page.dart'; import 'package:cake_wallet/src/screens/settings/background_sync_page.dart';
import 'package:cake_wallet/src/screens/start_tor/start_tor_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart'; import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart'; import 'package:cake_wallet/src/screens/wallet_connect/services/key_service/wallet_connect_key_service.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart'; import 'package:cake_wallet/src/screens/wallet_connect/services/walletkit_service.dart';
@ -43,9 +46,11 @@ import 'package:cake_wallet/themes/core/theme_store.dart';
import 'package:cake_wallet/view_model/dev/monero_background_sync.dart'; import 'package:cake_wallet/view_model/dev/monero_background_sync.dart';
import 'package:cake_wallet/view_model/dev/secure_preferences.dart'; import 'package:cake_wallet/view_model/dev/secure_preferences.dart';
import 'package:cake_wallet/view_model/dev/shared_preferences.dart'; import 'package:cake_wallet/view_model/dev/shared_preferences.dart';
import 'package:cake_wallet/view_model/integrations/deuro_view_model.dart';
import 'package:cake_wallet/view_model/link_view_model.dart'; import 'package:cake_wallet/view_model/link_view_model.dart';
import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
import 'package:cake_wallet/view_model/start_tor_view_model.dart';
import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/receive_page_option.dart';
import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart'; import 'package:cake_wallet/entities/wallet_edit_page_arguments.dart';
import 'package:cake_wallet/entities/wallet_manager.dart'; import 'package:cake_wallet/entities/wallet_manager.dart';
@ -136,7 +141,6 @@ import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
import 'package:cake_wallet/src/screens/settings/privacy_page.dart'; import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart'; import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart'; import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart';
import 'package:cake_wallet/src/screens/settings/tor_page.dart';
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart'; import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
@ -688,7 +692,6 @@ Future<void> setup({
return walletKitService; return walletKitService;
}); });
getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
getIt.registerFactory(() => BalancePage( getIt.registerFactory(() => BalancePage(
nftViewModel: getIt.get<NFTViewModel>(), nftViewModel: getIt.get<NFTViewModel>(),
dashboardViewModel: getIt.get<DashboardViewModel>(), dashboardViewModel: getIt.get<DashboardViewModel>(),
@ -1493,7 +1496,7 @@ Future<void> setup({
() => WalletConnectConnectionsView(walletKitService: getIt.get<WalletKitService>()), () => WalletConnectConnectionsView(walletKitService: getIt.get<WalletKitService>()),
); );
getIt.registerFactory<TorPage>(() => TorPage(getIt.get<AppStore>())); getIt.registerFactory(() => NFTViewModel(appStore, getIt.get<BottomSheetService>()));
getIt.registerFactory(() => SignViewModel(getIt.get<AppStore>().wallet!)); getIt.registerFactory(() => SignViewModel(getIt.get<AppStore>().wallet!));
@ -1511,5 +1514,13 @@ Future<void> setup({
getIt.registerFactory(() => DevBackgroundSyncLogsPage(getIt.get<BackgroundSyncLogsViewModel>())); getIt.registerFactory(() => DevBackgroundSyncLogsPage(getIt.get<BackgroundSyncLogsViewModel>()));
getIt.registerFactory(() => DevNetworkRequests());
getIt.registerFactory(() => StartTorPage(StartTorViewModel(),));
getIt.registerFactory(() => DEuroViewModel(getIt<AppStore>()));
getIt.registerFactory(() => DEuroSavingsPage(getIt<DEuroViewModel>()));
_isSetupFinished = true; _isSetupFinished = true;
} }

View file

@ -1,14 +1,16 @@
import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:ens_dart/ens_dart.dart'; import 'package:ens_dart/ens_dart.dart';
import 'package:http/http.dart';
import 'package:web3dart/web3dart.dart'; import 'package:web3dart/web3dart.dart';
class EnsRecord { class EnsRecord {
static Future<String> fetchEnsAddress(String name, {WalletBase? wallet}) async { static Future<String> fetchEnsAddress(String name, {WalletBase? wallet}) async {
Web3Client? _client; Web3Client? _client;
if (wallet != null && wallet.type == WalletType.ethereum) { if (wallet != null && wallet.type == WalletType.ethereum) {
@ -20,7 +22,9 @@ class EnsRecord {
} }
if (_client == null) { if (_client == null) {
_client = Web3Client("https://ethereum-rpc.publicnode.com", Client()); late final client = ProxyWrapper().getHttpIOClient();
_client = Web3Client("https://ethereum-rpc.publicnode.com", client);
} }
try { try {

View file

@ -1,6 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
class FioAddressProvider { class FioAddressProvider {
static const apiAuthority = 'fio.blockpane.com'; static const apiAuthority = 'fio.blockpane.com';
@ -13,13 +13,17 @@ class FioAddressProvider {
final body = <String, String>{"fio_name": fioAddress}; final body = <String, String>{"fio_name": fioAddress};
final uri = Uri.https(apiAuthority, availCheck); final uri = Uri.https(apiAuthority, availCheck);
final response = final response = await ProxyWrapper().post(
await http.post(uri, headers: headers, body: json.encode(body)); clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
return isFioRegistered; return isFioRegistered;
} }
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
isFioRegistered = responseJSON['is_registered'] as int == 1; isFioRegistered = responseJSON['is_registered'] as int == 1;
@ -35,9 +39,13 @@ class FioAddressProvider {
}; };
final uri = Uri.https(apiAuthority, getAddress); final uri = Uri.https(apiAuthority, getAddress);
final response = final response = await ProxyWrapper().post(
await http.post(uri, headers: headers, body: json.encode(body)); clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error'] as String; final error = responseJSON['error'] as String;

View file

@ -66,6 +66,7 @@ class PreferencesKey {
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1'; static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
static const syncModeKey = 'sync_mode'; static const syncModeKey = 'sync_mode';
static const syncAllKey = 'sync_all'; static const syncAllKey = 'sync_all';
static const builtinTorKey = 'builtin_tor';
static const lastPopupDate = 'last_popup_date'; static const lastPopupDate = 'last_popup_date';
static const lastAppReviewDate = 'last_app_review_date'; static const lastAppReviewDate = 'last_app_review_date';
static const sortBalanceBy = 'sort_balance_by'; static const sortBalanceBy = 'sort_balance_by';

View file

@ -1,15 +1,16 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async { Future<String> fetchUnstoppableDomainAddress(String domain, String ticker) async {
var address = ''; var address = '';
try { try {
final uri = Uri.parse("https://api.unstoppabledomains.com/profile/public/${Uri.encodeQueryComponent(domain)}?fields=records"); final uri = Uri.parse("https://api.unstoppabledomains.com/profile/public/${Uri.encodeQueryComponent(domain)}?fields=records");
final jsonString = await http.read(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
final jsonParsed = json.decode(jsonString) as Map<String, dynamic>;
final jsonParsed = json.decode(response.body) as Map<String, dynamic>;
if (jsonParsed["records"] == null) { if (jsonParsed["records"] == null) {
throw Exception(".records response from $uri is empty"); throw Exception(".records response from $uri is empty");
}; };

View file

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
class WellKnownRecord { class WellKnownRecord {
WellKnownRecord({ WellKnownRecord({
@ -40,14 +40,15 @@ class WellKnownRecord {
} }
// lookup domain/.well-known/nano-currency.json and check if it has a nano address: // lookup domain/.well-known/nano-currency.json and check if it has a nano address:
final http.Response response = await http.get( final response = await ProxyWrapper().get(
Uri.parse("https://$domain/.well-known/$jsonLocation.json?names=$name"), clearnetUri: Uri.parse("https://$domain/.well-known/$jsonLocation.json?names=$name"),
headers: <String, String>{"Accept": "application/json"}, headers: <String, String>{"Accept": "application/json"},
); );
if (response.statusCode != 200) { if (response.statusCode != 200) {
return null; return null;
} }
final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>; final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>;
// Access the first element in the names array and retrieve its address // Access the first element in the names array and retrieve its address

View file

@ -1,14 +1,14 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
class ZanoAlias { class ZanoAlias {
static Future<String?> fetchZanoAliasAddress(String alias) async { static Future<String?> fetchZanoAliasAddress(String alias) async {
try { try {
final uri = Uri.parse("http://zano.cakewallet.com:11211/json_rpc"); final uri = Uri.parse("http://zano.cakewallet.com:11211/json_rpc");
final response = await http.post( final response = await ProxyWrapper().post(
uri, clearnetUri: uri,
body: json.encode({ body: json.encode({
"id": 0, "id": 0,
"jsonrpc": "2.0", "jsonrpc": "2.0",
@ -16,6 +16,7 @@ class ZanoAlias {
"params": {"alias": alias} "params": {"alias": alias}
}), }),
); );
final jsonParsed = json.decode(response.body) as Map<String, dynamic>; final jsonParsed = json.decode(response.body) as Map<String, dynamic>;
return jsonParsed['result']['alias_details']['address'] as String?; return jsonParsed['result']['alias_details']['address'] as String?;

View file

@ -67,8 +67,7 @@ class CWEthereum extends Ethereum {
@override @override
String getPublicKey(WalletBase wallet) { String getPublicKey(WalletBase wallet) {
final privateKeyInUnitInt = (wallet as EthereumWallet).evmChainPrivateKey; final privateKeyInUnitInt = (wallet as EthereumWallet).evmChainPrivateKey;
final publicKey = privateKeyInUnitInt.address.hex; return privateKeyInUnitInt.address.hex;
return publicKey;
} }
@override @override
@ -138,29 +137,24 @@ class CWEthereum extends Ethereum {
} }
@override @override
List<Erc20Token> getERC20Currencies(WalletBase wallet) { List<Erc20Token> getERC20Currencies(WalletBase wallet) =>
final ethereumWallet = wallet as EthereumWallet; (wallet as EthereumWallet).erc20Currencies;
return ethereumWallet.erc20Currencies;
}
@override @override
Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token) async { Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token) =>
await (wallet as EthereumWallet).addErc20Token(token as Erc20Token); (wallet as EthereumWallet).addErc20Token(token as Erc20Token);
}
@override @override
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) =>
await (wallet as EthereumWallet).deleteErc20Token(token as Erc20Token); (wallet as EthereumWallet).deleteErc20Token(token as Erc20Token);
@override @override
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) async => Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) =>
await (wallet as EthereumWallet).removeTokenTransactionsInHistory(token as Erc20Token); (wallet as EthereumWallet).removeTokenTransactionsInHistory(token as Erc20Token);
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) =>
final ethereumWallet = wallet as EthereumWallet; (wallet as EthereumWallet).getErc20Token(contractAddress, 'eth');
return await ethereumWallet.getErc20Token(contractAddress, 'eth');
}
@override @override
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) { CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) {
@ -177,23 +171,19 @@ class CWEthereum extends Ethereum {
} }
@override @override
void updateEtherscanUsageState(WalletBase wallet, bool isEnabled) { void updateEtherscanUsageState(WalletBase wallet, bool isEnabled) =>
(wallet as EthereumWallet).updateScanProviderUsageState(isEnabled); (wallet as EthereumWallet).updateScanProviderUsageState(isEnabled);
}
@override @override
Web3Client? getWeb3Client(WalletBase wallet) { Web3Client? getWeb3Client(WalletBase wallet) => (wallet as EthereumWallet).getWeb3Client();
return (wallet as EthereumWallet).getWeb3Client();
}
@override
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress; String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress;
@override @override
void setLedgerConnection( void setLedgerConnection(WalletBase wallet, ledger.LedgerConnection connection) {
WalletBase wallet, ledger.LedgerConnection connection) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials) ((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials)
.setLedgerConnection( .setLedgerConnection(connection, wallet.walletInfo.derivationInfo?.derivationPath);
connection, wallet.walletInfo.derivationInfo?.derivationPath);
} }
@override @override
@ -212,4 +202,49 @@ class CWEthereum extends Ethereum {
List<String> getDefaultTokenContractAddresses() { List<String> getDefaultTokenContractAddresses() {
return DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList(); return DefaultEthereumErc20Tokens().initialErc20Tokens.map((e) => e.contractAddress).toList();
} }
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final ethereumWallet = wallet as EthereumWallet;
return ethereumWallet.erc20Currencies.any((element) => element.contractAddress.toLowerCase() == contractAddress.toLowerCase());
}
Future<PendingTransaction> createTokenApproval(WalletBase wallet, BigInt amount, String spender,
CryptoCurrency token, TransactionPriority priority) =>
(wallet as EVMChainWallet).createApprovalTransaction(
amount, spender, token, priority as EVMChainTransactionPriority);
// Integrations
@override
Future<BigInt> getDEuroSavingsBalance(WalletBase wallet) =>
DEuro(wallet as EthereumWallet).savingsBalance;
@override
Future<BigInt> getDEuroAccruedInterest(WalletBase wallet) =>
DEuro(wallet as EthereumWallet).accruedInterest;
@override
Future<BigInt> getDEuroInterestRate(WalletBase wallet) =>
DEuro(wallet as EthereumWallet).interestRate;
@override
Future<BigInt> getDEuroSavingsApproved(WalletBase wallet) =>
DEuro(wallet as EthereumWallet).approvedBalance;
@override
Future<PendingTransaction> addDEuroSaving(
WalletBase wallet, BigInt amount, TransactionPriority priority) =>
DEuro(wallet as EthereumWallet)
.depositSavings(amount, priority as EVMChainTransactionPriority);
@override
Future<PendingTransaction> removeDEuroSaving(
WalletBase wallet, BigInt amount, TransactionPriority priority) =>
DEuro(wallet as EthereumWallet)
.withdrawSavings(amount, priority as EVMChainTransactionPriority);
@override
Future<PendingTransaction> enableDEuroSaving(WalletBase wallet, TransactionPriority priority) =>
DEuro(wallet as EthereumWallet).enableSavings(priority as EVMChainTransactionPriority);
} }

View file

@ -12,7 +12,7 @@ import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
class ChainflipExchangeProvider extends ExchangeProvider { class ChainflipExchangeProvider extends ExchangeProvider {
ChainflipExchangeProvider({required this.tradesStore}) ChainflipExchangeProvider({required this.tradesStore})
@ -275,7 +275,8 @@ class ChainflipExchangeProvider extends ExchangeProvider {
Future<Map<String, dynamic>> _getRequest(String path, Map<String, String> params) async { Future<Map<String, dynamic>> _getRequest(String path, Map<String, String> params) async {
final uri = Uri.https(_baseURL, path, params); final uri = Uri.https(_baseURL, path, params);
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if ((response.statusCode != 200) || (response.body.contains('error'))) { if ((response.statusCode != 200) || (response.body.contains('error'))) {
throw Exception('Unexpected response: ${response.statusCode} / ${uri.toString()} / ${response.body}'); throw Exception('Unexpected response: ${response.statusCode} / ${uri.toString()} / ${response.body}');
@ -287,7 +288,8 @@ class ChainflipExchangeProvider extends ExchangeProvider {
Future<Map<String, dynamic>?> _getStatus(Map<String, String> params) async { Future<Map<String, dynamic>?> _getStatus(Map<String, String> params) async {
final uri = Uri.https(_baseURL, _txInfoPath, params); final uri = Uri.https(_baseURL, _txInfoPath, params);
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 404) return null; if (response.statusCode == 404) return null;

View file

@ -13,11 +13,11 @@ import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/distribution_info.dart'; import 'package:cake_wallet/utils/distribution_info.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart'; import 'package:cw_core/utils/proxy_wrapper.dart';
class ChangeNowExchangeProvider extends ExchangeProvider { class ChangeNowExchangeProvider extends ExchangeProvider {
ChangeNowExchangeProvider({required SettingsStore settingsStore}) ChangeNowExchangeProvider({required SettingsStore settingsStore})
: _settingsStore = settingsStore, : _settingsStore = settingsStore,
@ -73,7 +73,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
'flow': _getFlow(isFixedRateMode) 'flow': _getFlow(isFixedRateMode)
}; };
final uri = Uri.https(apiAuthority, rangePath, params); final uri = Uri.https(apiAuthority, rangePath, params);
final response = await get(uri, headers: headers); final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -118,7 +119,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
params['fromAmount'] = amount.toString(); params['fromAmount'] = amount.toString();
final uri = Uri.https(apiAuthority, estimatedAmountPath, params); final uri = Uri.https(apiAuthority, estimatedAmountPath, params);
final response = await get(uri, headers: headers); final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final fromAmount = double.parse(responseJSON['fromAmount'].toString()); final fromAmount = double.parse(responseJSON['fromAmount'].toString());
final toAmount = double.parse(responseJSON['toAmount'].toString()); final toAmount = double.parse(responseJSON['toAmount'].toString());
@ -177,7 +179,12 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
} }
final uri = Uri.https(apiAuthority, createTradePath); final uri = Uri.https(apiAuthority, createTradePath);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -220,7 +227,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
final headers = {apiHeaderKey: apiKey}; final headers = {apiHeaderKey: apiKey};
final params = <String, String>{'id': id}; final params = <String, String>{'id': id};
final uri = Uri.https(apiAuthority, findTradeByIdPath, params); final uri = Uri.https(apiAuthority, findTradeByIdPath, params);
final response = await get(uri, headers: headers); final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description); if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description);

View file

@ -9,9 +9,9 @@ import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart';
class ExolixExchangeProvider extends ExchangeProvider { class ExolixExchangeProvider extends ExchangeProvider {
ExolixExchangeProvider() : super(pairList: supportedPairs(_notSupported)); ExolixExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -86,8 +86,9 @@ class ExolixExchangeProvider extends ExchangeProvider {
// Maximum of 2 attempts to fetch limits // Maximum of 2 attempts to fetch limits
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
final uri = Uri.https(apiBaseUrl, ratePath, params); final uri = Uri.https(apiBaseUrl, ratePath, params);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 200) { if (response.statusCode == 200) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final minAmount = responseJSON['minAmount']; final minAmount = responseJSON['minAmount'];
@ -133,7 +134,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
params['amount'] = amount.toString(); params['amount'] = amount.toString();
final uri = Uri.https(apiBaseUrl, ratePath, params); final uri = Uri.https(apiBaseUrl, ratePath, params);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode != 200) { if (response.statusCode != 200) {
@ -172,7 +174,12 @@ class ExolixExchangeProvider extends ExchangeProvider {
body['amount'] = request.fromAmount; body['amount'] = request.fromAmount;
final uri = Uri.https(apiBaseUrl, transactionsPath); final uri = Uri.https(apiBaseUrl, transactionsPath);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -214,8 +221,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final findTradeByIdPath = '$transactionsPath/$id'; final findTradeByIdPath = '$transactionsPath/$id';
final uri = Uri.https(apiBaseUrl, findTradeByIdPath); final uri = Uri.https(apiBaseUrl, findTradeByIdPath);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description); if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description);
if (response.statusCode == 400) { if (response.statusCode == 400) {

View file

@ -10,9 +10,9 @@ import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http;
class LetsExchangeExchangeProvider extends ExchangeProvider { class LetsExchangeExchangeProvider extends ExchangeProvider {
LetsExchangeExchangeProvider() : super(pairList: supportedPairs(_notSupported)); LetsExchangeExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -152,7 +152,11 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
final uri = Uri.https(_baseUrl, final uri = Uri.https(_baseUrl,
isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath, tradeParams); isFixedRateMode ? _createTransactionRevertPath : _createTransactionPath, tradeParams);
final response = await http.post(uri, headers: headers); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('LetsExchange create trade failed: ${response.body}'); throw Exception('LetsExchange create trade failed: ${response.body}');
@ -218,7 +222,8 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
}; };
final url = Uri.https(_baseUrl, '$_getTransactionPath/$id'); final url = Uri.https(_baseUrl, '$_getTransactionPath/$id');
final response = await http.get(url, headers: headers); final response = await ProxyWrapper().get(clearnetUri: url, headers: headers);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('LetsExchange fetch trade failed: ${response.body}'); throw Exception('LetsExchange fetch trade failed: ${response.body}');
@ -266,7 +271,11 @@ class LetsExchangeExchangeProvider extends ExchangeProvider {
try { try {
final uri = Uri.https(_baseUrl, isFixedRateMode ? _infoRevertPath : _infoPath, params); final uri = Uri.https(_baseUrl, isFixedRateMode ? _infoRevertPath : _infoPath, params);
final response = await http.post(uri, headers: headers); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('LetsExchange fetch info failed: ${response.body}'); throw Exception('LetsExchange fetch info failed: ${response.body}');
} }

View file

@ -1,5 +1,4 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer';
import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/exchange/provider/exchange_provider.dart'; import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
@ -11,9 +10,9 @@ import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart';
class SideShiftExchangeProvider extends ExchangeProvider { class SideShiftExchangeProvider extends ExchangeProvider {
SideShiftExchangeProvider() : super(pairList: supportedPairs(_notSupported)); SideShiftExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -60,8 +59,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
Future<bool> checkIsAvailable() async { Future<bool> checkIsAvailable() async {
const url = apiBaseUrl + permissionPath; const url = apiBaseUrl + permissionPath;
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 500) { if (response.statusCode == 500) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error']['message'] as String; final error = responseJSON['error']['message'] as String;
@ -90,7 +89,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
"$apiBaseUrl$rangePath/${fromCurrency.title.toLowerCase()}-$fromNetwork/${toCurrency.title.toLowerCase()}-$toNetwork"; "$apiBaseUrl$rangePath/${fromCurrency.title.toLowerCase()}-$fromNetwork/${toCurrency.title.toLowerCase()}-$toNetwork";
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 500) { if (response.statusCode == 500) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -137,7 +137,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
"$apiBaseUrl$rangePath/$fromCurrency-$depositNetwork/$toCurrency-$settleNetwork?amount=$amount"; "$apiBaseUrl$rangePath/$fromCurrency-$depositNetwork/$toCurrency-$settleNetwork?amount=$amount";
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode == 500) { if (response.statusCode == 500) {
@ -186,7 +187,12 @@ class SideShiftExchangeProvider extends ExchangeProvider {
final headers = {'Content-Type': 'application/json'}; final headers = {'Content-Type': 'application/json'};
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 201) { if (response.statusCode != 201) {
if (response.statusCode == 400) { if (response.statusCode == 400) {
@ -227,8 +233,8 @@ class SideShiftExchangeProvider extends ExchangeProvider {
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final url = apiBaseUrl + orderPath + '/' + id; final url = apiBaseUrl + orderPath + '/' + id;
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 404) { if (response.statusCode == 404) {
throw TradeNotFoundException(id, provider: description); throw TradeNotFoundException(id, provider: description);
} }
@ -281,7 +287,12 @@ class SideShiftExchangeProvider extends ExchangeProvider {
'depositNetwork': _networkFor(request.fromCurrency), 'depositNetwork': _networkFor(request.fromCurrency),
}; };
final uri = Uri.parse(url); final uri = Uri.parse(url);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 201) { if (response.statusCode != 201) {
if (response.statusCode == 400) { if (response.statusCode == 400) {

View file

@ -11,8 +11,8 @@ import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:http/http.dart';
class SimpleSwapExchangeProvider extends ExchangeProvider { class SimpleSwapExchangeProvider extends ExchangeProvider {
SimpleSwapExchangeProvider() : super(pairList: supportedPairs(_notSupported)); SimpleSwapExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -48,7 +48,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
@override @override
Future<bool> checkIsAvailable() async { Future<bool> checkIsAvailable() async {
final uri = Uri.https(apiAuthority, getEstimatePath, <String, String>{'api_key': apiKey}); final uri = Uri.https(apiAuthority, getEstimatePath, <String, String>{'api_key': apiKey});
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
return !(response.statusCode == 403); return !(response.statusCode == 403);
} }
@ -66,7 +66,8 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
}; };
final uri = Uri.https(apiAuthority, rangePath, params); final uri = Uri.https(apiAuthority, rangePath, params);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 500) { if (response.statusCode == 500) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -104,10 +105,10 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
'fixed': isFixedRateMode.toString() 'fixed': isFixedRateMode.toString()
}; };
final uri = Uri.https(apiAuthority, getEstimatePath, params); final uri = Uri.https(apiAuthority, getEstimatePath, params);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.body == "null") return 0.00; if (response.body == "null") return 0.00;
final data = json.decode(response.body) as String; final data = json.decode(response.body) as String;
return double.parse(data) / amount; return double.parse(data) / amount;
@ -134,7 +135,12 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
}; };
final uri = Uri.https(apiAuthority, createExchangePath, params); final uri = Uri.https(apiAuthority, createExchangePath, params);
final response = await post(uri, headers: headers, body: json.encode(body)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 200 && response.statusCode != 201) { if (response.statusCode != 200 && response.statusCode != 201) {
if (response.statusCode == 400) { if (response.statusCode == 400) {
@ -176,8 +182,9 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final params = {'api_key': apiKey, 'id': id}; final params = {'api_key': apiKey, 'id': id};
final uri = Uri.https(apiAuthority, getExchangePath, params); final uri = Uri.https(apiAuthority, getExchangePath, params);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 404) { if (response.statusCode == 404) {
throw TradeNotFoundException(id, provider: description); throw TradeNotFoundException(id, provider: description);
} }

View file

@ -10,8 +10,8 @@ import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:http/http.dart' as http;
class StealthExExchangeProvider extends ExchangeProvider { class StealthExExchangeProvider extends ExchangeProvider {
StealthExExchangeProvider() : super(pairList: supportedPairs(_notSupported)); StealthExExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -63,8 +63,12 @@ class StealthExExchangeProvider extends ExchangeProvider {
}; };
try { try {
final response = await http.post(Uri.parse(_baseUrl + _rangePath), final response = await ProxyWrapper().post(
headers: headers, body: json.encode(body)); clearnetUri: Uri.parse(_baseUrl + _rangePath),
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('StealthEx fetch limits failed: ${response.body}'); throw Exception('StealthEx fetch limits failed: ${response.body}');
} }
@ -134,8 +138,12 @@ class StealthExExchangeProvider extends ExchangeProvider {
'additional_fee_percent': _additionalFeePercent, 'additional_fee_percent': _additionalFeePercent,
}; };
final response = await http.post(Uri.parse(_baseUrl + _exchangesPath), final response = await ProxyWrapper().post(
headers: headers, body: json.encode(body)); clearnetUri: Uri.parse(_baseUrl + _exchangesPath),
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 201) { if (response.statusCode != 201) {
throw Exception('StealthEx create trade failed: ${response.body}'); throw Exception('StealthEx create trade failed: ${response.body}');
@ -202,8 +210,9 @@ class StealthExExchangeProvider extends ExchangeProvider {
final headers = {'Authorization': apiKey, 'Content-Type': 'application/json'}; final headers = {'Authorization': apiKey, 'Content-Type': 'application/json'};
final uri = Uri.parse('$_baseUrl$_exchangesPath/$id'); final uri = Uri.parse('$_baseUrl$_exchangesPath/$id');
final response = await http.get(uri, headers: headers); final response = await ProxyWrapper().get(clearnetUri: uri, headers: headers);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('StealthEx fetch trade failed: ${response.body}'); throw Exception('StealthEx fetch trade failed: ${response.body}');
} }
@ -260,8 +269,12 @@ class StealthExExchangeProvider extends ExchangeProvider {
}; };
try { try {
final response = await http.post(Uri.parse(_baseUrl + _amountPath), final response = await ProxyWrapper().post(
headers: headers, body: json.encode(body)); clearnetUri: Uri.parse(_baseUrl + _amountPath),
headers: headers,
body: json.encode(body),
);
if (response.statusCode != 200) return {}; if (response.statusCode != 200) return {};
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final rate = responseJSON['rate'] as Map<String, dynamic>?; final rate = responseJSON['rate'] as Map<String, dynamic>?;

View file

@ -10,9 +10,9 @@ import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart';
class SwapTradeExchangeProvider extends ExchangeProvider { class SwapTradeExchangeProvider extends ExchangeProvider {
SwapTradeExchangeProvider() : super(pairList: supportedPairs(_notSupported)); SwapTradeExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -69,7 +69,8 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
}) async { }) async {
try { try {
final uri = Uri.https(apiAuthority, getCoins); final uri = Uri.https(apiAuthority, getCoins);
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -116,7 +117,12 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
}; };
final uri = Uri.https(apiAuthority, getRate, params); final uri = Uri.https(apiAuthority, getRate, params);
final response = await post(uri, body: body, headers: headers); final response = await ProxyWrapper().post(
clearnetUri: uri,
body: json.encode(body),
headers: headers,
);
final responseBody = json.decode(response.body) as Map<String, dynamic>; final responseBody = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode != 200) if (response.statusCode != 200)
@ -153,7 +159,12 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
}; };
final uri = Uri.https(apiAuthority, createOrder, params); final uri = Uri.https(apiAuthority, createOrder, params);
final response = await post(uri, body: body, headers: headers); final response = await ProxyWrapper().post(
clearnetUri: uri,
body: json.encode(body),
headers: headers,
);
final responseBody = json.decode(response.body) as Map<String, dynamic>; final responseBody = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode == 400 || responseBody["success"] == false) { if (response.statusCode == 400 || responseBody["success"] == false) {
@ -196,7 +207,12 @@ class SwapTradeExchangeProvider extends ExchangeProvider {
}; };
final uri = Uri.https(apiAuthority, order, params); final uri = Uri.https(apiAuthority, order, params);
final response = await post(uri, body: body, headers: headers); final response = await ProxyWrapper().post(
clearnetUri: uri,
body: json.encode(body),
headers: headers,
);
final responseBody = json.decode(response.body) as Map<String, dynamic>; final responseBody = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode == 400 || responseBody["success"] == false) { if (response.statusCode == 400 || responseBody["success"] == false) {

View file

@ -7,10 +7,10 @@ import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:http/http.dart' as http;
class ThorChainExchangeProvider extends ExchangeProvider { class ThorChainExchangeProvider extends ExchangeProvider {
ThorChainExchangeProvider({required this.tradesStore}) ThorChainExchangeProvider({required this.tradesStore})
@ -164,7 +164,8 @@ class ThorChainExchangeProvider extends ExchangeProvider {
if (id.isEmpty) throw Exception('Trade id is empty'); if (id.isEmpty) throw Exception('Trade id is empty');
final formattedId = id.startsWith('0x') ? id.substring(2) : id; final formattedId = id.startsWith('0x') ? id.substring(2) : id;
final uri = Uri.https(_baseNodeURL, '$_txInfoPath$formattedId'); final uri = Uri.https(_baseNodeURL, '$_txInfoPath$formattedId');
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode == 404) { if (response.statusCode == 404) {
throw Exception('Trade not found for id: $formattedId'); throw Exception('Trade not found for id: $formattedId');
@ -217,8 +218,8 @@ class ThorChainExchangeProvider extends ExchangeProvider {
static Future<Map<String, String>?>? lookupAddressByName(String name) async { static Future<Map<String, String>?>? lookupAddressByName(String name) async {
final uri = Uri.https(_baseURL, '$_nameLookUpPath$name'); final uri = Uri.https(_baseURL, '$_nameLookUpPath$name');
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) { if (response.statusCode != 200) {
return null; return null;
} }
@ -244,8 +245,8 @@ class ThorChainExchangeProvider extends ExchangeProvider {
Future<Map<String, dynamic>> _getSwapQuote(Map<String, String> params) async { Future<Map<String, dynamic>> _getSwapQuote(Map<String, String> params) async {
Uri uri = Uri.https(_baseNodeURL, _quotePath, params); Uri uri = Uri.https(_baseNodeURL, _quotePath, params);
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected HTTP status: ${response.statusCode}'); throw Exception('Unexpected HTTP status: ${response.statusCode}');
} }

View file

@ -8,9 +8,9 @@ import 'package:cake_wallet/exchange/trade.dart';
import 'package:cake_wallet/exchange/trade_request.dart'; import 'package:cake_wallet/exchange/trade_request.dart';
import 'package:cake_wallet/exchange/trade_state.dart'; import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart';
class TrocadorExchangeProvider extends ExchangeProvider { class TrocadorExchangeProvider extends ExchangeProvider {
TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}}) TrocadorExchangeProvider({this.useTorOnly = false, this.providerStates = const {}})
@ -52,8 +52,9 @@ class TrocadorExchangeProvider extends ExchangeProvider {
]; ];
static const apiKey = secrets.trocadorApiKey; static const apiKey = secrets.trocadorApiKey;
static const onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion';
static const clearNetAuthority = 'api.trocador.app'; static const clearNetAuthority = 'api.trocador.app';
static const onionApiAuthority = clearNetAuthority;
// static const onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion';
static const markup = secrets.trocadorExchangeMarkup; static const markup = secrets.trocadorExchangeMarkup;
static const newRatePath = '/new_rate'; static const newRatePath = '/new_rate';
static const createTradePath = '/new_trade'; static const createTradePath = '/new_trade';
@ -97,7 +98,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
}; };
final uri = await _getUri(coinPath, params); final uri = await _getUri(coinPath, params);
final response = await get(uri, headers: {'API-Key': apiKey}); final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'API-Key': apiKey});
if (response.statusCode != 200) if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
@ -138,12 +140,10 @@ class TrocadorExchangeProvider extends ExchangeProvider {
}; };
final uri = await _getUri(newRatePath, params); final uri = await _getUri(newRatePath, params);
final response = await get(uri, headers: {'API-Key': apiKey}); final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'API-Key': apiKey});
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
if (responseJSON['error'] != null) throw Exception(responseJSON['error']);
final fromAmount = double.parse(responseJSON['amount_from'].toString()); final fromAmount = double.parse(responseJSON['amount_from'].toString());
final toAmount = double.parse(responseJSON['amount_to'].toString()); final toAmount = double.parse(responseJSON['amount_to'].toString());
final rateId = responseJSON['trade_id'] as String? ?? ''; final rateId = responseJSON['trade_id'] as String? ?? '';
@ -206,8 +206,9 @@ class TrocadorExchangeProvider extends ExchangeProvider {
params['provider'] = _provider.first as String; params['provider'] = _provider.first as String;
final uri = await _getUri(createTradePath, params); final uri = await _getUri(createTradePath, params);
final response = await get(uri, headers: {'API-Key': apiKey}); final response = await ProxyWrapper().get(clearnetUri: uri, headers: {'API-Key': apiKey});
if (response.statusCode == 400) { if (response.statusCode == 400) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error'] as String; final error = responseJSON['error'] as String;
@ -255,9 +256,10 @@ class TrocadorExchangeProvider extends ExchangeProvider {
@override @override
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
final uri = await _getUri(tradePath, {'id': id}); final uri = await _getUri(tradePath, {'id': id});
return get(uri, headers: {'API-Key': apiKey}).then((response) { return ProxyWrapper().get(clearnetUri: uri, headers: {'API-Key': apiKey}).then((response) async {
if (response.statusCode != 200) if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
final responseListJson = json.decode(response.body) as List; final responseListJson = json.decode(response.body) as List;
final responseJSON = responseListJson.first; final responseJSON = responseListJson.first;
@ -292,7 +294,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
Future<List<TrocadorPartners>> fetchProviders() async { Future<List<TrocadorPartners>> fetchProviders() async {
final uri = await _getUri(providersListPath, {'api_key': apiKey}); final uri = await _getUri(providersListPath, {'api_key': apiKey});
final response = await get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) if (response.statusCode != 200)
throw Exception('Unexpected http status: ${response.statusCode}'); throw Exception('Unexpected http status: ${response.statusCode}');
@ -355,7 +358,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
if (useTorOnly) return uri; if (useTorOnly) return uri;
try { try {
await get(uri); await ProxyWrapper().get(clearnetUri: uri);
return uri; return uri;
} catch (e) { } catch (e) {

View file

@ -10,8 +10,7 @@ import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart'; import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http; import 'package:cw_core/utils/proxy_wrapper.dart';
class XOSwapExchangeProvider extends ExchangeProvider { class XOSwapExchangeProvider extends ExchangeProvider {
XOSwapExchangeProvider() : super(pairList: supportedPairs(_notSupported)); XOSwapExchangeProvider() : super(pairList: supportedPairs(_notSupported));
@ -72,7 +71,8 @@ class XOSwapExchangeProvider extends ExchangeProvider {
final uri = Uri.https(_apiAuthority, _apiPath + _assets, final uri = Uri.https(_apiAuthority, _apiPath + _assets,
{'networks': normalizedNetwork, 'query': currency.title}); {'networks': normalizedNetwork, 'query': currency.title});
final response = await http.get(uri, headers: _headers); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Failed to fetch assets for ${currency.title} on ${currency.tag}'); throw Exception('Failed to fetch assets for ${currency.title} on ${currency.tag}');
} }
@ -102,7 +102,8 @@ class XOSwapExchangeProvider extends ExchangeProvider {
if (curFrom == null || curTo == null) return []; if (curFrom == null || curTo == null) return [];
final pairId = curFrom + '_' + curTo; final pairId = curFrom + '_' + curTo;
final uri = Uri.https(_apiAuthority, '$_apiPath$_pairsPath/$pairId$_ratePath'); final uri = Uri.https(_apiAuthority, '$_apiPath$_pairsPath/$pairId$_ratePath');
final response = await http.get(uri, headers: _headers); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) return []; if (response.statusCode != 200) return [];
return json.decode(response.body) as List<dynamic>; return json.decode(response.body) as List<dynamic>;
} catch (e) { } catch (e) {
@ -205,7 +206,12 @@ class XOSwapExchangeProvider extends ExchangeProvider {
'pairId': pairId, 'pairId': pairId,
}; };
final response = await http.post(uri, headers: _headers, body: json.encode(payload)); final response = await ProxyWrapper().post(
clearnetUri: uri,
headers: _headers,
body: json.encode(payload),
);
if (response.statusCode != 201) { if (response.statusCode != 201) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final error = responseJSON['error'] ?? 'Unknown error'; final error = responseJSON['error'] ?? 'Unknown error';
@ -254,7 +260,8 @@ class XOSwapExchangeProvider extends ExchangeProvider {
Future<Trade> findTradeById({required String id}) async { Future<Trade> findTradeById({required String id}) async {
try { try {
final uri = Uri.https(_apiAuthority, '$_apiPath$_orders/$id'); final uri = Uri.https(_apiAuthority, '$_apiPath$_orders/$id');
final response = await http.get(uri, headers: _headers); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) { if (response.statusCode != 200) {
final responseJSON = json.decode(response.body) as Map<String, dynamic>; final responseJSON = json.decode(response.body) as Map<String, dynamic>;
if (responseJSON.containsKey('code') && responseJSON['code'] == 'NOT_FOUND') { if (responseJSON.containsKey('code') && responseJSON['code'] == 'NOT_FOUND') {

View file

@ -25,9 +25,12 @@ import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/root/root.dart'; import 'package:cake_wallet/src/screens/root/root.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/themes/core/material_base_theme.dart';
import 'package:cake_wallet/themes/utils/theme_provider.dart'; import 'package:cake_wallet/themes/utils/theme_provider.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/view_model/link_view_model.dart'; import 'package:cake_wallet/view_model/link_view_model.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/address_info.dart'; import 'package:cw_core/address_info.dart';
@ -38,6 +41,8 @@ import 'package:cw_core/node.dart';
import 'package:cw_core/payjoin_session.dart'; import 'package:cw_core/payjoin_session.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@ -87,6 +92,9 @@ Future<void> runAppWithZone({Key? topLevelKey}) async {
ledgerFile.writeAsStringSync("$content\n${event.message}"); ledgerFile.writeAsStringSync("$content\n${event.message}");
}); });
} }
if (FeatureFlag.hasDevOptions) {
ProxyWrapper.logger = MemoryProxyLogger();
}
runApp(App(key: topLevelKey)); runApp(App(key: topLevelKey));
isAppRunning = true; isAppRunning = true;
@ -194,8 +202,8 @@ Future<void> initializeAppConfigs({bool loadWallet = true}) async {
final powNodes = final powNodes =
await CakeHive.openBox<Node>(Node.boxName + "pow"); // must be different from Node.boxName await CakeHive.openBox<Node>(Node.boxName + "pow"); // must be different from Node.boxName
final transactionDescriptions = await CakeHive.openBox<TransactionDescription>( final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
TransactionDescription.boxName, TransactionDescription.boxName,
encryptionKey: transactionDescriptionsBoxKey); encryptionKey: transactionDescriptionsBoxKey);
final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey); final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey); final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName); final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
@ -279,7 +287,11 @@ Future<void> initialSetup({
navigatorKey: navigatorKey, navigatorKey: navigatorKey,
secureStorage: secureStorage, secureStorage: secureStorage,
); );
await bootstrap(navigatorKey, loadWallet: loadWallet); await bootstrapOffline();
final settingsStore = getIt<SettingsStore>();
if (!settingsStore.currentBuiltinTor) {
bootstrapOnline(navigatorKey, loadWallet: loadWallet);
}
} }
class App extends StatefulWidget { class App extends StatefulWidget {
@ -293,20 +305,24 @@ class App extends StatefulWidget {
class AppState extends State<App> with SingleTickerProviderStateMixin { class AppState extends State<App> with SingleTickerProviderStateMixin {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Observer( return Observer(builder: (BuildContext context) {
builder: (BuildContext context) {
final appStore = getIt.get<AppStore>(); final appStore = getIt.get<AppStore>();
final authService = getIt.get<AuthService>(); final authService = getIt.get<AuthService>();
final linkViewModel = getIt.get<LinkViewModel>(); final linkViewModel = getIt.get<LinkViewModel>();
final tradeMonitor = getIt.get<TradeMonitor>(); final tradeMonitor = getIt.get<TradeMonitor>();
final settingsStore = appStore.settingsStore;
final statusBarColor = Colors.transparent; final statusBarColor = Colors.transparent;
final authenticationStore = getIt.get<AuthenticationStore>(); final authenticationStore = getIt.get<AuthenticationStore>();
final initialRoute = authenticationStore.state == AuthenticationState.uninitialized final initialRoute = authenticationStore.state == AuthenticationState.uninitialized
? Routes.welcome ? Routes.welcome
: Routes.login; : settingsStore.currentBuiltinTor ? Routes.startTor : Routes.login;
final currentTheme = appStore.themeStore.currentTheme; final currentTheme = appStore.themeStore.currentTheme;
final statusBarBrightness = currentTheme.isDark ? Brightness.light : Brightness.dark; final statusBarBrightness = currentTheme.type == currentTheme.isDark
final statusBarIconBrightness = currentTheme.isDark ? Brightness.light : Brightness.dark; ? Brightness.light
: Brightness.dark;
final statusBarIconBrightness = currentTheme.type == currentTheme.isDark
? Brightness.light
: Brightness.dark;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle( SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: statusBarColor, statusBarColor: statusBarColor,
statusBarBrightness: statusBarBrightness, statusBarBrightness: statusBarBrightness,
@ -322,7 +338,8 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
tradeMonitor: tradeMonitor, tradeMonitor: tradeMonitor,
child: ThemeProvider( child: ThemeProvider(
themeStore: appStore.themeStore, themeStore: appStore.themeStore,
materialAppBuilder: (context, theme, darkTheme, themeMode) => MaterialApp( materialAppBuilder: (context, theme, darkTheme, themeMode) =>
MaterialApp(
navigatorObservers: [routeObserver], navigatorObservers: [routeObserver],
navigatorKey: navigatorKey, navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
@ -365,8 +382,10 @@ class _HomeState extends State<_Home> {
SystemChrome.setPreferredOrientations( SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]); [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
} else { } else {
SystemChrome.setPreferredOrientations( SystemChrome.setPreferredOrientations([
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]); DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight
]);
} }
} }
} }

View file

@ -1,6 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'package:cw_core/utils/proxy_wrapper.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:http/http.dart' as http;
import 'package:cake_wallet/mastodon/mastodon_user.dart'; import 'package:cake_wallet/mastodon/mastodon_user.dart';
class MastodonAPI { class MastodonAPI {
@ -20,7 +20,8 @@ class MastodonAPI {
queryParameters: queryParams, queryParameters: queryParams,
); );
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) return null; if (response.statusCode != 200) return null;
@ -47,7 +48,8 @@ class MastodonAPI {
queryParameters: queryParams, queryParameters: queryParams,
); );
final response = await http.get(uri); final response = await ProxyWrapper().get(clearnetUri: uri);
if (response.statusCode != 200) { if (response.statusCode != 200) {
throw Exception('Unexpected HTTP status: ${response.statusCode}'); throw Exception('Unexpected HTTP status: ${response.statusCode}');

View file

@ -67,8 +67,7 @@ class CWPolygon extends Polygon {
@override @override
String getPublicKey(WalletBase wallet) { String getPublicKey(WalletBase wallet) {
final privateKeyInUnitInt = (wallet as PolygonWallet).evmChainPrivateKey; final privateKeyInUnitInt = (wallet as PolygonWallet).evmChainPrivateKey;
final publicKey = privateKeyInUnitInt.address.hex; return privateKeyInUnitInt.address.hex;
return publicKey;
} }
@override @override
@ -137,28 +136,27 @@ class CWPolygon extends Polygon {
} }
@override @override
List<Erc20Token> getERC20Currencies(WalletBase wallet) { List<Erc20Token> getERC20Currencies(WalletBase wallet) =>
final polygonWallet = wallet as PolygonWallet; (wallet as PolygonWallet).erc20Currencies;
return polygonWallet.erc20Currencies;
}
@override @override
Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> addErc20Token(WalletBase wallet, CryptoCurrency token) =>
await (wallet as PolygonWallet).addErc20Token(token as Erc20Token); (wallet as PolygonWallet).addErc20Token(token as Erc20Token);
@override @override
Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) async => Future<void> deleteErc20Token(WalletBase wallet, CryptoCurrency token) =>
await (wallet as PolygonWallet).deleteErc20Token(token as Erc20Token); (wallet as PolygonWallet).deleteErc20Token(token as Erc20Token);
@override @override
Future<void> removeTokenTransactionsInHistory(WalletBase wallet, CryptoCurrency token) async => Future<void> removeTokenTransactionsInHistory(
await (wallet as PolygonWallet).removeTokenTransactionsInHistory(token as Erc20Token); WalletBase wallet, CryptoCurrency token) =>
(wallet as PolygonWallet)
.removeTokenTransactionsInHistory(token as Erc20Token);
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(
final polygonWallet = wallet as PolygonWallet; WalletBase wallet, String contractAddress) =>
return await polygonWallet.getErc20Token(contractAddress, 'polygon'); (wallet as PolygonWallet).getErc20Token(contractAddress, 'polygon');
}
@override @override
CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) { CryptoCurrency assetOfTransaction(WalletBase wallet, TransactionInfo transaction) {
@ -176,23 +174,29 @@ class CWPolygon extends Polygon {
} }
@override @override
void updatePolygonScanUsageState(WalletBase wallet, bool isEnabled) { void updatePolygonScanUsageState(WalletBase wallet, bool isEnabled) =>
(wallet as PolygonWallet).updateScanProviderUsageState(isEnabled); (wallet as PolygonWallet).updateScanProviderUsageState(isEnabled);
}
@override @override
Web3Client? getWeb3Client(WalletBase wallet) { Web3Client? getWeb3Client(WalletBase wallet) =>
return (wallet as PolygonWallet).getWeb3Client(); (wallet as PolygonWallet).getWeb3Client();
}
String getTokenAddress(CryptoCurrency asset) => (asset as Erc20Token).contractAddress; @override
String getTokenAddress(CryptoCurrency asset) =>
(asset as Erc20Token).contractAddress;
@override
Future<PendingTransaction> createTokenApproval(WalletBase wallet,
BigInt amount, String spender, CryptoCurrency token, TransactionPriority priority) =>
(wallet as EVMChainWallet)
.createApprovalTransaction(amount, spender, token, priority as EVMChainTransactionPriority);
@override @override
void setLedgerConnection( void setLedgerConnection(
WalletBase wallet, ledger.LedgerConnection connection) { WalletBase wallet, ledger.LedgerConnection connection) {
((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials) ((wallet as EVMChainWallet).evmChainPrivateKey as EvmLedgerCredentials)
.setLedgerConnection( .setLedgerConnection(
connection, wallet.walletInfo.derivationInfo?.derivationPath); connection, wallet.walletInfo.derivationInfo?.derivationPath);
} }
@override @override
@ -206,9 +210,16 @@ class CWPolygon extends Polygon {
throw err; throw err;
} }
} }
@override @override
List<String> getDefaultTokenContractAddresses() { List<String> getDefaultTokenContractAddresses() => DefaultPolygonErc20Tokens()
return DefaultPolygonErc20Tokens().initialPolygonErc20Tokens.map((e) => e.contractAddress).toList(); .initialPolygonErc20Tokens
.map((e) => e.contractAddress)
.toList();
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final polygonWallet = wallet as PolygonWallet;
return polygonWallet.erc20Currencies.any((element) => element.contractAddress.toLowerCase() == contractAddress.toLowerCase());
} }
} }

View file

@ -15,24 +15,29 @@ import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
Future<void> bootstrap(GlobalKey<NavigatorState> navigatorKey, {required bool loadWallet}) async { Future<void> bootstrapOffline() async {
final appStore = getIt.get<AppStore>();
final authenticationStore = getIt.get<AuthenticationStore>(); final authenticationStore = getIt.get<AuthenticationStore>();
final settingsStore = getIt.get<SettingsStore>();
final fiatConversionStore = getIt.get<FiatConversionStore>();
final currentWalletName = final currentWalletName =
getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName); getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName);
if (currentWalletName != null) { if (currentWalletName != null) {
authenticationStore.installed(); authenticationStore.installed();
} }
}
void bootstrapOnline(GlobalKey<NavigatorState> navigatorKey, {required bool loadWallet}) {
final appStore = getIt.get<AppStore>();
final authenticationStore = getIt.get<AuthenticationStore>();
final settingsStore = getIt.get<SettingsStore>();
final fiatConversionStore = getIt.get<FiatConversionStore>();
if (loadWallet) { if (loadWallet) {
startAuthenticationStateChange(authenticationStore, navigatorKey); startAuthenticationStateChange(authenticationStore, navigatorKey);
} }
startCurrentWalletChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentWalletChangeReaction(appStore, settingsStore, fiatConversionStore);
startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatChangeReaction(appStore, settingsStore, fiatConversionStore);
startCurrentFiatApiModeChangeReaction(appStore, settingsStore, fiatConversionStore); startCurrentFiatApiModeChangeReaction(appStore, settingsStore, fiatConversionStore);
startOnCurrentNodeChangeReaction(appStore); startOnCurrentNodeChangeReaction(appStore);
startFiatRateUpdate(appStore, settingsStore, fiatConversionStore); startFiatRateUpdate(appStore, settingsStore, fiatConversionStore);
} }

View file

@ -1,11 +1,15 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/utils/tor.dart';
import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/sync_status.dart'; import 'package:cw_core/sync_status.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
Timer? _checkConnectionTimer; Timer? _checkConnectionTimer;
@ -36,6 +40,10 @@ void startCheckConnectionReaction(WalletBase wallet, SettingsStore settingsStore
final alive = await settingsStore.getCurrentNode(wallet.type).requestNode(); final alive = await settingsStore.getCurrentNode(wallet.type).requestNode();
if (alive) { if (alive) {
if (settingsStore.currentBuiltinTor) {
await ensureTorStarted(context: null);
}
await wallet.connectToNode(node: settingsStore.getCurrentNode(wallet.type)); await wallet.connectToNode(node: settingsStore.getCurrentNode(wallet.type));
} }
} }

View file

@ -9,6 +9,7 @@ import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart'; import 'package:cake_wallet/src/screens/connect_device/connect_device_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart'; import 'package:cake_wallet/src/screens/wallet_connect/services/bottom_sheet_service.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.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/store/authentication_store.dart'; import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/exception_handler.dart'; import 'package:cake_wallet/utils/exception_handler.dart';
@ -63,14 +64,49 @@ void startAuthenticationStateChange(
monero!.setGlobalLedgerConnection(ledgerVM.connection); monero!.setGlobalLedgerConnection(ledgerVM.connection);
showPopUp<void>( showPopUp<void>(
context: context, context: context,
builder: (BuildContext context) => AlertWithOneAction( builder: (context) => AlertWithOneAction(
alertTitle: S.of(context).proceed_on_device, alertTitle: S.of(context).proceed_on_device,
alertContent: S.of(context).proceed_on_device_description, alertContent: S.of(context).proceed_on_device_description,
buttonText: S.of(context).cancel, buttonText: S.of(context).cancel,
alertBarrierDismissible: false, alertBarrierDismissible: false,
buttonAction: () => Navigator.of(context).pop()), buttonAction: () => Navigator.of(context).pop(),
),
); );
await loadCurrentWallet(); bool tryOpening = true;
while (tryOpening) {
try {
await loadCurrentWallet();
tryOpening = false;
} on Exception catch (e) {
final errorCode = RegExp(r'0x\S*?(?= )').firstMatch(
e.toString());
final errorMessage = ledgerVM.interpretErrorCode(
errorCode?.group(0).toString().replaceAll("0x", "") ??
"");
if (errorMessage != null) {
await showPopUp<void>(
context: context,
builder: (context) => AlertWithTwoActions(
alertTitle: "Ledger Error",
alertContent: errorMessage,
leftButtonText: S.of(context).try_again,
alertBarrierDismissible: false,
actionLeftButton: () => Navigator.of(context).pop(),
rightButtonText: S.of(context).cancel,
actionRightButton: () {
tryOpening = false;
Navigator.of(context).pop();
},
),
);
} else {
tryOpening = false;
rethrow;
}
}
}
getIt.get<BottomSheetService>().showNext(); getIt.get<BottomSheetService>().showNext();
await navigatorKey.currentState! await navigatorKey.currentState!
.pushNamedAndRemoveUntil(Routes.dashboard, (route) => false); .pushNamedAndRemoveUntil(Routes.dashboard, (route) => false);

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/polygon/polygon.dart'; import 'package:cake_wallet/polygon/polygon.dart';
import 'package:cake_wallet/solana/solana.dart'; import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/tron/tron.dart'; import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/utils/tor.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/balance.dart'; import 'package:cw_core/balance.dart';
@ -65,7 +66,7 @@ void startCurrentWalletChangeReaction(
final node = settingsStore.getCurrentNode(wallet.type); final node = settingsStore.getCurrentNode(wallet.type);
startWalletSyncStatusChangeReaction(wallet, fiatConversionStore); startWalletSyncStatusChangeReaction(wallet, settingsStore);
startCheckConnectionReaction(wallet, settingsStore); startCheckConnectionReaction(wallet, settingsStore);
await Future.delayed(Duration.zero); await Future.delayed(Duration.zero);
@ -83,6 +84,10 @@ void startCurrentWalletChangeReaction(
bitcoin!.updatePayjoinState(wallet, settingsStore.usePayjoin); bitcoin!.updatePayjoinState(wallet, settingsStore.usePayjoin);
} }
if (settingsStore.currentBuiltinTor) {
await ensureTorStarted(context: null);
}
await wallet.connectToNode(node: node); await wallet.connectToNode(node: node);
if (wallet.type == WalletType.nano || wallet.type == WalletType.banano) { if (wallet.type == WalletType.nano || wallet.type == WalletType.banano) {
final powNode = settingsStore.getCurrentPowNode(wallet.type); final powNode = settingsStore.getCurrentPowNode(wallet.type);

View file

@ -1,5 +1,7 @@
import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/utils/print_verbose.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_core/transaction_history.dart'; import 'package:cw_core/transaction_history.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
@ -12,7 +14,7 @@ ReactionDisposer? _onWalletSyncStatusChangeReaction;
void startWalletSyncStatusChangeReaction( void startWalletSyncStatusChangeReaction(
WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet, WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> wallet,
FiatConversionStore fiatConversionStore) { SettingsStore settingsStore) {
_onWalletSyncStatusChangeReaction?.reaction.dispose(); _onWalletSyncStatusChangeReaction?.reaction.dispose();
_onWalletSyncStatusChangeReaction = reaction((_) => wallet.syncStatus, (SyncStatus status) async { _onWalletSyncStatusChangeReaction = reaction((_) => wallet.syncStatus, (SyncStatus status) async {
try { try {
@ -25,6 +27,12 @@ void startWalletSyncStatusChangeReaction(
if (status is SyncedSyncStatus || status is FailedSyncStatus) { if (status is SyncedSyncStatus || status is FailedSyncStatus) {
await WakelockPlus.disable(); await WakelockPlus.disable();
} }
if (status is SyncedSyncStatus &&
wallet.type == WalletType.bitcoin &&
settingsStore.usePayjoin) {
bitcoin!.resumePayjoinSessions(wallet);
}
} catch (e) { } catch (e) {
printV(e.toString()); printV(e.toString());
} }

View file

@ -38,6 +38,7 @@ import 'package:cake_wallet/src/screens/dashboard/pages/transactions_page.dart';
import 'package:cake_wallet/src/screens/dashboard/sign_page.dart'; import 'package:cake_wallet/src/screens/dashboard/sign_page.dart';
import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart'; import 'package:cake_wallet/src/screens/dev/monero_background_sync.dart';
import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart'; import 'package:cake_wallet/src/screens/dev/moneroc_call_profiler.dart';
import 'package:cake_wallet/src/screens/dev/network_requests.dart';
import 'package:cake_wallet/src/screens/dev/secure_preferences_page.dart'; import 'package:cake_wallet/src/screens/dev/secure_preferences_page.dart';
import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart'; import 'package:cake_wallet/src/screens/dev/shared_preferences_page.dart';
import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart'; import 'package:cake_wallet/src/screens/dev/background_sync_logs_page.dart';
@ -48,6 +49,7 @@ import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dar
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_external_send_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_external_send_page.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart';
import 'package:cake_wallet/src/screens/faq/faq_page.dart'; import 'package:cake_wallet/src/screens/faq/faq_page.dart';
import 'package:cake_wallet/src/screens/integrations/deuro/savings_page.dart';
import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart'; import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
@ -92,7 +94,6 @@ import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
import 'package:cake_wallet/src/screens/settings/privacy_page.dart'; import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart'; import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart'; import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart';
import 'package:cake_wallet/src/screens/settings/tor_page.dart';
import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart'; import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
@ -100,6 +101,7 @@ import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_info_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_info_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart'; import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
import 'package:cake_wallet/src/screens/start_tor/start_tor_page.dart';
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/support/support_page.dart';
import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart'; import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
@ -856,9 +858,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
), ),
); );
case Routes.torPage:
return MaterialPageRoute<void>(builder: (_) => getIt.get<TorPage>());
case Routes.signPage: case Routes.signPage:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => SignPage( builder: (_) => SignPage(
@ -909,7 +908,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevBackgroundSyncLogsPage>(), builder: (_) => getIt.get<DevBackgroundSyncLogsPage>(),
); );
case Routes.devNetworkRequests:
return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevNetworkRequests>(),
);
case Routes.devMoneroCallProfiler: case Routes.devMoneroCallProfiler:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevMoneroCallProfilerPage>(), builder: (_) => getIt.get<DevMoneroCallProfilerPage>(),
@ -919,6 +923,16 @@ Route<dynamic> createRoute(RouteSettings settings) {
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
builder: (_) => getIt.get<DevSecurePreferencesPage>(), builder: (_) => getIt.get<DevSecurePreferencesPage>(),
); );
case Routes.startTor:
return MaterialPageRoute<void>(
builder: (_) => getIt.get<StartTorPage>(),
);
case Routes.dEuroSavings:
return MaterialPageRoute<void>(
builder: (_) => getIt.get<DEuroSavingsPage>(),
);
default: default:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(

View file

@ -110,14 +110,16 @@ class Routes {
static const walletConnectConnectionsListing = '/wallet-connect-connections-listing'; static const walletConnectConnectionsListing = '/wallet-connect-connections-listing';
static const nftDetailsPage = '/nft_details_page'; static const nftDetailsPage = '/nft_details_page';
static const importNFTPage = '/import_nft_page'; static const importNFTPage = '/import_nft_page';
static const torPage = '/tor_page';
static const backgroundSync = '/background_sync'; static const backgroundSync = '/background_sync';
static const startTor = '/start_tor';
static const devMoneroBackgroundSync = '/dev/monero_background_sync'; static const devMoneroBackgroundSync = '/dev/monero_background_sync';
static const devMoneroCallProfiler = '/dev/monero_call_profiler'; static const devMoneroCallProfiler = '/dev/monero_call_profiler';
static const devSharedPreferences = '/dev/shared_preferences'; static const devSharedPreferences = '/dev/shared_preferences';
static const devSecurePreferences = '/dev/secure_preferences'; static const devSecurePreferences = '/dev/secure_preferences';
static const devBackgroundSyncLogs = '/dev/background_sync_logs'; static const devBackgroundSyncLogs = '/dev/background_sync_logs';
static const devNetworkRequests = '/dev/network_requests';
static const signPage = '/sign_page'; static const signPage = '/sign_page';
static const connectDevices = '/device/connect'; static const connectDevices = '/device/connect';
@ -127,4 +129,6 @@ class Routes {
static const walletGroupExistingSeedDescriptionPage = '/wallet_group_existing_seed_description_page'; static const walletGroupExistingSeedDescriptionPage = '/wallet_group_existing_seed_description_page';
static const walletSeedVerificationPage = '/wallet_seed_verification_page'; static const walletSeedVerificationPage = '/wallet_seed_verification_page';
static const exchangeTradeExternalSendPage = '/exchange_trade_external_send_page'; static const exchangeTradeExternalSendPage = '/exchange_trade_external_send_page';
static const dEuroSavings = '/integration/dEuro/savings';
} }

View file

@ -155,4 +155,10 @@ class CWSolana extends Solana {
List<String> getDefaultTokenContractAddresses() { List<String> getDefaultTokenContractAddresses() {
return DefaultSPLTokens().initialSPLTokens.map((e) => e.mintAddress).toList(); return DefaultSPLTokens().initialSPLTokens.map((e) => e.mintAddress).toList();
} }
@override
bool isTokenAlreadyAdded(WalletBase wallet, String contractAddress) {
final solanaWallet = wallet as SolanaWallet;
return solanaWallet.splTokenCurrencies.any((element) => element.mintAddress == contractAddress);
}
} }

Some files were not shown because too many files have changed in this diff Show more