mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-16 17:27:39 +00:00
nanswap
This commit is contained in:
parent
40f8767b11
commit
df3935d5d4
20 changed files with 1605 additions and 172 deletions
69
asset_sources/svg/campfire/exchange_icons/nanswap.svg
Normal file
69
asset_sources/svg/campfire/exchange_icons/nanswap.svg
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="75.209999mm"
|
||||||
|
height="75.209999mm"
|
||||||
|
viewBox="0 0 213.19692 213.2"
|
||||||
|
version="1.1"
|
||||||
|
id="svg30"
|
||||||
|
sodipodi:docname="nanswap2.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||||
|
<metadata
|
||||||
|
id="metadata36">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>nanswap</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs34" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2635"
|
||||||
|
inkscape:window-height="1461"
|
||||||
|
id="namedview32"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.29390619"
|
||||||
|
inkscape:cx="-79.957486"
|
||||||
|
inkscape:cy="142.12913"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg30" />
|
||||||
|
<title
|
||||||
|
id="title2">nanswap</title>
|
||||||
|
<circle
|
||||||
|
cx="106.6"
|
||||||
|
cy="106.6"
|
||||||
|
r="106.6"
|
||||||
|
id="circle4"
|
||||||
|
style="fill:#4a90e2" />
|
||||||
|
<path
|
||||||
|
d="m 166.7,66.500006 a 20,20 0 0 1 -20,20 c -15,0 -20,5 -20,19.999994 a 20,20 0 0 1 -20,20 c -15,0 -20,5 -20,20 a 20,20 0 1 1 -20,-20 c 15,0 20,-5 20,-20 a 20,20 0 0 1 20,-19.999994 c 15,0 20,-5 20,-20 a 20,20 0 0 1 40,0 z"
|
||||||
|
id="path6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#000034" />
|
||||||
|
<path
|
||||||
|
d="m 66.5,46.500006 a 20,20 0 0 1 20,20 c 0,15 5,20 20,20 A 20,20 0 0 1 126.5,106.5 c 0,15 5,20 20,20 a 20,20 0 1 1 -20,20 c 0,-15 -5,-20 -20,-20 a 20,20 0 0 1 -20,-20 c 0,-14.999994 -5,-19.999994 -20,-19.999994 a 20,20 0 0 1 0,-40 z"
|
||||||
|
id="path8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#000034" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
69
asset_sources/svg/stack_duo/exchange_icons/nanswap.svg
Normal file
69
asset_sources/svg/stack_duo/exchange_icons/nanswap.svg
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="75.209999mm"
|
||||||
|
height="75.209999mm"
|
||||||
|
viewBox="0 0 213.19692 213.2"
|
||||||
|
version="1.1"
|
||||||
|
id="svg30"
|
||||||
|
sodipodi:docname="nanswap2.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||||
|
<metadata
|
||||||
|
id="metadata36">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>nanswap</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs34" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2635"
|
||||||
|
inkscape:window-height="1461"
|
||||||
|
id="namedview32"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.29390619"
|
||||||
|
inkscape:cx="-79.957486"
|
||||||
|
inkscape:cy="142.12913"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg30" />
|
||||||
|
<title
|
||||||
|
id="title2">nanswap</title>
|
||||||
|
<circle
|
||||||
|
cx="106.6"
|
||||||
|
cy="106.6"
|
||||||
|
r="106.6"
|
||||||
|
id="circle4"
|
||||||
|
style="fill:#4a90e2" />
|
||||||
|
<path
|
||||||
|
d="m 166.7,66.500006 a 20,20 0 0 1 -20,20 c -15,0 -20,5 -20,19.999994 a 20,20 0 0 1 -20,20 c -15,0 -20,5 -20,20 a 20,20 0 1 1 -20,-20 c 15,0 20,-5 20,-20 a 20,20 0 0 1 20,-19.999994 c 15,0 20,-5 20,-20 a 20,20 0 0 1 40,0 z"
|
||||||
|
id="path6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#000034" />
|
||||||
|
<path
|
||||||
|
d="m 66.5,46.500006 a 20,20 0 0 1 20,20 c 0,15 5,20 20,20 A 20,20 0 0 1 126.5,106.5 c 0,15 5,20 20,20 a 20,20 0 1 1 -20,20 c 0,-15 -5,-20 -20,-20 a 20,20 0 0 1 -20,-20 c 0,-14.999994 -5,-19.999994 -20,-19.999994 a 20,20 0 0 1 0,-40 z"
|
||||||
|
id="path8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#000034" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
69
asset_sources/svg/stack_wallet/exchange_icons/nanswap.svg
Normal file
69
asset_sources/svg/stack_wallet/exchange_icons/nanswap.svg
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="75.209999mm"
|
||||||
|
height="75.209999mm"
|
||||||
|
viewBox="0 0 213.19692 213.2"
|
||||||
|
version="1.1"
|
||||||
|
id="svg30"
|
||||||
|
sodipodi:docname="nanswap2.svg"
|
||||||
|
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)">
|
||||||
|
<metadata
|
||||||
|
id="metadata36">
|
||||||
|
<rdf:RDF>
|
||||||
|
<cc:Work
|
||||||
|
rdf:about="">
|
||||||
|
<dc:format>image/svg+xml</dc:format>
|
||||||
|
<dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||||
|
<dc:title>nanswap</dc:title>
|
||||||
|
</cc:Work>
|
||||||
|
</rdf:RDF>
|
||||||
|
</metadata>
|
||||||
|
<defs
|
||||||
|
id="defs34" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="2635"
|
||||||
|
inkscape:window-height="1461"
|
||||||
|
id="namedview32"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="0.29390619"
|
||||||
|
inkscape:cx="-79.957486"
|
||||||
|
inkscape:cy="142.12913"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="svg30" />
|
||||||
|
<title
|
||||||
|
id="title2">nanswap</title>
|
||||||
|
<circle
|
||||||
|
cx="106.6"
|
||||||
|
cy="106.6"
|
||||||
|
r="106.6"
|
||||||
|
id="circle4"
|
||||||
|
style="fill:#4a90e2" />
|
||||||
|
<path
|
||||||
|
d="m 166.7,66.500006 a 20,20 0 0 1 -20,20 c -15,0 -20,5 -20,19.999994 a 20,20 0 0 1 -20,20 c -15,0 -20,5 -20,20 a 20,20 0 1 1 -20,-20 c 15,0 20,-5 20,-20 a 20,20 0 0 1 20,-19.999994 c 15,0 20,-5 20,-20 a 20,20 0 0 1 40,0 z"
|
||||||
|
id="path6"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#000034" />
|
||||||
|
<path
|
||||||
|
d="m 66.5,46.500006 a 20,20 0 0 1 20,20 c 0,15 5,20 20,20 A 20,20 0 0 1 126.5,106.5 c 0,15 5,20 20,20 a 20,20 0 1 1 -20,20 c 0,-15 -5,-20 -20,-20 a 20,20 0 0 1 -20,-20 c 0,-14.999994 -5,-19.999994 -20,-19.999994 a 20,20 0 0 1 0,-40 z"
|
||||||
|
id="path8"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
style="fill:#000034" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
|
@ -22,6 +22,7 @@ import '../../../services/exchange/change_now/change_now_exchange.dart';
|
||||||
import '../../../services/exchange/exchange.dart';
|
import '../../../services/exchange/exchange.dart';
|
||||||
import '../../../services/exchange/exchange_data_loading_service.dart';
|
import '../../../services/exchange/exchange_data_loading_service.dart';
|
||||||
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import '../../../services/exchange/nanswap/nanswap_exchange.dart';
|
||||||
import '../../../services/exchange/trocador/trocador_exchange.dart';
|
import '../../../services/exchange/trocador/trocador_exchange.dart';
|
||||||
import '../../../themes/stack_colors.dart';
|
import '../../../themes/stack_colors.dart';
|
||||||
import '../../../utilities/assets.dart';
|
import '../../../utilities/assets.dart';
|
||||||
|
@ -117,6 +118,8 @@ class _ExchangeCurrencySelectionViewState
|
||||||
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
.exchangeNameEqualTo(MajesticBankExchange.exchangeName)
|
||||||
.or()
|
.or()
|
||||||
.exchangeNameStartsWith(TrocadorExchange.exchangeName)
|
.exchangeNameStartsWith(TrocadorExchange.exchangeName)
|
||||||
|
.or()
|
||||||
|
.exchangeNameStartsWith(NanswapExchange.exchangeName)
|
||||||
.findAll();
|
.findAll();
|
||||||
|
|
||||||
final cn = await ChangeNowExchange.instance.getPairedCurrencies(
|
final cn = await ChangeNowExchange.instance.getPairedCurrencies(
|
||||||
|
|
|
@ -33,6 +33,7 @@ import '../../services/exchange/exchange.dart';
|
||||||
import '../../services/exchange/exchange_data_loading_service.dart';
|
import '../../services/exchange/exchange_data_loading_service.dart';
|
||||||
import '../../services/exchange/exchange_response.dart';
|
import '../../services/exchange/exchange_response.dart';
|
||||||
import '../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
import '../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import '../../services/exchange/nanswap/nanswap_exchange.dart';
|
||||||
import '../../services/exchange/trocador/trocador_exchange.dart';
|
import '../../services/exchange/trocador/trocador_exchange.dart';
|
||||||
import '../../themes/stack_colors.dart';
|
import '../../themes/stack_colors.dart';
|
||||||
import '../../utilities/amount/amount_unit.dart';
|
import '../../utilities/amount/amount_unit.dart';
|
||||||
|
@ -87,6 +88,7 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
||||||
MajesticBankExchange.instance,
|
MajesticBankExchange.instance,
|
||||||
ChangeNowExchange.instance,
|
ChangeNowExchange.instance,
|
||||||
TrocadorExchange.instance,
|
TrocadorExchange.instance,
|
||||||
|
NanswapExchange.instance,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import '../../../app_config.dart';
|
import '../../../app_config.dart';
|
||||||
import '../../../models/exchange/incomplete_exchange.dart';
|
import '../../../models/exchange/incomplete_exchange.dart';
|
||||||
import '../../../providers/providers.dart';
|
import '../../../providers/providers.dart';
|
||||||
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
|
||||||
import '../../../themes/stack_colors.dart';
|
import '../../../themes/stack_colors.dart';
|
||||||
import '../../../utilities/address_utils.dart';
|
import '../../../utilities/address_utils.dart';
|
||||||
import '../../../utilities/barcode_scanner_interface.dart';
|
import '../../../utilities/barcode_scanner_interface.dart';
|
||||||
|
@ -126,8 +125,7 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final supportsRefund =
|
final supportsRefund = ref.watch(efExchangeProvider).supportsRefundAddress;
|
||||||
ref.watch(efExchangeProvider).name != MajesticBankExchange.exchangeName;
|
|
||||||
|
|
||||||
return Background(
|
return Background(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
|
|
@ -18,7 +18,6 @@ import '../../../models/exchange/response_objects/trade.dart';
|
||||||
import '../../../providers/global/trades_service_provider.dart';
|
import '../../../providers/global/trades_service_provider.dart';
|
||||||
import '../../../providers/providers.dart';
|
import '../../../providers/providers.dart';
|
||||||
import '../../../services/exchange/exchange_response.dart';
|
import '../../../services/exchange/exchange_response.dart';
|
||||||
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
|
||||||
import '../../../services/notifications_api.dart';
|
import '../../../services/notifications_api.dart';
|
||||||
import '../../../themes/stack_colors.dart';
|
import '../../../themes/stack_colors.dart';
|
||||||
import '../../../utilities/assets.dart';
|
import '../../../utilities/assets.dart';
|
||||||
|
@ -63,8 +62,7 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final supportsRefund =
|
final supportsRefund = ref.watch(efExchangeProvider).supportsRefundAddress;
|
||||||
ref.watch(efExchangeProvider).name != MajesticBankExchange.exchangeName;
|
|
||||||
|
|
||||||
return Background(
|
return Background(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
|
|
@ -10,17 +10,19 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
|
||||||
import '../../../models/exchange/aggregate_currency.dart';
|
import '../../../models/exchange/aggregate_currency.dart';
|
||||||
import 'exchange_provider_option.dart';
|
|
||||||
import '../../../providers/providers.dart';
|
import '../../../providers/providers.dart';
|
||||||
import '../../../services/exchange/change_now/change_now_exchange.dart';
|
import '../../../services/exchange/change_now/change_now_exchange.dart';
|
||||||
import '../../../services/exchange/exchange.dart';
|
import '../../../services/exchange/exchange.dart';
|
||||||
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
import '../../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import '../../../services/exchange/nanswap/nanswap_exchange.dart';
|
||||||
import '../../../services/exchange/trocador/trocador_exchange.dart';
|
import '../../../services/exchange/trocador/trocador_exchange.dart';
|
||||||
import '../../../themes/stack_colors.dart';
|
import '../../../themes/stack_colors.dart';
|
||||||
import '../../../utilities/prefs.dart';
|
import '../../../utilities/prefs.dart';
|
||||||
import '../../../utilities/util.dart';
|
import '../../../utilities/util.dart';
|
||||||
import '../../../widgets/rounded_white_container.dart';
|
import '../../../widgets/rounded_white_container.dart';
|
||||||
|
import 'exchange_provider_option.dart';
|
||||||
|
|
||||||
class ExchangeProviderOptions extends ConsumerStatefulWidget {
|
class ExchangeProviderOptions extends ConsumerStatefulWidget {
|
||||||
const ExchangeProviderOptions({
|
const ExchangeProviderOptions({
|
||||||
|
@ -88,6 +90,11 @@ class _ExchangeProviderOptionsState
|
||||||
sendCurrency: sendCurrency,
|
sendCurrency: sendCurrency,
|
||||||
receiveCurrency: receivingCurrency,
|
receiveCurrency: receivingCurrency,
|
||||||
);
|
);
|
||||||
|
final showNanswap = exchangeSupported(
|
||||||
|
exchangeName: NanswapExchange.exchangeName,
|
||||||
|
sendCurrency: sendCurrency,
|
||||||
|
receiveCurrency: receivingCurrency,
|
||||||
|
);
|
||||||
|
|
||||||
return RoundedWhiteContainer(
|
return RoundedWhiteContainer(
|
||||||
padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12),
|
padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12),
|
||||||
|
@ -134,6 +141,23 @@ class _ExchangeProviderOptionsState
|
||||||
reversed: widget.reversed,
|
reversed: widget.reversed,
|
||||||
exchange: TrocadorExchange.instance,
|
exchange: TrocadorExchange.instance,
|
||||||
),
|
),
|
||||||
|
if ((showChangeNow || showMajesticBank || showTrocador) &&
|
||||||
|
showNanswap)
|
||||||
|
isDesktop
|
||||||
|
? Container(
|
||||||
|
height: 1,
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.background,
|
||||||
|
)
|
||||||
|
: const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
if (showNanswap)
|
||||||
|
ExchangeOption(
|
||||||
|
fixedRate: widget.fixedRate,
|
||||||
|
reversed: widget.reversed,
|
||||||
|
exchange: NanswapExchange.instance,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -30,6 +30,7 @@ import '../../route_generator.dart';
|
||||||
import '../../services/exchange/change_now/change_now_exchange.dart';
|
import '../../services/exchange/change_now/change_now_exchange.dart';
|
||||||
import '../../services/exchange/exchange.dart';
|
import '../../services/exchange/exchange.dart';
|
||||||
import '../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
import '../../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import '../../services/exchange/nanswap/nanswap_exchange.dart';
|
||||||
import '../../services/exchange/simpleswap/simpleswap_exchange.dart';
|
import '../../services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||||
import '../../services/exchange/trocador/trocador_exchange.dart';
|
import '../../services/exchange/trocador/trocador_exchange.dart';
|
||||||
import '../../themes/stack_colors.dart';
|
import '../../themes/stack_colors.dart';
|
||||||
|
@ -1330,6 +1331,10 @@ class _TradeDetailsViewState extends ConsumerState<TradeDetailsView> {
|
||||||
url =
|
url =
|
||||||
"https://majesticbank.sc/track?trx=${trade.tradeId}";
|
"https://majesticbank.sc/track?trx=${trade.tradeId}";
|
||||||
break;
|
break;
|
||||||
|
case NanswapExchange.exchangeName:
|
||||||
|
url =
|
||||||
|
"https://nanswap.com/transaction/${trade.tradeId}";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (trade.exchangeName
|
if (trade.exchangeName
|
||||||
|
|
|
@ -15,8 +15,7 @@ import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
import '../../../../app_config.dart';
|
import '../../../../app_config.dart';
|
||||||
import '../../../../models/contact_address_entry.dart';
|
import '../../../../models/contact_address_entry.dart';
|
||||||
import '../../../../providers/exchange/exchange_send_from_wallet_id_provider.dart';
|
import '../../../../providers/providers.dart';
|
||||||
import '../../../../providers/global/wallets_provider.dart';
|
|
||||||
import '../../../../themes/stack_colors.dart';
|
import '../../../../themes/stack_colors.dart';
|
||||||
import '../../../../utilities/clipboard_interface.dart';
|
import '../../../../utilities/clipboard_interface.dart';
|
||||||
import '../../../../utilities/constants.dart';
|
import '../../../../utilities/constants.dart';
|
||||||
|
@ -88,7 +87,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
}
|
}
|
||||||
|
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty && _refundController.text.isNotEmpty,
|
_next(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +119,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
Logging.instance.log("$e\n$s", level: LogLevel.Info);
|
Logging.instance.log("$e\n$s", level: LogLevel.Info);
|
||||||
}
|
}
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty && _refundController.text.isNotEmpty,
|
_next(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +166,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
_toController.text = entry.address;
|
_toController.text = entry.address;
|
||||||
ref.read(desktopExchangeModelProvider)!.recipientAddress = entry.address;
|
ref.read(desktopExchangeModelProvider)!.recipientAddress = entry.address;
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty && _refundController.text.isNotEmpty,
|
_next(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,11 +214,21 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
_refundController.text = entry.address;
|
_refundController.text = entry.address;
|
||||||
ref.read(desktopExchangeModelProvider)!.refundAddress = entry.address;
|
ref.read(desktopExchangeModelProvider)!.refundAddress = entry.address;
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty && _refundController.text.isNotEmpty,
|
_next(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _next() {
|
||||||
|
if (doesRefundAddress) {
|
||||||
|
return _toController.text.isNotEmpty && _refundController.text.isNotEmpty;
|
||||||
|
} else {
|
||||||
|
return _toController.text.isNotEmpty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
late final bool doesRefundAddress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
clipboard = widget.clipboard;
|
clipboard = widget.clipboard;
|
||||||
|
@ -230,6 +239,13 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
_toFocusNode = FocusNode();
|
_toFocusNode = FocusNode();
|
||||||
_refundFocusNode = FocusNode();
|
_refundFocusNode = FocusNode();
|
||||||
|
|
||||||
|
doesRefundAddress = ref.read(efExchangeProvider).supportsRefundAddress;
|
||||||
|
|
||||||
|
if (!doesRefundAddress) {
|
||||||
|
// hack: set to empty to not throw null unwrap error later
|
||||||
|
ref.read(desktopExchangeModelProvider)!.refundAddress = "";
|
||||||
|
}
|
||||||
|
|
||||||
final tuple = ref.read(exchangeSendFromWalletIdStateProvider.state).state;
|
final tuple = ref.read(exchangeSendFromWalletIdStateProvider.state).state;
|
||||||
if (tuple != null) {
|
if (tuple != null) {
|
||||||
if (ref.read(desktopExchangeModelProvider)!.receiveTicker.toLowerCase() ==
|
if (ref.read(desktopExchangeModelProvider)!.receiveTicker.toLowerCase() ==
|
||||||
|
@ -243,8 +259,9 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
ref.read(desktopExchangeModelProvider)!.recipientAddress =
|
ref.read(desktopExchangeModelProvider)!.recipientAddress =
|
||||||
_toController.text;
|
_toController.text;
|
||||||
} else {
|
} else {
|
||||||
if (ref.read(desktopExchangeModelProvider)!.sendTicker.toUpperCase() ==
|
if (doesRefundAddress &&
|
||||||
tuple.item2.ticker.toUpperCase()) {
|
ref.read(desktopExchangeModelProvider)!.sendTicker.toUpperCase() ==
|
||||||
|
tuple.item2.ticker.toUpperCase()) {
|
||||||
_refundController.text = ref
|
_refundController.text = ref
|
||||||
.read(pWallets)
|
.read(pWallets)
|
||||||
.getWallet(tuple.item1)
|
.getWallet(tuple.item1)
|
||||||
|
@ -341,8 +358,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
style: STextStyles.field(context),
|
style: STextStyles.field(context),
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty &&
|
_next(),
|
||||||
_refundController.text.isNotEmpty,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
decoration: standardInputDecoration(
|
decoration: standardInputDecoration(
|
||||||
|
@ -376,8 +392,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
.read(desktopExchangeModelProvider)!
|
.read(desktopExchangeModelProvider)!
|
||||||
.recipientAddress = _toController.text;
|
.recipientAddress = _toController.text;
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty &&
|
_next(),
|
||||||
_refundController.text.isNotEmpty,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: const XIcon(),
|
child: const XIcon(),
|
||||||
|
@ -397,8 +412,7 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
.read(desktopExchangeModelProvider)!
|
.read(desktopExchangeModelProvider)!
|
||||||
.recipientAddress = _toController.text;
|
.recipientAddress = _toController.text;
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty &&
|
_next(),
|
||||||
_refundController.text.isNotEmpty,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -435,155 +449,158 @@ class _DesktopStep2State extends ConsumerState<DesktopStep2> {
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
if (doesRefundAddress)
|
||||||
height: 24,
|
const SizedBox(
|
||||||
),
|
height: 24,
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Refund Wallet (required)",
|
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.extension<StackColors>()!
|
|
||||||
.textFieldActiveSearchIconRight,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (AppConfig.isStackCoin(
|
|
||||||
ref.watch(
|
|
||||||
desktopExchangeModelProvider
|
|
||||||
.select((value) => value!.sendTicker),
|
|
||||||
),
|
|
||||||
))
|
|
||||||
CustomTextButton(
|
|
||||||
text: "Choose from Stack",
|
|
||||||
onTap: selectRefundAddressFromStack,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
Constants.size.circularBorderRadius,
|
|
||||||
),
|
),
|
||||||
child: TextField(
|
if (doesRefundAddress)
|
||||||
key: const Key("refundExchangeStep2ViewAddressFieldKey"),
|
Row(
|
||||||
controller: _refundController,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
readOnly: false,
|
children: [
|
||||||
autocorrect: false,
|
Text(
|
||||||
enableSuggestions: false,
|
"Refund Wallet (required)",
|
||||||
// inputFormatters: <TextInputFormatter>[
|
style: STextStyles.desktopTextExtraExtraSmall(context).copyWith(
|
||||||
// FilteringTextInputFormatter.allow(RegExp("[a-zA-Z0-9]{34}")),
|
color: Theme.of(context)
|
||||||
// ],
|
.extension<StackColors>()!
|
||||||
toolbarOptions: const ToolbarOptions(
|
.textFieldActiveSearchIconRight,
|
||||||
copy: false,
|
),
|
||||||
cut: false,
|
|
||||||
paste: true,
|
|
||||||
selectAll: false,
|
|
||||||
),
|
|
||||||
focusNode: _refundFocusNode,
|
|
||||||
style: STextStyles.field(context),
|
|
||||||
onChanged: (value) {
|
|
||||||
widget.enableNextChanged.call(
|
|
||||||
_toController.text.isNotEmpty &&
|
|
||||||
_refundController.text.isNotEmpty,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
decoration: standardInputDecoration(
|
|
||||||
"Enter ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} refund address",
|
|
||||||
_refundFocusNode,
|
|
||||||
context,
|
|
||||||
desktopMed: true,
|
|
||||||
).copyWith(
|
|
||||||
contentPadding: const EdgeInsets.only(
|
|
||||||
left: 16,
|
|
||||||
top: 6,
|
|
||||||
bottom: 8,
|
|
||||||
right: 5,
|
|
||||||
),
|
),
|
||||||
suffixIcon: Padding(
|
if (AppConfig.isStackCoin(
|
||||||
padding: _refundController.text.isEmpty
|
ref.watch(
|
||||||
? const EdgeInsets.only(right: 16)
|
desktopExchangeModelProvider
|
||||||
: const EdgeInsets.only(right: 0),
|
.select((value) => value!.sendTicker),
|
||||||
child: UnconstrainedBox(
|
),
|
||||||
child: Row(
|
))
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
CustomTextButton(
|
||||||
children: [
|
text: "Choose from Stack",
|
||||||
_refundController.text.isNotEmpty
|
onTap: selectRefundAddressFromStack,
|
||||||
? TextFieldIconButton(
|
),
|
||||||
key: const Key(
|
],
|
||||||
"sendViewClearAddressFieldButtonKey",
|
),
|
||||||
),
|
if (doesRefundAddress)
|
||||||
onTap: () {
|
const SizedBox(
|
||||||
_refundController.text = "";
|
height: 10,
|
||||||
ref
|
),
|
||||||
.read(desktopExchangeModelProvider)!
|
if (doesRefundAddress)
|
||||||
.refundAddress = _refundController.text;
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
widget.enableNextChanged.call(
|
Constants.size.circularBorderRadius,
|
||||||
_toController.text.isNotEmpty &&
|
),
|
||||||
_refundController.text.isNotEmpty,
|
child: TextField(
|
||||||
);
|
key: const Key("refundExchangeStep2ViewAddressFieldKey"),
|
||||||
},
|
controller: _refundController,
|
||||||
child: const XIcon(),
|
readOnly: false,
|
||||||
)
|
autocorrect: false,
|
||||||
: TextFieldIconButton(
|
enableSuggestions: false,
|
||||||
key: const Key(
|
// inputFormatters: <TextInputFormatter>[
|
||||||
"sendViewPasteAddressFieldButtonKey",
|
// FilteringTextInputFormatter.allow(RegExp("[a-zA-Z0-9]{34}")),
|
||||||
),
|
// ],
|
||||||
onTap: () async {
|
toolbarOptions: const ToolbarOptions(
|
||||||
final ClipboardData? data = await clipboard
|
copy: false,
|
||||||
.getData(Clipboard.kTextPlain);
|
cut: false,
|
||||||
if (data?.text != null &&
|
paste: true,
|
||||||
data!.text!.isNotEmpty) {
|
selectAll: false,
|
||||||
final content = data.text!.trim();
|
),
|
||||||
|
focusNode: _refundFocusNode,
|
||||||
_refundController.text = content;
|
style: STextStyles.field(context),
|
||||||
|
onChanged: (value) {
|
||||||
|
widget.enableNextChanged.call(
|
||||||
|
_next(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
decoration: standardInputDecoration(
|
||||||
|
"Enter ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} refund address",
|
||||||
|
_refundFocusNode,
|
||||||
|
context,
|
||||||
|
desktopMed: true,
|
||||||
|
).copyWith(
|
||||||
|
contentPadding: const EdgeInsets.only(
|
||||||
|
left: 16,
|
||||||
|
top: 6,
|
||||||
|
bottom: 8,
|
||||||
|
right: 5,
|
||||||
|
),
|
||||||
|
suffixIcon: Padding(
|
||||||
|
padding: _refundController.text.isEmpty
|
||||||
|
? const EdgeInsets.only(right: 16)
|
||||||
|
: const EdgeInsets.only(right: 0),
|
||||||
|
child: UnconstrainedBox(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
_refundController.text.isNotEmpty
|
||||||
|
? TextFieldIconButton(
|
||||||
|
key: const Key(
|
||||||
|
"sendViewClearAddressFieldButtonKey",
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
_refundController.text = "";
|
||||||
ref
|
ref
|
||||||
.read(desktopExchangeModelProvider)!
|
.read(desktopExchangeModelProvider)!
|
||||||
.refundAddress = _refundController.text;
|
.refundAddress = _refundController.text;
|
||||||
|
|
||||||
widget.enableNextChanged.call(
|
widget.enableNextChanged.call(
|
||||||
_toController.text.isNotEmpty &&
|
_next(),
|
||||||
_refundController.text.isNotEmpty,
|
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
},
|
child: const XIcon(),
|
||||||
child: _refundController.text.isEmpty
|
)
|
||||||
? const ClipboardIcon()
|
: TextFieldIconButton(
|
||||||
: const XIcon(),
|
key: const Key(
|
||||||
),
|
"sendViewPasteAddressFieldButtonKey",
|
||||||
if (_refundController.text.isEmpty &&
|
),
|
||||||
AppConfig.isStackCoin(
|
onTap: () async {
|
||||||
ref.watch(
|
final ClipboardData? data = await clipboard
|
||||||
desktopExchangeModelProvider
|
.getData(Clipboard.kTextPlain);
|
||||||
.select((value) => value!.sendTicker),
|
if (data?.text != null &&
|
||||||
),
|
data!.text!.isNotEmpty) {
|
||||||
))
|
final content = data.text!.trim();
|
||||||
TextFieldIconButton(
|
|
||||||
key: const Key("sendViewAddressBookButtonKey"),
|
_refundController.text = content;
|
||||||
onTap: selectRefundFromAddressBook,
|
ref
|
||||||
child: const AddressBookIcon(),
|
.read(desktopExchangeModelProvider)!
|
||||||
),
|
.refundAddress = _refundController.text;
|
||||||
],
|
|
||||||
|
widget.enableNextChanged.call(
|
||||||
|
_next(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: _refundController.text.isEmpty
|
||||||
|
? const ClipboardIcon()
|
||||||
|
: const XIcon(),
|
||||||
|
),
|
||||||
|
if (_refundController.text.isEmpty &&
|
||||||
|
AppConfig.isStackCoin(
|
||||||
|
ref.watch(
|
||||||
|
desktopExchangeModelProvider
|
||||||
|
.select((value) => value!.sendTicker),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
TextFieldIconButton(
|
||||||
|
key: const Key("sendViewAddressBookButtonKey"),
|
||||||
|
onTap: selectRefundFromAddressBook,
|
||||||
|
child: const AddressBookIcon(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (doesRefundAddress)
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
),
|
),
|
||||||
RoundedWhiteContainer(
|
if (doesRefundAddress)
|
||||||
borderColor: Theme.of(context).extension<StackColors>()!.background,
|
RoundedWhiteContainer(
|
||||||
child: Text(
|
borderColor: Theme.of(context).extension<StackColors>()!.background,
|
||||||
"In case something goes wrong during the exchange, we might need a refund address so we can return your coins back to you.",
|
child: Text(
|
||||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
"In case something goes wrong during the exchange, we might need a refund address so we can return your coins back to you.",
|
||||||
|
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,14 @@
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import '../step_scaffold.dart';
|
|
||||||
import 'desktop_step_item.dart';
|
|
||||||
import '../../../../providers/providers.dart';
|
import '../../../../providers/providers.dart';
|
||||||
import '../../../../themes/stack_colors.dart';
|
import '../../../../themes/stack_colors.dart';
|
||||||
import '../../../../utilities/enums/exchange_rate_type_enum.dart';
|
import '../../../../utilities/enums/exchange_rate_type_enum.dart';
|
||||||
import '../../../../utilities/text_styles.dart';
|
import '../../../../utilities/text_styles.dart';
|
||||||
import '../../../../widgets/rounded_white_container.dart';
|
import '../../../../widgets/rounded_white_container.dart';
|
||||||
|
import '../step_scaffold.dart';
|
||||||
|
import 'desktop_step_item.dart';
|
||||||
|
|
||||||
class DesktopStep3 extends ConsumerStatefulWidget {
|
class DesktopStep3 extends ConsumerStatefulWidget {
|
||||||
const DesktopStep3({
|
const DesktopStep3({
|
||||||
|
@ -97,20 +98,22 @@ class _DesktopStep3State extends ConsumerState<DesktopStep3> {
|
||||||
) ??
|
) ??
|
||||||
"Error",
|
"Error",
|
||||||
),
|
),
|
||||||
Container(
|
if (ref.watch(efExchangeProvider).supportsRefundAddress)
|
||||||
height: 1,
|
Container(
|
||||||
color: Theme.of(context).extension<StackColors>()!.background,
|
height: 1,
|
||||||
),
|
color: Theme.of(context).extension<StackColors>()!.background,
|
||||||
DesktopStepItem(
|
),
|
||||||
vertical: true,
|
if (ref.watch(efExchangeProvider).supportsRefundAddress)
|
||||||
label:
|
DesktopStepItem(
|
||||||
"Refund ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} address",
|
vertical: true,
|
||||||
value: ref.watch(
|
label:
|
||||||
desktopExchangeModelProvider
|
"Refund ${ref.watch(desktopExchangeModelProvider.select((value) => value!.sendTicker.toUpperCase()))} address",
|
||||||
.select((value) => value!.refundAddress),
|
value: ref.watch(
|
||||||
) ??
|
desktopExchangeModelProvider
|
||||||
"Error",
|
.select((value) => value!.refundAddress),
|
||||||
),
|
) ??
|
||||||
|
"Error",
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'package:decimal/decimal.dart';
|
import 'package:decimal/decimal.dart';
|
||||||
|
|
||||||
import '../../models/exchange/response_objects/estimate.dart';
|
import '../../models/exchange/response_objects/estimate.dart';
|
||||||
import '../../models/exchange/response_objects/range.dart';
|
import '../../models/exchange/response_objects/range.dart';
|
||||||
import '../../models/exchange/response_objects/trade.dart';
|
import '../../models/exchange/response_objects/trade.dart';
|
||||||
|
@ -17,6 +18,7 @@ import '../../models/isar/exchange_cache/pair.dart';
|
||||||
import 'change_now/change_now_exchange.dart';
|
import 'change_now/change_now_exchange.dart';
|
||||||
import 'exchange_response.dart';
|
import 'exchange_response.dart';
|
||||||
import 'majestic_bank/majestic_bank_exchange.dart';
|
import 'majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import 'nanswap/nanswap_exchange.dart';
|
||||||
import 'simpleswap/simpleswap_exchange.dart';
|
import 'simpleswap/simpleswap_exchange.dart';
|
||||||
import 'trocador/trocador_exchange.dart';
|
import 'trocador/trocador_exchange.dart';
|
||||||
|
|
||||||
|
@ -33,6 +35,8 @@ abstract class Exchange {
|
||||||
return MajesticBankExchange.instance;
|
return MajesticBankExchange.instance;
|
||||||
case TrocadorExchange.exchangeName:
|
case TrocadorExchange.exchangeName:
|
||||||
return TrocadorExchange.instance;
|
return TrocadorExchange.instance;
|
||||||
|
case NanswapExchange.exchangeName:
|
||||||
|
return NanswapExchange.instance;
|
||||||
default:
|
default:
|
||||||
final split = name.split(" ");
|
final split = name.split(" ");
|
||||||
if (split.length >= 2) {
|
if (split.length >= 2) {
|
||||||
|
@ -45,6 +49,8 @@ abstract class Exchange {
|
||||||
|
|
||||||
String get name;
|
String get name;
|
||||||
|
|
||||||
|
bool get supportsRefundAddress => true;
|
||||||
|
|
||||||
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(bool fixedRate);
|
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(bool fixedRate);
|
||||||
|
|
||||||
Future<ExchangeResponse<List<Currency>>> getPairedCurrencies(
|
Future<ExchangeResponse<List<Currency>>> getPairedCurrencies(
|
||||||
|
@ -97,6 +103,7 @@ abstract class Exchange {
|
||||||
static List<Exchange> get exchangesWithTorSupport => [
|
static List<Exchange> get exchangesWithTorSupport => [
|
||||||
MajesticBankExchange.instance,
|
MajesticBankExchange.instance,
|
||||||
TrocadorExchange.instance,
|
TrocadorExchange.instance,
|
||||||
|
NanswapExchange.instance, // Maybe??
|
||||||
];
|
];
|
||||||
|
|
||||||
/// List of exchange names which support Tor.
|
/// List of exchange names which support Tor.
|
||||||
|
|
|
@ -23,6 +23,7 @@ import '../../utilities/prefs.dart';
|
||||||
import '../../utilities/stack_file_system.dart';
|
import '../../utilities/stack_file_system.dart';
|
||||||
import 'change_now/change_now_exchange.dart';
|
import 'change_now/change_now_exchange.dart';
|
||||||
import 'majestic_bank/majestic_bank_exchange.dart';
|
import 'majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import 'nanswap/nanswap_exchange.dart';
|
||||||
import 'trocador/trocador_exchange.dart';
|
import 'trocador/trocador_exchange.dart';
|
||||||
|
|
||||||
class ExchangeDataLoadingService {
|
class ExchangeDataLoadingService {
|
||||||
|
@ -170,6 +171,7 @@ class ExchangeDataLoadingService {
|
||||||
final futures = [
|
final futures = [
|
||||||
loadMajesticBankCurrencies(),
|
loadMajesticBankCurrencies(),
|
||||||
loadTrocadorCurrencies(),
|
loadTrocadorCurrencies(),
|
||||||
|
loadNanswapCurrencies(),
|
||||||
];
|
];
|
||||||
|
|
||||||
// If using Tor, don't load data for exchanges which don't support Tor.
|
// If using Tor, don't load data for exchanges which don't support Tor.
|
||||||
|
@ -382,6 +384,31 @@ class ExchangeDataLoadingService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> loadNanswapCurrencies() async {
|
||||||
|
if (_isar == null) {
|
||||||
|
await initDB();
|
||||||
|
}
|
||||||
|
final responseCurrencies =
|
||||||
|
await NanswapExchange.instance.getAllCurrencies(false);
|
||||||
|
|
||||||
|
if (responseCurrencies.value != null) {
|
||||||
|
await isar.writeTxn(() async {
|
||||||
|
final idsToDelete = await isar.currencies
|
||||||
|
.where()
|
||||||
|
.exchangeNameEqualTo(NanswapExchange.exchangeName)
|
||||||
|
.idProperty()
|
||||||
|
.findAll();
|
||||||
|
await isar.currencies.deleteAll(idsToDelete);
|
||||||
|
await isar.currencies.putAll(responseCurrencies.value!);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Logging.instance.log(
|
||||||
|
"loadNanswapCurrencies: $responseCurrencies",
|
||||||
|
level: LogLevel.Warning,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Future<void> loadMajesticBankPairs() async {
|
// Future<void> loadMajesticBankPairs() async {
|
||||||
// final exchange = MajesticBankExchange.instance;
|
// final exchange = MajesticBankExchange.instance;
|
||||||
//
|
//
|
||||||
|
|
|
@ -46,6 +46,9 @@ class MajesticBankExchange extends Exchange {
|
||||||
"XMR": "Monero",
|
"XMR": "Monero",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get supportsRefundAddress => false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ExchangeResponse<Trade>> createTrade({
|
Future<ExchangeResponse<Trade>> createTrade({
|
||||||
required String from,
|
required String from,
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
class NCurrency {
|
||||||
|
final String id;
|
||||||
|
final String ticker;
|
||||||
|
final String name;
|
||||||
|
final String image;
|
||||||
|
final String network;
|
||||||
|
final bool hasExternalId;
|
||||||
|
final bool feeLess;
|
||||||
|
|
||||||
|
NCurrency({
|
||||||
|
required this.id,
|
||||||
|
required this.ticker,
|
||||||
|
required this.name,
|
||||||
|
required this.image,
|
||||||
|
required this.network,
|
||||||
|
required this.hasExternalId,
|
||||||
|
required this.feeLess,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory NCurrency.fromJson(Map<String, dynamic> json) {
|
||||||
|
return NCurrency(
|
||||||
|
id: json["id"] as String,
|
||||||
|
ticker: json['ticker'] as String,
|
||||||
|
name: json['name'] as String,
|
||||||
|
image: json['image'] as String,
|
||||||
|
network: json['network'] as String,
|
||||||
|
hasExternalId: json['hasExternalId'] as bool,
|
||||||
|
feeLess: json['feeless'] as bool,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'NCurrency {'
|
||||||
|
'ticker: $ticker, '
|
||||||
|
'name: $name, '
|
||||||
|
'image: $image, '
|
||||||
|
'network: $network, '
|
||||||
|
'hasExternalId: $hasExternalId, '
|
||||||
|
'feeless: $feeLess'
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
class NEstimate {
|
||||||
|
final String from;
|
||||||
|
final String to;
|
||||||
|
final num amountFrom;
|
||||||
|
final num amountTo;
|
||||||
|
|
||||||
|
NEstimate({
|
||||||
|
required this.from,
|
||||||
|
required this.to,
|
||||||
|
required this.amountFrom,
|
||||||
|
required this.amountTo,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory NEstimate.fromJson(Map<String, dynamic> json) {
|
||||||
|
return NEstimate(
|
||||||
|
from: json['from'] as String,
|
||||||
|
to: json['to'] as String,
|
||||||
|
amountFrom: json['amountFrom'] as num,
|
||||||
|
amountTo: json['amountTo'] as num,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'NEstimate {'
|
||||||
|
'from: $from, '
|
||||||
|
'to: $to, '
|
||||||
|
'amountFrom: $amountFrom, '
|
||||||
|
'amountTo: $amountTo '
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
class NTrade {
|
||||||
|
final String id;
|
||||||
|
final String from;
|
||||||
|
final String to;
|
||||||
|
final num expectedAmountFrom;
|
||||||
|
final num expectedAmountTo;
|
||||||
|
final String payinAddress;
|
||||||
|
final String payoutAddress;
|
||||||
|
|
||||||
|
final String? payinExtraId;
|
||||||
|
final String? fullLink;
|
||||||
|
final String? status;
|
||||||
|
final String? payinHash;
|
||||||
|
final String? payoutHash;
|
||||||
|
final num? fromAmount;
|
||||||
|
final num? toAmount;
|
||||||
|
final String? fromNetwork;
|
||||||
|
final String? toNetwork;
|
||||||
|
|
||||||
|
NTrade({
|
||||||
|
required this.id,
|
||||||
|
required this.from,
|
||||||
|
required this.to,
|
||||||
|
required this.expectedAmountFrom,
|
||||||
|
required this.expectedAmountTo,
|
||||||
|
required this.payinAddress,
|
||||||
|
required this.payoutAddress,
|
||||||
|
this.payinExtraId,
|
||||||
|
this.fullLink,
|
||||||
|
this.status,
|
||||||
|
this.payinHash,
|
||||||
|
this.payoutHash,
|
||||||
|
this.fromAmount,
|
||||||
|
this.toAmount,
|
||||||
|
this.fromNetwork,
|
||||||
|
this.toNetwork,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory NTrade.fromJson(Map<String, dynamic> json) {
|
||||||
|
return NTrade(
|
||||||
|
id: json['id'] as String,
|
||||||
|
from: json['from'] as String,
|
||||||
|
to: json['to'] as String,
|
||||||
|
expectedAmountFrom: num.parse(json['expectedAmountFrom'].toString()),
|
||||||
|
expectedAmountTo: json['expectedAmountTo'] as num,
|
||||||
|
payinAddress: json['payinAddress'] as String,
|
||||||
|
payoutAddress: json['payoutAddress'] as String,
|
||||||
|
fullLink: json['fullLink'] as String?,
|
||||||
|
payinExtraId: json['payinExtraId'] as String?,
|
||||||
|
status: json['status'] as String?,
|
||||||
|
payinHash: json['payinHash'] as String?,
|
||||||
|
payoutHash: json['payoutHash'] as String?,
|
||||||
|
fromAmount: json['fromAmount'] as num?,
|
||||||
|
toAmount: json['toAmount'] as num?,
|
||||||
|
fromNetwork: json['fromNetwork'] as String?,
|
||||||
|
toNetwork: json['toNetwork'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'NTrade {'
|
||||||
|
' id: $id, '
|
||||||
|
' from: $from, '
|
||||||
|
' to: $to, '
|
||||||
|
' expectedAmountFrom: $expectedAmountFrom, '
|
||||||
|
' expectedAmountTo: $expectedAmountTo, '
|
||||||
|
' payinAddress: $payinAddress, '
|
||||||
|
' payoutAddress: $payoutAddress, '
|
||||||
|
' fullLink: $fullLink, '
|
||||||
|
' payinExtraId: $payinExtraId, '
|
||||||
|
' status: $status, '
|
||||||
|
' payinHash: $payinHash, '
|
||||||
|
' payoutHash: $payoutHash '
|
||||||
|
' fromAmount: $fromAmount, '
|
||||||
|
' toAmount: $toAmount, '
|
||||||
|
' fromNetwork: $fromNetwork, '
|
||||||
|
' toNetwork: $toNetwork, '
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
517
lib/services/exchange/nanswap/nanswap_api.dart
Normal file
517
lib/services/exchange/nanswap/nanswap_api.dart
Normal file
|
@ -0,0 +1,517 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
import '../../../exceptions/exchange/exchange_exception.dart';
|
||||||
|
import '../../../external_api_keys.dart';
|
||||||
|
import '../../../networking/http.dart';
|
||||||
|
import '../../../utilities/logger.dart';
|
||||||
|
import '../../../utilities/prefs.dart';
|
||||||
|
import '../../tor_service.dart';
|
||||||
|
import '../exchange_response.dart';
|
||||||
|
import 'api_response_models/n_currency.dart';
|
||||||
|
import 'api_response_models/n_estimate.dart';
|
||||||
|
import 'api_response_models/n_trade.dart';
|
||||||
|
|
||||||
|
class NanswapAPI {
|
||||||
|
NanswapAPI._();
|
||||||
|
|
||||||
|
static const authority = "api.nanswap.com";
|
||||||
|
static const version = "v1";
|
||||||
|
|
||||||
|
static NanswapAPI? _instance;
|
||||||
|
static NanswapAPI get instance => _instance ??= NanswapAPI._();
|
||||||
|
|
||||||
|
final _client = HTTP();
|
||||||
|
|
||||||
|
Uri _buildUri({required String endpoint, Map<String, String>? params}) {
|
||||||
|
return Uri.https(authority, "/$version/$endpoint", params);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> _makeGetRequest(Uri uri) async {
|
||||||
|
int code = -1;
|
||||||
|
try {
|
||||||
|
final response = await _client.get(
|
||||||
|
url: uri,
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
proxyInfo: Prefs.instance.useTor
|
||||||
|
? TorService.sharedInstance.getProxyInfo()
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
code = response.code;
|
||||||
|
|
||||||
|
final parsed = jsonDecode(response.body);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"NanswapAPI._makeRequest($uri) HTTP:$code threw: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<dynamic> _makePostRequest(
|
||||||
|
Uri uri,
|
||||||
|
Map<String, dynamic> body,
|
||||||
|
) async {
|
||||||
|
int code = -1;
|
||||||
|
try {
|
||||||
|
final response = await _client.post(
|
||||||
|
url: uri,
|
||||||
|
headers: {
|
||||||
|
'nanswap-api-key': kNanswapApiKey,
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Accept': 'application/json',
|
||||||
|
},
|
||||||
|
body: jsonEncode(body),
|
||||||
|
proxyInfo: Prefs.instance.useTor
|
||||||
|
? TorService.sharedInstance.getProxyInfo()
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
code = response.code;
|
||||||
|
|
||||||
|
final data = response.body;
|
||||||
|
final parsed = jsonDecode(data);
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"NanswapAPI._makePostRequest($uri) HTTP:$code threw: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============= API ===================================================
|
||||||
|
|
||||||
|
// GET List of supported currencies
|
||||||
|
// https://api.nanswap.com/v1/all-currencies
|
||||||
|
//
|
||||||
|
// Returns a Key => Value map of available currencies.
|
||||||
|
//
|
||||||
|
// The Key is the ticker, that can be used in the from and to params of the /get-estimate, /get-limit, /create-order.
|
||||||
|
//
|
||||||
|
// The Value is the currency info:
|
||||||
|
//
|
||||||
|
// name
|
||||||
|
//
|
||||||
|
// logo
|
||||||
|
//
|
||||||
|
// network Network of the crypto.
|
||||||
|
//
|
||||||
|
// hasExternalId Boolean. If the crypto require a memo/id.
|
||||||
|
//
|
||||||
|
// feeless Boolean. If crypto has 0 network fees.
|
||||||
|
//
|
||||||
|
// HEADERS
|
||||||
|
// Accept
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
Future<ExchangeResponse<List<NCurrency>>> getSupportedCurrencies() async {
|
||||||
|
final uri = _buildUri(
|
||||||
|
endpoint: "all-currencies",
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final json = await _makeGetRequest(uri);
|
||||||
|
|
||||||
|
final List<NCurrency> result = [];
|
||||||
|
for (final key in (json as Map).keys) {
|
||||||
|
final _map = json[key] as Map;
|
||||||
|
_map["id"] = key;
|
||||||
|
result.add(
|
||||||
|
NCurrency.fromJson(
|
||||||
|
Map<String, dynamic>.from(_map),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExchangeResponse(value: result);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.getSupportedCurrencies() exception: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET Get estimate
|
||||||
|
// https://api.nanswap.com/v1/get-estimate?from=XNO&to=BAN&amount=10
|
||||||
|
//
|
||||||
|
// Get estimated exchange amount.
|
||||||
|
// HEADERS
|
||||||
|
// Accept
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
// PARAMS
|
||||||
|
//
|
||||||
|
// from
|
||||||
|
// XNO
|
||||||
|
// Ticker from
|
||||||
|
//
|
||||||
|
// to
|
||||||
|
// BAN
|
||||||
|
// Ticker to
|
||||||
|
//
|
||||||
|
// amount
|
||||||
|
// 10
|
||||||
|
// Amount from
|
||||||
|
Future<ExchangeResponse<NEstimate>> getEstimate({
|
||||||
|
required String amountFrom,
|
||||||
|
required String from,
|
||||||
|
required String to,
|
||||||
|
}) async {
|
||||||
|
final uri = _buildUri(
|
||||||
|
endpoint: "get-estimate",
|
||||||
|
params: {
|
||||||
|
"to": to.toUpperCase(),
|
||||||
|
"from": from.toUpperCase(),
|
||||||
|
"amount": amountFrom,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final json = await _makeGetRequest(uri);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final map = Map<String, dynamic>.from(json as Map);
|
||||||
|
|
||||||
|
// not sure why the api responds without these sometimes...
|
||||||
|
map["to"] ??= to.toUpperCase();
|
||||||
|
map["from"] ??= from.toUpperCase();
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: NEstimate.fromJson(
|
||||||
|
map,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.getEstimate() response was: $json",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.getEstimate() exception: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET Get estimate reverse
|
||||||
|
// https://api.nanswap.com/v1/get-estimate-reverse?from=XNO&to=BAN&amount=1650
|
||||||
|
//
|
||||||
|
// (Only available for feeless crypto)
|
||||||
|
//
|
||||||
|
// Get estimate but reversed, it takes toAmount and returns the fromAmount
|
||||||
|
// estimation. Allows to let user input directly their toAmount wanted.
|
||||||
|
// HEADERS
|
||||||
|
// Accept
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
// PARAMS
|
||||||
|
// from
|
||||||
|
// XNO
|
||||||
|
// Ticker from
|
||||||
|
//
|
||||||
|
// to
|
||||||
|
// BAN
|
||||||
|
// Ticker to
|
||||||
|
//
|
||||||
|
// amount
|
||||||
|
// 1650
|
||||||
|
// Amount to
|
||||||
|
Future<ExchangeResponse<NEstimate>> getEstimateReversed({
|
||||||
|
required String amountTo,
|
||||||
|
required String from,
|
||||||
|
required String to,
|
||||||
|
}) async {
|
||||||
|
final uri = _buildUri(
|
||||||
|
endpoint: "get-estimate-reverse",
|
||||||
|
params: {
|
||||||
|
"to": to.toUpperCase(),
|
||||||
|
"from": from.toUpperCase(),
|
||||||
|
"amount": amountTo,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final json = await _makeGetRequest(uri);
|
||||||
|
|
||||||
|
final map = Map<String, dynamic>.from(json as Map);
|
||||||
|
|
||||||
|
// not sure why the api responds without these sometimes...
|
||||||
|
map["to"] ??= to.toUpperCase();
|
||||||
|
map["from"] ??= from.toUpperCase();
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: NEstimate.fromJson(
|
||||||
|
map,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.getEstimateReverse() exception: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET Get order limit amount
|
||||||
|
// https://api.nanswap.com/v1/get-limits?from=XNO&to=BAN
|
||||||
|
//
|
||||||
|
// Returns minimum and maximum from amount for a given pair. Maximum amount depends of current liquidity.
|
||||||
|
// HEADERS
|
||||||
|
// Accept
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
// PARAMS
|
||||||
|
// from
|
||||||
|
// XNO
|
||||||
|
// Ticker from
|
||||||
|
//
|
||||||
|
// to
|
||||||
|
// BAN
|
||||||
|
// Ticker to
|
||||||
|
Future<ExchangeResponse<({num minFrom, num maxFrom})>> getOrderLimits({
|
||||||
|
required String from,
|
||||||
|
required String to,
|
||||||
|
}) async {
|
||||||
|
final uri = _buildUri(
|
||||||
|
endpoint: "get-limits",
|
||||||
|
params: {
|
||||||
|
"to": to.toUpperCase(),
|
||||||
|
"from": from.toUpperCase(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final json = await _makeGetRequest(uri);
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: (
|
||||||
|
minFrom: json["min"] as num,
|
||||||
|
maxFrom: json["max"] as num,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.getOrderLimits() exception: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST Create a new order
|
||||||
|
// https://api.nanswap.com/v1/create-order
|
||||||
|
//
|
||||||
|
// Create a new order and returns order data. You need to send the request body as JSON.
|
||||||
|
// A valid API key is required in nanswap-api-key header for this request.
|
||||||
|
// You can get one at https://nanswap.com/API
|
||||||
|
// Request:
|
||||||
|
//
|
||||||
|
// * from ticker of currency you want to exchange
|
||||||
|
// * to ticker of currency you want to receive
|
||||||
|
// * amount The amount you want to send
|
||||||
|
// * toAddress The address that will recieve the exchanged funds
|
||||||
|
// * extraId (optional) Memo/Id of the toAddress
|
||||||
|
//
|
||||||
|
// * itemName (optional) An item name that will be displayed on transaction
|
||||||
|
// page. Can be used by merchant to provide a better UX to users. Max 128 char.
|
||||||
|
// * maxDurationSeconds (optional) Maximum seconds after what transaction
|
||||||
|
// expires. Min: 30s Max: 259200s. Default to 72h or 5min if itemName is set
|
||||||
|
// Reponse:
|
||||||
|
//
|
||||||
|
// * id Order id.
|
||||||
|
// * from ticker of currency you want to exchange
|
||||||
|
// * to ticker of currency you want to receive
|
||||||
|
// * expectedAmountFrom The amount you want to send
|
||||||
|
// * expectedAmountTo Estimated value that you will get based on the field expectedAmountFrom
|
||||||
|
// * payinAddress Nanswap's address you need to send the funds to
|
||||||
|
// * payinExtraId If present, the extra/memo id required for the payinAddress
|
||||||
|
// * payoutAddress The address that will recieve the exchanged funds
|
||||||
|
// * fullLink URL of the transaction
|
||||||
|
// AUTHORIZATIONAPI Key
|
||||||
|
// Key
|
||||||
|
//
|
||||||
|
// nanswap-api-key
|
||||||
|
// Value
|
||||||
|
//
|
||||||
|
// <value>
|
||||||
|
// HEADERS
|
||||||
|
// nanswap-api-key
|
||||||
|
//
|
||||||
|
// API_KEY
|
||||||
|
//
|
||||||
|
// (Required)
|
||||||
|
// Content-Type
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
// Accept
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
Future<ExchangeResponse<NTrade>> createOrder({
|
||||||
|
required String from,
|
||||||
|
required String to,
|
||||||
|
required num fromAmount,
|
||||||
|
required String toAddress,
|
||||||
|
String? extraIdOrMemo,
|
||||||
|
}) async {
|
||||||
|
final uri = _buildUri(
|
||||||
|
endpoint: "create-order",
|
||||||
|
);
|
||||||
|
|
||||||
|
final body = {
|
||||||
|
"from": from.toUpperCase(),
|
||||||
|
"to": to.toUpperCase(),
|
||||||
|
"amount": fromAmount,
|
||||||
|
"toAddress": toAddress,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extraIdOrMemo != null) {
|
||||||
|
body["extraId"] = extraIdOrMemo;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final json = await _makePostRequest(uri, body);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: NTrade.fromJson(
|
||||||
|
Map<String, dynamic>.from(json as Map),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
debugPrint(json.toString());
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.createOrder() exception: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET Get order id data
|
||||||
|
// https://api.nanswap.com/v1/get-order?id=zYkxDxfmYRM
|
||||||
|
//
|
||||||
|
// Returns data of an order id.
|
||||||
|
// Response:
|
||||||
|
//
|
||||||
|
// id Order id.
|
||||||
|
//
|
||||||
|
// status Order status, can be one of the following : [waiting, exchanging, sending, completed, error]
|
||||||
|
//
|
||||||
|
// from ticker of currency you want to exchange
|
||||||
|
//
|
||||||
|
// fromNetwork network of the currency you want to exchange.
|
||||||
|
//
|
||||||
|
// to ticker of currency you want to receive
|
||||||
|
//
|
||||||
|
// toNetwork network of the currency you want to receive.
|
||||||
|
//
|
||||||
|
// expectedAmountFrom The amount you want to send
|
||||||
|
//
|
||||||
|
// expectedAmountTo Estimated value that you will get based on the field expectedAmountFrom
|
||||||
|
//
|
||||||
|
// amountFrom From Amount Exchanged
|
||||||
|
//
|
||||||
|
// amountTo To Amount Exchanged
|
||||||
|
//
|
||||||
|
// payinAddress Nanswap's address you need to send the funds to
|
||||||
|
//
|
||||||
|
// payinExtraId If present, the extra/memo id required for the payinAddress
|
||||||
|
//
|
||||||
|
// payoutAddress The address that will recieve the exchanged funds
|
||||||
|
//
|
||||||
|
// payinHash Hash of the transaction you sent us
|
||||||
|
//
|
||||||
|
// senderAddress Address which sent us the funds
|
||||||
|
//
|
||||||
|
// payoutHash Hash of the transaction we sent to you
|
||||||
|
//
|
||||||
|
// HEADERS
|
||||||
|
// Accept
|
||||||
|
//
|
||||||
|
// application/json
|
||||||
|
// PARAMS
|
||||||
|
// id
|
||||||
|
//
|
||||||
|
// zYkxDxfmYRM
|
||||||
|
//
|
||||||
|
// The order id
|
||||||
|
Future<ExchangeResponse<NTrade>> getOrder({required String id}) async {
|
||||||
|
final uri = _buildUri(
|
||||||
|
endpoint: "get-order",
|
||||||
|
params: {
|
||||||
|
"id": id,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final json = await _makeGetRequest(uri);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: NTrade.fromJson(
|
||||||
|
Map<String, dynamic>.from(json as Map),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (_) {
|
||||||
|
debugPrint(json.toString());
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Nanswap.getOrder($id) exception: $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
461
lib/services/exchange/nanswap/nanswap_exchange.dart
Normal file
461
lib/services/exchange/nanswap/nanswap_exchange.dart
Normal file
|
@ -0,0 +1,461 @@
|
||||||
|
import 'package:decimal/decimal.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
|
|
||||||
|
import '../../../app_config.dart';
|
||||||
|
import '../../../exceptions/exchange/exchange_exception.dart';
|
||||||
|
import '../../../models/exchange/response_objects/estimate.dart';
|
||||||
|
import '../../../models/exchange/response_objects/range.dart';
|
||||||
|
import '../../../models/exchange/response_objects/trade.dart';
|
||||||
|
import '../../../models/isar/exchange_cache/currency.dart';
|
||||||
|
import '../../../models/isar/exchange_cache/pair.dart';
|
||||||
|
import '../exchange.dart';
|
||||||
|
import '../exchange_response.dart';
|
||||||
|
import 'api_response_models/n_estimate.dart';
|
||||||
|
import 'nanswap_api.dart';
|
||||||
|
|
||||||
|
class NanswapExchange extends Exchange {
|
||||||
|
NanswapExchange._();
|
||||||
|
|
||||||
|
static NanswapExchange? _instance;
|
||||||
|
static NanswapExchange get instance => _instance ??= NanswapExchange._();
|
||||||
|
|
||||||
|
static const exchangeName = "Nanswap";
|
||||||
|
|
||||||
|
static const filter = ["BTC", "BAN", "XNO"];
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get supportsRefundAddress => false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<Trade>> createTrade({
|
||||||
|
required String from,
|
||||||
|
required String to,
|
||||||
|
required bool fixedRate,
|
||||||
|
required Decimal amount,
|
||||||
|
required String addressTo,
|
||||||
|
String? extraId,
|
||||||
|
required String addressRefund,
|
||||||
|
required String refundExtraId,
|
||||||
|
Estimate? estimate,
|
||||||
|
required bool reversed,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
if (fixedRate) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap fixedRate not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (refundExtraId.isNotEmpty) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap refundExtraId not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (addressRefund.isNotEmpty) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap addressRefund not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (reversed) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap reversed not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await NanswapAPI.instance.createOrder(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
fromAmount: amount.toDouble(),
|
||||||
|
toAddress: addressTo,
|
||||||
|
extraIdOrMemo: extraId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final t = response.value!;
|
||||||
|
print(t);
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: Trade(
|
||||||
|
uuid: const Uuid().v1(),
|
||||||
|
tradeId: t.id,
|
||||||
|
rateType: "estimated",
|
||||||
|
direction: "normal",
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
payInCurrency: from,
|
||||||
|
payInAmount: t.expectedAmountFrom.toString(),
|
||||||
|
payInAddress: t.payinAddress,
|
||||||
|
payInNetwork: t.toNetwork ?? t.to,
|
||||||
|
payInExtraId: t.payinExtraId ?? "",
|
||||||
|
payInTxid: t.payinHash ?? "",
|
||||||
|
payOutCurrency: to,
|
||||||
|
payOutAmount: t.expectedAmountTo.toString(),
|
||||||
|
payOutAddress: t.payoutAddress,
|
||||||
|
payOutNetwork: t.fromNetwork ?? t.from,
|
||||||
|
payOutExtraId: "",
|
||||||
|
payOutTxid: t.payoutHash ?? "",
|
||||||
|
refundAddress: "",
|
||||||
|
refundExtraId: "",
|
||||||
|
status: "waiting",
|
||||||
|
exchangeName: exchangeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<List<Currency>>> getAllCurrencies(
|
||||||
|
bool fixedRate,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
if (fixedRate) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap fixedRate not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await NanswapAPI.instance.getSupportedCurrencies();
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: response.value!
|
||||||
|
.where((e) => filter.contains(e.id))
|
||||||
|
.map(
|
||||||
|
(e) => Currency(
|
||||||
|
exchangeName: exchangeName,
|
||||||
|
ticker: e.id,
|
||||||
|
name: e.name,
|
||||||
|
network: e.network,
|
||||||
|
image: e.image,
|
||||||
|
isFiat: false,
|
||||||
|
rateType: SupportedRateType.estimated,
|
||||||
|
isStackCoin: AppConfig.isStackCoin(e.id),
|
||||||
|
tokenContract: null,
|
||||||
|
isAvailable: true,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<List<Pair>>> getAllPairs(bool fixedRate) async {
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<List<Estimate>>> getEstimates(
|
||||||
|
String from,
|
||||||
|
String to,
|
||||||
|
Decimal amount,
|
||||||
|
bool fixedRate,
|
||||||
|
bool reversed,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
if (fixedRate) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap fixedRate not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ExchangeResponse<NEstimate> response;
|
||||||
|
if (reversed) {
|
||||||
|
response = await NanswapAPI.instance.getEstimateReversed(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
amountTo: amount.toString(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
response = await NanswapAPI.instance.getEstimate(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
amountFrom: amount.toString(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final t = response.value!;
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: [
|
||||||
|
Estimate(
|
||||||
|
estimatedAmount: Decimal.parse(
|
||||||
|
(reversed ? t.amountFrom : t.amountTo).toString(),
|
||||||
|
),
|
||||||
|
fixedRate: fixedRate,
|
||||||
|
reversed: reversed,
|
||||||
|
exchangeProvider: exchangeName,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<List<Currency>>> getPairedCurrencies(
|
||||||
|
String forCurrency,
|
||||||
|
bool fixedRate,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
if (fixedRate) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap fixedRate not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await getAllCurrencies(
|
||||||
|
fixedRate,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: response.value!..removeWhere((e) => e.ticker == forCurrency),
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<List<Pair>>> getPairsFor(
|
||||||
|
String currency,
|
||||||
|
bool fixedRate,
|
||||||
|
) async {
|
||||||
|
throw UnsupportedError("Not used");
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<Range>> getRange(
|
||||||
|
String from,
|
||||||
|
String to,
|
||||||
|
bool fixedRate,
|
||||||
|
) async {
|
||||||
|
try {
|
||||||
|
if (fixedRate) {
|
||||||
|
throw ExchangeException(
|
||||||
|
"Nanswap fixedRate not available",
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await NanswapAPI.instance.getOrderLimits(
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final t = response.value!;
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: Range(
|
||||||
|
min: Decimal.parse(t.minFrom.toString()),
|
||||||
|
max: Decimal.parse(t.maxFrom.toString()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<Trade>> getTrade(String tradeId) async {
|
||||||
|
try {
|
||||||
|
final response = await NanswapAPI.instance.getOrder(
|
||||||
|
id: tradeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final t = response.value!;
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: Trade(
|
||||||
|
uuid: const Uuid().v1(),
|
||||||
|
tradeId: t.id,
|
||||||
|
rateType: "estimated",
|
||||||
|
direction: "normal",
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
payInCurrency: t.from,
|
||||||
|
payInAmount: t.expectedAmountFrom.toString(),
|
||||||
|
payInAddress: t.payinAddress,
|
||||||
|
payInNetwork: t.toNetwork ?? t.to,
|
||||||
|
payInExtraId: t.payinExtraId ?? "",
|
||||||
|
payInTxid: t.payinHash ?? "",
|
||||||
|
payOutCurrency: t.to,
|
||||||
|
payOutAmount: t.expectedAmountTo.toString(),
|
||||||
|
payOutAddress: t.payoutAddress,
|
||||||
|
payOutNetwork: t.fromNetwork ?? t.from,
|
||||||
|
payOutExtraId: "",
|
||||||
|
payOutTxid: t.payoutHash ?? "",
|
||||||
|
refundAddress: "",
|
||||||
|
refundExtraId: "",
|
||||||
|
status: t.status ?? "unknown",
|
||||||
|
exchangeName: exchangeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<List<Trade>>> getTrades() async {
|
||||||
|
// TODO: implement getTrades
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => exchangeName;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ExchangeResponse<Trade>> updateTrade(Trade trade) async {
|
||||||
|
try {
|
||||||
|
final response = await NanswapAPI.instance.getOrder(
|
||||||
|
id: trade.tradeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.exception != null) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: response.exception,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final t = response.value!;
|
||||||
|
|
||||||
|
return ExchangeResponse(
|
||||||
|
value: Trade(
|
||||||
|
uuid: trade.uuid,
|
||||||
|
tradeId: t.id,
|
||||||
|
rateType: trade.rateType,
|
||||||
|
direction: trade.rateType,
|
||||||
|
timestamp: trade.timestamp,
|
||||||
|
updatedAt: DateTime.now(),
|
||||||
|
payInCurrency: t.from,
|
||||||
|
payInAmount: t.expectedAmountFrom.toString(),
|
||||||
|
payInAddress: t.payinAddress,
|
||||||
|
payInNetwork: t.toNetwork ?? trade.payInNetwork,
|
||||||
|
payInExtraId: t.payinExtraId ?? trade.payInExtraId,
|
||||||
|
payInTxid: t.payinHash ?? trade.payInTxid,
|
||||||
|
payOutCurrency: t.to,
|
||||||
|
payOutAmount: t.expectedAmountTo.toString(),
|
||||||
|
payOutAddress: t.payoutAddress,
|
||||||
|
payOutNetwork: t.fromNetwork ?? trade.payOutNetwork,
|
||||||
|
payOutExtraId: trade.payOutExtraId,
|
||||||
|
payOutTxid: t.payoutHash ?? trade.payOutTxid,
|
||||||
|
refundAddress: trade.refundAddress,
|
||||||
|
refundExtraId: trade.refundExtraId,
|
||||||
|
status: t.status ?? "unknown",
|
||||||
|
exchangeName: exchangeName,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on ExchangeException catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: e,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return ExchangeResponse(
|
||||||
|
exception: ExchangeException(
|
||||||
|
e.toString(),
|
||||||
|
ExchangeExceptionType.generic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,8 +9,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../services/exchange/change_now/change_now_exchange.dart';
|
import '../services/exchange/change_now/change_now_exchange.dart';
|
||||||
import '../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
import '../services/exchange/majestic_bank/majestic_bank_exchange.dart';
|
||||||
|
import '../services/exchange/nanswap/nanswap_exchange.dart';
|
||||||
import '../services/exchange/simpleswap/simpleswap_exchange.dart';
|
import '../services/exchange/simpleswap/simpleswap_exchange.dart';
|
||||||
import '../services/exchange/trocador/trocador_exchange.dart';
|
import '../services/exchange/trocador/trocador_exchange.dart';
|
||||||
|
|
||||||
|
@ -45,6 +47,7 @@ class _EXCHANGE {
|
||||||
String get majesticBankBlue => "${_path}mb_blue.svg";
|
String get majesticBankBlue => "${_path}mb_blue.svg";
|
||||||
String get majesticBankGreen => "${_path}mb_green.svg";
|
String get majesticBankGreen => "${_path}mb_green.svg";
|
||||||
String get trocador => "${_path}trocador.svg";
|
String get trocador => "${_path}trocador.svg";
|
||||||
|
String get nanswap => "${_path}nanswap.svg";
|
||||||
|
|
||||||
String getIconFor({required String exchangeName}) {
|
String getIconFor({required String exchangeName}) {
|
||||||
switch (exchangeName) {
|
switch (exchangeName) {
|
||||||
|
@ -56,6 +59,8 @@ class _EXCHANGE {
|
||||||
return majesticBankBlue;
|
return majesticBankBlue;
|
||||||
case TrocadorExchange.exchangeName:
|
case TrocadorExchange.exchangeName:
|
||||||
return trocador;
|
return trocador;
|
||||||
|
case NanswapExchange.exchangeName:
|
||||||
|
return nanswap;
|
||||||
default:
|
default:
|
||||||
throw ArgumentError("Invalid exchange name passed to "
|
throw ArgumentError("Invalid exchange name passed to "
|
||||||
"Assets.exchange.getIconFor()");
|
"Assets.exchange.getIconFor()");
|
||||||
|
|
Loading…
Reference in a new issue