Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-492-moonpay
|
@ -0,0 +1,74 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
android:height="108dp"
|
||||
android:width="108dp"
|
||||
android:viewportHeight="108"
|
||||
android:viewportWidth="108"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#3DDC84"
|
||||
android:pathData="M0,0h108v108h-108z"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||
</vector>
|
|
@ -1,7 +1,7 @@
|
|||
[
|
||||
{
|
||||
"question" : "Was ist der Unterschied zwischen verfügbarem Guthaben und vollständigem Guthaben?",
|
||||
"answer" : "Nachdem Sie eine Transaktion getätigt oder Monero erhalten haben, muss die Transaktion noch bestätigt werden. In ungefähr 20 Minuten sollte Ihr \"verfügbares Guthaben\" aktualisiert werden!\nWenn Sie Monero senden, verringert sich manchmal Ihr verfügbares Guthaben um mehr als den Betrag, den Sie gesendet haben. Dies ist normal und zum Schutz Ihrer Privatsphäre erforderlich. Ihr \"vollständiges Gleichgewicht\" sollte in 20 Minuten wieder normal sein.\n"
|
||||
"answer" : "Nachdem Sie eine Transaktion getätigt oder Monero erhalten haben, muss die Transaktion noch bestätigt werden. In ungefähr 20 Minuten sollte Ihr \"verfügbares Guthaben\" aktualisiert werden!\nWenn Sie Monero senden, verringert sich manchmal Ihr verfügbares Guthaben um mehr als den Betrag, den Sie gesendet haben. Dies ist normal und zum Schutz Ihrer Privatsphäre erforderlich. Ihr \"vollständiges Guthaben\" sollte in 20 Minuten wieder normal sein.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Wie sende ich Monero an eine Börse, für die eine Zahlungs-ID erforderlich ist?",
|
||||
|
@ -12,24 +12,24 @@
|
|||
"answer" : "Obwohl unser Support Sie bei diesem Problem nicht direkt unterstützen kann, ist es ein sehr häufiges Problem, mit dem die meisten Börsen vertraut sind. Wenden Sie sich einfach an den Support der Börse, erklären Sie, dass Sie vergessen haben, Ihre Zahlungs-ID anzugeben, und senden Sie ihnen dann Ihre Transaktions-ID als Nachweis. Sie finden die Transaktions-ID, indem Sie auf die Transaktion in Ihrem Wallet-Bildschirm tippen.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Was bedeuten \"Samen\" und \"Schlüssel\"?",
|
||||
"answer" : "Ihre Schlüssel verschlüsseln die privaten Informationen in Ihrer Brieftasche und ermöglichen es Ihnen, Münzen auszugeben und eingehende Transaktionen anzuzeigen.\nIhr Startwert ist nur eine Version Ihres privaten Schlüssels, die so geschrieben wurde, dass Sie sie leichter notieren können. Ihr Same und Schlüssel sind tatsächlich dasselbe, nur in verschiedenen Formen!\nGeben Sie niemals Ihren Samen oder Schlüssel an jemanden weiter. Ihr Geld wird gestohlen, wenn Sie Ihren Samen oder Schlüssel herausgeben. Bitte notieren Sie sich jedoch Ihren Samen und bewahren Sie ihn an einem sicheren Ort auf (so können Sie Ihre Brieftasche wiederherstellen, wenn Sie Ihr Telefon verlieren.)\n"
|
||||
"question" : "Was bedeuten \"Seed\" und \"Schlüssel\"?",
|
||||
"answer" : "Ihre Schlüssel verschlüsseln die privaten Informationen in Ihrer Brieftasche und ermöglichen es Ihnen, Münzen auszugeben und eingehende Transaktionen anzuzeigen.\nIhr Startwert ist nur eine Version Ihres privaten Schlüssels, die so geschrieben wurde, dass Sie sie leichter notieren können. Ihr Same und Schlüssel sind tatsächlich dasselbe, nur in verschiedenen Formen!\nGeben Sie niemals Ihren Seed oder Schlüssel an jemanden weiter. Ihr Geld wird gestohlen, wenn Sie Ihren Seed oder Schlüssel herausgeben. Bitte notieren Sie sich jedoch Ihren Seed und bewahren Sie ihn an einem sicheren Ort auf (so können Sie Ihr Wallet wiederherstellen, wenn Sie Ihr Telefon verlieren.)\n"
|
||||
},
|
||||
{
|
||||
"question" : "Wie viele Geldbörsen kann ich erstellen?",
|
||||
"answer" : "Es gibt keine Grenzen! Sie können so viele Brieftaschen erstellen, wie Sie möchten.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Wie kann ich meine Brieftasche wiederherstellen?",
|
||||
"answer" : "Tippen Sie auf das Menü •••, wählen Sie „Brieftaschen“ und dann „Brieftasche wiederherstellen“. Geben Sie dann Ihren Startwert (oder Ihre Schlüssel) und optional ein Datum vor der ersten Transaktion in Ihrer Brieftasche ein (dies beschleunigt den Synchronisierungsvorgang) .) Möglicherweise müssen Sie die App 15 bis 30 Minuten geöffnet lassen, um Ihr Portemonnaie vollständig wiederherzustellen.\n"
|
||||
"question" : "Wie kann ich mein Wallet wiederherstellen?",
|
||||
"answer" : "Tippen Sie auf das Menü •••, wählen Sie „Wallest“ und dann „Wallet wiederherstellen“. Geben Sie dann Ihren Seed (oder Ihre Schlüssel) und optional ein Datum vor der ersten Transaktion in Ihrem Wallet ein (dies beschleunigt den Synchronisierungsvorgang) .) Möglicherweise müssen Sie die App 15 bis 30 Minuten geöffnet lassen, um Ihr Wallet vollständig wiederherzustellen.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Was kann ich tun, wenn ich meinen Samen verliere?",
|
||||
"answer" : "Wenn Sie Ihren Samen vergessen haben, haben Sie ihn wahrscheinlich irgendwo aufgeschrieben. Bitte überprüfen Sie Ihre Notizen und schauen Sie sich auf Ihrem Computer um. Wenn Sie es nirgendwo finden, haben Sie möglicherweise Cake Wallet gesichert (in diesem Fall können Sie es aus diesem Backup wiederherstellen.) Wenn keines dieser Probleme auftritt, können wir leider nichts tun.\n"
|
||||
"question" : "Was kann ich tun, wenn ich meinen Seed verliere?",
|
||||
"answer" : "Wenn Sie Ihren Seed vergessen haben, haben Sie ihn wahrscheinlich irgendwo aufgeschrieben. Bitte überprüfen Sie Ihre Notizen und schauen Sie sich auf Ihrem Computer um. Wenn Sie es nirgendwo finden, haben Sie möglicherweise Cake Wallet gesichert (in diesem Fall können Sie es aus diesem Backup wiederherstellen.) Wenn keines dieser Probleme auftritt, können wir leider nichts tun.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Sammeln Sie Informationen zu meiner Brieftasche?",
|
||||
"answer" : "Cake Wallet sammelt oder zeichnet keine Informationen über Ihre Brieftasche auf. Ihre Privatsphäre ist uns wichtig.\n"
|
||||
"question" : "Sammeln Sie Informationen zu meinem Wallet?",
|
||||
"answer" : "Cake Wallet sammelt oder zeichnet keine Informationen über Ihr Wallet auf. Ihre Privatsphäre ist uns wichtig.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Kann ich eine Transaktion stornieren?",
|
||||
|
@ -37,7 +37,7 @@
|
|||
},
|
||||
{
|
||||
"question" : "Was sind Subadressen und wie verwende ich sie?",
|
||||
"answer" : "Eine Unteradresse ist im Grunde eine eindeutige Adresse, die Sie jederzeit generieren können. An sie gesendete Münzen landen weiterhin in Ihrer Hauptbrieftasche, aber die Person, die die Münzen sendet, kann Ihre Hauptadresse nicht ermitteln. Unteradressen beginnen immer mit „8“.\nSie können eine neue Unteradresse im Empfangsbildschirm erstellen, indem Sie auf das „+“ neben der Schaltfläche Unteradressen tippen. Geben Sie einen Namen für die Unteradresse ein und tippen Sie auf \"Hinzufügen\". Dann tippen Sie einfach auf den Namen der Subadresse, wenn Sie ihn verwenden möchten!\nWenn Sie paranoid sind, sollten Sie wahrscheinlich jedes Mal, wenn Sie Monero erhalten, eine neue Unteradresse erstellen.\n"
|
||||
"answer" : "Eine Unteradresse ist im Grunde eine eindeutige Adresse, die Sie jederzeit generieren können. An sie gesendete Münzen landen weiterhin in Ihrer Hauptwallet, aber die Person, die die Coins sendet, kann Ihre Hauptadresse nicht ermitteln. Unteradressen beginnen immer mit „8“.\nSie können eine neue Unteradresse im Empfangsbildschirm erstellen, indem Sie auf das „+“ neben der Schaltfläche Unteradressen tippen. Geben Sie einen Namen für die Unteradresse ein und tippen Sie auf \"Hinzufügen\". Dann tippen Sie einfach auf den Namen der Subadresse, wenn Sie ihn verwenden möchten!\nWenn Sie paranoid sind, sollten Sie wahrscheinlich jedes Mal, wenn Sie Monero erhalten, eine neue Unteradresse erstellen.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Was ist eine Transaktions-ID?",
|
||||
|
@ -48,11 +48,11 @@
|
|||
"answer" : "Wenn Sie Ihren Monero nicht erhalten haben, möchten Sie möglicherweise auf das Menü ••• tippen und auf Reconnect (Neu verbinden) klicken. Wenn dies nicht funktioniert, gehen Sie in das Einstellungsmenü, tippen Sie auf das Feld \"Aktueller Knoten\" und wählen Sie einen Knoten mit einem grünen Punkt daneben aus.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Ich habe in der App keine Münzen aus dem Umtausch erhalten. Was kann ich tun?",
|
||||
"answer" : "Wenn Sie Probleme mit einem Austausch haben, wenden Sie sich am besten an den Austausch. Wir sind eine Partnerschaft mit XMR.TO, Morph und ChangeNow eingegangen. Rufen Sie daher am besten http://xmr.to, http://changenow.io oder http://morphtoken.com auf und wenden Sie sich an deren Support.\n"
|
||||
"question" : "Ich habe in der App keine Coins aus dem Umtausch erhalten. Was kann ich tun?",
|
||||
"answer" : "Wenn Sie Probleme mit einem Austausch haben, besteht die beste Option, den Austausch selbst zu kontaktieren. Wir haben uns mit Chechenow, Simpleswap, Sideshift und Trocador zusammengetan. Am besten wechseln Sie zu https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ und kontaktieren Sie ihre Unterstützung.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Wie kontaktiere ich den Cake Wallet-Support?",
|
||||
"answer" : "Senden Sie eine E-Mail an support@cakewallet.com, schließen Sie sich dem Telegramm unter @cakewallet_bot an oder twittern Sie @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "I didn't receive my coins from the exchange in the app. What can I do?",
|
||||
"answer" : "If you're having issues with an exchange, the best option is to contact the exchange itself. We're partnered with XMR.TO, Morph and ChangeNow, so your best bet is to go to http://xmr.to, http://changenow.io, or http://morphtoken.com and contact their support.\n"
|
||||
"answer" : "If you're having issues with an exchange, the best option is to contact the exchange itself. We're partnered with ChangeNow, SimpleSwap, SideShift and Trocador. So your best bet is to go to https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ and contact their support.\n"
|
||||
},
|
||||
{
|
||||
"question" : "How do I contact Cake Wallet support?",
|
||||
"answer" : "Email support@cakewallet.com, join the Telegram at @cakewallet_bot, or tweet @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "No recibí mis monedas del intercambio en la aplicación. ¿Que puedo hacer?",
|
||||
"answer" : "Si tiene problemas con un intercambio, la mejor opción es ponerse en contacto con el intercambio en sí. Estamos asociados con XMR.TO, Morph y ChangeNow, por lo que su mejor opción es ir a http://xmr.to, http://changenow.io o http://morphtoken.com y contactar a su soporte.\n"
|
||||
"answer" : "Si tiene problemas con un intercambio, la mejor opción es comunicarse con el intercambio en sí. Estamos asociados con ChangeNow, SimpleSwap, SideShift y Trocador. Entonces, su mejor opción es ir a https://changenow.io, https://simplewap.io/, https://sideshift.ai/, https://trocador.app/ y contactar su soporte.\n"
|
||||
},
|
||||
{
|
||||
"question" : "¿Cómo contacto al soporte de Cake Wallet?",
|
||||
"answer" : "¡Envíe un correo electrónico a support@cakewallet.com, únase al Telegram en @cakewallet_bot o envíe un tweet a @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
},
|
||||
{
|
||||
"question" : "Je n'ai pas reçu mes fonds en provenance de la plateforme d'échange dans l'application. Que puis-je faire ?",
|
||||
"answer" : "Si vous avez des soucis avec une plateforme d'échange, le mieux est de contacter la plateforme d'échange directement. Nous avons des partenariats avec XMR.TO, Morph et ChangeNow, donc essayez http://xmr.to, http://changenow.io, ou http://morphtoken.com et contactez leur support.\n"
|
||||
"answer" : "Si vous rencontrez des problèmes avec un échange, la meilleure option est de contacter l'échange lui-même. Nous sommes en partenariat avec Changenow, Simpleswap, Sideshift et le Trocador. Donc, votre meilleur pari est d'aller sur https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ et contactez leur support.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Comment puis-je contacter le support de Cake Wallet ?",
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "मुझे ऐप में एक्सचेंज से मेरे सिक्के नहीं मिले। मैं क्या कर सकता हूँ?",
|
||||
"answer" : "यदि आप एक एक्सचेंज के साथ समस्या कर रहे हैं, तो सबसे अच्छा विकल्प एक्सचेंज से संपर्क करना है। हम XMR.TO, Morph और ChangeNow के साथ भागीदारी कर रहे हैं, इसलिए आपका सबसे अच्छा दांव http://xmr.to, http://changenow.io, या http://morphtoken.com पर जाना है और उनके समर्थन से संपर्क करना है।\n"
|
||||
"answer" : "यदि आप एक एक्सचेंज के साथ समस्याएं कर रहे हैं, तो सबसे अच्छा विकल्प एक्सचेंज से संपर्क करना है। हम चंगेनो, सिम्प्लेवैप, सिडशिफ्ट और ट्रोकैडर के साथ भागीदारी कर रहे हैं। तो आपका सबसे अच्छा दांव https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ पर जाना और उनके समर्थन से संपर्क करना है।\n"
|
||||
},
|
||||
{
|
||||
"question" : "मैं केक वॉलेट से कैसे संपर्क करूं?",
|
||||
"answer" : "ईमेल support@cakewallet.com, @cakewallet_bot पर टेलीग्राम में शामिल हों, या @CakeWalletXMR पर ट्वीट करें!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "アプリの取引所からコインを受け取りませんでした。 私に何ができる?",
|
||||
"answer" : "取引所に問題がある場合、最良の選択肢は取引所自体に連絡することです。 XMR.TO、Morph、ChangeNowと提携しているため、最善の策はhttp://xmr.to、http://changenow.io、またはhttp://morphtoken.comにアクセスしてサポートに連絡することです。\n"
|
||||
"answer" : "交換に問題がある場合、最良の選択肢は、交換自体に連絡することです。 Changenow、SimpleSwap、Sideshift、Trocadorと提携しています。したがって、あなたの最善の策は、https://changenow.io、https://simpleswap.io/、https://sideshift.ai/、https://trocador.app/に行くことです。\n"
|
||||
},
|
||||
{
|
||||
"question" : "Cake Walletサポートに連絡するにはどうすればよいですか?",
|
||||
"answer" : "support@cakewallet.comにメールを送信するか、@cakewallet_botで電報に参加するか、@CakeWalletXMRにツイートしてください。\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "앱의 거래소에서 동전을받지 못했습니다. 내가 무엇을 할 수 있을지?",
|
||||
"answer" : "교환에 문제가있는 경우 교환기에 연락하는 것이 가장 좋습니다. 우리는 XMR.TO, Morph 및 ChangeNow와 파트너 관계를 맺고 있으므로 가장 좋은 방법은 http://xmr.to, http://changenow.io 또는 http://morphtoken.com으로 이동하여 지원 부서에 문의하는 것입니다.\n"
|
||||
"answer" : "교환에 문제가있는 경우 가장 좋은 선택은 Exchange 자체에 연락하는 것입니다. 우리는 Changenow, Simpleswap, Sideshift 및 Trocador와 파트너 관계를 맺고 있습니다. 따라서 가장 좋은 방법은 https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/로 이동하여 지원에 연락하는 것입니다.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Cake Wallet 지원팀에 연락하려면 어떻게해야합니까?",
|
||||
"answer" : "support@cakewallet.com로 이메일을 보내거나 @cakewallet_bot에서 전보에 가입하거나 @CakeWalletXMR을 트윗하십시오!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "Ik heb mijn munten niet ontvangen van de beurs in de app. Wat kan ik doen?",
|
||||
"answer" : "Als u problemen ondervindt met een uitwisseling, kunt u het beste contact opnemen met de uitwisseling zelf. We werken samen met XMR.TO, Morph en ChangeNow, dus u kunt het beste naar http://xmr.to, http://changenow.io of http://morphtoken.com gaan en contact opnemen met hun ondersteuning.\n"
|
||||
"answer" : "Als u problemen heeft met een uitwisseling, is de beste optie om contact op te nemen met de uitwisseling zelf. We werken samen met ChangeNow, SimpleSwap, SideShift en Trocador. Dus het beste is om naar https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ te gaan en contact op te nemen met hun ondersteuning.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Hoe neem ik contact op met Cake Wallet-ondersteuning?",
|
||||
"answer" : "E-mail support@cakewallet.com, word lid van het Telegram op @cakewallet_bot of tweet @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "Nie otrzymałem moich monet z wymiany w aplikacji. Co mogę zrobić?",
|
||||
"answer" : "Jeśli masz problemy z wymianą, najlepszym rozwiązaniem jest skontaktowanie się z samą giełdą. Współpracujemy z XMR.TO, Morph i ChangeNow, więc najlepiej postawić się na stronie http://xmr.to, http://changenow.io lub http://morphtoken.com i skontaktować się z ich wsparciem.\n"
|
||||
"answer" : "Jeśli masz problemy z wymianą, najlepszą opcją jest skontaktowanie się z samą wymianą. Współpracujemy z Changenow, Simpleswap, Sideshift i Trocador. Więc najlepszym rozwiązaniem jest przejście na https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ i skontaktować się z ich obsługą.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Jak skontaktować się z obsługą Cake Wallet?",
|
||||
"answer" : "Wyślij e-mail na adres support@cakewallet.com, dołącz do telegramu na @cakewallet_bot lub tweet @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "Não recebi minhas moedas da troca no aplicativo. O que eu posso fazer?",
|
||||
"answer" : "Se você estiver tendo problemas com uma troca, a melhor opção é entrar em contato com a troca. Somos parceiros do XMR.TO, Morph e ChangeNow, portanto, sua melhor aposta é ir para http://xmr.to, http://changenow.io ou http://morphtoken.com e entrar em contato com o suporte deles.\n"
|
||||
"answer" : "Se você estiver com problemas com uma troca, a melhor opção é entrar em contato com a própria troca. Estamos em parceria com ChangeNow, SimpleSwap, Sideshift e Trocador. Portanto, sua melhor aposta é ir para https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ e entre em contato com seu suporte.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Como entro em contato com o suporte da Cake Wallet?",
|
||||
"answer" : "Envie um e-mail para support@cakewallet.com, participe do Telegram em @cakewallet_bot ou envie um tweet para @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "Я не получил свои монеты после обмена в приложении. Что я могу сделать?",
|
||||
"answer" : "Если у вас возникли проблемы с обменом, лучше всего связаться с провайдером обмена. Мы сотрудничаем с XMR.TO, Morph и ChangeNow, поэтому вам лучше всего зайти на http://xmr.to, http://changenow.io или http://morphtoken.com и связаться с их поддержкой.\n"
|
||||
"answer" : "Если у вас есть проблемы с обменом, лучший вариант - связаться с самой биржей. Мы сотрудничаем с Changenow, Simpleswap, SideShift и Trocador. Так что лучше всего пойти по адресу https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ и свяжитесь с их поддержкой.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Как мне связаться со службой поддержки Cake Wallet?",
|
||||
"answer" : "По электронной почте support@cakewallet.com, присоединитесь к Telegram по адресу @cakewallet_bot или отправьте твит @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "Я не отримав свої монети після обміну в додатку. Що я можу зробити?",
|
||||
"answer" : "Якщо у вас виникли проблеми з обміном, найкраще зв'язатися з провайдером обміну. Ми співпрацюємо з XMR.TO, Morph і ChangeNow, тому вам найкраще зайти на http://xmr.to, http://changenow.io або http://morphtoken.com і зв'язатися з їх підтримкою.\n"
|
||||
"answer" : "Якщо у вас є проблеми з обміном, найкращим варіантом є зв’язок із самою біржею. Ми співпрацюємо з Changenow, Simplewap, Sideshift та Trocador. Тож найкраща ставка - перейти на https://changenow.io, https://simpleswap.io/, https://sideshift.ai/, https://trocador.app/ та звернутися до їх підтримки.\n"
|
||||
},
|
||||
{
|
||||
"question" : "Як мені зв'язатися зі службою підтримки Cake Wallet?",
|
||||
"answer" : "По електронній пошті support@cakewallet.com, приєднайтеся до Telegram за адресою @cakewallet_bot або надішліть твіт @CakeWalletXMR!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -49,10 +49,10 @@
|
|||
},
|
||||
{
|
||||
"question" : "我没有从应用程序中的交易所收到硬币。 我能做什么?",
|
||||
"answer" : "如果您对交易所有疑问,最好的选择是与交易所本身联系。 我们与XMR.TO,Morph和ChangeNow合作,因此最好的选择是访问http://xmr.to、http://changenow.io或http://morphtoken.com,并与他们的支持部门联系。\n"
|
||||
"answer" : "如果您对交易所有问题,最好的选择是与交易所本身联系。我们与ChangeNow,SimplesWap,SideShift和Trocador合作。因此,最好的选择是访问https://changenow.io,https://simpleswap.io/,https://sideshift.ai/,https://trocador.app/并联系他们的支持。\n"
|
||||
},
|
||||
{
|
||||
"question" : "如何联系蛋糕钱包支持?",
|
||||
"answer" : "电子邮件support@cakewallet.com,通过@cakewallet_bot加入电报,或在@CakeWalletXMR上发布推文!\n"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 30 KiB |
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_adaptive_back"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/>
|
||||
<background android:drawable="@mipmap/ic_launcher_adaptive_back"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 932 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 327 B |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 677 B |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1,017 B |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 9.2 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 28 KiB |
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_adaptive_back"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/>
|
||||
<background android:drawable="@mipmap/ic_launcher_adaptive_back"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/>
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 932 B After Width: | Height: | Size: 509 B |
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 327 B |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 677 B |
Before Width: | Height: | Size: 8.8 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1,017 B |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 8.5 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 12 KiB |
|
@ -5,7 +5,8 @@
|
|||
uri: cakexmrl7bonq7ovjka5kuwuyd3f7qnkz6z6s6dmsy3uckwra7bvggyd.onion:18081
|
||||
is_default: false
|
||||
-
|
||||
uri: node.sethforprivacy.com:18089
|
||||
uri: node.sethforprivacy.com:443
|
||||
useSSL: true
|
||||
is_default: false
|
||||
-
|
||||
uri: nodes.hashvault.pro:18081
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
Support getting Addresses from ENS and Mastodon
|
||||
Bug fixes
|
||||
Minor enhancements
|
||||
UI enhancements
|
||||
Privacy settings enhancements
|
||||
Tablet/iPad fixes
|
||||
Bug fixes
|
|
@ -1,3 +1,5 @@
|
|||
Add BitcoinCash (BCH)
|
||||
Bug fixes
|
||||
Accessibility enhancements
|
||||
WalletConnect enhancements
|
||||
UI enhancements
|
||||
Privacy settings enhancements
|
||||
Tablet/iPad fixes
|
||||
Bug fixes
|
|
@ -1 +1 @@
|
|||
C:/Users/borod/AppData/Local/Pub/Cache/hosted/pub.dev/path_provider_linux-2.2.0/
|
||||
/Users/blazebrain/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/
|
|
@ -6,6 +6,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
String title = '',
|
||||
int raw = -1,
|
||||
required this.name,
|
||||
required this.decimals,
|
||||
this.fullName,
|
||||
this.iconPath,
|
||||
this.tag})
|
||||
|
@ -15,6 +16,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
final String? tag;
|
||||
final String? fullName;
|
||||
final String? iconPath;
|
||||
final int decimals;
|
||||
|
||||
static const all = [
|
||||
CryptoCurrency.xmr,
|
||||
|
@ -110,96 +112,96 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
];
|
||||
|
||||
// title, tag (if applicable), fullName (if unique), raw, name, iconPath
|
||||
static const xmr = CryptoCurrency(title: 'XMR', fullName: 'Monero', raw: 0, name: 'xmr', iconPath: 'assets/images/monero_icon.png');
|
||||
static const ada = CryptoCurrency(title: 'ADA', fullName: 'Cardano', raw: 1, name: 'ada', iconPath: 'assets/images/ada_icon.png');
|
||||
static const bch = CryptoCurrency(title: 'BCH', fullName: 'Bitcoin Cash', raw: 2, name: 'bch', iconPath: 'assets/images/bch_icon.png');
|
||||
static const bnb = CryptoCurrency(title: 'BNB', tag: 'BSC', fullName: 'Binance Coin', raw: 3, name: 'bnb', iconPath: 'assets/images/bnb_icon.png');
|
||||
static const btc = CryptoCurrency(title: 'BTC', fullName: 'Bitcoin', raw: 4, name: 'btc', iconPath: 'assets/images/btc.png');
|
||||
static const dai = CryptoCurrency(title: 'DAI', tag: 'ETH', fullName: 'Dai', raw: 5, name: 'dai', iconPath: 'assets/images/dai_icon.png');
|
||||
static const dash = CryptoCurrency(title: 'DASH', fullName: 'Dash', raw: 6, name: 'dash', iconPath: 'assets/images/dash_icon.png');
|
||||
static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png');
|
||||
static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/images/eth_icon.png');
|
||||
static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/images/litecoin-ltc_icon.png');
|
||||
static const nano = CryptoCurrency(title: 'XNO', raw: 10, fullName: 'Nano', name: 'xno', iconPath: 'assets/images/nano_icon.png');
|
||||
static const trx = CryptoCurrency(title: 'TRX', fullName: 'TRON', raw: 11, name: 'trx', iconPath: 'assets/images/trx_icon.png');
|
||||
static const usdt = CryptoCurrency(title: 'USDT', tag: 'OMNI', fullName: 'USDT Tether', raw: 12, name: 'usdt', iconPath: 'assets/images/usdt_icon.png');
|
||||
static const usdterc20 = CryptoCurrency(title: 'USDT', tag: 'ETH', fullName: 'USDT Tether', raw: 13, name: 'usdterc20', iconPath: 'assets/images/usdterc20_icon.png');
|
||||
static const xlm = CryptoCurrency(title: 'XLM', fullName: 'Stellar', raw: 14, name: 'xlm', iconPath: 'assets/images/xlm_icon.png');
|
||||
static const xrp = CryptoCurrency(title: 'XRP', fullName: 'Ripple', raw: 15, name: 'xrp', iconPath: 'assets/images/xrp_icon.png');
|
||||
static const xhv = CryptoCurrency(title: 'XHV', fullName: 'Haven Protocol', raw: 16, name: 'xhv', iconPath: 'assets/images/xhv_logo.png');
|
||||
static const xmr = CryptoCurrency(title: 'XMR', fullName: 'Monero', raw: 0, name: 'xmr', iconPath: 'assets/images/monero_icon.png', decimals: 12);
|
||||
static const ada = CryptoCurrency(title: 'ADA', fullName: 'Cardano', raw: 1, name: 'ada', iconPath: 'assets/images/ada_icon.png', decimals: 6);
|
||||
static const bch = CryptoCurrency(title: 'BCH', fullName: 'Bitcoin Cash', raw: 2, name: 'bch', iconPath: 'assets/images/bch_icon.png', decimals: 8);
|
||||
static const bnb = CryptoCurrency(title: 'BNB', tag: 'BSC', fullName: 'Binance Coin', raw: 3, name: 'bnb', iconPath: 'assets/images/bnb_icon.png', decimals: 8);
|
||||
static const btc = CryptoCurrency(title: 'BTC', fullName: 'Bitcoin', raw: 4, name: 'btc', iconPath: 'assets/images/btc.png', decimals: 8);
|
||||
static const dai = CryptoCurrency(title: 'DAI', tag: 'ETH', fullName: 'Dai', raw: 5, name: 'dai', iconPath: 'assets/images/dai_icon.png', decimals: 18);
|
||||
static const dash = CryptoCurrency(title: 'DASH', fullName: 'Dash', raw: 6, name: 'dash', iconPath: 'assets/images/dash_icon.png', decimals: 8);
|
||||
static const eos = CryptoCurrency(title: 'EOS', fullName: 'EOS', raw: 7, name: 'eos', iconPath: 'assets/images/eos_icon.png', decimals: 4);
|
||||
static const eth = CryptoCurrency(title: 'ETH', fullName: 'Ethereum', raw: 8, name: 'eth', iconPath: 'assets/images/eth_icon.png', decimals: 18);
|
||||
static const ltc = CryptoCurrency(title: 'LTC', fullName: 'Litecoin', raw: 9, name: 'ltc', iconPath: 'assets/images/litecoin-ltc_icon.png', decimals: 8);
|
||||
static const nano = CryptoCurrency(title: 'XNO', fullName: 'Nano', raw: 10, name: 'xno', iconPath: 'assets/images/nano_icon.png', decimals: 30);
|
||||
static const trx = CryptoCurrency(title: 'TRX', fullName: 'TRON', raw: 11, name: 'trx', iconPath: 'assets/images/trx_icon.png', decimals: 6);
|
||||
static const usdt = CryptoCurrency(title: 'USDT', tag: 'OMNI', fullName: 'USDT Tether', raw: 12, name: 'usdt', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
|
||||
static const usdterc20 = CryptoCurrency(title: 'USDT', tag: 'ETH', fullName: 'USDT Tether', raw: 13, name: 'usdterc20', iconPath: 'assets/images/usdterc20_icon.png', decimals: 6);
|
||||
static const xlm = CryptoCurrency(title: 'XLM', fullName: 'Stellar', raw: 14, name: 'xlm', iconPath: 'assets/images/xlm_icon.png', decimals: 7);
|
||||
static const xrp = CryptoCurrency(title: 'XRP', fullName: 'Ripple', raw: 15, name: 'xrp', iconPath: 'assets/images/xrp_icon.png', decimals: 6);
|
||||
static const xhv = CryptoCurrency(title: 'XHV', fullName: 'Haven Protocol', raw: 16, name: 'xhv', iconPath: 'assets/images/xhv_logo.png', decimals: 12);
|
||||
|
||||
static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag');
|
||||
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau');
|
||||
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19, name: 'xaud');
|
||||
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20, name: 'xbtc');
|
||||
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21, name: 'xcad');
|
||||
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22, name: 'xchf');
|
||||
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23, name: 'xcny');
|
||||
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24, name: 'xeur');
|
||||
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25, name: 'xgbp');
|
||||
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26, name: 'xjpy');
|
||||
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27, name: 'xnok');
|
||||
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28, name: 'xnzd');
|
||||
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd');
|
||||
static const xag = CryptoCurrency(title: 'XAG', tag: 'XHV', raw: 17, name: 'xag', decimals: 12);
|
||||
static const xau = CryptoCurrency(title: 'XAU', tag: 'XHV', raw: 18, name: 'xau', decimals: 12);
|
||||
static const xaud = CryptoCurrency(title: 'XAUD', tag: 'XHV', raw: 19, name: 'xaud', decimals: 12);
|
||||
static const xbtc = CryptoCurrency(title: 'XBTC', tag: 'XHV', raw: 20, name: 'xbtc', decimals: 12);
|
||||
static const xcad = CryptoCurrency(title: 'XCAD', tag: 'XHV', raw: 21, name: 'xcad', decimals: 12);
|
||||
static const xchf = CryptoCurrency(title: 'XCHF', tag: 'XHV', raw: 22, name: 'xchf', decimals: 12);
|
||||
static const xcny = CryptoCurrency(title: 'XCNY', tag: 'XHV', raw: 23, name: 'xcny', decimals: 12);
|
||||
static const xeur = CryptoCurrency(title: 'XEUR', tag: 'XHV', raw: 24, name: 'xeur', decimals: 12);
|
||||
static const xgbp = CryptoCurrency(title: 'XGBP', tag: 'XHV', raw: 25, name: 'xgbp', decimals: 12);
|
||||
static const xjpy = CryptoCurrency(title: 'XJPY', tag: 'XHV', raw: 26, name: 'xjpy', decimals: 12);
|
||||
static const xnok = CryptoCurrency(title: 'XNOK', tag: 'XHV', raw: 27, name: 'xnok', decimals: 12);
|
||||
static const xnzd = CryptoCurrency(title: 'XNZD', tag: 'XHV', raw: 28, name: 'xnzd', decimals: 12);
|
||||
static const xusd = CryptoCurrency(title: 'XUSD', tag: 'XHV', raw: 29, name: 'xusd', decimals: 12);
|
||||
|
||||
static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png');
|
||||
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'AVAXC', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png');
|
||||
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png');
|
||||
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/btt_icon.png');
|
||||
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png');
|
||||
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png');
|
||||
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png');
|
||||
static const hbar = CryptoCurrency(title: 'HBAR', fullName: 'Hedera', raw: 37, name: 'hbar', iconPath: 'assets/images/hbar_icon.png', );
|
||||
static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png');
|
||||
static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/images/sol_icon.png');
|
||||
static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USD Coin', raw: 40, name: 'usdc', iconPath: 'assets/images/usdc_icon.png');
|
||||
static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/images/usdc_icon.png');
|
||||
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', raw: 42, name: 'zaddr', iconPath: 'assets/images/zec_icon.png');
|
||||
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', fullName: 'Transparent Zcash', raw: 43, name: 'zec', iconPath: 'assets/images/zec_icon.png');
|
||||
static const zen = CryptoCurrency(title: 'ZEN', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png');
|
||||
static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png');
|
||||
static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png', decimals: 18);
|
||||
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'AVAXC', fullName: 'Avalanche', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png', decimals: 9);
|
||||
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png', decimals: 18);
|
||||
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/btt_icon.png', decimals: 18);
|
||||
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png', decimals: 8);
|
||||
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png', decimals: 8);
|
||||
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png', decimals: 6);
|
||||
static const hbar = CryptoCurrency(title: 'HBAR', fullName: 'Hedera', raw: 37, name: 'hbar', iconPath: 'assets/images/hbar_icon.png', decimals: 8);
|
||||
static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png', decimals: 16);
|
||||
static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/images/sol_icon.png', decimals: 9);
|
||||
static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USD Coin', raw: 40, name: 'usdc', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
|
||||
static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
|
||||
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', raw: 42, name: 'zaddr', iconPath: 'assets/images/zec_icon.png', decimals: 8);
|
||||
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', fullName: 'Transparent Zcash', raw: 43, name: 'zec', iconPath: 'assets/images/zec_icon.png', decimals: 8);
|
||||
static const zen = CryptoCurrency(title: 'ZEN', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png', decimals: 8);
|
||||
static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png', decimals: 8);
|
||||
|
||||
static const usdcpoly = CryptoCurrency(title: 'USDC', tag: 'POLY', fullName: 'USD Coin', raw: 46, name: 'usdcpoly', iconPath: 'assets/images/usdc_icon.png');
|
||||
static const dcr = CryptoCurrency(title: 'DCR', fullName: 'Decred', raw: 47, name: 'dcr', iconPath: 'assets/images/dcr_icon.png');
|
||||
static const kmd = CryptoCurrency(title: 'KMD', fullName: 'Komodo', raw: 48, name: 'kmd', iconPath: 'assets/images/kmd_icon.png');
|
||||
static const mana = CryptoCurrency(title: 'MANA', tag: 'ETH', fullName: 'Decentraland', raw: 49, name: 'mana', iconPath: 'assets/images/mana_icon.png');
|
||||
static const maticpoly = CryptoCurrency(title: 'MATIC', tag: 'POLY', fullName: 'Polygon', raw: 50, name: 'maticpoly', iconPath: 'assets/images/matic_icon.png');
|
||||
static const matic = CryptoCurrency(title: 'MATIC', tag: 'ETH', fullName: 'Polygon', raw: 51, name: 'matic', iconPath: 'assets/images/matic_icon.png');
|
||||
static const mkr = CryptoCurrency(title: 'MKR', tag: 'ETH', fullName: 'Maker', raw: 52, name: 'mkr', iconPath: 'assets/images/mkr_icon.png');
|
||||
static const near = CryptoCurrency(title: 'NEAR', fullName: 'NEAR Protocol', raw: 53, name: 'near', iconPath: 'assets/images/near_icon.png');
|
||||
static const oxt = CryptoCurrency(title: 'OXT', tag: 'ETH', fullName: 'Orchid', raw: 54, name: 'oxt', iconPath: 'assets/images/oxt_icon.png');
|
||||
static const paxg = CryptoCurrency(title: 'PAXG', tag: 'ETH', fullName: 'Pax Gold', raw: 55, name: 'paxg', iconPath: 'assets/images/paxg_icon.png');
|
||||
static const pivx = CryptoCurrency(title: 'PIVX', raw: 56, name: 'pivx', iconPath: 'assets/images/pivx_icon.png');
|
||||
static const rune = CryptoCurrency(title: 'RUNE', fullName: 'Thorchain', raw: 57, name: 'rune', iconPath: 'assets/images/rune_icon.png');
|
||||
static const rvn = CryptoCurrency(title: 'RVN', fullName: 'Ravencoin', raw: 58, name: 'rvn', iconPath: 'assets/images/rvn_icon.png');
|
||||
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png');
|
||||
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png');
|
||||
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png');
|
||||
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png');
|
||||
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png');
|
||||
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png');
|
||||
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/images/arb_icon.png');
|
||||
static const bat = CryptoCurrency(title: 'BAT', tag: 'ETH', fullName: 'Basic Attention Token', raw: 66, name: 'bat', iconPath: 'assets/images/bat_icon.png');
|
||||
static const comp = CryptoCurrency(title: 'COMP', tag: 'ETH', fullName: 'Compound', raw: 67, name: 'comp', iconPath: 'assets/images/comp_icon.png');
|
||||
static const cro = CryptoCurrency(title: 'CRO', tag: 'ETH', fullName: 'Crypto.com Cronos', raw: 68, name: 'cro', iconPath: 'assets/images/cro_icon.png');
|
||||
static const ens = CryptoCurrency(title: 'ENS', tag: 'ETH', fullName: 'Ethereum Name Service', raw: 69, name: 'ens', iconPath: 'assets/images/ens_icon.png');
|
||||
static const ftm = CryptoCurrency(title: 'FTM', tag: 'ETH', fullName: 'Fantom', raw: 70, name: 'ftm', iconPath: 'assets/images/ftm_icon.png');
|
||||
static const frax = CryptoCurrency(title: 'FRAX', tag: 'ETH', fullName: 'Frax', raw: 71, name: 'frax', iconPath: 'assets/images/frax_icon.png');
|
||||
static const gusd = CryptoCurrency(title: 'GUSD', tag: 'ETH', fullName: 'Gemini USD', raw: 72, name: 'gusd', iconPath: 'assets/images/gusd_icon.png');
|
||||
static const gtc = CryptoCurrency(title: 'GTC', tag: 'ETH', fullName: 'Gitcoin', raw: 73, name: 'gtc', iconPath: 'assets/images/gtc_icon.png');
|
||||
static const grt = CryptoCurrency(title: 'GRT', tag: 'ETH', fullName: 'The Graph', raw: 74, name: 'grt', iconPath: 'assets/images/grt_icon.png');
|
||||
static const ldo = CryptoCurrency(title: 'LDO', tag: 'ETH', fullName: 'Lido DAO', raw: 75, name: 'ldo', iconPath: 'assets/images/ldo_icon.png');
|
||||
static const nexo = CryptoCurrency(title: 'NEXO', tag: 'ETH', fullName: 'Nexo', raw: 76, name: 'nexo', iconPath: 'assets/images/nexo_icon.png');
|
||||
static const cake = CryptoCurrency(title: 'CAKE', tag: 'BSC', fullName: 'PancakeSwap', raw: 77, name: 'cake', iconPath: 'assets/images/cake_icon.png');
|
||||
static const pepe = CryptoCurrency(title: 'PEPE', tag: 'ETH', fullName: 'Pepe', raw: 78, name: 'pepe', iconPath: 'assets/images/pepe_icon.png');
|
||||
static const storj = CryptoCurrency(title: 'STORJ', tag: 'ETH', fullName: 'Storj', raw: 79, name: 'storj', iconPath: 'assets/images/storj_icon.png');
|
||||
static const tusd = CryptoCurrency(title: 'TUSD', tag: 'ETH', fullName: 'TrueUSD', raw: 80, name: 'tusd', iconPath: 'assets/images/tusd_icon.png');
|
||||
static const wbtc = CryptoCurrency(title: 'WBTC', tag: 'ETH', fullName: 'Wrapped Bitcoin', raw: 81, name: 'wbtc', iconPath: 'assets/images/wbtc_icon.png');
|
||||
static const weth = CryptoCurrency(title: 'WETH', tag: 'ETH', fullName: 'Wrapped Ethereum', raw: 82, name: 'weth', iconPath: 'assets/images/weth_icon.png');
|
||||
static const zrx = CryptoCurrency(title: 'ZRX', tag: 'ETH', fullName: '0x Protocol', raw: 83, name: 'zrx', iconPath: 'assets/images/zrx_icon.png');
|
||||
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png');
|
||||
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png');
|
||||
static const banano = CryptoCurrency(title: 'BAN', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png');
|
||||
static const usdcpoly = CryptoCurrency(title: 'USDC', tag: 'POLY', fullName: 'USD Coin', raw: 46, name: 'usdcpoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
|
||||
static const dcr = CryptoCurrency(title: 'DCR', fullName: 'Decred', raw: 47, name: 'dcr', iconPath: 'assets/images/dcr_icon.png', decimals: 8);
|
||||
static const kmd = CryptoCurrency(title: 'KMD', fullName: 'Komodo', raw: 48, name: 'kmd', iconPath: 'assets/images/kmd_icon.png', decimals: 8);
|
||||
static const mana = CryptoCurrency(title: 'MANA', tag: 'ETH', fullName: 'Decentraland', raw: 49, name: 'mana', iconPath: 'assets/images/mana_icon.png', decimals: 18);
|
||||
static const maticpoly = CryptoCurrency(title: 'MATIC', tag: 'POLY', fullName: 'Polygon', raw: 50, name: 'maticpoly', iconPath: 'assets/images/matic_icon.png', decimals: 18);
|
||||
static const matic = CryptoCurrency(title: 'MATIC', tag: 'ETH', fullName: 'Polygon', raw: 51, name: 'matic', iconPath: 'assets/images/matic_icon.png', decimals: 18);
|
||||
static const mkr = CryptoCurrency(title: 'MKR', tag: 'ETH', fullName: 'Maker', raw: 52, name: 'mkr', iconPath: 'assets/images/mkr_icon.png', decimals: 18);
|
||||
static const near = CryptoCurrency(title: 'NEAR', fullName: 'NEAR Protocol', raw: 53, name: 'near', iconPath: 'assets/images/near_icon.png', decimals: 24);
|
||||
static const oxt = CryptoCurrency(title: 'OXT', tag: 'ETH', fullName: 'Orchid', raw: 54, name: 'oxt', iconPath: 'assets/images/oxt_icon.png', decimals: 18);
|
||||
static const paxg = CryptoCurrency(title: 'PAXG', tag: 'ETH', fullName: 'Pax Gold', raw: 55, name: 'paxg', iconPath: 'assets/images/paxg_icon.png', decimals: 18);
|
||||
static const pivx = CryptoCurrency(title: 'PIVX', raw: 56, name: 'pivx', iconPath: 'assets/images/pivx_icon.png', decimals: 8);
|
||||
static const rune = CryptoCurrency(title: 'RUNE', fullName: 'Thorchain', raw: 57, name: 'rune', iconPath: 'assets/images/rune_icon.png', decimals: 18);
|
||||
static const rvn = CryptoCurrency(title: 'RVN', fullName: 'Ravencoin', raw: 58, name: 'rvn', iconPath: 'assets/images/rvn_icon.png', decimals: 8);
|
||||
static const scrt = CryptoCurrency(title: 'SCRT', fullName: 'Secret Network', raw: 59, name: 'scrt', iconPath: 'assets/images/scrt_icon.png', decimals: 6);
|
||||
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png', decimals: 18);
|
||||
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png', decimals: 8);
|
||||
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png', decimals: 8);
|
||||
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png', decimals: 18);
|
||||
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png', decimals: 18);
|
||||
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/images/arb_icon.png', decimals: 18);
|
||||
static const bat = CryptoCurrency(title: 'BAT', tag: 'ETH', fullName: 'Basic Attention Token', raw: 66, name: 'bat', iconPath: 'assets/images/bat_icon.png', decimals: 18);
|
||||
static const comp = CryptoCurrency(title: 'COMP', tag: 'ETH', fullName: 'Compound', raw: 67, name: 'comp', iconPath: 'assets/images/comp_icon.png', decimals: 18);
|
||||
static const cro = CryptoCurrency(title: 'CRO', tag: 'ETH', fullName: 'Crypto.com Cronos', raw: 68, name: 'cro', iconPath: 'assets/images/cro_icon.png', decimals: 8);
|
||||
static const ens = CryptoCurrency(title: 'ENS', tag: 'ETH', fullName: 'Ethereum Name Service', raw: 69, name: 'ens', iconPath: 'assets/images/ens_icon.png', decimals: 18);
|
||||
static const ftm = CryptoCurrency(title: 'FTM', tag: 'ETH', fullName: 'Fantom', raw: 70, name: 'ftm', iconPath: 'assets/images/ftm_icon.png', decimals: 18);
|
||||
static const frax = CryptoCurrency(title: 'FRAX', tag: 'ETH', fullName: 'Frax', raw: 71, name: 'frax', iconPath: 'assets/images/frax_icon.png', decimals: 18);
|
||||
static const gusd = CryptoCurrency(title: 'GUSD', tag: 'ETH', fullName: 'Gemini USD', raw: 72, name: 'gusd', iconPath: 'assets/images/gusd_icon.png', decimals: 2);
|
||||
static const gtc = CryptoCurrency(title: 'GTC', tag: 'ETH', fullName: 'Gitcoin', raw: 73, name: 'gtc', iconPath: 'assets/images/gtc_icon.png', decimals: 18);
|
||||
static const grt = CryptoCurrency(title: 'GRT', tag: 'ETH', fullName: 'The Graph', raw: 74, name: 'grt', iconPath: 'assets/images/grt_icon.png', decimals: 18);
|
||||
static const ldo = CryptoCurrency(title: 'LDO', tag: 'ETH', fullName: 'Lido DAO', raw: 75, name: 'ldo', iconPath: 'assets/images/ldo_icon.png', decimals: 18);
|
||||
static const nexo = CryptoCurrency(title: 'NEXO', tag: 'ETH', fullName: 'Nexo', raw: 76, name: 'nexo', iconPath: 'assets/images/nexo_icon.png', decimals: 18);
|
||||
static const cake = CryptoCurrency(title: 'CAKE', tag: 'BSC', fullName: 'PancakeSwap', raw: 77, name: 'cake', iconPath: 'assets/images/cake_icon.png', decimals: 18);
|
||||
static const pepe = CryptoCurrency(title: 'PEPE', tag: 'ETH', fullName: 'Pepe', raw: 78, name: 'pepe', iconPath: 'assets/images/pepe_icon.png', decimals: 18);
|
||||
static const storj = CryptoCurrency(title: 'STORJ', tag: 'ETH', fullName: 'Storj', raw: 79, name: 'storj', iconPath: 'assets/images/storj_icon.png', decimals: 8);
|
||||
static const tusd = CryptoCurrency(title: 'TUSD', tag: 'ETH', fullName: 'TrueUSD', raw: 80, name: 'tusd', iconPath: 'assets/images/tusd_icon.png', decimals: 18);
|
||||
static const wbtc = CryptoCurrency(title: 'WBTC', tag: 'ETH', fullName: 'Wrapped Bitcoin', raw: 81, name: 'wbtc', iconPath: 'assets/images/wbtc_icon.png', decimals: 8);
|
||||
static const weth = CryptoCurrency(title: 'WETH', tag: 'ETH', fullName: 'Wrapped Ethereum', raw: 82, name: 'weth', iconPath: 'assets/images/weth_icon.png', decimals: 18);
|
||||
static const zrx = CryptoCurrency(title: 'ZRX', tag: 'ETH', fullName: '0x Protocol', raw: 83, name: 'zrx', iconPath: 'assets/images/zrx_icon.png', decimals: 18);
|
||||
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18);
|
||||
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png', decimals: 18);
|
||||
static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29);
|
||||
|
||||
|
||||
static final Map<int, CryptoCurrency> _rawCurrencyMap =
|
||||
|
@ -223,7 +225,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
});
|
||||
|
||||
static CryptoCurrency deserialize({required int raw}) {
|
||||
|
||||
if (CryptoCurrency._rawCurrencyMap[raw] == null) {
|
||||
final s = 'Unexpected token: $raw for CryptoCurrency deserialize';
|
||||
throw ArgumentError.value(raw, 'raw', s);
|
||||
|
@ -232,7 +233,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
}
|
||||
|
||||
static CryptoCurrency fromString(String name) {
|
||||
|
||||
if (CryptoCurrency._nameCurrencyMap[name.toLowerCase()] == null) {
|
||||
final s = 'Unexpected token: $name for CryptoCurrency fromString';
|
||||
throw ArgumentError.value(name, 'name', s);
|
||||
|
@ -241,14 +241,12 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
|
|||
}
|
||||
|
||||
static CryptoCurrency fromFullName(String name) {
|
||||
|
||||
if (CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()] == null) {
|
||||
final s = 'Unexpected token: $name for CryptoCurrency fromFullName';
|
||||
throw ArgumentError.value(name, 'Fullname', s);
|
||||
}
|
||||
return CryptoCurrency._fullNameCurrencyMap[name.toLowerCase()]!;
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
|
|
|
@ -37,6 +37,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
|||
fullName: name,
|
||||
tag: "ETH",
|
||||
iconPath: iconPath,
|
||||
decimals: decimal
|
||||
);
|
||||
|
||||
Erc20Token.copyWith(Erc20Token other, String? icon)
|
||||
|
@ -52,6 +53,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
|
|||
fullName: other.name,
|
||||
tag: "ETH",
|
||||
iconPath: icon,
|
||||
decimals: other.decimal
|
||||
);
|
||||
|
||||
static const typeId = ERC20_TOKEN_TYPE_ID;
|
||||
|
|
|
@ -162,6 +162,9 @@ class Node extends HiveObject with Keyable {
|
|||
try {
|
||||
final authenticatingClient = HttpClient();
|
||||
|
||||
authenticatingClient.badCertificateCallback =
|
||||
((X509Certificate cert, String host, int port) => true);
|
||||
|
||||
authenticatingClient.addCredentials(
|
||||
rpcUri,
|
||||
realm,
|
||||
|
|
|
@ -36,4 +36,6 @@ abstract class WalletAddresses {
|
|||
print(e.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool containsAddress(String address) => addressesMap.containsKey(address);
|
||||
}
|
||||
|
|
|
@ -63,14 +63,14 @@ abstract class HavenWalletAddressesBase extends WalletAddressesWithAccount<Accou
|
|||
|
||||
bool validate() {
|
||||
accountList.update();
|
||||
final accountListLength = accountList.accounts.length ?? 0;
|
||||
final accountListLength = accountList.accounts.length;
|
||||
|
||||
if (accountListLength <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
subaddressList.update(accountIndex: accountList.accounts.first.id);
|
||||
final subaddressListLength = subaddressList.subaddresses.length ?? 0;
|
||||
final subaddressListLength = subaddressList.subaddresses.length;
|
||||
|
||||
if (subaddressListLength <= 0) {
|
||||
return false;
|
||||
|
@ -84,4 +84,8 @@ abstract class HavenWalletAddressesBase extends WalletAddressesWithAccount<Accou
|
|||
subaddress = subaddressList.subaddresses.first;
|
||||
address = subaddress!.address;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool containsAddress(String address) =>
|
||||
addressInfos[account?.id ?? 0]?.any((it) => it.address == address) ?? false;
|
||||
}
|
||||
|
|
|
@ -57,9 +57,7 @@ abstract class MoneroWalletBase
|
|||
walletAddresses = MoneroWalletAddresses(walletInfo, transactionHistory);
|
||||
|
||||
_onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
if (account == null) return;
|
||||
|
||||
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
|
||||
currency: MoneroBalance(
|
||||
|
@ -67,6 +65,7 @@ abstract class MoneroWalletBase
|
|||
unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
||||
});
|
||||
_updateSubAddress(isEnabledAutoGenerateSubaddress, account: account);
|
||||
_askForUpdateTransactionHistory();
|
||||
});
|
||||
|
||||
reaction((_) => isEnabledAutoGenerateSubaddress, (bool enabled) {
|
||||
|
@ -362,9 +361,7 @@ abstract class MoneroWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> changePassword(String password) async {
|
||||
monero_wallet.setPasswordSync(password);
|
||||
}
|
||||
Future<void> changePassword(String password) async => monero_wallet.setPasswordSync(password);
|
||||
|
||||
Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
|
||||
|
||||
|
@ -499,9 +496,8 @@ abstract class MoneroWalletBase
|
|||
}
|
||||
}
|
||||
|
||||
String getSubaddressLabel(int accountIndex, int addressIndex) {
|
||||
return monero_wallet.getSubaddressLabel(accountIndex, addressIndex);
|
||||
}
|
||||
String getSubaddressLabel(int accountIndex, int addressIndex) =>
|
||||
monero_wallet.getSubaddressLabel(accountIndex, addressIndex);
|
||||
|
||||
List<MoneroTransactionInfo> _getAllTransactionsOfAccount(int? accountIndex) => transaction_history
|
||||
.getAllTransactions()
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import 'package:cw_core/account.dart';
|
||||
import 'package:cw_core/address_info.dart';
|
||||
import 'package:cw_core/subaddress.dart';
|
||||
import 'package:cw_core/wallet_addresses.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/account.dart';
|
||||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:cw_monero/monero_account_list.dart';
|
||||
import 'package:cw_monero/monero_subaddress_list.dart';
|
||||
import 'package:cw_core/subaddress.dart';
|
||||
import 'package:cw_monero/monero_transaction_history.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
|
@ -112,4 +112,8 @@ abstract class MoneroWalletAddressesBase extends WalletAddresses with Store {
|
|||
subaddress = subaddressList.subaddresses.last;
|
||||
address = subaddress!.address;
|
||||
}
|
||||
|
||||
@override
|
||||
bool containsAddress(String address) =>
|
||||
addressInfos[account?.id ?? 0]?.any((it) => it.address == address) ?? false;
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ class MoneroWalletService extends WalletService<
|
|||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||
|
||||
|
||||
static bool walletFilesExist(String path) =>
|
||||
!File(path).existsSync() && !File('$path.keys').existsSync();
|
||||
|
||||
|
@ -135,9 +135,18 @@ class MoneroWalletService extends WalletService<
|
|||
(e is WalletOpeningException && e.message.contains('basic_string'));
|
||||
|
||||
final bool isMissingCacheFilesAndroid = e.toString().contains('input_stream') ||
|
||||
(e is WalletOpeningException && e.message.contains('input_stream'));
|
||||
e.toString().contains('input stream error') ||
|
||||
(e is WalletOpeningException &&
|
||||
(e.message.contains('input_stream') || e.message.contains('input stream error')));
|
||||
|
||||
if (isBadAlloc || doesNotCorrespond || isMissingCacheFilesIOS || isMissingCacheFilesAndroid) {
|
||||
final bool invalidSignature = e.toString().contains('invalid signature') ||
|
||||
(e is WalletOpeningException && e.message.contains('invalid signature'));
|
||||
|
||||
if (isBadAlloc ||
|
||||
doesNotCorrespond ||
|
||||
isMissingCacheFilesIOS ||
|
||||
isMissingCacheFilesAndroid ||
|
||||
invalidSignature) {
|
||||
await restoreOrResetWalletFiles(name);
|
||||
return openWallet(name, password);
|
||||
}
|
||||
|
|
|
@ -10,13 +10,11 @@ class NanoRestoreWalletFromSeedCredentials extends WalletCredentials {
|
|||
NanoRestoreWalletFromSeedCredentials({
|
||||
required String name,
|
||||
required this.mnemonic,
|
||||
int height = 0,
|
||||
String? password,
|
||||
DerivationType? derivationType,
|
||||
}) : super(
|
||||
name: name,
|
||||
password: password,
|
||||
height: height,
|
||||
derivationType: derivationType,
|
||||
);
|
||||
|
||||
|
@ -33,9 +31,12 @@ class NanoRestoreWalletFromKeysCredentials extends WalletCredentials {
|
|||
required String name,
|
||||
required String password,
|
||||
required this.seedKey,
|
||||
this.derivationType,
|
||||
}) : super(name: name, password: password);
|
||||
DerivationType? derivationType,
|
||||
}) : super(
|
||||
name: name,
|
||||
password: password,
|
||||
derivationType: derivationType,
|
||||
);
|
||||
|
||||
final String seedKey;
|
||||
final DerivationType? derivationType;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,9 @@ PODS:
|
|||
- Flutter
|
||||
- flutter_secure_storage (6.0.0):
|
||||
- Flutter
|
||||
- fluttertoast (0.0.2):
|
||||
- Flutter
|
||||
- Toast
|
||||
- in_app_review (0.2.0):
|
||||
- Flutter
|
||||
- local_auth_ios (0.0.1):
|
||||
|
@ -143,6 +146,7 @@ PODS:
|
|||
- FlutterMacOS
|
||||
- SwiftProtobuf (1.22.0)
|
||||
- SwiftyGif (5.4.4)
|
||||
- Toast (4.0.0)
|
||||
- uni_links (0.0.1):
|
||||
- Flutter
|
||||
- UnstoppableDomainsResolution (4.0.0):
|
||||
|
@ -171,6 +175,7 @@ DEPENDENCIES:
|
|||
- flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`)
|
||||
- flutter_mailer (from `.symlinks/plugins/flutter_mailer/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- fluttertoast (from `.symlinks/plugins/fluttertoast/ios`)
|
||||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||
|
@ -198,6 +203,7 @@ SPEC REPOS:
|
|||
- SDWebImage
|
||||
- SwiftProtobuf
|
||||
- SwiftyGif
|
||||
- Toast
|
||||
- UnstoppableDomainsResolution
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
|
@ -229,6 +235,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/flutter_mailer/ios"
|
||||
flutter_secure_storage:
|
||||
:path: ".symlinks/plugins/flutter_secure_storage/ios"
|
||||
fluttertoast:
|
||||
:path: ".symlinks/plugins/fluttertoast/ios"
|
||||
in_app_review:
|
||||
:path: ".symlinks/plugins/in_app_review/ios"
|
||||
local_auth_ios:
|
||||
|
@ -275,6 +283,7 @@ SPEC CHECKSUMS:
|
|||
flutter_inappwebview: 3d32228f1304635e7c028b0d4252937730bbc6cf
|
||||
flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83
|
||||
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
|
||||
fluttertoast: eb263d302cc92e04176c053d2385237e9f43fad0
|
||||
in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d
|
||||
local_auth_ios: c6cf091ded637a88f24f86a8875d8b0f526e2605
|
||||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
|
@ -290,9 +299,10 @@ SPEC CHECKSUMS:
|
|||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
|
||||
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
|
||||
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
|
||||
uni_links: d97da20c7701486ba192624d99bffaaffcfc298a
|
||||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
url_launcher_ios: 68d46cc9766d0c41dbdc884310529557e3cd7a86
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class RobinhoodBuyProvider {
|
|||
case WalletType.bitcoin:
|
||||
return _wallet.signMessage(message, address: _wallet.walletAddresses.address);
|
||||
default:
|
||||
throw Exception("WalletType is not available for Robinhood");
|
||||
throw Exception("WalletType is not available for Robinhood ${_wallet.type}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -246,6 +246,12 @@ class BackupService {
|
|||
final sortBalanceTokensBy = data[PreferencesKey.sortBalanceBy] as int?;
|
||||
final pinNativeTokenAtTop = data[PreferencesKey.pinNativeTokenAtTop] as bool?;
|
||||
final useEtherscan = data[PreferencesKey.useEtherscan] as bool?;
|
||||
final lookupsTwitter = data[PreferencesKey.lookupsTwitter] as bool?;
|
||||
final lookupsMastodon = data[PreferencesKey.lookupsMastodon] as bool?;
|
||||
final lookupsYatService = data[PreferencesKey.lookupsYatService] as bool?;
|
||||
final lookupsUnstoppableDomains = data[PreferencesKey.lookupsUnstoppableDomains] as bool?;
|
||||
final lookupsOpenAlias = data[PreferencesKey.lookupsOpenAlias] as bool?;
|
||||
final lookupsENS = data[PreferencesKey.lookupsENS] as bool?;
|
||||
final syncAll = data[PreferencesKey.syncAllKey] as bool?;
|
||||
final syncMode = data[PreferencesKey.syncModeKey] as int?;
|
||||
final autoGenerateSubaddressStatus = data[PreferencesKey.autoGenerateSubaddressStatusKey] as int?;
|
||||
|
@ -285,7 +291,7 @@ class BackupService {
|
|||
await _sharedPreferences.setInt(
|
||||
PreferencesKey.currentTransactionPriorityKeyLegacy, currentTransactionPriorityKeyLegacy);
|
||||
|
||||
if (allowBiometricalAuthentication != null)
|
||||
if (allowBiometricalAuthentication != null && !Platform.isMacOS && !Platform.isLinux)
|
||||
await _sharedPreferences.setBool(
|
||||
PreferencesKey.allowBiometricalAuthenticationKey, allowBiometricalAuthentication);
|
||||
|
||||
|
@ -373,6 +379,24 @@ class BackupService {
|
|||
if (useEtherscan != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan);
|
||||
|
||||
if (lookupsTwitter != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsTwitter, lookupsTwitter);
|
||||
|
||||
if (lookupsMastodon != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsMastodon, lookupsMastodon);
|
||||
|
||||
if (lookupsYatService != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsYatService, lookupsYatService);
|
||||
|
||||
if (lookupsUnstoppableDomains != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsUnstoppableDomains, lookupsUnstoppableDomains);
|
||||
|
||||
if (lookupsOpenAlias != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsOpenAlias, lookupsOpenAlias);
|
||||
|
||||
if (lookupsENS != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.lookupsENS, lookupsENS);
|
||||
|
||||
if (syncAll != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
||||
|
||||
|
@ -529,6 +553,18 @@ class BackupService {
|
|||
_sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop),
|
||||
PreferencesKey.useEtherscan:
|
||||
_sharedPreferences.getBool(PreferencesKey.useEtherscan),
|
||||
PreferencesKey.lookupsTwitter:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsTwitter),
|
||||
PreferencesKey.lookupsMastodon:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsMastodon),
|
||||
PreferencesKey.lookupsYatService:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsYatService),
|
||||
PreferencesKey.lookupsUnstoppableDomains:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains),
|
||||
PreferencesKey.lookupsOpenAlias:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias),
|
||||
PreferencesKey.lookupsENS:
|
||||
_sharedPreferences.getBool(PreferencesKey.lookupsENS),
|
||||
PreferencesKey.syncModeKey:
|
||||
_sharedPreferences.getInt(PreferencesKey.syncModeKey),
|
||||
PreferencesKey.syncAllKey:
|
||||
|
|
|
@ -6,7 +6,7 @@ import 'package:cake_wallet/core/wallet_connect/eth_transaction_model.dart';
|
|||
import 'package:cake_wallet/core/wallet_connect/evm_chain_id.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/wc_bottom_sheet_service.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/error_display_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/models/connection_model.dart';
|
||||
|
|
|
@ -10,7 +10,7 @@ import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
|
|||
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
|
||||
import 'package:cake_wallet/core/wallet_connect/models/session_request_model.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/connection_request_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/error_display_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/message_display_widget.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/widgets/modals/web3_request_modal.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:eth_sig_util/eth_sig_util.dart';
|
||||
|
@ -200,6 +200,24 @@ abstract class Web3WalletServiceBase with Store {
|
|||
);
|
||||
}
|
||||
|
||||
@action
|
||||
Future<void> pairWithUri(Uri uri) async {
|
||||
try {
|
||||
log('Pairing with URI: $uri');
|
||||
await _web3Wallet.pair(uri: uri);
|
||||
} on WalletConnectError catch (e) {
|
||||
_bottomSheetHandler.queueBottomSheet(
|
||||
isModalDismissible: true,
|
||||
widget: BottomSheetMessageDisplayWidget(message: e.message),
|
||||
);
|
||||
} catch (e) {
|
||||
_bottomSheetHandler.queueBottomSheet(
|
||||
isModalDismissible: true,
|
||||
widget: BottomSheetMessageDisplayWidget(message: e.toString()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void _onPairingCreate(PairingEvent? args) {
|
||||
log('Pairing Create Event: $args');
|
||||
}
|
||||
|
|
24
lib/di.dart
|
@ -38,6 +38,7 @@ import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
|||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/wallet_restore_choose_derivation.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/domain_lookups_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
|
@ -53,6 +54,7 @@ import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
|
|||
import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
|
||||
import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
|
@ -222,6 +224,7 @@ import 'package:cw_core/crypto_currency.dart';
|
|||
import 'package:cake_wallet/entities/qr_view_data.dart';
|
||||
|
||||
import 'core/totp_request_details.dart';
|
||||
import 'src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
||||
|
||||
final getIt = GetIt.instance;
|
||||
|
||||
|
@ -250,6 +253,7 @@ Future<void> setup({
|
|||
required Box<Order> ordersSource,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||
required FlutterSecureStorage secureStorage,
|
||||
}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
|
@ -279,7 +283,7 @@ Future<void> setup({
|
|||
powNodeSource: _powNodeSource,
|
||||
isBitcoinBuyEnabled: isBitcoinBuyEnabled,
|
||||
// Enforce darkTheme on platforms other than mobile till the design for other themes is completed
|
||||
initialTheme: ResponsiveLayoutUtil.instance.isMobile && DeviceInfo.instance.isMobile
|
||||
initialTheme: responsiveLayoutUtil.shouldRenderMobileUI && DeviceInfo.instance.isMobile
|
||||
? null
|
||||
: ThemeList.darkTheme,
|
||||
);
|
||||
|
@ -291,7 +295,7 @@ Future<void> setup({
|
|||
getIt.registerFactory<Box<Node>>(() => _nodeSource);
|
||||
getIt.registerFactory<Box<Node>>(() => _powNodeSource, instanceName: Node.boxName + "pow");
|
||||
|
||||
getIt.registerSingleton<FlutterSecureStorage>(FlutterSecureStorage());
|
||||
getIt.registerSingleton<FlutterSecureStorage>(secureStorage);
|
||||
getIt.registerSingleton(AuthenticationStore());
|
||||
getIt.registerSingleton<WalletListStore>(WalletListStore());
|
||||
getIt.registerSingleton(NodeListStoreBase.instance);
|
||||
|
@ -489,6 +493,7 @@ Future<void> setup({
|
|||
getIt.registerFactory<DesktopSidebarWrapper>(() {
|
||||
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
|
||||
return DesktopSidebarWrapper(
|
||||
bottomSheetService: getIt.get<BottomSheetService>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
desktopSidebarViewModel: getIt.get<DesktopSidebarViewModel>(),
|
||||
child: getIt.get<DesktopDashboardPage>(param1: _navigatorKey),
|
||||
|
@ -497,7 +502,6 @@ Future<void> setup({
|
|||
});
|
||||
getIt.registerFactoryParam<DesktopDashboardPage, GlobalKey<NavigatorState>, void>(
|
||||
(desktopKey, _) => DesktopDashboardPage(
|
||||
bottomSheetService: getIt.get<BottomSheetService>(),
|
||||
balancePage: getIt.get<BalancePage>(),
|
||||
dashboardViewModel: getIt.get<DashboardViewModel>(),
|
||||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
|
@ -516,6 +520,9 @@ Future<void> setup({
|
|||
getIt.registerFactory<Modify2FAPage>(
|
||||
() => Modify2FAPage(setup2FAViewModel: getIt.get<Setup2FAViewModel>()));
|
||||
|
||||
getIt.registerFactory<DesktopSettingsPage>(
|
||||
() => DesktopSettingsPage());
|
||||
|
||||
getIt.registerFactoryParam<ReceiveOptionViewModel, ReceivePageOption?, void>(
|
||||
(pageOption, _) => ReceiveOptionViewModel(getIt.get<AppStore>().wallet!, pageOption));
|
||||
|
||||
|
@ -747,6 +754,8 @@ Future<void> setup({
|
|||
|
||||
getIt.registerFactory(() => PrivacyPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => DomainLookupsPage(getIt.get<PrivacySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => DisplaySettingsPage(getIt.get<DisplaySettingsViewModel>()));
|
||||
|
||||
getIt.registerFactory(() => OtherSettingsPage(getIt.get<OtherSettingsViewModel>()));
|
||||
|
@ -984,7 +993,10 @@ Future<void> setup({
|
|||
getIt.registerFactory(() => YatService());
|
||||
|
||||
getIt.registerFactory(() =>
|
||||
AddressResolver(yatService: getIt.get<YatService>(), wallet: getIt.get<AppStore>().wallet!));
|
||||
AddressResolver(
|
||||
yatService: getIt.get<YatService>(),
|
||||
wallet: getIt.get<AppStore>().wallet!,
|
||||
settingsStore: getIt.get<SettingsStore>()));
|
||||
|
||||
getIt.registerFactoryParam<FullscreenQRPage, QrViewData, void>(
|
||||
(QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData));
|
||||
|
@ -1157,5 +1169,9 @@ Future<void> setup({
|
|||
return ManageNodesPage(isPow, nodeListViewModel: getIt.get<NodeListViewModel>());
|
||||
});
|
||||
|
||||
getIt.registerFactory(
|
||||
() => WalletConnectConnectionsView(web3walletService: getIt.get<Web3WalletService>()));
|
||||
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ enum VerboseControlSettings {
|
|||
sendsToNonContacts,
|
||||
sendsToInternalWallets,
|
||||
exchangesToInternalWallets,
|
||||
exchangesToExternalWallets,
|
||||
securityAndBackupSettings,
|
||||
creatingNewWallets,
|
||||
}
|
||||
|
|
|
@ -191,63 +191,70 @@ Future<void> defaultSettingsMigration(
|
|||
}
|
||||
|
||||
Future<void> _validateWalletInfoBoxData(Box<WalletInfo> walletInfoSource) async {
|
||||
final root = await getApplicationDocumentsDirectory();
|
||||
try {
|
||||
final root = await getApplicationDocumentsDirectory();
|
||||
|
||||
for (var type in WalletType.values) {
|
||||
if (type == WalletType.none) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String prefix = walletTypeToString(type).toLowerCase();
|
||||
Directory walletsDir = Directory('${root.path}/wallets/$prefix/');
|
||||
|
||||
if (!walletsDir.existsSync()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<String> walletNames = walletsDir.listSync().map((e) => e.path.split("/").last).toList();
|
||||
|
||||
for (var name in walletNames) {
|
||||
final dir = Directory(await pathForWalletDir(name: name, type: type));
|
||||
|
||||
final walletFiles = dir.listSync();
|
||||
final hasCacheFile = walletFiles.any((element) => element.path.contains("$name/$name"));
|
||||
|
||||
if (!hasCacheFile) {
|
||||
for (var type in WalletType.values) {
|
||||
if (type == WalletType.none) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == WalletType.monero || type == WalletType.haven) {
|
||||
final hasKeysFile = walletFiles.any((element) => element.path.contains(".keys"));
|
||||
String prefix = walletTypeToString(type).toLowerCase();
|
||||
Directory walletsDir = Directory('${root.path}/wallets/$prefix/');
|
||||
|
||||
if (!hasKeysFile) {
|
||||
if (!walletsDir.existsSync()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<String> walletNames = walletsDir.listSync().map((e) => e.path.split("/").last).toList();
|
||||
|
||||
for (var name in walletNames) {
|
||||
final Directory dir;
|
||||
try {
|
||||
dir = Directory(await pathForWalletDir(name: name, type: type));
|
||||
} catch (_) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final walletFiles = dir.listSync();
|
||||
final hasCacheFile = walletFiles.any((element) => element.path.contains("$name/$name"));
|
||||
|
||||
if (!hasCacheFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type == WalletType.monero || type == WalletType.haven) {
|
||||
final hasKeysFile = walletFiles.any((element) => element.path.contains(".keys"));
|
||||
|
||||
if (!hasKeysFile) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
final id = prefix + '_' + name;
|
||||
final exist = walletInfoSource.values.any((el) => el.id == id);
|
||||
|
||||
if (exist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final walletInfo = WalletInfo.external(
|
||||
id: id,
|
||||
type: type,
|
||||
name: name,
|
||||
isRecovery: true,
|
||||
restoreHeight: 0,
|
||||
date: DateTime.now(),
|
||||
dirPath: dir.path,
|
||||
path: '${dir.path}/$name',
|
||||
address: '',
|
||||
showIntroCakePayCard: false,
|
||||
);
|
||||
|
||||
walletInfoSource.add(walletInfo);
|
||||
}
|
||||
|
||||
final id = prefix + '_' + name;
|
||||
final exist = walletInfoSource.values.any((el) => el.id == id);
|
||||
|
||||
if (exist) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final walletInfo = WalletInfo.external(
|
||||
id: id,
|
||||
type: type,
|
||||
name: name,
|
||||
isRecovery: true,
|
||||
restoreHeight: 0,
|
||||
date: DateTime.now(),
|
||||
dirPath: dir.path,
|
||||
path: '${dir.path}/$name',
|
||||
address: '',
|
||||
showIntroCakePayCard: false,
|
||||
);
|
||||
|
||||
walletInfoSource.add(walletInfo);
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future<void> validateBitcoinSavedTransactionPriority(SharedPreferences sharedPreferences) async {
|
||||
|
|
|
@ -54,7 +54,7 @@ class MainActions {
|
|||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.ethereum:
|
||||
case WalletType.bitcoinCash:
|
||||
// case WalletType.bitcoinCash: // TODO: add sign message function to BCH first
|
||||
switch (defaultBuyProvider) {
|
||||
case BuyProviderType.AskEachTime:
|
||||
Navigator.pushNamed(context, Routes.buy);
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:cake_wallet/entities/parsed_address.dart';
|
|||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
||||
import 'package:cake_wallet/mastodon/mastodon_api.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/twitter/twitter_api.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -13,11 +14,13 @@ import 'package:cw_core/wallet_type.dart';
|
|||
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||
|
||||
class AddressResolver {
|
||||
AddressResolver({required this.yatService, required this.wallet}) : walletType = wallet.type;
|
||||
AddressResolver({required this.yatService, required this.wallet, required this.settingsStore})
|
||||
: walletType = wallet.type;
|
||||
|
||||
final YatService yatService;
|
||||
final WalletType walletType;
|
||||
final WalletBase wallet;
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
static const unstoppableDomains = [
|
||||
'crypto',
|
||||
|
@ -46,62 +49,67 @@ class AddressResolver {
|
|||
}
|
||||
|
||||
final match = RegExp(addressPattern).firstMatch(raw);
|
||||
return match?.group(0)?.replaceAll(RegExp('[^0-9a-zA-Z]'), '');
|
||||
return match?.group(0)?.replaceAllMapped(RegExp('[^0-9a-zA-Z]|bitcoincash:|nano_'), (Match match) {
|
||||
String group = match.group(0)!;
|
||||
if (group.startsWith('bitcoincash:') || group.startsWith('nano_')) {
|
||||
return group;
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}
|
||||
|
||||
Future<ParsedAddress> resolve(String text, String ticker) async {
|
||||
try {
|
||||
if (text.startsWith('@') && !text.substring(1).contains('@')) {
|
||||
final formattedName = text.substring(1);
|
||||
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
||||
final addressFromBio = extractAddressByType(
|
||||
raw: twitterUser.description, type: CryptoCurrency.fromString(ticker));
|
||||
if (addressFromBio != null) {
|
||||
return ParsedAddress.fetchTwitterAddress(address: addressFromBio, name: text);
|
||||
}
|
||||
final tweets = twitterUser.tweets;
|
||||
if (tweets != null) {
|
||||
var subString = StringBuffer();
|
||||
tweets.forEach((item) {
|
||||
subString.writeln(item.text);
|
||||
});
|
||||
final userTweetsText = subString.toString();
|
||||
final addressFromPinnedTweet =
|
||||
extractAddressByType(raw: userTweetsText, type: CryptoCurrency.fromString(ticker));
|
||||
if(settingsStore.lookupsTwitter) {
|
||||
final formattedName = text.substring(1);
|
||||
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
||||
final addressFromBio = extractAddressByType(
|
||||
raw: twitterUser.description, type: CryptoCurrency.fromString(ticker));
|
||||
if (addressFromBio != null) {
|
||||
return ParsedAddress.fetchTwitterAddress(address: addressFromBio, name: text);
|
||||
}
|
||||
|
||||
if (addressFromPinnedTweet != null) {
|
||||
return ParsedAddress.fetchTwitterAddress(address: addressFromPinnedTweet, name: text);
|
||||
final pinnedTweet = twitterUser.pinnedTweet?.text;
|
||||
if (pinnedTweet != null) {
|
||||
final addressFromPinnedTweet =
|
||||
extractAddressByType(raw: pinnedTweet, type: CryptoCurrency.fromString(ticker));
|
||||
if (addressFromPinnedTweet != null) {
|
||||
return ParsedAddress.fetchTwitterAddress(address: addressFromPinnedTweet, name: text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (text.startsWith('@') && text.contains('@', 1) && text.contains('.', 1)) {
|
||||
final subText = text.substring(1);
|
||||
final hostNameIndex = subText.indexOf('@');
|
||||
final hostName = subText.substring(hostNameIndex + 1);
|
||||
final userName = subText.substring(0, hostNameIndex);
|
||||
if (settingsStore.lookupsMastodon) {
|
||||
final subText = text.substring(1);
|
||||
final hostNameIndex = subText.indexOf('@');
|
||||
final hostName = subText.substring(hostNameIndex + 1);
|
||||
final userName = subText.substring(0, hostNameIndex);
|
||||
|
||||
final mastodonUser =
|
||||
await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
|
||||
final mastodonUser =
|
||||
await MastodonAPI.lookupUserByUserName(userName: userName, apiHost: hostName);
|
||||
|
||||
if (mastodonUser != null) {
|
||||
String? addressFromBio =
|
||||
extractAddressByType(raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
|
||||
if (mastodonUser != null) {
|
||||
String? addressFromBio =
|
||||
extractAddressByType(raw: mastodonUser.note, type: CryptoCurrency.fromString(ticker));
|
||||
|
||||
if (addressFromBio != null) {
|
||||
return ParsedAddress.fetchMastodonAddress(address: addressFromBio, name: text);
|
||||
} else {
|
||||
final pinnedPosts =
|
||||
await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
|
||||
if (addressFromBio != null) {
|
||||
return ParsedAddress.fetchMastodonAddress(address: addressFromBio, name: text);
|
||||
} else {
|
||||
final pinnedPosts =
|
||||
await MastodonAPI.getPinnedPosts(userId: mastodonUser.id, apiHost: hostName);
|
||||
|
||||
if (pinnedPosts.isNotEmpty) {
|
||||
final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n');
|
||||
String? addressFromPinnedPost = extractAddressByType(
|
||||
raw: userPinnedPostsText, type: CryptoCurrency.fromString(ticker));
|
||||
if (pinnedPosts.isNotEmpty) {
|
||||
final userPinnedPostsText = pinnedPosts.map((item) => item.content).join('\n');
|
||||
String? addressFromPinnedPost = extractAddressByType(
|
||||
raw: userPinnedPostsText, type: CryptoCurrency.fromString(ticker));
|
||||
|
||||
if (addressFromPinnedPost != null) {
|
||||
return ParsedAddress.fetchMastodonAddress(
|
||||
address: addressFromPinnedPost, name: text);
|
||||
if (addressFromPinnedPost != null) {
|
||||
return ParsedAddress.fetchMastodonAddress(
|
||||
address: addressFromPinnedPost, name: text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,9 +124,11 @@ class AddressResolver {
|
|||
}
|
||||
}
|
||||
if (text.hasOnlyEmojis) {
|
||||
if (walletType != WalletType.haven) {
|
||||
final addresses = await yatService.fetchYatAddress(text, ticker);
|
||||
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
||||
if(settingsStore.lookupsYatService) {
|
||||
if (walletType != WalletType.haven) {
|
||||
final addresses = await yatService.fetchYatAddress(text, ticker);
|
||||
return ParsedAddress.fetchEmojiAddress(addresses: addresses, name: text);
|
||||
}
|
||||
}
|
||||
}
|
||||
final formattedName = OpenaliasRecord.formatDomainName(text);
|
||||
|
@ -130,23 +140,29 @@ class AddressResolver {
|
|||
}
|
||||
|
||||
if (unstoppableDomains.any((domain) => name.trim() == domain)) {
|
||||
final address = await fetchUnstoppableDomainAddress(text, ticker);
|
||||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||
if(settingsStore.lookupsUnstoppableDomains) {
|
||||
final address = await fetchUnstoppableDomainAddress(text, ticker);
|
||||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||
}
|
||||
}
|
||||
|
||||
if (text.endsWith(".eth")) {
|
||||
final address = await EnsRecord.fetchEnsAddress(text, wallet: wallet);
|
||||
if (address.isNotEmpty && address != "0x0000000000000000000000000000000000000000") {
|
||||
return ParsedAddress.fetchEnsAddress(name: text, address: address);
|
||||
if (settingsStore.lookupsENS) {
|
||||
final address = await EnsRecord.fetchEnsAddress(text, wallet: wallet);
|
||||
if (address.isNotEmpty && address != "0x0000000000000000000000000000000000000000") {
|
||||
return ParsedAddress.fetchEnsAddress(name: text, address: address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (formattedName.contains(".")) {
|
||||
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
||||
if (txtRecord != null) {
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
formattedName: formattedName, ticker: ticker, txtRecord: txtRecord);
|
||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||
if(settingsStore.lookupsOpenAlias) {
|
||||
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
||||
if (txtRecord != null) {
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
formattedName: formattedName, ticker: ticker, txtRecord: txtRecord);
|
||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
|
@ -51,6 +51,12 @@ class PreferencesKey {
|
|||
static const sortBalanceBy = 'sort_balance_by';
|
||||
static const pinNativeTokenAtTop = 'pin_native_token_at_top';
|
||||
static const useEtherscan = 'use_etherscan';
|
||||
static const lookupsTwitter = 'looks_up_twitter';
|
||||
static const lookupsMastodon = 'looks_up_mastodon';
|
||||
static const lookupsYatService = 'looks_up_mastodon';
|
||||
static const lookupsUnstoppableDomains = 'looks_up_mastodon';
|
||||
static const lookupsOpenAlias = 'looks_up_mastodon';
|
||||
static const lookupsENS = 'looks_up_ens';
|
||||
|
||||
static String moneroWalletUpdateV1Key(String name) =>
|
||||
'${PreferencesKey.moneroWalletPasswordUpdateV1Base}_${name}';
|
||||
|
@ -72,6 +78,8 @@ class PreferencesKey {
|
|||
'should_require_totp_2fa_for_sends_to_internal_wallets';
|
||||
static const shouldRequireTOTP2FAForExchangesToInternalWallets =
|
||||
'should_require_totp_2fa_for_exchanges_to_internal_wallets';
|
||||
static const shouldRequireTOTP2FAForExchangesToExternalWallets =
|
||||
'should_require_totp_2fa_for_exchanges_to_external_wallets';
|
||||
static const shouldRequireTOTP2FAForAddingContacts =
|
||||
'should_require_totp_2fa_for_adding_contacts';
|
||||
static const shouldRequireTOTP2FAForCreatingNewWallets =
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
|
||||
class ChangeNowRequest extends TradeRequest {
|
||||
ChangeNowRequest(
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.fromAmount,
|
||||
required this.toAmount,
|
||||
required this.refundAddress,
|
||||
required this.isReverse});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
String address;
|
||||
String fromAmount;
|
||||
String toAmount;
|
||||
String refundAddress;
|
||||
bool isReverse;
|
||||
}
|
|
@ -1,10 +1,7 @@
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class ExchangePair {
|
||||
ExchangePair({
|
||||
required this.from,
|
||||
required this.to,
|
||||
this.reverse = true});
|
||||
ExchangePair({required this.from, required this.to, this.reverse = true});
|
||||
|
||||
final CryptoCurrency from;
|
||||
final CryptoCurrency to;
|
||||
|
|
|
@ -14,16 +14,12 @@ class ExchangeProviderDescription extends EnumerableItem<int> with Serializable<
|
|||
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1, image: 'assets/images/changenow.png');
|
||||
static const morphToken =
|
||||
ExchangeProviderDescription(title: 'MorphToken', raw: 2, image: 'assets/images/morph.png');
|
||||
|
||||
static const sideShift =
|
||||
ExchangeProviderDescription(title: 'SideShift', raw: 3, image: 'assets/images/sideshift.png');
|
||||
|
||||
static const simpleSwap = ExchangeProviderDescription(
|
||||
title: 'SimpleSwap', raw: 4, image: 'assets/images/simpleSwap.png');
|
||||
|
||||
static const trocador =
|
||||
ExchangeProviderDescription(title: 'Trocador', raw: 5, image: 'assets/images/trocador.png');
|
||||
|
||||
static const exolix =
|
||||
ExchangeProviderDescription(title: 'Exolix', raw: 6, image: 'assets/images/exolix.png');
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
|
||||
abstract class ExchangeTradeState {}
|
||||
|
@ -18,4 +17,4 @@ class TradeIsCreatedFailure extends ExchangeTradeState {
|
|||
|
||||
final String title;
|
||||
final String error;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
|
||||
class ExolixRequest extends TradeRequest {
|
||||
ExolixRequest(
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.fromAmount,
|
||||
required this.toAmount,
|
||||
required this.refundAddress});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
String address;
|
||||
String fromAmount;
|
||||
String toAmount;
|
||||
String refundAddress;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
class Limits {
|
||||
const Limits({this.min, this.max});
|
||||
|
||||
|
||||
final double? min;
|
||||
final double? max;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
|
||||
abstract class LimitsState {}
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cw_core/amount_converter.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/morphtoken/morphtoken_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
|
||||
class MorphTokenExchangeProvider extends ExchangeProvider {
|
||||
MorphTokenExchangeProvider({required this.trades})
|
||||
: super(pairList: [
|
||||
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.eth),
|
||||
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.bch),
|
||||
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.ltc),
|
||||
ExchangePair(from: CryptoCurrency.xmr, to: CryptoCurrency.dash),
|
||||
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.btc),
|
||||
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.eth),
|
||||
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.bch),
|
||||
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.ltc),
|
||||
ExchangePair(from: CryptoCurrency.dash, to: CryptoCurrency.xmr),
|
||||
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.btc),
|
||||
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.eth),
|
||||
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.bch),
|
||||
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.dash),
|
||||
ExchangePair(from: CryptoCurrency.ltc, to: CryptoCurrency.xmr),
|
||||
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.btc),
|
||||
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.eth),
|
||||
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.ltc),
|
||||
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.dash),
|
||||
ExchangePair(from: CryptoCurrency.bch, to: CryptoCurrency.xmr),
|
||||
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.btc),
|
||||
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.bch),
|
||||
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.ltc),
|
||||
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.dash),
|
||||
ExchangePair(from: CryptoCurrency.eth, to: CryptoCurrency.xmr),
|
||||
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.eth),
|
||||
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.bch),
|
||||
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.ltc),
|
||||
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.dash),
|
||||
ExchangePair(from: CryptoCurrency.btc, to: CryptoCurrency.xmr)
|
||||
]);
|
||||
|
||||
Box<Trade> trades;
|
||||
|
||||
static const apiUri = 'https://api.morphtoken.com';
|
||||
static const _morphURISuffix = '/morph';
|
||||
static const _limitsURISuffix = '/limits';
|
||||
static const _ratesURISuffix = '/rates';
|
||||
static const weight = 10000;
|
||||
|
||||
@override
|
||||
String get title => 'MorphToken';
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.morphToken;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final url = apiUri + _limitsURISuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final headers = {'Content-type': 'application/json'};
|
||||
final body = json.encode({
|
||||
"input": {"asset": from.toString()},
|
||||
"output": [
|
||||
{"asset": to.toString(), "weight": weight}
|
||||
]
|
||||
});
|
||||
final response = await post(uri, headers: headers, body: body);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
final min = responseJSON['input']['limits']['min'] as int;
|
||||
int max = 0;
|
||||
double ethMax;
|
||||
|
||||
if (from == CryptoCurrency.eth) {
|
||||
ethMax = responseJSON['input']['limits']['max'] as double;
|
||||
} else {
|
||||
max = responseJSON['input']['limits']['max'] as int;
|
||||
}
|
||||
|
||||
final minFormatted = AmountConverter.amountIntToDouble(from, min);
|
||||
final maxFormatted = AmountConverter.amountIntToDouble(from, max);
|
||||
|
||||
return Limits(min: minFormatted, max: maxFormatted);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({
|
||||
required TradeRequest request,
|
||||
required bool isFixedRateMode}) async {
|
||||
const url = apiUri + _morphURISuffix;
|
||||
final _request = request as MorphTokenRequest;
|
||||
final body = {
|
||||
"input": {
|
||||
"asset": _request.from.toString(),
|
||||
"refund": _request.refundAddress
|
||||
},
|
||||
"output": [
|
||||
{
|
||||
"asset": _request.to.toString(),
|
||||
"weight": weight,
|
||||
"address": _request.address
|
||||
}
|
||||
],
|
||||
"tag": "cakewallet"
|
||||
};
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri,
|
||||
headers: {'Content-Type': 'application/json'}, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['description'] as String;
|
||||
|
||||
throw TradeNotCreatedException(description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
provider: description,
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
state: TradeState.created,
|
||||
amount: _request.amount,
|
||||
createdAt: DateTime.now());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final url = apiUri + _morphURISuffix + '/' + id;
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['description'] as String;
|
||||
|
||||
throw TradeNotFoundException(id,
|
||||
provider: description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotFoundException(id, provider: description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['input']['asset'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency.toLowerCase());
|
||||
final toCurrency = responseJSON['output'][0]['asset'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency.toLowerCase());
|
||||
final inputAddress = responseJSON['input']['deposit_address'] as String;
|
||||
final status = responseJSON['state'] as String;
|
||||
final state = TradeState.deserialize(raw: status.toLowerCase());
|
||||
|
||||
String amount = "";
|
||||
for (final trade in trades.values) {
|
||||
if (trade.id == id) {
|
||||
amount = trade.amount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: amount,
|
||||
state: state);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
final url = apiUri + _ratesURISuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final rate = responseJSON['data'][from.toString()][to.toString()] as String;
|
||||
|
||||
try {
|
||||
final estimatedAmount = double.parse(rate) * amount;
|
||||
return estimatedAmount;
|
||||
} catch (_) {
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
|
||||
class MorphTokenRequest extends TradeRequest {
|
||||
MorphTokenRequest(
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.amount,
|
||||
required this.refundAddress});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
String address;
|
||||
String amount;
|
||||
String refundAddress;
|
||||
}
|
|
@ -1,33 +1,32 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/distribution_info.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/changenow/changenow_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||
ChangeNowExchangeProvider({required this.settingsStore})
|
||||
: _lastUsedRateId = '',
|
||||
super(
|
||||
pairList: CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.xhv)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
ChangeNowExchangeProvider({required SettingsStore settingsStore})
|
||||
: _settingsStore = settingsStore,
|
||||
_lastUsedRateId = '',
|
||||
super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.zaddr,
|
||||
CryptoCurrency.xhv,
|
||||
];
|
||||
|
||||
static final apiKey =
|
||||
DeviceInfo.instance.isMobile ? secrets.changeNowApiKey : secrets.changeNowApiKeyDesktop;
|
||||
|
@ -38,6 +37,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
static const rangePath = '/v2/exchange/range';
|
||||
static const apiHeaderKey = 'x-changenow-api-key';
|
||||
|
||||
final SettingsStore _settingsStore;
|
||||
String _lastUsedRateId;
|
||||
|
||||
@override
|
||||
String get title => 'ChangeNOW';
|
||||
|
||||
|
@ -56,25 +58,18 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
final SettingsStore settingsStore;
|
||||
|
||||
String _lastUsedRateId;
|
||||
|
||||
static String getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final params = <String, String>{
|
||||
'fromCurrency': _normalizeCurrency(from),
|
||||
'toCurrency': _normalizeCurrency(to),
|
||||
'fromNetwork': _networkFor(from),
|
||||
'toNetwork': _networkFor(to),
|
||||
'flow': flow
|
||||
'flow': _getFlow(isFixedRateMode)
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, rangePath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
|
@ -86,20 +81,61 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
throw Exception('${error}\n$message');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
return Limits(
|
||||
min: responseJSON['minAmount'] as double?, max: responseJSON['maxAmount'] as double?);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) return 0.0;
|
||||
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final isReverse = isReceiveAmount;
|
||||
final type = isReverse ? 'reverse' : 'direct';
|
||||
final params = <String, String>{
|
||||
'fromCurrency': _normalizeCurrency(from),
|
||||
'toCurrency': _normalizeCurrency(to),
|
||||
'fromNetwork': _networkFor(from),
|
||||
'toNetwork': _networkFor(to),
|
||||
'type': type,
|
||||
'flow': _getFlow(isFixedRateMode)
|
||||
};
|
||||
|
||||
if (isReverse)
|
||||
params['toAmount'] = amount.toString();
|
||||
else
|
||||
params['fromAmount'] = amount.toString();
|
||||
|
||||
final uri = Uri.https(apiAuthority, estimatedAmountPath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromAmount = double.parse(responseJSON['fromAmount'].toString());
|
||||
final toAmount = double.parse(responseJSON['toAmount'].toString());
|
||||
final rateId = responseJSON['rateId'] as String? ?? '';
|
||||
|
||||
if (rateId.isNotEmpty) _lastUsedRateId = rateId;
|
||||
|
||||
return isReverse ? (amount / fromAmount) : (toAmount / amount);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as ChangeNowRequest;
|
||||
final distributionPath = await DistributionInfo.instance.getDistributionPath();
|
||||
final formattedAppVersion = int.tryParse(settingsStore.appVersion.replaceAll('.', '')) ?? 0;
|
||||
final formattedAppVersion = int.tryParse(_settingsStore.appVersion.replaceAll('.', '')) ?? 0;
|
||||
final payload = {
|
||||
'app': isMoneroOnly ? 'monerocom' : 'cakewallet',
|
||||
'device': Platform.operatingSystem,
|
||||
|
@ -107,19 +143,18 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
'version': formattedAppVersion
|
||||
};
|
||||
final headers = {apiHeaderKey: apiKey, 'Content-Type': 'application/json'};
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final type = isFixedRateMode ? 'reverse' : 'direct';
|
||||
final body = <String, dynamic>{
|
||||
'fromCurrency': _normalizeCurrency(_request.from),
|
||||
'toCurrency': _normalizeCurrency(_request.to),
|
||||
'fromNetwork': _networkFor(_request.from),
|
||||
'toNetwork': _networkFor(_request.to),
|
||||
if (!isFixedRateMode) 'fromAmount': _request.fromAmount,
|
||||
if (isFixedRateMode) 'toAmount': _request.toAmount,
|
||||
'address': _request.address,
|
||||
'flow': flow,
|
||||
'fromCurrency': _normalizeCurrency(request.fromCurrency),
|
||||
'toCurrency': _normalizeCurrency(request.toCurrency),
|
||||
'fromNetwork': _networkFor(request.fromCurrency),
|
||||
'toNetwork': _networkFor(request.toCurrency),
|
||||
if (!isFixedRateMode) 'fromAmount': request.fromAmount,
|
||||
if (isFixedRateMode) 'toAmount': request.toAmount,
|
||||
'address': request.toAddress,
|
||||
'flow': _getFlow(isFixedRateMode),
|
||||
'type': type,
|
||||
'refundAddress': _request.refundAddress,
|
||||
'refundAddress': request.refundAddress,
|
||||
'payload': payload,
|
||||
};
|
||||
|
||||
|
@ -127,9 +162,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
// since we schedule to calculate the rate every 5 seconds we need to ensure that
|
||||
// we have the latest rate id with the given inputs before creating the trade
|
||||
await fetchRate(
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
amount: double.tryParse(_request.toAmount) ?? 0,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
amount: double.tryParse(request.toAmount) ?? 0,
|
||||
isFixedRateMode: true,
|
||||
isReceiveAmount: true,
|
||||
);
|
||||
|
@ -146,9 +181,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
throw Exception('${error}\n$message');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
|
@ -159,14 +193,14 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: refundAddress,
|
||||
extraId: extraId,
|
||||
createdAt: DateTime.now(),
|
||||
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
||||
amount: responseJSON['fromAmount']?.toString() ?? request.fromAmount,
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
@ -178,9 +212,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final uri = Uri.https(apiAuthority, findTradeByIdPath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
|
||||
if (response.statusCode == 404) {
|
||||
throw TradeNotFoundException(id, provider: description);
|
||||
}
|
||||
if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description);
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
@ -189,9 +221,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
throw TradeNotFoundException(id, provider: description, description: error);
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['fromCurrency'] as String;
|
||||
|
@ -222,54 +253,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final isReverse = isReceiveAmount;
|
||||
final type = isReverse ? 'reverse' : 'direct';
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final params = <String, String>{
|
||||
'fromCurrency': _normalizeCurrency(from),
|
||||
'toCurrency': _normalizeCurrency(to),
|
||||
'fromNetwork': _networkFor(from),
|
||||
'toNetwork': _networkFor(to),
|
||||
'type': type,
|
||||
'flow': flow
|
||||
};
|
||||
|
||||
if (isReverse) {
|
||||
params['toAmount'] = amount.toString();
|
||||
} else {
|
||||
params['fromAmount'] = amount.toString();
|
||||
}
|
||||
|
||||
final uri = Uri.https(apiAuthority, estimatedAmountPath, params);
|
||||
final response = await get(uri, headers: headers);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromAmount = double.parse(responseJSON['fromAmount'].toString());
|
||||
final toAmount = double.parse(responseJSON['toAmount'].toString());
|
||||
final rateId = responseJSON['rateId'] as String? ?? '';
|
||||
|
||||
if (rateId.isNotEmpty) {
|
||||
_lastUsedRateId = rateId;
|
||||
}
|
||||
|
||||
return isReverse ? (amount / fromAmount) : (toAmount / amount);
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
String _getFlow(bool isFixedRate) => isFixedRate ? 'fixed-rate' : 'standard';
|
||||
|
||||
String _networkFor(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
|
@ -301,4 +285,4 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
return tag.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +1,43 @@
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
abstract class ExchangeProvider {
|
||||
ExchangeProvider({required this.pairList});
|
||||
|
||||
|
||||
String get title;
|
||||
|
||||
List<ExchangePair> pairList;
|
||||
|
||||
ExchangeProviderDescription get description;
|
||||
|
||||
bool get isAvailable;
|
||||
|
||||
bool get isEnabled;
|
||||
|
||||
bool get supportsFixedRate;
|
||||
|
||||
bool get supportsOnionAddress => false;
|
||||
|
||||
@override
|
||||
String toString() => title;
|
||||
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from, required CryptoCurrency to, required bool isFixedRateMode});
|
||||
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode});
|
||||
|
||||
Future<Trade> findTradeById({required String id});
|
||||
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode});
|
||||
Future<Trade> createTrade({
|
||||
required TradeRequest request,
|
||||
required bool isFixedRateMode});
|
||||
Future<Trade> findTradeById({required String id});
|
||||
Future<double> fetchRate({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount});
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount});
|
||||
|
||||
Future<bool> checkIsAvailable();
|
||||
}
|
|
@ -1,19 +1,19 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/exolix/exolix_request.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class ExolixExchangeProvider extends ExchangeProvider {
|
||||
ExolixExchangeProvider() : super(pairList: _supportedPairs());
|
||||
ExolixExchangeProvider() : super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
static final apiKey = secrets.exolixApiKey;
|
||||
static const apiBaseUrl = 'exolix.com';
|
||||
|
@ -40,16 +40,6 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
CryptoCurrency.weth,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
final supportedCurrencies =
|
||||
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList();
|
||||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
String get title => 'Exolix';
|
||||
|
||||
|
@ -68,15 +58,13 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
static String getRateType(bool isFixedRate) => isFixedRate ? 'fixed' : 'float';
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final params = <String, String>{
|
||||
'rateType': getRateType(isFixedRateMode),
|
||||
'rateType': _getRateType(isFixedRateMode),
|
||||
'amount': '1',
|
||||
};
|
||||
if (isFixedRateMode) {
|
||||
|
@ -93,35 +81,71 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
final uri = Uri.https(apiBaseUrl, ratePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
return Limits(min: responseJSON['minAmount'] as double?);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as ExolixRequest;
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) return 0.0;
|
||||
|
||||
final params = {
|
||||
'coinFrom': _normalizeCurrency(from),
|
||||
'coinTo': _normalizeCurrency(to),
|
||||
'networkFrom': _networkFor(from),
|
||||
'networkTo': _networkFor(to),
|
||||
'rateType': _getRateType(isFixedRateMode),
|
||||
'apiToken': apiKey,
|
||||
};
|
||||
|
||||
if (isReceiveAmount)
|
||||
params['withdrawalAmount'] = amount.toString();
|
||||
else
|
||||
params['amount'] = amount.toString();
|
||||
|
||||
final uri = Uri.https(apiBaseUrl, ratePath, params);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
final message = responseJSON['message'] as String?;
|
||||
throw Exception(message);
|
||||
}
|
||||
|
||||
return responseJSON['rate'] as double;
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = <String, dynamic>{
|
||||
'coinFrom': _normalizeCurrency(_request.from),
|
||||
'coinTo': _normalizeCurrency(_request.to),
|
||||
'networkFrom': _networkFor(_request.from),
|
||||
'networkTo': _networkFor(_request.to),
|
||||
'withdrawalAddress': _request.address,
|
||||
'refundAddress': _request.refundAddress,
|
||||
'rateType': getRateType(isFixedRateMode),
|
||||
final body = {
|
||||
'coinFrom': _normalizeCurrency(request.fromCurrency),
|
||||
'coinTo': _normalizeCurrency(request.toCurrency),
|
||||
'networkFrom': _networkFor(request.fromCurrency),
|
||||
'networkTo': _networkFor(request.toCurrency),
|
||||
'withdrawalAddress': request.toAddress,
|
||||
'refundAddress': request.refundAddress,
|
||||
'rateType': _getRateType(isFixedRateMode),
|
||||
'apiToken': apiKey,
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
body['withdrawalAmount'] = _request.toAmount;
|
||||
} else {
|
||||
body['amount'] = _request.fromAmount;
|
||||
}
|
||||
if (isFixedRateMode)
|
||||
body['withdrawalAmount'] = request.toAmount;
|
||||
else
|
||||
body['amount'] = request.fromAmount;
|
||||
|
||||
final uri = Uri.https(apiBaseUrl, transactionsPath);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
@ -133,9 +157,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
throw Exception(errorMessage);
|
||||
}
|
||||
|
||||
if (response.statusCode != 200 && response.statusCode != 201) {
|
||||
if (response.statusCode != 200 && response.statusCode != 201)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
|
@ -147,8 +170,8 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: refundAddress,
|
||||
|
@ -161,13 +184,11 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final findTradeByIdPath = transactionsPath + '/$id';
|
||||
final findTradeByIdPath = '$transactionsPath/$id';
|
||||
final uri = Uri.https(apiBaseUrl, findTradeByIdPath);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 404) {
|
||||
throw TradeNotFoundException(id, provider: description);
|
||||
}
|
||||
if (response.statusCode == 404) throw TradeNotFoundException(id, provider: description);
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
@ -177,80 +198,33 @@ class ExolixExchangeProvider extends ExchangeProvider {
|
|||
throw TradeNotFoundException(id, provider: description, description: errorMessage);
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final coinFrom = responseJSON['coinFrom']['coinCode'] as String;
|
||||
final from = CryptoCurrency.fromString(coinFrom);
|
||||
final coinTo = responseJSON['coinTo']['coinCode'] as String;
|
||||
final to = CryptoCurrency.fromString(coinTo);
|
||||
final inputAddress = responseJSON['depositAddress'] as String;
|
||||
final amount = responseJSON['amount'].toString();
|
||||
final status = responseJSON['status'] as String;
|
||||
final state = TradeState.deserialize(raw: _prepareStatus(status));
|
||||
final extraId = responseJSON['depositExtraId'] as String?;
|
||||
final outputTransaction = responseJSON['hashOut']['hash'] as String?;
|
||||
final payoutAddress = responseJSON['withdrawalAddress'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
from: CryptoCurrency.fromString(coinFrom),
|
||||
to: CryptoCurrency.fromString(coinTo),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: amount,
|
||||
state: state,
|
||||
state: TradeState.deserialize(raw: _prepareStatus(status)),
|
||||
extraId: extraId,
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
final params = <String, String>{
|
||||
'coinFrom': _normalizeCurrency(from),
|
||||
'coinTo': _normalizeCurrency(to),
|
||||
'networkFrom': _networkFor(from),
|
||||
'networkTo': _networkFor(to),
|
||||
'rateType': getRateType(isFixedRateMode),
|
||||
'apiToken': apiKey,
|
||||
};
|
||||
|
||||
if (isReceiveAmount) {
|
||||
params['withdrawalAmount'] = amount.toString();
|
||||
} else {
|
||||
params['amount'] = amount.toString();
|
||||
}
|
||||
|
||||
final uri = Uri.https(apiBaseUrl, ratePath, params);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
final message = responseJSON['message'] as String?;
|
||||
throw Exception(message);
|
||||
}
|
||||
|
||||
final rate = responseJSON['rate'] as double;
|
||||
|
||||
return rate;
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
String _getRateType(bool isFixedRate) => isFixedRate ? 'fixed' : 'float';
|
||||
|
||||
String _prepareStatus(String status) {
|
||||
switch (status) {
|
|
@ -1,28 +1,20 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/sideshift/sideshift_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class SideShiftExchangeProvider extends ExchangeProvider {
|
||||
SideShiftExchangeProvider() : super(pairList: _supportedPairs());
|
||||
|
||||
static const affiliateId = secrets.sideShiftAffiliateId;
|
||||
static const apiBaseUrl = 'https://sideshift.ai/api';
|
||||
static const rangePath = '/v2/pair';
|
||||
static const orderPath = '/v2/shifts';
|
||||
static const quotePath = '/v2/quotes';
|
||||
static const permissionPath = '/v2/permissions';
|
||||
SideShiftExchangeProvider() : super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.xhv,
|
||||
|
@ -39,49 +31,28 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
CryptoCurrency.eos,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
final supportedCurrencies =
|
||||
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList();
|
||||
static const affiliateId = secrets.sideShiftAffiliateId;
|
||||
static const apiBaseUrl = 'https://sideshift.ai/api';
|
||||
static const rangePath = '/v2/pair';
|
||||
static const orderPath = '/v2/shifts';
|
||||
static const quotePath = '/v2/quotes';
|
||||
static const permissionPath = '/v2/permissions';
|
||||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
@override
|
||||
String get title => 'SideShift';
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.sideShift;
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
final fromCurrency = from.title.toLowerCase();
|
||||
final toCurrency = to.title.toLowerCase();
|
||||
final depositNetwork = _networkFor(from);
|
||||
final settleNetwork = _networkFor(to);
|
||||
|
||||
final url = "$apiBaseUrl$rangePath/$fromCurrency-$depositNetwork/$toCurrency-$settleNetwork?amount=$amount";
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final rate = double.parse(responseJSON['rate'] as String);
|
||||
|
||||
return rate;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async {
|
||||
const url = apiBaseUrl + permissionPath;
|
||||
|
@ -95,110 +66,10 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
throw Exception('$error');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return false;
|
||||
}
|
||||
if (response.statusCode != 200) return false;
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final cancreateShift = responseJSON['createShift'] as bool;
|
||||
return cancreateShift;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as SideShiftRequest;
|
||||
String url = '';
|
||||
final depositCoin = request.depositMethod.title.toLowerCase();
|
||||
final settleCoin = request.settleMethod.title.toLowerCase();
|
||||
final body = {
|
||||
'affiliateId': affiliateId,
|
||||
'settleAddress': _request.settleAddress,
|
||||
'refundAddress': _request.refundAddress,
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
final quoteId = await _createQuote(_request);
|
||||
body['quoteId'] = quoteId;
|
||||
|
||||
url = apiBaseUrl + orderPath + '/fixed';
|
||||
} else {
|
||||
url = apiBaseUrl + orderPath + '/variable';
|
||||
final depositNetwork = _networkFor(request.depositMethod);
|
||||
final settleNetwork = _networkFor(request.settleMethod);
|
||||
body["depositCoin"] = depositCoin;
|
||||
body["settleCoin"] = settleCoin;
|
||||
body["settleNetwork"] = settleNetwork;
|
||||
body["depositNetwork"] = depositNetwork;
|
||||
}
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error']['message'] as String;
|
||||
|
||||
throw TradeNotCreatedException(description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
final inputAddress = responseJSON['depositAddress'] as String;
|
||||
final settleAddress = responseJSON['settleAddress'] as String;
|
||||
final depositAmount = responseJSON['depositAmount'] as String?;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
provider: description,
|
||||
from: _request.depositMethod,
|
||||
to: _request.settleMethod,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: settleAddress,
|
||||
state: TradeState.created,
|
||||
amount: depositAmount ?? _request.depositAmount,
|
||||
payoutAddress: settleAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<String> _createQuote(SideShiftRequest request) async {
|
||||
final url = apiBaseUrl + quotePath;
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final depositMethod = request.depositMethod.title.toLowerCase();
|
||||
final settleMethod = request.settleMethod.title.toLowerCase();
|
||||
final depositNetwork = _networkFor(request.depositMethod);
|
||||
final settleNetwork = _networkFor(request.settleMethod);
|
||||
final body = {
|
||||
'depositCoin': depositMethod,
|
||||
'settleCoin': settleMethod,
|
||||
'affiliateId': affiliateId,
|
||||
'settleAmount': request.depositAmount,
|
||||
'settleNetwork': settleNetwork,
|
||||
'depositNetwork': depositNetwork,
|
||||
};
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error']['message'] as String;
|
||||
|
||||
throw TradeNotCreatedException(description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final quoteId = responseJSON['id'] as String;
|
||||
|
||||
return quoteId;
|
||||
return responseJSON['createShift'] as bool;
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -244,6 +115,91 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) return 0.0;
|
||||
|
||||
final fromCurrency = from.title.toLowerCase();
|
||||
final toCurrency = to.title.toLowerCase();
|
||||
final depositNetwork = _networkFor(from);
|
||||
final settleNetwork = _networkFor(to);
|
||||
|
||||
final url =
|
||||
"$apiBaseUrl$rangePath/$fromCurrency-$depositNetwork/$toCurrency-$settleNetwork?amount=$amount";
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
return double.parse(responseJSON['rate'] as String);
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
String url = '';
|
||||
final body = {
|
||||
'affiliateId': affiliateId,
|
||||
'settleAddress': request.toAddress,
|
||||
'refundAddress': request.refundAddress,
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
final quoteId = await _createQuote(request);
|
||||
body['quoteId'] = quoteId;
|
||||
|
||||
url = apiBaseUrl + orderPath + '/fixed';
|
||||
} else {
|
||||
url = apiBaseUrl + orderPath + '/variable';
|
||||
body["depositCoin"] = request.fromCurrency.title.toLowerCase();
|
||||
body["settleCoin"] = request.toCurrency.title.toLowerCase();
|
||||
body["settleNetwork"] = _networkFor(request.toCurrency);
|
||||
body["depositNetwork"] = _networkFor(request.fromCurrency);
|
||||
}
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error']['message'] as String;
|
||||
|
||||
throw TradeNotCreatedException(description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
final inputAddress = responseJSON['depositAddress'] as String;
|
||||
final settleAddress = responseJSON['settleAddress'] as String;
|
||||
final depositAmount = responseJSON['depositAmount'] as String?;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
provider: description,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: settleAddress,
|
||||
state: TradeState.created,
|
||||
amount: depositAmount ?? request.fromAmount,
|
||||
payoutAddress: settleAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final url = apiBaseUrl + orderPath + '/' + id;
|
||||
|
@ -267,44 +223,56 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['depositCoin'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency);
|
||||
final toCurrency = responseJSON['settleCoin'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final inputAddress = responseJSON['depositAddress'] as String;
|
||||
final expectedSendAmount = responseJSON['depositAmount'] as String?;
|
||||
final status = responseJSON['status'] as String?;
|
||||
final settleAddress = responseJSON['settleAddress'] as String;
|
||||
TradeState? state;
|
||||
|
||||
state = TradeState.deserialize(raw: status ?? 'created');
|
||||
final isVariable = (responseJSON['type'] as String) == 'variable';
|
||||
|
||||
final expiredAtRaw = responseJSON['expiresAt'] as String;
|
||||
final expiredAt = isVariable ? null : DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
from: CryptoCurrency.fromString(fromCurrency),
|
||||
to: CryptoCurrency.fromString(toCurrency),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount ?? '',
|
||||
state: state,
|
||||
state: TradeState.deserialize(raw: status ?? 'created'),
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
Future<String> _createQuote(TradeRequest request) async {
|
||||
final url = apiBaseUrl + quotePath;
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final body = {
|
||||
'depositCoin': request.fromCurrency.title.toLowerCase(),
|
||||
'settleCoin': request.toCurrency.title.toLowerCase(),
|
||||
'affiliateId': affiliateId,
|
||||
'settleAmount': request.toAmount,
|
||||
'settleNetwork': _networkFor(request.toCurrency),
|
||||
'depositNetwork': _networkFor(request.fromCurrency),
|
||||
};
|
||||
final uri = Uri.parse(url);
|
||||
final response = await post(uri, headers: headers, body: json.encode(body));
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error']['message'] as String;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
throw TradeNotCreatedException(description, description: error);
|
||||
}
|
||||
|
||||
@override
|
||||
String get title => 'SideShift';
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
return responseJSON['id'] as String;
|
||||
}
|
||||
|
||||
String _networkFor(CryptoCurrency currency) =>
|
||||
currency.tag != null ? _normalizeTag(currency.tag!) : 'mainnet';
|
|
@ -1,71 +1,49 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/simpleswap/simpleswap_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exception.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class SimpleSwapExchangeProvider extends ExchangeProvider {
|
||||
SimpleSwapExchangeProvider()
|
||||
: super(
|
||||
pairList: CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((i) => CryptoCurrency.all
|
||||
.where((i) => i != CryptoCurrency.zaddr)
|
||||
.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList());
|
||||
SimpleSwapExchangeProvider() : super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.zaddr,
|
||||
CryptoCurrency.xhv,
|
||||
];
|
||||
|
||||
static final apiKey =
|
||||
DeviceInfo.instance.isMobile ? secrets.simpleSwapApiKey : secrets.simpleSwapApiKeyDesktop;
|
||||
static const apiAuthority = 'api.simpleswap.io';
|
||||
static const getEstimatePath = '/v1/get_estimated';
|
||||
static const rangePath = '/v1/get_ranges';
|
||||
static const getExchangePath = '/v1/get_exchange';
|
||||
static const createExchangePath = '/v1/create_exchange';
|
||||
static final apiKey = DeviceInfo.instance.isMobile ? secrets.simpleSwapApiKey : secrets.simpleSwapApiKeyDesktop;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.simpleSwap;
|
||||
String get title => 'SimpleSwap';
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'currency_from': fromCurrency,
|
||||
'currency_to': toCurrency,
|
||||
'amount': amount.toString(),
|
||||
'fixed': isFixedRateMode.toString()
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, getEstimatePath, params);
|
||||
final response = await get(uri);
|
||||
bool get isAvailable => true;
|
||||
|
||||
if (response.body == "null") return 0.00;
|
||||
final data = json.decode(response.body) as String;
|
||||
return double.parse(data) / amount;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.simpleSwap;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async {
|
||||
|
@ -76,20 +54,79 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as SimpleSwapRequest;
|
||||
final headers = {
|
||||
'Content-Type': 'application/json'};
|
||||
final params = <String, String>{
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final params = <String, dynamic>{
|
||||
'api_key': apiKey,
|
||||
'fixed': isFixedRateMode.toString(),
|
||||
'currency_from': _normalizeCurrency(from),
|
||||
'currency_to': _normalizeCurrency(to),
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, rangePath, params);
|
||||
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 500) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['message'] as String;
|
||||
|
||||
throw Exception('$error');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
||||
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
||||
|
||||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) return 0.0;
|
||||
|
||||
final params = {
|
||||
'api_key': apiKey,
|
||||
'currency_from': _normalizeCurrency(from),
|
||||
'currency_to': _normalizeCurrency(to),
|
||||
'amount': amount.toString(),
|
||||
'fixed': isFixedRateMode.toString()
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, getEstimatePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.body == "null") return 0.00;
|
||||
|
||||
final data = json.decode(response.body) as String;
|
||||
|
||||
return double.parse(data) / amount;
|
||||
} catch (_) {
|
||||
return 0.00;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final headers = {'Content-Type': 'application/json'};
|
||||
final params = {'api_key': apiKey};
|
||||
final body = <String, dynamic>{
|
||||
"currency_from": _normalizeCryptoCurrency(_request.from),
|
||||
"currency_to": _normalizeCryptoCurrency(_request.to),
|
||||
"amount": _request.amount,
|
||||
"currency_from": _normalizeCurrency(request.fromCurrency),
|
||||
"currency_to": _normalizeCurrency(request.toCurrency),
|
||||
"amount": request.fromAmount,
|
||||
"fixed": isFixedRateMode,
|
||||
"user_refund_address": _request.refundAddress,
|
||||
"address_to": _request.address
|
||||
"user_refund_address": request.refundAddress,
|
||||
"address_to": request.toAddress
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, createExchangePath, params);
|
||||
|
||||
|
@ -112,56 +149,22 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final payoutAddress = responseJSON['address_to'] as String;
|
||||
final settleAddress = responseJSON['user_refund_address'] as String;
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
provider: description,
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: settleAddress,
|
||||
extraId: extraId,
|
||||
state: TradeState.created,
|
||||
amount: _request.amount,
|
||||
amount: request.fromAmount,
|
||||
payoutAddress: payoutAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final fromCurrency = _normalizeCryptoCurrency(from);
|
||||
final toCurrency = _normalizeCryptoCurrency(to);
|
||||
final params = <String, dynamic>{
|
||||
'api_key': apiKey,
|
||||
'fixed': isFixedRateMode.toString(),
|
||||
'currency_from': fromCurrency,
|
||||
'currency_to': toCurrency,
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, rangePath, params);
|
||||
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 500) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['message'] as String;
|
||||
|
||||
throw Exception('$error');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final min = double.tryParse(responseJSON['min'] as String? ?? '');
|
||||
final max = double.tryParse(responseJSON['max'] as String? ?? '');
|
||||
|
||||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final params = {'api_key': apiKey, 'id': id};
|
||||
|
@ -185,42 +188,27 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final fromCurrency = responseJSON['currency_from'] as String;
|
||||
final from = CryptoCurrency.fromString(fromCurrency);
|
||||
final toCurrency = responseJSON['currency_to'] as String;
|
||||
final to = CryptoCurrency.fromString(toCurrency);
|
||||
final inputAddress = responseJSON['address_from'] as String;
|
||||
final expectedSendAmount = responseJSON['expected_amount'].toString();
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
final status = responseJSON['status'] as String;
|
||||
final payoutAddress = responseJSON['address_to'] as String;
|
||||
final state = TradeState.deserialize(raw: status);
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
from: CryptoCurrency.fromString(fromCurrency),
|
||||
to: CryptoCurrency.fromString(toCurrency),
|
||||
extraId: extraId,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
state: TradeState.deserialize(raw: status),
|
||||
payoutAddress: payoutAddress,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
String get title => 'SimpleSwap';
|
||||
|
||||
static String _normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
static String _normalizeCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zaddr:
|
||||
return 'zec';
|
|
@ -1,21 +1,20 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/trocador/trocador_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/provider/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/utils/currency_pairs_utils.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:http/http.dart';
|
||||
|
||||
class TrocadorExchangeProvider extends ExchangeProvider {
|
||||
TrocadorExchangeProvider({this.useTorOnly = false})
|
||||
: _lastUsedRateId = '',
|
||||
super(pairList: _supportedPairs());
|
||||
super(pairList: supportedPairs(_notSupported));
|
||||
|
||||
bool useTorOnly;
|
||||
|
||||
|
@ -24,135 +23,58 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
CryptoCurrency.zaddr,
|
||||
];
|
||||
|
||||
static List<ExchangePair> _supportedPairs() {
|
||||
final supportedCurrencies =
|
||||
CryptoCurrency.all.where((element) => !_notSupported.contains(element)).toList();
|
||||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
||||
|
||||
static const apiKey = secrets.trocadorApiKey;
|
||||
static const onionApiAuthority = 'trocadorfyhlu27aefre5u7zri66gudtzdyelymftvr4yjwcxhfaqsid.onion';
|
||||
static const clearNetAuthority = 'trocador.app';
|
||||
static const apiKey = secrets.trocadorApiKey;
|
||||
static const markup = secrets.trocadorExchangeMarkup;
|
||||
static const newRatePath = '/api/new_rate';
|
||||
static const createTradePath = 'api/new_trade';
|
||||
static const tradePath = 'api/trade';
|
||||
static const coinPath = 'api/coin';
|
||||
|
||||
String _lastUsedRateId;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
String get title => 'Trocador';
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) {
|
||||
final _request = request as TrocadorRequest;
|
||||
return _createTrade(request: _request, isFixedRateMode: isFixedRateMode);
|
||||
}
|
||||
bool get isAvailable => true;
|
||||
|
||||
Future<Trade> _createTrade({
|
||||
required TrocadorRequest request,
|
||||
required bool isFixedRateMode,
|
||||
}) async {
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'ticker_from': _normalizeCurrency(request.from),
|
||||
'ticker_to': _normalizeCurrency(request.to),
|
||||
'network_from': _networkFor(request.from),
|
||||
'network_to': _networkFor(request.to),
|
||||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
'min_kycrating': 'C',
|
||||
'markup': markup,
|
||||
'best_only': 'True',
|
||||
if (!isFixedRateMode) 'amount_from': request.fromAmount,
|
||||
if (isFixedRateMode) 'amount_to': request.toAmount,
|
||||
'address': request.address,
|
||||
'refund': request.refundAddress
|
||||
};
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
if (isFixedRateMode) {
|
||||
await fetchRate(
|
||||
from: request.from,
|
||||
to: request.to,
|
||||
amount: double.tryParse(request.toAmount) ?? 0,
|
||||
isFixedRateMode: true,
|
||||
isReceiveAmount: true,
|
||||
);
|
||||
params['id'] = _lastUsedRateId;
|
||||
}
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
final uri = await _getUri(createTradePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error'] as String;
|
||||
final message = responseJSON['message'] as String;
|
||||
throw Exception('${error}\n$message');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['trade_id'] as String;
|
||||
final inputAddress = responseJSON['address_provider'] as String;
|
||||
final refundAddress = responseJSON['refund_address'] as String;
|
||||
final status = responseJSON['status'] as String;
|
||||
final state = TradeState.deserialize(raw: status);
|
||||
final payoutAddress = responseJSON['address_user'] as String;
|
||||
final date = responseJSON['date'] as String;
|
||||
final password = responseJSON['password'] as String;
|
||||
final providerId = responseJSON['id_provider'] as String;
|
||||
final providerName = responseJSON['provider'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: request.from,
|
||||
to: request.to,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: refundAddress,
|
||||
state: state,
|
||||
password: password,
|
||||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
createdAt: DateTime.tryParse(date)?.toLocal(),
|
||||
amount: responseJSON['amount_from']?.toString() ?? request.fromAmount,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
@override
|
||||
bool get supportsOnionAddress => true;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description => ExchangeProviderDescription.trocador;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async => true;
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final params = <String, String>{
|
||||
final params = {
|
||||
'api_key': apiKey,
|
||||
'ticker': _normalizeCurrency(from),
|
||||
'name': from.name,
|
||||
};
|
||||
|
||||
final uri = await _getUri(coinPath, params);
|
||||
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as List<dynamic>;
|
||||
|
||||
if (responseJSON.isEmpty) {
|
||||
throw Exception('No data');
|
||||
}
|
||||
if (responseJSON.isEmpty) throw Exception('No data');
|
||||
|
||||
final coinJson = responseJSON.first as Map<String, dynamic>;
|
||||
|
||||
|
@ -170,9 +92,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
try {
|
||||
if (amount == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
if (amount == 0) return 0.0;
|
||||
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
|
@ -195,9 +115,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
final toAmount = double.parse(responseJSON['amount_to'].toString());
|
||||
final rateId = responseJSON['trade_id'] as String? ?? '';
|
||||
|
||||
if (rateId.isNotEmpty) {
|
||||
_lastUsedRateId = rateId;
|
||||
}
|
||||
if (rateId.isNotEmpty) _lastUsedRateId = rateId;
|
||||
|
||||
return isReceiveAmount ? (amount / fromAmount) : (toAmount / amount);
|
||||
} catch (e) {
|
||||
|
@ -206,40 +124,103 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final params = {
|
||||
'api_key': apiKey,
|
||||
'ticker_from': _normalizeCurrency(request.fromCurrency),
|
||||
'ticker_to': _normalizeCurrency(request.toCurrency),
|
||||
'network_from': _networkFor(request.fromCurrency),
|
||||
'network_to': _networkFor(request.toCurrency),
|
||||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
'min_kycrating': 'C',
|
||||
'markup': markup,
|
||||
'best_only': 'True',
|
||||
if (!isFixedRateMode) 'amount_from': request.fromAmount,
|
||||
if (isFixedRateMode) 'amount_to': request.toAmount,
|
||||
'address': request.toAddress,
|
||||
'refund': request.refundAddress
|
||||
};
|
||||
|
||||
if (isFixedRateMode) {
|
||||
await fetchRate(
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
amount: double.tryParse(request.toAmount) ?? 0,
|
||||
isFixedRateMode: true,
|
||||
isReceiveAmount: true,
|
||||
);
|
||||
params['id'] = _lastUsedRateId;
|
||||
}
|
||||
|
||||
final uri = await _getUri(createTradePath, params);
|
||||
final response = await get(uri);
|
||||
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error'] as String;
|
||||
final message = responseJSON['message'] as String;
|
||||
throw Exception('${error}\n$message');
|
||||
}
|
||||
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['trade_id'] as String;
|
||||
final inputAddress = responseJSON['address_provider'] as String;
|
||||
final refundAddress = responseJSON['refund_address'] as String;
|
||||
final status = responseJSON['status'] as String;
|
||||
final payoutAddress = responseJSON['address_user'] as String;
|
||||
final date = responseJSON['date'] as String;
|
||||
final password = responseJSON['password'] as String;
|
||||
final providerId = responseJSON['id_provider'] as String;
|
||||
final providerName = responseJSON['provider'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: request.fromCurrency,
|
||||
to: request.toCurrency,
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: refundAddress,
|
||||
state: TradeState.deserialize(raw: status),
|
||||
password: password,
|
||||
providerId: providerId,
|
||||
providerName: providerName,
|
||||
createdAt: DateTime.tryParse(date)?.toLocal(),
|
||||
amount: responseJSON['amount_from']?.toString() ?? request.fromAmount,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final uri = await _getUri(tradePath, {'api_key': apiKey, 'id': id});
|
||||
return get(uri).then((response) {
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode != 200)
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
|
||||
final responseListJson = json.decode(response.body) as List;
|
||||
|
||||
final responseJSON = responseListJson.first;
|
||||
final id = responseJSON['trade_id'] as String;
|
||||
final payoutAddress = responseJSON['address_user'] as String;
|
||||
final refundAddress = responseJSON['refund_address'] as String;
|
||||
final inputAddress = responseJSON['address_provider'] as String;
|
||||
final fromAmount = responseJSON['amount_from']?.toString() ?? '0';
|
||||
final from = CryptoCurrency.fromString(responseJSON['ticker_from'] as String);
|
||||
final to = CryptoCurrency.fromString(responseJSON['ticker_to'] as String);
|
||||
final state = TradeState.deserialize(raw: responseJSON['status'] as String);
|
||||
final date = DateTime.parse(responseJSON['date'] as String);
|
||||
final password = responseJSON['password'] as String;
|
||||
final providerId = responseJSON['id_provider'] as String;
|
||||
final providerName = responseJSON['provider'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
from: from,
|
||||
to: to,
|
||||
from: CryptoCurrency.fromString(responseJSON['ticker_from'] as String),
|
||||
to: CryptoCurrency.fromString(responseJSON['ticker_to'] as String),
|
||||
provider: description,
|
||||
inputAddress: inputAddress,
|
||||
refundAddress: refundAddress,
|
||||
createdAt: date,
|
||||
createdAt: DateTime.parse(responseJSON['date'] as String),
|
||||
amount: fromAmount,
|
||||
state: state,
|
||||
state: TradeState.deserialize(raw: responseJSON['status'] as String),
|
||||
payoutAddress: payoutAddress,
|
||||
password: password,
|
||||
providerId: providerId,
|
||||
|
@ -248,21 +229,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
});
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isAvailable => true;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => true;
|
||||
|
||||
@override
|
||||
bool get supportsOnionAddress => true;
|
||||
|
||||
@override
|
||||
String get title => 'Trocador';
|
||||
|
||||
String _networkFor(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.eth:
|
||||
|
@ -301,15 +267,9 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
|
||||
Future<Uri> _getUri(String path, Map<String, String> queryParams) async {
|
||||
if (!supportsOnionAddress) {
|
||||
return Uri.https(clearNetAuthority, path, queryParams);
|
||||
}
|
||||
|
||||
final uri = Uri.http(onionApiAuthority, path, queryParams);
|
||||
|
||||
if (useTorOnly) {
|
||||
return uri;
|
||||
}
|
||||
if (useTorOnly) return uri;
|
||||
|
||||
try {
|
||||
await get(uri);
|
|
@ -1,17 +0,0 @@
|
|||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class SideShiftRequest extends TradeRequest {
|
||||
SideShiftRequest(
|
||||
{required this.depositMethod,
|
||||
required this.settleMethod,
|
||||
required this.depositAmount,
|
||||
required this.settleAddress,
|
||||
required this.refundAddress});
|
||||
|
||||
final CryptoCurrency depositMethod;
|
||||
final CryptoCurrency settleMethod;
|
||||
final String depositAmount;
|
||||
final String settleAddress;
|
||||
final String refundAddress;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SimpleSwapRequest extends TradeRequest {
|
||||
SimpleSwapRequest({
|
||||
required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.amount,
|
||||
required this.refundAddress,
|
||||
this.toAmount = ''
|
||||
});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
String address;
|
||||
String amount;
|
||||
String toAmount;
|
||||
String refundAddress;
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/format_amount.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
@ -27,19 +27,15 @@ class Trade extends HiveObject {
|
|||
this.password,
|
||||
this.providerId,
|
||||
this.providerName,
|
||||
this.fromWalletAddress
|
||||
}) {
|
||||
if (provider != null) {
|
||||
providerRaw = provider.raw;
|
||||
}
|
||||
if (from != null) {
|
||||
fromRaw = from.raw;
|
||||
}
|
||||
if (to != null) {
|
||||
toRaw = to.raw;
|
||||
}
|
||||
if (state != null) {
|
||||
stateRaw = state.raw;
|
||||
}
|
||||
if (provider != null) providerRaw = provider.raw;
|
||||
|
||||
if (from != null) fromRaw = from.raw;
|
||||
|
||||
if (to != null) toRaw = to.raw;
|
||||
|
||||
if (state != null) stateRaw = state.raw;
|
||||
}
|
||||
|
||||
static const typeId = TRADE_TYPE_ID;
|
||||
|
@ -106,6 +102,9 @@ class Trade extends HiveObject {
|
|||
@HiveField(16)
|
||||
String? providerName;
|
||||
|
||||
@HiveField(17)
|
||||
String? fromWalletAddress;
|
||||
|
||||
static Trade fromMap(Map<String, Object?> map) {
|
||||
return Trade(
|
||||
id: map['id'] as String,
|
||||
|
@ -115,7 +114,9 @@ class Trade extends HiveObject {
|
|||
createdAt:
|
||||
map['date'] != null ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int) : null,
|
||||
amount: map['amount'] as String,
|
||||
walletId: map['wallet_id'] as String);
|
||||
walletId: map['wallet_id'] as String,
|
||||
fromWalletAddress: map['from_wallet_address'] as String?
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
|
@ -126,7 +127,8 @@ class Trade extends HiveObject {
|
|||
'output': to.serialize(),
|
||||
'date': createdAt != null ? createdAt!.millisecondsSinceEpoch : null,
|
||||
'amount': amount,
|
||||
'wallet_id': walletId
|
||||
'wallet_id': walletId,
|
||||
'from_wallet_address': fromWalletAddress
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -8,12 +8,5 @@ class TradeNotCreatedException implements Exception {
|
|||
String description;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var text = provider != null
|
||||
? S.current.trade_for_not_created(provider.title)
|
||||
: S.current.trade_not_created;
|
||||
text += ' $description';
|
||||
|
||||
return text;
|
||||
}
|
||||
String toString() => '${S.current.trade_for_not_created(provider.title)} $description';
|
||||
}
|
13
lib/exchange/trade_not_found_exception.dart
Normal file
|
@ -0,0 +1,13 @@
|
|||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class TradeNotFoundException implements Exception {
|
||||
TradeNotFoundException(this.tradeId, {required this.provider, this.description = ''});
|
||||
|
||||
String tradeId;
|
||||
ExchangeProviderDescription provider;
|
||||
String description;
|
||||
|
||||
@override
|
||||
String toString() => '${S.current.trade_id_not_found(tradeId, provider.title)} $description';
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class TradeNotFoundException implements Exception {
|
||||
TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
|
||||
|
||||
String? tradeId;
|
||||
ExchangeProviderDescription? provider;
|
||||
String description;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
var text = tradeId != null && provider != null
|
||||
? S.current.trade_id_not_found(tradeId!, provider!.title)
|
||||
: S.current.trade_not_found;
|
||||
text += ' $description';
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
|
@ -1 +1,20 @@
|
|||
abstract class TradeRequest {}
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class TradeRequest {
|
||||
TradeRequest(
|
||||
{required this.fromCurrency,
|
||||
required this.toCurrency,
|
||||
required this.toAddress,
|
||||
required this.refundAddress,
|
||||
required this.fromAmount,
|
||||
this.toAmount = '',
|
||||
this.isFixedRate = false});
|
||||
|
||||
final CryptoCurrency fromCurrency;
|
||||
final CryptoCurrency toCurrency;
|
||||
final String toAddress;
|
||||
final String refundAddress;
|
||||
final String fromAmount;
|
||||
final String toAmount;
|
||||
final bool isFixedRate;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/enumerable_item.dart';
|
||||
|
||||
class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||
const TradeState({required String raw, required String title})
|
||||
: super(raw: raw, title: title);
|
||||
const TradeState({required String raw, required String title}) : super(raw: raw, title: title);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => other is TradeState && other.raw == raw;
|
||||
|
@ -13,12 +11,10 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
static const trading = TradeState(raw: 'trading', title: 'Trading');
|
||||
static const traded = TradeState(raw: 'traded', title: 'Traded');
|
||||
static const complete = TradeState(raw: 'complete', title: 'Complete');
|
||||
static const toBeCreated =
|
||||
TradeState(raw: 'TO_BE_CREATED', title: 'To be created');
|
||||
static const toBeCreated = TradeState(raw: 'TO_BE_CREATED', title: 'To be created');
|
||||
static const unpaid = TradeState(raw: 'UNPAID', title: 'Unpaid');
|
||||
static const underpaid = TradeState(raw: 'UNDERPAID', title: 'Underpaid');
|
||||
static const paidUnconfirmed =
|
||||
TradeState(raw: 'PAID_UNCONFIRMED', title: 'Paid unconfirmed');
|
||||
static const paidUnconfirmed = TradeState(raw: 'PAID_UNCONFIRMED', title: 'Paid unconfirmed');
|
||||
static const paid = TradeState(raw: 'PAID', title: 'Paid');
|
||||
static const btcSent = TradeState(raw: 'BTC_SENT', title: 'Btc sent');
|
||||
static const timeout = TradeState(raw: 'TIMED_OUT', title: 'Timeout');
|
||||
|
@ -27,8 +23,7 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
|||
static const finished = TradeState(raw: 'finished', title: 'Finished');
|
||||
static const waiting = TradeState(raw: 'waiting', title: 'Waiting');
|
||||
static const processing = TradeState(raw: 'processing', title: 'Processing');
|
||||
static const waitingPayment =
|
||||
TradeState(raw: 'waitingPayment', title: 'Waiting payment');
|
||||
static const waitingPayment = TradeState(raw: 'waitingPayment', title: 'Waiting payment');
|
||||
static const waitingAuthorization =
|
||||
TradeState(raw: 'waitingAuthorization', title: 'Waiting authorization');
|
||||
static const failed = TradeState(raw: 'failed', title: 'Failed');
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
class TrocadorRequest extends TradeRequest {
|
||||
TrocadorRequest(
|
||||
{required this.from,
|
||||
required this.to,
|
||||
required this.address,
|
||||
required this.fromAmount,
|
||||
required this.toAmount,
|
||||
required this.refundAddress,
|
||||
required this.isReverse});
|
||||
|
||||
CryptoCurrency from;
|
||||
CryptoCurrency to;
|
||||
String address;
|
||||
String fromAmount;
|
||||
String toAmount;
|
||||
String refundAddress;
|
||||
bool isReverse;
|
||||
}
|
12
lib/exchange/utils/currency_pairs_utils.dart
Normal file
|
@ -0,0 +1,12 @@
|
|||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
||||
List<ExchangePair> supportedPairs(List<CryptoCurrency> notSupported) {
|
||||
final supportedCurrencies =
|
||||
CryptoCurrency.all.where((element) => !notSupported.contains(element)).toList();
|
||||
|
||||
return supportedCurrencies
|
||||
.map((i) => supportedCurrencies.map((k) => ExchangePair(from: i, to: k, reverse: true)))
|
||||
.expand((i) => i)
|
||||
.toList();
|
||||
}
|
|
@ -1,236 +0,0 @@
|
|||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_pair.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider.dart';
|
||||
import 'package:cake_wallet/exchange/limits.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cake_wallet/exchange/trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_state.dart';
|
||||
import 'package:cake_wallet/exchange/xmrto/xmrto_trade_request.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
|
||||
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
|
||||
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class XMRTOExchangeProvider extends ExchangeProvider {
|
||||
XMRTOExchangeProvider()
|
||||
: _isAvailable = false,
|
||||
super(pairList: [
|
||||
ExchangePair(
|
||||
from: CryptoCurrency.xmr, to: CryptoCurrency.btc, reverse: false)
|
||||
]);
|
||||
|
||||
static const userAgent = 'CakeWallet/XMR iOS';
|
||||
static const originalApiUri = 'https://xmr.to/api/v3/xmr2btc';
|
||||
static const _orderParameterUriSuffix = '/order_parameter_query';
|
||||
static const _orderStatusUriSuffix = '/order_status_query/';
|
||||
static const _orderCreateUriSuffix = '/order_create/';
|
||||
static const _headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'User-Agent': userAgent
|
||||
};
|
||||
|
||||
static Future<bool> _checkIsAvailable() async {
|
||||
const url = originalApiUri + _orderParameterUriSuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri, headers: _headers);
|
||||
return !(response.statusCode == 403);
|
||||
}
|
||||
|
||||
@override
|
||||
String get title => 'XMR.TO';
|
||||
|
||||
@override
|
||||
bool get isAvailable => _isAvailable;
|
||||
|
||||
@override
|
||||
bool get isEnabled => true;
|
||||
|
||||
@override
|
||||
bool get supportsFixedRate => false;
|
||||
|
||||
@override
|
||||
ExchangeProviderDescription get description =>
|
||||
ExchangeProviderDescription.xmrto;
|
||||
|
||||
double _rate = 0;
|
||||
bool _isAvailable;
|
||||
|
||||
@override
|
||||
Future<bool> checkIsAvailable() async {
|
||||
_isAvailable = await _checkIsAvailable();
|
||||
return isAvailable;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Limits> fetchLimits({
|
||||
required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final url = originalApiUri + _orderParameterUriSuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri);
|
||||
final correction = 0.001;
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
return Limits(min: 0, max: 0);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
double min = double.parse(responseJSON['lower_limit'] as String);
|
||||
double max = double.parse(responseJSON['upper_limit'] as String);
|
||||
final price = double.parse(responseJSON['price'] as String);
|
||||
|
||||
if (price > 0) {
|
||||
try {
|
||||
min = min / price + correction;
|
||||
min = _limitsFormat(min);
|
||||
max = max / price - correction;
|
||||
max = _limitsFormat(max);
|
||||
} catch (e) {
|
||||
min = 0;
|
||||
max = 0;
|
||||
}
|
||||
} else {
|
||||
min = 0;
|
||||
max = 0;
|
||||
}
|
||||
|
||||
return Limits(min: min, max: max);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> createTrade({required TradeRequest request, required bool isFixedRateMode}) async {
|
||||
final _request = request as XMRTOTradeRequest;
|
||||
final url = originalApiUri + _orderCreateUriSuffix;
|
||||
final _amount =
|
||||
_request.isBTCRequest ? _request.receiveAmount : _request.amount;
|
||||
final _amountCurrency = _request.isBTCRequest
|
||||
? _request.to.toString()
|
||||
: _request.from.toString();
|
||||
final pattern = '^([0-9]+([.\,][0-9]{0,8})?|[.\,][0-9]{1,8})\$';
|
||||
final isValid = RegExp(pattern).hasMatch(_amount);
|
||||
|
||||
if (!isValid) {
|
||||
throw TradeNotCreatedException(description,
|
||||
description: S.current.xmr_to_error_description);
|
||||
}
|
||||
|
||||
final body = {
|
||||
'amount': _amount,
|
||||
'amount_currency': _amountCurrency,
|
||||
'btc_dest_address': _request.address};
|
||||
final uri = Uri.parse(url);
|
||||
final response =
|
||||
await post(uri, headers: _headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 201) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error_msg'] as String;
|
||||
|
||||
throw TradeNotCreatedException(description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotCreatedException(description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final uuid = responseJSON["uuid"] as String;
|
||||
|
||||
return Trade(
|
||||
id: uuid,
|
||||
provider: description,
|
||||
from: _request.from,
|
||||
to: _request.to,
|
||||
state: TradeState.created,
|
||||
amount: _request.amount,
|
||||
createdAt: DateTime.now());
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Trade> findTradeById({required String id}) async {
|
||||
final url = originalApiUri + _orderStatusUriSuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final body = {'uuid': id};
|
||||
final response =
|
||||
await post(uri, headers: _headers, body: json.encode(body));
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
if (response.statusCode == 400) {
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final error = responseJSON['error_msg'] as String;
|
||||
|
||||
throw TradeNotFoundException(id,
|
||||
provider: description, description: error);
|
||||
}
|
||||
|
||||
throw TradeNotFoundException(id, provider: description);
|
||||
}
|
||||
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final address = responseJSON['receiving_subaddress'] as String;
|
||||
final paymentId = responseJSON['xmr_required_payment_id_short'] as String;
|
||||
final amount = responseJSON['incoming_amount_total'].toString();
|
||||
final stateRaw = responseJSON['state'] as String;
|
||||
final expiredAtRaw = responseJSON['expires_at'] as String;
|
||||
final expiredAt = DateTime.parse(expiredAtRaw).toLocal();
|
||||
final outputTransaction = responseJSON['btc_transaction_id'] as String;
|
||||
final state = TradeState.deserialize(raw: stateRaw);
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
provider: description,
|
||||
from: CryptoCurrency.xmr,
|
||||
to: CryptoCurrency.btc,
|
||||
inputAddress: address,
|
||||
extraId: paymentId,
|
||||
expiredAt: expiredAt,
|
||||
amount: amount,
|
||||
state: state,
|
||||
outputTransaction: outputTransaction);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> fetchRate(
|
||||
{required CryptoCurrency from,
|
||||
required CryptoCurrency to,
|
||||
required double amount,
|
||||
required bool isFixedRateMode,
|
||||
required bool isReceiveAmount}) async {
|
||||
if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (_rate == 0) {
|
||||
_rate = await _fetchRates();
|
||||
}
|
||||
|
||||
final double result = isReceiveAmount
|
||||
? _rate == 0
|
||||
? 0
|
||||
: amount / _rate
|
||||
: _rate * amount;
|
||||
|
||||
return double.parse(result.toStringAsFixed(12));
|
||||
}
|
||||
|
||||
Future<double> _fetchRates() async {
|
||||
try {
|
||||
final url = originalApiUri + _orderParameterUriSuffix;
|
||||
final uri = Uri.parse(url);
|
||||
final response = await get(uri, headers: _headers);
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final price = double.parse(responseJSON['price'] as String);
|
||||
|
||||
return price;
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
double _limitsFormat(double limit) => double.parse(limit.toStringAsFixed(3));
|
||||
}
|