Modify HTTP to take in proxy info rather than rely on the tor service singleton

This commit is contained in:
julian 2023-09-08 14:41:39 -06:00
parent 6d0bb27711
commit 9d6cdfd2c1
6 changed files with 250 additions and 226 deletions

View file

@ -1,9 +1,9 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:socks5_proxy/socks_client.dart'; import 'package:socks5_proxy/socks_client.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
// WIP wrapper layer // WIP wrapper layer
@ -11,28 +11,29 @@ import 'package:stackwallet/utilities/logger.dart';
// TODO expand this class // TODO expand this class
class Response { class Response {
final int code; final int code;
final String body; final List<int> bodyBytes;
Response(this.body, this.code); String get body => utf8.decode(bodyBytes, allowMalformed: true);
Response(this.bodyBytes, this.code);
} }
class HTTP { class HTTP {
/// Visible for testing so we can override with a mock TorService
@visibleForTesting
TorService torService = TorService.sharedInstance;
Future<Response> get({ Future<Response> get({
required Uri url, required Uri url,
Map<String, String>? headers, Map<String, String>? headers,
required bool routeOverTor, required ({
InternetAddress host,
int port,
})? proxyInfo,
}) async { }) async {
final httpClient = HttpClient(); final httpClient = HttpClient();
try { try {
if (routeOverTor) { if (proxyInfo != null) {
SocksTCPClient.assignToHttpClient(httpClient, [ SocksTCPClient.assignToHttpClient(httpClient, [
ProxySettings( ProxySettings(
torService.proxyInfo.host, proxyInfo.host,
torService.proxyInfo.port, proxyInfo.port,
), ),
]); ]);
} }
@ -46,8 +47,9 @@ class HTTP {
} }
final response = await request.close(); final response = await request.close();
return Response( return Response(
await response.transform(utf8.decoder).join(), await _bodyBytes(response),
response.statusCode, response.statusCode,
); );
} catch (e, s) { } catch (e, s) {
@ -66,15 +68,18 @@ class HTTP {
Map<String, String>? headers, Map<String, String>? headers,
Object? body, Object? body,
Encoding? encoding, Encoding? encoding,
required bool routeOverTor, required ({
InternetAddress host,
int port,
})? proxyInfo,
}) async { }) async {
final httpClient = HttpClient(); final httpClient = HttpClient();
try { try {
if (routeOverTor) { if (proxyInfo != null) {
SocksTCPClient.assignToHttpClient(httpClient, [ SocksTCPClient.assignToHttpClient(httpClient, [
ProxySettings( ProxySettings(
torService.proxyInfo.host, proxyInfo.host,
torService.proxyInfo.port, proxyInfo.port,
), ),
]); ]);
} }
@ -92,7 +97,7 @@ class HTTP {
final response = await request.close(); final response = await request.close();
return Response( return Response(
await response.transform(utf8.decoder).join(), await _bodyBytes(response),
response.statusCode, response.statusCode,
); );
} catch (e, s) { } catch (e, s) {
@ -105,4 +110,18 @@ class HTTP {
httpClient.close(force: true); httpClient.close(force: true);
} }
} }
Future<Uint8List> _bodyBytes(HttpClientResponse response) {
final completer = Completer<Uint8List>();
final List<int> bytes = [];
response.listen(
(data) {
bytes.addAll(data);
},
onDone: () => completer.complete(
Uint8List.fromList(bytes),
),
);
return completer.future;
}
} }

View file

@ -28,6 +28,7 @@ import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/networking/http.dart'; import 'package:stackwallet/networking/http.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart'; import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_response.dart'; import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/tor_service.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/prefs.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
@ -38,10 +39,12 @@ class ChangeNowAPI {
static const String apiVersion = "/v1"; static const String apiVersion = "/v1";
static const String apiVersionV2 = "/v2"; static const String apiVersionV2 = "/v2";
HTTP client = HTTP(); final HTTP client;
ChangeNowAPI._(); @visibleForTesting
static final ChangeNowAPI _instance = ChangeNowAPI._(); ChangeNowAPI({HTTP? http}) : client = http ?? HTTP();
static final ChangeNowAPI _instance = ChangeNowAPI();
static ChangeNowAPI get instance => _instance; static ChangeNowAPI get instance => _instance;
Uri _buildUri(String path, Map<String, dynamic>? params) { Uri _buildUri(String path, Map<String, dynamic>? params) {
@ -57,7 +60,8 @@ class ChangeNowAPI {
final response = await client.get( final response = await client.get(
url: uri, url: uri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: Prefs.instance.useTor, proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
); );
String? data; String? data;
try { try {
@ -86,7 +90,8 @@ class ChangeNowAPI {
// 'Content-Type': 'application/json', // 'Content-Type': 'application/json',
'x-changenow-api-key': apiKey, 'x-changenow-api-key': apiKey,
}, },
routeOverTor: Prefs.instance.useTor, proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
); );
final data = response.body; final data = response.body;
@ -109,7 +114,8 @@ class ChangeNowAPI {
url: uri, url: uri,
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: jsonEncode(body), body: jsonEncode(body),
routeOverTor: Prefs.instance.useTor, proxyInfo:
Prefs.instance.useTor ? TorService.sharedInstance.proxyInfo : null,
); );
String? data; String? data;

View file

@ -802,14 +802,6 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
), ),
) as _i2.HTTP); ) as _i2.HTTP);
@override @override
set client(_i2.HTTP? _client) => super.noSuchMethod(
Invocation.setter(
#client,
_client,
),
returnValueForMissingStub: null,
);
@override
_i7.Future<_i3.ExchangeResponse<List<_i15.Currency>>> getAvailableCurrencies({ _i7.Future<_i3.ExchangeResponse<List<_i15.Currency>>> getAvailableCurrencies({
bool? fixedRate, bool? fixedRate,
bool? active, bool? active,
@ -1073,8 +1065,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
[], [],
{#apiKey: apiKey}, {#apiKey: apiKey},
), ),
returnValue: _i7.Future< returnValue: _i7
_i3.ExchangeResponse<List<_i20.FixedRateMarket>>>.value( .Future<_i3.ExchangeResponse<List<_i20.FixedRateMarket>>>.value(
_FakeExchangeResponse_1<List<_i20.FixedRateMarket>>( _FakeExchangeResponse_1<List<_i20.FixedRateMarket>>(
this, this,
Invocation.method( Invocation.method(
@ -1115,8 +1107,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
#apiKey: apiKey, #apiKey: apiKey,
}, },
), ),
returnValue: _i7.Future< returnValue: _i7
_i3.ExchangeResponse<_i21.ExchangeTransaction>>.value( .Future<_i3.ExchangeResponse<_i21.ExchangeTransaction>>.value(
_FakeExchangeResponse_1<_i21.ExchangeTransaction>( _FakeExchangeResponse_1<_i21.ExchangeTransaction>(
this, this,
Invocation.method( Invocation.method(
@ -1172,8 +1164,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
#apiKey: apiKey, #apiKey: apiKey,
}, },
), ),
returnValue: _i7.Future< returnValue: _i7
_i3.ExchangeResponse<_i21.ExchangeTransaction>>.value( .Future<_i3.ExchangeResponse<_i21.ExchangeTransaction>>.value(
_FakeExchangeResponse_1<_i21.ExchangeTransaction>( _FakeExchangeResponse_1<_i21.ExchangeTransaction>(
this, this,
Invocation.method( Invocation.method(
@ -1197,8 +1189,9 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
)), )),
) as _i7.Future<_i3.ExchangeResponse<_i21.ExchangeTransaction>>); ) as _i7.Future<_i3.ExchangeResponse<_i21.ExchangeTransaction>>);
@override @override
_i7.Future<_i3.ExchangeResponse<_i22.ExchangeTransactionStatus>> _i7.Future<
getTransactionStatus({ _i3
.ExchangeResponse<_i22.ExchangeTransactionStatus>> getTransactionStatus({
required String? id, required String? id,
String? apiKey, String? apiKey,
}) => }) =>
@ -1211,8 +1204,8 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
#apiKey: apiKey, #apiKey: apiKey,
}, },
), ),
returnValue: _i7.Future< returnValue: _i7
_i3.ExchangeResponse<_i22.ExchangeTransactionStatus>>.value( .Future<_i3.ExchangeResponse<_i22.ExchangeTransactionStatus>>.value(
_FakeExchangeResponse_1<_i22.ExchangeTransactionStatus>( _FakeExchangeResponse_1<_i22.ExchangeTransactionStatus>(
this, this,
Invocation.method( Invocation.method(
@ -1224,8 +1217,7 @@ class MockChangeNowAPI extends _i1.Mock implements _i14.ChangeNowAPI {
}, },
), ),
)), )),
) as _i7 ) as _i7.Future<_i3.ExchangeResponse<_i22.ExchangeTransactionStatus>>);
.Future<_i3.ExchangeResponse<_i22.ExchangeTransactionStatus>>);
@override @override
_i7.Future<_i3.ExchangeResponse<List<_i23.Pair>>> _i7.Future<_i3.ExchangeResponse<List<_i23.Pair>>>
getAvailableFloatingRatePairs({bool? includePartners = false}) => getAvailableFloatingRatePairs({bool? includePartners = false}) =>

View file

@ -20,16 +20,17 @@ void main() {
group("getAvailableCurrencies", () { group("getAvailableCurrencies", () {
test("getAvailableCurrencies succeeds without options", () async { test("getAvailableCurrencies succeeds without options", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client;
final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async =>
Response(jsonEncode(availableCurrenciesJSON), 200)); Response(utf8.encode(jsonEncode(availableCurrenciesJSON)), 200));
final result = await ChangeNowAPI.instance.getAvailableCurrencies(); final result = await instance.getAvailableCurrencies();
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -38,17 +39,16 @@ void main() {
test("getAvailableCurrencies succeeds with active option", () async { test("getAvailableCurrencies succeeds with active option", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies?active=true"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies?active=true"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response(jsonEncode(availableCurrenciesJSONActive), 200)); utf8.encode(jsonEncode(availableCurrenciesJSONActive)), 200));
final result = final result = await instance.getAvailableCurrencies(active: true);
await ChangeNowAPI.instance.getAvailableCurrencies(active: true);
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -57,17 +57,16 @@ void main() {
test("getAvailableCurrencies succeeds with fixedRate option", () async { test("getAvailableCurrencies succeeds with fixedRate option", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies?fixedRate=true"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies?fixedRate=true"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response(jsonEncode(availableCurrenciesJSONFixedRate), 200)); utf8.encode(jsonEncode(availableCurrenciesJSONFixedRate)), 200));
final result = final result = await instance.getAvailableCurrencies(fixedRate: true);
await ChangeNowAPI.instance.getAvailableCurrencies(fixedRate: true);
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -77,18 +76,19 @@ void main() {
test("getAvailableCurrencies succeeds with fixedRate and active options", test("getAvailableCurrencies succeeds with fixedRate and active options",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/currencies?fixedRate=true&active=true"), "https://api.ChangeNow.io/v1/currencies?fixedRate=true&active=true"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response(jsonEncode(availableCurrenciesJSONActiveFixedRate), 200)); utf8.encode(jsonEncode(availableCurrenciesJSONActiveFixedRate)),
200));
final result = await ChangeNowAPI.instance final result =
.getAvailableCurrencies(active: true, fixedRate: true); await instance.getAvailableCurrencies(active: true, fixedRate: true);
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -99,16 +99,16 @@ void main() {
"getAvailableCurrencies fails with ChangeNowExceptionType.serializeResponseError", "getAvailableCurrencies fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response('{"some unexpected": "but valid json data"}', 200)); utf8.encode('{"some unexpected": "but valid json data"}'), 200));
final result = await ChangeNowAPI.instance.getAvailableCurrencies(); final result = await instance.getAvailableCurrencies();
expect( expect(
result.exception!.type, ExchangeExceptionType.serializeResponseError); result.exception!.type, ExchangeExceptionType.serializeResponseError);
@ -117,15 +117,15 @@ void main() {
test("getAvailableCurrencies fails for any other reason", () async { test("getAvailableCurrencies fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response("", 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(""), 400));
final result = await ChangeNowAPI.instance.getAvailableCurrencies(); final result = await instance.getAvailableCurrencies();
expect( expect(
result.exception!.type, ExchangeExceptionType.serializeResponseError); result.exception!.type, ExchangeExceptionType.serializeResponseError);
@ -136,17 +136,16 @@ void main() {
group("getPairedCurrencies", () { group("getPairedCurrencies", () {
test("getPairedCurrencies succeeds without fixedRate option", () async { test("getPairedCurrencies succeeds without fixedRate option", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async =>
Response(jsonEncode(getPairedCurrenciesJSON), 200)); Response(utf8.encode(jsonEncode(getPairedCurrenciesJSON)), 200));
final result = final result = await instance.getPairedCurrencies(ticker: "XMR");
await ChangeNowAPI.instance.getPairedCurrencies(ticker: "XMR");
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -155,18 +154,18 @@ void main() {
test("getPairedCurrencies succeeds with fixedRate option", () async { test("getPairedCurrencies succeeds with fixedRate option", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/currencies-to/XMR?fixedRate=true"), "https://api.ChangeNow.io/v1/currencies-to/XMR?fixedRate=true"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response(jsonEncode(getPairedCurrenciesJSONFixedRate), 200)); utf8.encode(jsonEncode(getPairedCurrenciesJSONFixedRate)), 200));
final result = await ChangeNowAPI.instance final result =
.getPairedCurrencies(ticker: "XMR", fixedRate: true); await instance.getPairedCurrencies(ticker: "XMR", fixedRate: true);
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -177,17 +176,16 @@ void main() {
"getPairedCurrencies fails with ChangeNowExceptionType.serializeResponseError A", "getPairedCurrencies fails with ChangeNowExceptionType.serializeResponseError A",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies-to/XMR"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response('[{"some unexpected": "but valid json data"}]', 200)); utf8.encode('[{"some unexpected": "but valid json data"}]'), 200));
final result = final result = await instance.getPairedCurrencies(ticker: "XMR");
await ChangeNowAPI.instance.getPairedCurrencies(ticker: "XMR");
expect( expect(
result.exception!.type, ExchangeExceptionType.serializeResponseError); result.exception!.type, ExchangeExceptionType.serializeResponseError);
@ -196,16 +194,16 @@ void main() {
test("getPairedCurrencies fails for any other reason", () async { test("getPairedCurrencies fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse("https://api.ChangeNow.io/v1/currencies"), url: Uri.parse("https://api.ChangeNow.io/v1/currencies"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response("", 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(""), 400));
final result = await ChangeNowAPI.instance final result =
.getPairedCurrencies(ticker: "XMR", fixedRate: true); await instance.getPairedCurrencies(ticker: "XMR", fixedRate: true);
expect(result.exception!.type, ExchangeExceptionType.generic); expect(result.exception!.type, ExchangeExceptionType.generic);
expect(result.value == null, true); expect(result.value == null, true);
@ -215,17 +213,17 @@ void main() {
group("getMinimalExchangeAmount", () { group("getMinimalExchangeAmount", () {
test("getMinimalExchangeAmount succeeds", () async { test("getMinimalExchangeAmount succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"), "https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer( )).thenAnswer((realInvocation) async =>
(realInvocation) async => Response('{"minAmount": 42}', 200)); Response(utf8.encode('{"minAmount": 42}'), 200));
final result = await ChangeNowAPI.instance.getMinimalExchangeAmount( final result = await instance.getMinimalExchangeAmount(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
@ -240,16 +238,17 @@ void main() {
"getMinimalExchangeAmount fails with ChangeNowExceptionType.serializeResponseError", "getMinimalExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"), "https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); )).thenAnswer((realInvocation) async =>
Response(utf8.encode('{"error": 42}'), 200));
final result = await ChangeNowAPI.instance.getMinimalExchangeAmount( final result = await instance.getMinimalExchangeAmount(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
@ -262,16 +261,16 @@ void main() {
test("getMinimalExchangeAmount fails for any other reason", () async { test("getMinimalExchangeAmount fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"), "https://api.ChangeNow.io/v1/min-amount/xmr_btc?api_key=testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = await ChangeNowAPI.instance.getMinimalExchangeAmount( final result = await instance.getMinimalExchangeAmount(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
@ -286,18 +285,19 @@ void main() {
group("getEstimatedExchangeAmount", () { group("getEstimatedExchangeAmount", () {
test("getEstimatedExchangeAmount succeeds", () async { test("getEstimatedExchangeAmount succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"), "https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response( )).thenAnswer((realInvocation) async => Response(
'{"estimatedAmount": 58.4142873, "transactionSpeedForecast": "10-60", "warningMessage": null}', utf8.encode(
'{"estimatedAmount": 58.4142873, "transactionSpeedForecast": "10-60", "warningMessage": null}'),
200)); 200));
final result = await ChangeNowAPI.instance.getEstimatedExchangeAmount( final result = await instance.getEstimatedExchangeAmount(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
fromAmount: Decimal.fromInt(42), fromAmount: Decimal.fromInt(42),
@ -313,16 +313,17 @@ void main() {
"getEstimatedExchangeAmount fails with ChangeNowExceptionType.serializeResponseError", "getEstimatedExchangeAmount fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"), "https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); )).thenAnswer((realInvocation) async =>
Response(utf8.encode('{"error": 42}'), 200));
final result = await ChangeNowAPI.instance.getEstimatedExchangeAmount( final result = await instance.getEstimatedExchangeAmount(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
fromAmount: Decimal.fromInt(42), fromAmount: Decimal.fromInt(42),
@ -336,16 +337,16 @@ void main() {
test("getEstimatedExchangeAmount fails for any other reason", () async { test("getEstimatedExchangeAmount fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"), "https://api.ChangeNow.io/v1/exchange-amount/42/xmr_btc?api_key=testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = await ChangeNowAPI.instance.getEstimatedExchangeAmount( final result = await instance.getEstimatedExchangeAmount(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
fromAmount: Decimal.fromInt(42), fromAmount: Decimal.fromInt(42),
@ -366,9 +367,9 @@ void main() {
// Uri.parse( // Uri.parse(
// "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"), // "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
// headers: {'Content-Type': 'application/json'}, // headers: {'Content-Type': 'application/json'},
// routeOverTor: false, // proxyInfo: null,
// )).thenAnswer((realInvocation) async => // )).thenAnswer((realInvocation) async =>
// Response(jsonEncode(estFixedRateExchangeAmountJSON), 200)); // Response(utf8.encode(jsonEncode(estFixedRateExchangeAmountJSON )), 200));
// //
// final result = // final result =
// await ChangeNow.instance.getEstimatedFixedRateExchangeAmount( // await ChangeNow.instance.getEstimatedFixedRateExchangeAmount(
@ -394,7 +395,7 @@ void main() {
// Uri.parse( // Uri.parse(
// "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"), // "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
// headers: {'Content-Type': 'application/json'}, // headers: {'Content-Type': 'application/json'},
// routeOverTor: false, // proxyInfo: null,
// )).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); // )).thenAnswer((realInvocation) async => Response('{"error": 42}', 200));
// //
// final result = // final result =
@ -419,7 +420,7 @@ void main() {
// Uri.parse( // Uri.parse(
// "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"), // "https://api.ChangeNow.io/v1/exchange-amount/fixed-rate/10/xmr_btc?api_key=testAPIKEY&useRateId=true"),
// headers: {'Content-Type': 'application/json'}, // headers: {'Content-Type': 'application/json'},
// routeOverTor: false, // proxyInfo: null,
// )).thenAnswer((realInvocation) async => Response('', 400)); // )).thenAnswer((realInvocation) async => Response('', 400));
// //
// final result = // final result =
@ -438,17 +439,17 @@ void main() {
group("getAvailableFixedRateMarkets", () { group("getAvailableFixedRateMarkets", () {
test("getAvailableFixedRateMarkets succeeds", () async { test("getAvailableFixedRateMarkets succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async =>
Response(jsonEncode(fixedRateMarketsJSON), 200)); Response(utf8.encode(jsonEncode(fixedRateMarketsJSON)), 200));
final result = await ChangeNowAPI.instance.getAvailableFixedRateMarkets( final result = await instance.getAvailableFixedRateMarkets(
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
); );
@ -461,16 +462,17 @@ void main() {
"getAvailableFixedRateMarkets fails with ChangeNowExceptionType.serializeResponseError", "getAvailableFixedRateMarkets fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); )).thenAnswer((realInvocation) async =>
Response(utf8.encode('{"error": 42}'), 200));
final result = await ChangeNowAPI.instance.getAvailableFixedRateMarkets( final result = await instance.getAvailableFixedRateMarkets(
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
); );
@ -481,16 +483,16 @@ void main() {
test("getAvailableFixedRateMarkets fails for any other reason", () async { test("getAvailableFixedRateMarkets fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/market-info/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = await ChangeNowAPI.instance.getAvailableFixedRateMarkets( final result = await instance.getAvailableFixedRateMarkets(
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
); );
@ -503,20 +505,19 @@ void main() {
group("createStandardExchangeTransaction", () { group("createStandardExchangeTransaction", () {
test("createStandardExchangeTransaction succeeds", () async { test("createStandardExchangeTransaction succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.post( when(client.post(
url: Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"), url: Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
body: body:
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}', '{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response(jsonEncode(createStandardTransactionResponse), 200)); utf8.encode(jsonEncode(createStandardTransactionResponse)), 200));
final result = final result = await instance.createStandardExchangeTransaction(
await ChangeNowAPI.instance.createStandardExchangeTransaction(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5", receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
@ -535,19 +536,19 @@ void main() {
"createStandardExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError", "createStandardExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.post( when(client.post(
url: Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"), url: Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
body: body:
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}', '{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); )).thenAnswer((realInvocation) async =>
Response(utf8.encode('{"error": 42}'), 200));
final result = final result = await instance.createStandardExchangeTransaction(
await ChangeNowAPI.instance.createStandardExchangeTransaction(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5", receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
@ -565,19 +566,18 @@ void main() {
test("createStandardExchangeTransaction fails for any other reason", test("createStandardExchangeTransaction fails for any other reason",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.post( when(client.post(
url: Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"), url: Uri.parse("https://api.ChangeNow.io/v1/transactions/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
body: body:
'{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}', '{"from":"xmr","to":"btc","address":"bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5","amount":"0.3","flow":"standard","extraId":"","userId":"","contactEmail":"","refundAddress":"888tNkZrPN6JsEgekjMnABU4TBzc2Dt29EPAvkRxbANsAnjyPbb3iQ1YBRk1UXcdRsiKc9dhwMVgN5S9cQUiyoogDavup3H","refundExtraId":""}',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = final result = await instance.createStandardExchangeTransaction(
await ChangeNowAPI.instance.createStandardExchangeTransaction(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5", receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
@ -595,22 +595,26 @@ void main() {
group("createFixedRateExchangeTransaction", () { group("createFixedRateExchangeTransaction", () {
test("createFixedRateExchangeTransaction succeeds", () async { test("createFixedRateExchangeTransaction succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.post( when(client.post(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
body: body:
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":"","amount":"0.3"}', '{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":"","amount":"0.3"}',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => Response( )).thenAnswer((realInvocation) async => Response(
'{"payinAddress": "33eFX2jfeWbXMSmRe9ewUUTrmSVSxZi5cj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886","payoutExtraId": "", "fromCurrency": "btc", "toCurrency": "eth", "refundAddress": "","refundExtraId": "","validUntil": "2019-09-09T14:01:04.921Z","id": "a5c73e2603f40d","amount": 62.9737711}', utf8.encode(
'{"payinAddress": "33eFX2jfeWbXMSmRe9ewUUTrmSVSxZi5cj", "payoutAddress":'
' "0x57f31ad4b64095347F87eDB1675566DAfF5EC886","payoutExtraId": "",'
' "fromCurrency": "btc", "toCurrency": "eth", "refundAddress": "",'
'"refundExtraId": "","validUntil": "2019-09-09T14:01:04.921Z","id":'
' "a5c73e2603f40d","amount": 62.9737711}'),
200)); 200));
final result = final result = await instance.createFixedRateExchangeTransaction(
await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
fromTicker: "btc", fromTicker: "btc",
toTicker: "eth", toTicker: "eth",
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
@ -630,21 +634,20 @@ void main() {
"createFixedRateExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError", "createFixedRateExchangeTransaction fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.post( when(client.post(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
body: body:
'{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}', '{"from":"btc","to":"eth","address":"0x57f31ad4b64095347F87eDB1675566DAfF5EC886","amount":"0.3","flow":"fixed-rate","extraId":"","userId":"","contactEmail":"","refundAddress":"","refundExtraId":"","rateId":""}',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response('{"id": "a5c73e2603f40d","amount": 62.9737711}', 200)); utf8.encode('{"id": "a5c73e2603f40d","amount": 62.9737711}'), 200));
final result = final result = await instance.createFixedRateExchangeTransaction(
await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
fromTicker: "btc", fromTicker: "btc",
toTicker: "eth", toTicker: "eth",
receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", receivingAddress: "0x57f31ad4b64095347F87eDB1675566DAfF5EC886",
@ -662,20 +665,19 @@ void main() {
test("createFixedRateExchangeTransaction fails for any other reason", test("createFixedRateExchangeTransaction fails for any other reason",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.post( when(client.post(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/fixed-rate/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
body: body:
'{"from": "btc","to": "eth","address": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "amount": "1.12345","extraId": "", "userId": "","contactEmail": "","refundAddress": "", "refundExtraId": "", "rateId": "" }', '{"from": "btc","to": "eth","address": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "amount": "1.12345","extraId": "", "userId": "","contactEmail": "","refundAddress": "", "refundExtraId": "", "rateId": "" }',
encoding: null, encoding: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = final result = await instance.createFixedRateExchangeTransaction(
await ChangeNowAPI.instance.createFixedRateExchangeTransaction(
fromTicker: "xmr", fromTicker: "xmr",
toTicker: "btc", toTicker: "btc",
receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5", receivingAddress: "bc1qu58svs9983e2vuyqh7gq7ratf8k5qehz5k0cn5",
@ -695,18 +697,24 @@ void main() {
group("getTransactionStatus", () { group("getTransactionStatus", () {
test("getTransactionStatus succeeds", () async { test("getTransactionStatus succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response( )).thenAnswer((realInvocation) async => Response(
'{"status": "waiting", "payinAddress": "32Ge2ci26rj1sRGw2NjiQa9L7Xvxtgzhrj", "payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", "fromCurrency": "btc", "toCurrency": "eth", "id": "50727663e5d9a4", "updatedAt": "2019-08-22T14:47:49.943Z", "expectedSendAmount": 1, "expectedReceiveAmount": 52.31667, "createdAt": "2019-08-22T14:47:49.943Z", "isPartner": false}', utf8.encode(
'{"status": "waiting", "payinAddress": "32Ge2ci26rj1sRGw2NjiQa9L7Xvxtgzhrj", '
'"payoutAddress": "0x57f31ad4b64095347F87eDB1675566DAfF5EC886", '
'"fromCurrency": "btc", "toCurrency": "eth", "id": "50727663e5d9a4", '
'"updatedAt": "2019-08-22T14:47:49.943Z", "expectedSendAmount": 1, '
'"expectedReceiveAmount": 52.31667, "createdAt": "2019-08-22T14:47:49.943Z",'
' "isPartner": false}'),
200)); 200));
final result = await ChangeNowAPI.instance.getTransactionStatus( final result = await instance.getTransactionStatus(
id: "47F87eDB1675566DAfF5EC886", id: "47F87eDB1675566DAfF5EC886",
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
); );
@ -720,16 +728,17 @@ void main() {
"getTransactionStatus fails with ChangeNowExceptionType.serializeResponseError", "getTransactionStatus fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); )).thenAnswer((realInvocation) async =>
Response(utf8.encode('{"error": 42}'), 200));
final result = await ChangeNowAPI.instance.getTransactionStatus( final result = await instance.getTransactionStatus(
id: "47F87eDB1675566DAfF5EC886", id: "47F87eDB1675566DAfF5EC886",
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
); );
@ -741,16 +750,16 @@ void main() {
test("getTransactionStatus fails for any other reason", () async { test("getTransactionStatus fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"), "https://api.ChangeNow.io/v1/transactions/47F87eDB1675566DAfF5EC886/testAPIKEY"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = await ChangeNowAPI.instance.getTransactionStatus( final result = await instance.getTransactionStatus(
id: "47F87eDB1675566DAfF5EC886", id: "47F87eDB1675566DAfF5EC886",
apiKey: "testAPIKEY", apiKey: "testAPIKEY",
); );
@ -764,18 +773,17 @@ void main() {
group("getAvailableFloatingRatePairs", () { group("getAvailableFloatingRatePairs", () {
test("getAvailableFloatingRatePairs succeeds", () async { test("getAvailableFloatingRatePairs succeeds", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"), "https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => )).thenAnswer((realInvocation) async => Response(
Response('["btc_xmr","btc_firo","btc_doge","eth_ltc"]', 200)); utf8.encode('["btc_xmr","btc_firo","btc_doge","eth_ltc"]'), 200));
final result = final result = await instance.getAvailableFloatingRatePairs();
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
expect(result.exception, null); expect(result.exception, null);
expect(result.value == null, false); expect(result.value == null, false);
@ -786,17 +794,17 @@ void main() {
"getAvailableFloatingRatePairs fails with ChangeNowExceptionType.serializeResponseError", "getAvailableFloatingRatePairs fails with ChangeNowExceptionType.serializeResponseError",
() async { () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"), "https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('{"error": 42}', 200)); )).thenAnswer((realInvocation) async =>
Response(utf8.encode('{"error": 42}'), 200));
final result = final result = await instance.getAvailableFloatingRatePairs();
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
expect( expect(
result.exception!.type, ExchangeExceptionType.serializeResponseError); result.exception!.type, ExchangeExceptionType.serializeResponseError);
@ -805,17 +813,16 @@ void main() {
test("getAvailableFloatingRatePairs fails for any other reason", () async { test("getAvailableFloatingRatePairs fails for any other reason", () async {
final client = MockHTTP(); final client = MockHTTP();
ChangeNowAPI.instance.client = client; final instance = ChangeNowAPI(http: client);
when(client.get( when(client.get(
url: Uri.parse( url: Uri.parse(
"https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"), "https://api.ChangeNow.io/v1/market-info/available-pairs?includePartners=false"),
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
routeOverTor: false, proxyInfo: null,
)).thenAnswer((realInvocation) async => Response('', 400)); )).thenAnswer((realInvocation) async => Response(utf8.encode(''), 400));
final result = final result = await instance.getAvailableFloatingRatePairs();
await ChangeNowAPI.instance.getAvailableFloatingRatePairs();
expect( expect(
result.exception!.type, ExchangeExceptionType.serializeResponseError); result.exception!.type, ExchangeExceptionType.serializeResponseError);

View file

@ -4,7 +4,8 @@
// ignore_for_file: no_leading_underscores_for_library_prefixes // ignore_for_file: no_leading_underscores_for_library_prefixes
import 'dart:async' as _i3; import 'dart:async' as _i3;
import 'dart:convert' as _i4; import 'dart:convert' as _i5;
import 'dart:io' as _i4;
import 'package:mockito/mockito.dart' as _i1; import 'package:mockito/mockito.dart' as _i1;
import 'package:stackwallet/networking/http.dart' as _i2; import 'package:stackwallet/networking/http.dart' as _i2;
@ -42,7 +43,7 @@ class MockHTTP extends _i1.Mock implements _i2.HTTP {
_i3.Future<_i2.Response> get({ _i3.Future<_i2.Response> get({
required Uri? url, required Uri? url,
Map<String, String>? headers, Map<String, String>? headers,
required bool? routeOverTor, required ({_i4.InternetAddress host, int port})? proxyInfo,
}) => }) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -51,7 +52,7 @@ class MockHTTP extends _i1.Mock implements _i2.HTTP {
{ {
#url: url, #url: url,
#headers: headers, #headers: headers,
#routeOverTor: routeOverTor, #proxyInfo: proxyInfo,
}, },
), ),
returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0(
@ -62,7 +63,7 @@ class MockHTTP extends _i1.Mock implements _i2.HTTP {
{ {
#url: url, #url: url,
#headers: headers, #headers: headers,
#routeOverTor: routeOverTor, #proxyInfo: proxyInfo,
}, },
), ),
)), )),
@ -72,8 +73,8 @@ class MockHTTP extends _i1.Mock implements _i2.HTTP {
required Uri? url, required Uri? url,
Map<String, String>? headers, Map<String, String>? headers,
Object? body, Object? body,
_i4.Encoding? encoding, _i5.Encoding? encoding,
required bool? routeOverTor, required ({_i4.InternetAddress host, int port})? proxyInfo,
}) => }) =>
(super.noSuchMethod( (super.noSuchMethod(
Invocation.method( Invocation.method(
@ -84,7 +85,7 @@ class MockHTTP extends _i1.Mock implements _i2.HTTP {
#headers: headers, #headers: headers,
#body: body, #body: body,
#encoding: encoding, #encoding: encoding,
#routeOverTor: routeOverTor, #proxyInfo: proxyInfo,
}, },
), ),
returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0( returnValue: _i3.Future<_i2.Response>.value(_FakeResponse_0(
@ -97,7 +98,7 @@ class MockHTTP extends _i1.Mock implements _i2.HTTP {
#headers: headers, #headers: headers,
#body: body, #body: body,
#encoding: encoding, #encoding: encoding,
#routeOverTor: routeOverTor, #proxyInfo: proxyInfo,
}, },
), ),
)), )),

View file

@ -537,7 +537,6 @@ class MockTransactionNotificationTracker extends _i1.Mock
Invocation.getter(#confirmeds), Invocation.getter(#confirmeds),
returnValue: <String>[], returnValue: <String>[],
) as List<String>); ) as List<String>);
@override @override
bool wasNotifiedPending(String? txid) => (super.noSuchMethod( bool wasNotifiedPending(String? txid) => (super.noSuchMethod(
Invocation.method( Invocation.method(